Unverified Commit eed9e970 authored by Jonas Devlieghere's avatar Jonas Devlieghere Committed by GitHub
Browse files

[lldb] Highlight matching keywords in apropos output (#194997)

When color is enabled, `apropos` now highlights occurrences of the
search term in both command names/help text and settings descriptions
using the configurable regex match ANSI settings.

Implements #194877
parent 9a625ab4
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -449,12 +449,14 @@ public:

  void GetAliasHelp(const char *alias_name, StreamString &help_string);

  void OutputFormattedHelpText(Stream &strm, llvm::StringRef prefix,
                               llvm::StringRef help_text);

  void OutputFormattedHelpText(Stream &stream, llvm::StringRef command_word,
                               llvm::StringRef separator,
                               llvm::StringRef help_text, size_t max_word_len);
  void OutputFormattedHelpText(
      Stream &strm, llvm::StringRef prefix, llvm::StringRef help_text,
      std::optional<Stream::HighlightSettings> highlight = std::nullopt);

  void OutputFormattedHelpText(
      Stream &stream, llvm::StringRef command_word, llvm::StringRef separator,
      llvm::StringRef help_text, size_t max_word_len,
      std::optional<Stream::HighlightSettings> highlight = std::nullopt);

  // this mimics OutputFormattedHelpText but it does perform a much simpler
  // formatting, basically ensuring line alignment. This is only good if you
+6 −3
Original line number Diff line number Diff line
@@ -11,9 +11,11 @@

#include "lldb/Interpreter/OptionValue.h"
#include "lldb/Utility/Flags.h"
#include "lldb/Utility/Stream.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-private-types.h"

#include <optional>
#include <string>

namespace lldb_private {
@@ -60,9 +62,10 @@ public:

  bool DumpQualifiedName(Stream &strm) const;

  void DumpDescription(CommandInterpreter &interpreter, Stream &strm,
                       uint32_t output_width,
                       bool display_qualified_name) const;
  void DumpDescription(
      CommandInterpreter &interpreter, Stream &strm, uint32_t output_width,
      bool display_qualified_name,
      std::optional<Stream::HighlightSettings> highlight = std::nullopt) const;

  void SetValueChangedCallback(std::function<void()> callback);

+3 −2
Original line number Diff line number Diff line
@@ -38,10 +38,11 @@ public:
    llvm::StringRef pattern; ///< Regex pattern for highlighting.
    llvm::StringRef prefix;  ///< ANSI color code to start colorization.
    llvm::StringRef suffix;  ///< ANSI color code to end colorization.
    bool ignore_case = false; ///< Whether to match case-insensitively.

    HighlightSettings(llvm::StringRef p, llvm::StringRef pre,
                      llvm::StringRef suf)
        : pattern(p), prefix(pre), suffix(suf) {}
                      llvm::StringRef suf, bool ic = false)
        : pattern(p), prefix(pre), suffix(suf), ignore_case(ic) {}
  };

  /// Utility class for counting the bytes that were written to a stream in a
+14 −2
Original line number Diff line number Diff line
@@ -7,11 +7,13 @@
//===----------------------------------------------------------------------===//

#include "CommandObjectApropos.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/Property.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/Support/Regex.h"

using namespace lldb;
using namespace lldb_private;
@@ -35,6 +37,15 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
    if (!search_word.empty()) {
      ReturnStatus return_status = eReturnStatusSuccessFinishNoResult;

      std::string escaped_search_word;
      std::optional<Stream::HighlightSettings> highlight;
      Debugger &dbg = GetDebugger();
      if (dbg.GetUseColor()) {
        escaped_search_word = llvm::Regex::escape(search_word);
        highlight.emplace(escaped_search_word, dbg.GetRegexMatchAnsiPrefix(),
                          dbg.GetRegexMatchAnsiSuffix(), true);
      }

      // Find all commands matching the search word.
      StringList commands_found;
      StringList commands_help;
@@ -54,7 +65,8 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
        for (size_t i = 0; i < commands_found.GetSize(); ++i)
          m_interpreter.OutputFormattedHelpText(
              result.GetOutputStream(), commands_found.GetStringAtIndex(i),
              "--", commands_help.GetStringAtIndex(i), commands_max_len);
              "--", commands_help.GetStringAtIndex(i), commands_max_len,
              highlight);
        return_status = eReturnStatusSuccessFinishResult;
      }

@@ -86,7 +98,7 @@ void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
        for (size_t i = 0; i < num_properties; ++i)
          properties[i]->DumpDescription(
              m_interpreter, result.GetOutputStream(), properties_max_len,
              dump_qualified_name);
              dump_qualified_name, highlight);
        return_status = eReturnStatusSuccessFinishResult;
      }

+20 −10
Original line number Diff line number Diff line
@@ -3100,15 +3100,25 @@ void CommandInterpreter::SetSynchronous(bool value) {
  m_synchronous_execution = value;
}

void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
                                                 llvm::StringRef prefix,
                                                 llvm::StringRef help_text) {
void CommandInterpreter::OutputFormattedHelpText(
    Stream &strm, llvm::StringRef prefix, llvm::StringRef help_text,
    std::optional<Stream::HighlightSettings> highlight) {
  const uint32_t max_columns = m_debugger.GetTerminalWidth();

  size_t line_width_max = max_columns - prefix.size();
  if (line_width_max < 16)
    line_width_max = help_text.size() + prefix.size();

  // Apply highlighting to the full text before line splitting so that matches
  // spanning a line break are highlighted on both lines.
  std::string highlighted_storage;
  if (highlight) {
    StreamString ss;
    ss.PutCStringColorHighlighted(help_text, highlight);
    highlighted_storage = std::string(ss.GetString());
    help_text = highlighted_storage;
  }

  strm.IndentMore(prefix.size());
  bool prefixed_yet = false;
  // Even if we have no help text we still want to emit the command name.
@@ -3117,7 +3127,7 @@ void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
  while (!help_text.empty()) {
    // Prefix the first line, indent subsequent lines to line up
    if (!prefixed_yet) {
      strm << prefix;
      strm.PutCStringColorHighlighted(prefix, highlight);
      prefixed_yet = true;
    } else
      strm.Indent();
@@ -3144,15 +3154,15 @@ void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
  strm.IndentLess(prefix.size());
}

void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
                                                 llvm::StringRef word_text,
                                                 llvm::StringRef separator,
                                                 llvm::StringRef help_text,
                                                 size_t max_word_len) {
void CommandInterpreter::OutputFormattedHelpText(
    Stream &strm, llvm::StringRef word_text, llvm::StringRef separator,
    llvm::StringRef help_text, size_t max_word_len,
    std::optional<Stream::HighlightSettings> highlight) {
  StreamString prefix_stream;
  prefix_stream.Printf("  %-*s %*s ", (int)max_word_len, word_text.data(),
                       (int)separator.size(), separator.data());
  OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
  OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text,
                          highlight);
}

void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
Loading