[Lldb-commits] [lldb] r341003 - Move the column marking functionality to the Highlighter framework

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 29 17:09:21 PDT 2018


Author: teemperor
Date: Wed Aug 29 17:09:21 2018
New Revision: 341003

URL: http://llvm.org/viewvc/llvm-project?rev=341003&view=rev
Log:
Move the column marking functionality to the Highlighter framework

Summary:
The syntax highlighting feature so far is mutually exclusive with the lldb feature
that marks the current column in the line by underlining it via an ANSI color code.
Meaning that if you enable one, the other is automatically disabled by LLDB.

This was caused by the fact that both features inserted color codes into the the
source code and were likely to interfere with each other (which would result
in a broken source code printout to the user).

This patch moves the cursor code into the highlighting framework, which provides
the same feature to the user in normal non-C source code. For any source code
that is highlighted by Clang, we now also have cursor marking for the whole token
that is under the current source location. E.g., before we underlined only the '!' in the
expression '1 != 2', but now the whole token '!=' is underlined. The same for function
calls and so on. Below you can see two examples where we before only underlined
the first character of the token, but now underline the whole token.

{F7075400}
{F7075414}

It also simplifies the DisplaySourceLines method in the SourceManager as most of
the code in there was essentially just for getting this column marker to work as
a FormatEntity.

Reviewers: aprantl

Reviewed By: aprantl

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D51466

Modified:
    lldb/trunk/include/lldb/Core/Debugger.h
    lldb/trunk/include/lldb/Core/Highlighter.h
    lldb/trunk/include/lldb/Core/SourceManager.h
    lldb/trunk/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
    lldb/trunk/source/Core/Debugger.cpp
    lldb/trunk/source/Core/Highlighter.cpp
    lldb/trunk/source/Core/SourceManager.cpp
    lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
    lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.h
    lldb/trunk/unittests/Language/Highlighting/HighlighterTest.cpp

Modified: lldb/trunk/include/lldb/Core/Debugger.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Debugger.h (original)
+++ lldb/trunk/include/lldb/Core/Debugger.h Wed Aug 29 17:09:21 2018
@@ -277,9 +277,9 @@ public:
 
   lldb::StopShowColumn GetStopShowColumn() const;
 
-  const FormatEntity::Entry *GetStopShowColumnAnsiPrefix() const;
+  llvm::StringRef GetStopShowColumnAnsiPrefix() const;
 
-  const FormatEntity::Entry *GetStopShowColumnAnsiSuffix() const;
+  llvm::StringRef GetStopShowColumnAnsiSuffix() const;
 
   uint32_t GetStopSourceLineCount(bool before) const;
 

Modified: lldb/trunk/include/lldb/Core/Highlighter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Highlighter.h?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Highlighter.h (original)
+++ lldb/trunk/include/lldb/Core/Highlighter.h Wed Aug 29 17:09:21 2018
@@ -53,6 +53,11 @@ struct HighlightStyle {
     void Set(llvm::StringRef prefix, llvm::StringRef suffix);
   };
 
+  /// The style for the token which is below the cursor of the user. Note that
+  /// this style is overwritten by the SourceManager with the values of
+  /// stop-show-column-ansi-prefix/stop-show-column-ansi-suffix.
+  ColorStyle selected;
+
   /// Matches identifiers to variable or functions.
   ColorStyle identifier;
   /// Matches any string or character literals in the language: "foo" or 'f'
@@ -106,6 +111,9 @@ public:
   /// \param options
   /// \param line
   ///     The user supplied line that needs to be highlighted.
+  /// \param cursor_pos
+  ///     The cursor position of the user in this line, starting at 0 (which
+  ///     means the cursor is on the first character in 'line').
   /// \param previous_lines
   ///     Any previous lines the user has written which we should only use
   ///     for getting the context of the Highlighting right.
@@ -113,25 +121,29 @@ public:
   ///     The stream to which the highlighted version of the user string should
   ///     be written.
   virtual void Highlight(const HighlightStyle &options, llvm::StringRef line,
+                         llvm::Optional<size_t> cursor_pos,
                          llvm::StringRef previous_lines, Stream &s) const = 0;
 
   /// Utility method for calling Highlight without a stream.
   std::string Highlight(const HighlightStyle &options, llvm::StringRef line,
+                        llvm::Optional<size_t> cursor_pos,
                         llvm::StringRef previous_lines = "") const;
 };
 
-/// A default highlighter that does nothing. Used as a fallback.
-class NoHighlighter : public Highlighter {
+/// A default highlighter that only highlights the user cursor, but doesn't
+/// do any other highlighting.
+class DefaultHighlighter : public Highlighter {
 public:
   llvm::StringRef GetName() const override { return "none"; }
 
   void Highlight(const HighlightStyle &options, llvm::StringRef line,
+                 llvm::Optional<size_t> cursor_pos,
                  llvm::StringRef previous_lines, Stream &s) const override;
 };
 
 /// Manages the available highlighters.
 class HighlighterManager {
-  NoHighlighter m_no_highlighter;
+  DefaultHighlighter m_default;
 
 public:
   /// Queries all known highlighter for one that can highlight some source code.
@@ -145,6 +157,7 @@ public:
   ///     empty highlighter that does nothing.
   const Highlighter &getHighlighterFor(lldb::LanguageType language_type,
                                        llvm::StringRef path) const;
+  const Highlighter &getDefaultHighlighter() const { return m_default; }
 };
 
 } // namespace lldb_private

Modified: lldb/trunk/include/lldb/Core/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/SourceManager.h?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/SourceManager.h (original)
+++ lldb/trunk/include/lldb/Core/SourceManager.h Wed Aug 29 17:09:21 2018
@@ -52,7 +52,7 @@ public:
 
     void UpdateIfNeeded();
 
-    size_t DisplaySourceLines(uint32_t line, uint32_t column,
+    size_t DisplaySourceLines(uint32_t line, llvm::Optional<size_t> column,
                               uint32_t context_before, uint32_t context_after,
                               Stream *s);
     void FindLinesMatchingRegex(RegularExpression &regex, uint32_t start_line,

Modified: lldb/trunk/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py Wed Aug 29 17:09:21 2018
@@ -113,7 +113,7 @@ class SourceManagerTestCase(TestBase):
         """Test display of source using the SBSourceManager API, using a
         dumb terminal and thus no color support (the default)."""
         use_color = True
-        underline_regex = ansi_underline_surround_regex(r".")
+        underline_regex = ansi_underline_surround_regex(r"printf")
         self.do_display_source_python_api(use_color, underline_regex)
 
     @add_test_categories(['pyapi'])
@@ -132,7 +132,8 @@ class SourceManagerTestCase(TestBase):
         self.do_display_source_python_api(use_color, color_regex, syntax_highlighting)
 
         # Test that we didn't color unrelated identifiers.
-        self.do_display_source_python_api(use_color, r" printf\(", syntax_highlighting)
+        self.do_display_source_python_api(use_color, r" main\(", syntax_highlighting)
+        self.do_display_source_python_api(use_color, r"\);", syntax_highlighting)
 
     def test_move_and_then_display_source(self):
         """Test that target.source-map settings work by moving main.c to hidden/main.c."""

Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Wed Aug 29 17:09:21 2018
@@ -177,9 +177,6 @@ OptionEnumValueElement g_language_enumer
 // args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-
 // without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}:
 
-#define DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX "${ansi.underline}"
-#define DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX "${ansi.normal}"
-
 static OptionEnumValueElement s_stop_show_column_values[] = {
     {eStopShowColumnAnsiOrCaret, "ansi-or-caret",
      "Highlight the stop column with ANSI terminal codes when color/ANSI mode "
@@ -239,13 +236,13 @@ static PropertyDefinition g_properties[]
      eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values,
      "If true, LLDB will use the column information from the debug info to "
      "mark the current position when displaying a stopped context."},
-    {"stop-show-column-ansi-prefix", OptionValue::eTypeFormatEntity, true, 0,
-     DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX, nullptr,
+    {"stop-show-column-ansi-prefix", OptionValue::eTypeString, true, 0,
+     "${ansi.underline}", nullptr,
      "When displaying the column marker in a color-enabled (i.e. ANSI) "
      "terminal, use the ANSI terminal code specified in this format at the "
      "immediately before the column to be marked."},
-    {"stop-show-column-ansi-suffix", OptionValue::eTypeFormatEntity, true, 0,
-     DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX, nullptr,
+    {"stop-show-column-ansi-suffix", OptionValue::eTypeString, true, 0,
+     "${ansi.normal}", nullptr,
      "When displaying the column marker in a color-enabled (i.e. ANSI) "
      "terminal, use the ANSI terminal code specified in this format "
      "immediately after the column to be marked."},
@@ -485,14 +482,14 @@ StopShowColumn Debugger::GetStopShowColu
       nullptr, idx, g_properties[idx].default_uint_value);
 }
 
-const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiPrefix() const {
+llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const {
   const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;
-  return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
+  return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
 }
 
-const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiSuffix() const {
+llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const {
   const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;
-  return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
+  return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
 }
 
 uint32_t Debugger::GetStopSourceLineCount(bool before) const {

Modified: lldb/trunk/source/Core/Highlighter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Highlighter.cpp?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/source/Core/Highlighter.cpp (original)
+++ lldb/trunk/source/Core/Highlighter.cpp Wed Aug 29 17:09:21 2018
@@ -25,11 +25,28 @@ void HighlightStyle::ColorStyle::Set(llv
   m_suffix = lldb_utility::ansi::FormatAnsiTerminalCodes(suffix);
 }
 
-void NoHighlighter::Highlight(const HighlightStyle &options,
-                              llvm::StringRef line,
-                              llvm::StringRef previous_lines, Stream &s) const {
-  // We just forward the input to the output and do no highlighting.
-  s << line;
+void DefaultHighlighter::Highlight(const HighlightStyle &options,
+                                   llvm::StringRef line,
+                                   llvm::Optional<size_t> cursor_pos,
+                                   llvm::StringRef previous_lines,
+                                   Stream &s) const {
+  // If we don't have a valid cursor, then we just print the line as-is.
+  if (!cursor_pos || *cursor_pos >= line.size()) {
+    s << line;
+    return;
+  }
+
+  // If we have a valid cursor, we have to apply the 'selected' style around
+  // the character below the cursor.
+
+  // Split the line around the character which is below the cursor.
+  size_t column = *cursor_pos;
+  // Print the characters before the cursor.
+  s << line.substr(0, column);
+  // Print the selected character with the defined color codes.
+  options.selected.Apply(s, line.substr(column, 1));
+  // Print the rest of the line.
+  s << line.substr(column + 1U);
 }
 
 static HighlightStyle::ColorStyle GetColor(const char *c) {
@@ -50,14 +67,15 @@ HighlighterManager::getHighlighterFor(ll
   Language *language = lldb_private::Language::FindPlugin(language_type, path);
   if (language && language->GetHighlighter())
     return *language->GetHighlighter();
-  return m_no_highlighter;
+  return m_default;
 }
 
 std::string Highlighter::Highlight(const HighlightStyle &options,
                                    llvm::StringRef line,
+                                   llvm::Optional<size_t> cursor_pos,
                                    llvm::StringRef previous_lines) const {
   StreamString s;
-  Highlight(options, line, previous_lines, s);
+  Highlight(options, line, cursor_pos, previous_lines, s);
   s.Flush();
   return s.GetString().str();
 }

Modified: lldb/trunk/source/Core/SourceManager.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/SourceManager.cpp?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/source/Core/SourceManager.cpp (original)
+++ lldb/trunk/source/Core/SourceManager.cpp Wed Aug 29 17:09:21 2018
@@ -127,11 +127,6 @@ static bool should_show_stop_column_with
   if (!debugger_sp->GetUseColor())
     return false;
 
-  // Don't use terminal attributes when we have highlighting enabled. This
-  // can mess up the command line.
-  if (debugger_sp->GetHighlightSource())
-    return false;
-
   // We only use ANSI stop column formatting if we're either supposed to show
   // ANSI where available (which we know we have when we get to this point), or
   // if we're only supposed to use ANSI.
@@ -201,8 +196,16 @@ size_t SourceManager::DisplaySourceLines
       return_value +=
           s->Printf("%s%2.2s %-4u\t", prefix,
                     line == curr_line ? current_line_cstr : "", line);
-      size_t this_line_size = m_last_file_sp->DisplaySourceLines(
-          line, line == curr_line ? column : 0, 0, 0, s);
+
+      // So far we treated column 0 as a special 'no column value', but
+      // DisplaySourceLines starts counting columns from 0 (and no column is
+      // expressed by passing an empty optional).
+      llvm::Optional<size_t> columnToHighlight;
+      if (line == curr_line && column)
+        columnToHighlight = column - 1;
+
+      size_t this_line_size =
+          m_last_file_sp->DisplaySourceLines(line, columnToHighlight, 0, 0, s);
       if (column != 0 && line == curr_line &&
           should_show_stop_column_with_caret(m_debugger_wp.lock())) {
         // Display caret cursor.
@@ -521,7 +524,8 @@ void SourceManager::File::UpdateIfNeeded
   }
 }
 
-size_t SourceManager::File::DisplaySourceLines(uint32_t line, uint32_t column,
+size_t SourceManager::File::DisplaySourceLines(uint32_t line,
+                                               llvm::Optional<size_t> column,
                                                uint32_t context_before,
                                                uint32_t context_after,
                                                Stream *s) {
@@ -535,15 +539,24 @@ size_t SourceManager::File::DisplaySourc
 
   size_t bytes_written = s->GetWrittenBytes();
 
-  std::string previous_content;
+  auto debugger_sp = m_debugger_wp.lock();
+
+  HighlightStyle style;
+  // Use the default Vim style if source highlighting is enabled.
+  if (should_highlight_source(debugger_sp))
+    style = HighlightStyle::MakeVimStyle();
+
+  // If we should mark the stop column with color codes, then copy the prefix
+  // and suffix to our color style.
+  if (should_show_stop_column_with_ansi(debugger_sp))
+    style.selected.Set(debugger_sp->GetStopShowColumnAnsiPrefix(),
+                       debugger_sp->GetStopShowColumnAnsiSuffix());
 
-  HighlightStyle style = HighlightStyle::MakeVimStyle();
   HighlighterManager mgr;
   std::string path = GetFileSpec().GetPath(/*denormalize*/ false);
   // FIXME: Find a way to get the definitive language this file was written in
   // and pass it to the highlighter.
-  auto &highlighter =
-      mgr.getHighlighterFor(lldb::LanguageType::eLanguageTypeUnknown, path);
+  const auto &h = mgr.getHighlighterFor(lldb::eLanguageTypeUnknown, path);
 
   const uint32_t start_line =
       line <= context_before ? 1 : line - context_before;
@@ -560,64 +573,8 @@ size_t SourceManager::File::DisplaySourc
       const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
 
       auto ref = llvm::StringRef(reinterpret_cast<const char *>(cstr), count);
-      bool displayed_line = false;
-
-      auto debugger_sp = m_debugger_wp.lock();
-      if (should_highlight_source(debugger_sp)) {
-        highlighter.Highlight(style, ref, previous_content, *s);
-        displayed_line = true;
-        // Add the new line to the previous lines.
-        previous_content += ref.str();
-      }
-
-      if (!displayed_line && column && (column < count)) {
-        if (should_show_stop_column_with_ansi(debugger_sp) && debugger_sp) {
-          // Check if we have any ANSI codes with which to mark this column. If
-          // not, no need to do this work.
-          auto ansi_prefix_entry = debugger_sp->GetStopShowColumnAnsiPrefix();
-          auto ansi_suffix_entry = debugger_sp->GetStopShowColumnAnsiSuffix();
-
-          // We only bother breaking up the line to format the marked column if
-          // there is any marking specified on both sides of the marked column.
-          // In ANSI-terminal-sequence land, there must be a post if there is a
-          // pre format, and vice versa.
-          if (ansi_prefix_entry && ansi_suffix_entry) {
-            // Mark the current column with the desired escape sequence for
-            // formatting the column (e.g. underline, inverse, etc.)
-
-            // First print the part before the column to mark.
-            s->Write(cstr, column - 1);
-
-            // Write the pre escape sequence.
-            const SymbolContext *sc = nullptr;
-            const ExecutionContext *exe_ctx = nullptr;
-            const Address addr = LLDB_INVALID_ADDRESS;
-            ValueObject *valobj = nullptr;
-            const bool function_changed = false;
-            const bool initial_function = false;
-
-            FormatEntity::Format(*ansi_prefix_entry, *s, sc, exe_ctx, &addr,
-                                 valobj, function_changed, initial_function);
-
-            s->Write(cstr + column - 1, 1);
-
-            // Write the post escape sequence.
-            FormatEntity::Format(*ansi_suffix_entry, *s, sc, exe_ctx, &addr,
-                                 valobj, function_changed, initial_function);
-
-            // And finish up with the rest of the line.
-            s->Write(cstr + column, count - column);
-
-            // Keep track of the fact that we just wrote the line.
-            displayed_line = true;
-          }
-        }
-      }
 
-      // If we didn't end up displaying the line with ANSI codes for whatever
-      // reason, display it now sans codes.
-      if (!displayed_line)
-        s->PutCString(ref);
+      h.Highlight(style, ref, column, "", *s);
 
       // Ensure we get an end of line character one way or another.
       if (!is_newline_char(ref.back()))

Modified: lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp (original)
+++ lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp Wed Aug 29 17:09:21 2018
@@ -130,6 +130,7 @@ determineClangStyle(const ClangHighlight
 
 void ClangHighlighter::Highlight(const HighlightStyle &options,
                                  llvm::StringRef line,
+                                 llvm::Optional<size_t> cursor_pos,
                                  llvm::StringRef previous_lines,
                                  Stream &result) const {
   using namespace clang;
@@ -168,6 +169,8 @@ void ClangHighlighter::Highlight(const H
   // True once we actually lexed the user provided line.
   bool found_user_line = false;
 
+  // True if we already highlighted the token under the cursor, false otherwise.
+  bool highlighted_cursor = false;
   Token token;
   bool exit = false;
   while (!exit) {
@@ -204,11 +207,22 @@ void ClangHighlighter::Highlight(const H
     if (tok_str.empty())
       continue;
 
+    // If the cursor is inside this token, we have to apply the 'selected'
+    // highlight style before applying the actual token color.
+    llvm::StringRef to_print = tok_str;
+    StreamString storage;
+    auto end = start + token.getLength();
+    if (cursor_pos && end > *cursor_pos && !highlighted_cursor) {
+      highlighted_cursor = true;
+      options.selected.Apply(storage, tok_str);
+      to_print = storage.GetString();
+    }
+
     // See how we are supposed to highlight this token.
     HighlightStyle::ColorStyle color =
         determineClangStyle(*this, token, tok_str, options, in_pp_directive);
 
-    color.Apply(result, tok_str);
+    color.Apply(result, to_print);
   }
 
   // If we went over the whole file but couldn't find our own file, then

Modified: lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.h?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.h (original)
+++ lldb/trunk/source/Plugins/Language/ClangCommon/ClangHighlighter.h Wed Aug 29 17:09:21 2018
@@ -29,6 +29,7 @@ public:
   llvm::StringRef GetName() const override { return "clang"; }
 
   void Highlight(const HighlightStyle &options, llvm::StringRef line,
+                 llvm::Optional<size_t> cursor_pos,
                  llvm::StringRef previous_lines, Stream &s) const override;
 
   /// Returns true if the given string represents a keywords in any Clang

Modified: lldb/trunk/unittests/Language/Highlighting/HighlighterTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Language/Highlighting/HighlighterTest.cpp?rev=341003&r1=341002&r2=341003&view=diff
==============================================================================
--- lldb/trunk/unittests/Language/Highlighting/HighlighterTest.cpp (original)
+++ lldb/trunk/unittests/Language/Highlighting/HighlighterTest.cpp Wed Aug 29 17:09:21 2018
@@ -99,31 +99,49 @@ TEST_F(HighlighterTest, FallbackHighligh
   style.semicolons.Set("<", ">");
 
   const char *code = "program Hello;";
-  std::string output = h.Highlight(style, code);
+  std::string output = h.Highlight(style, code, llvm::Optional<size_t>());
 
   EXPECT_STREQ(output.c_str(), code);
 }
 
-TEST_F(HighlighterTest, DefaultHighlighter) {
+static std::string
+highlightDefault(llvm::StringRef code, HighlightStyle style,
+                 llvm::Optional<size_t> cursor = llvm::Optional<size_t>()) {
   HighlighterManager mgr;
-  const Highlighter &h = mgr.getHighlighterFor(lldb::eLanguageTypeC, "main.c");
-
-  HighlightStyle style;
+  return mgr.getDefaultHighlighter().Highlight(style, code, cursor);
+}
 
+TEST_F(HighlighterTest, DefaultHighlighter) {
   const char *code = "int my_main() { return 22; } \n";
-  std::string output = h.Highlight(style, code);
 
-  EXPECT_STREQ(output.c_str(), code);
+  HighlightStyle style;
+  EXPECT_EQ(code, highlightDefault(code, style));
+}
+
+TEST_F(HighlighterTest, DefaultHighlighterWithCursor) {
+  HighlightStyle style;
+  style.selected.Set("<c>", "</c>");
+  EXPECT_EQ("<c>a</c> bc", highlightDefault("a bc", style, 0));
+  EXPECT_EQ("a<c> </c>bc", highlightDefault("a bc", style, 1));
+  EXPECT_EQ("a <c>b</c>c", highlightDefault("a bc", style, 2));
+  EXPECT_EQ("a b<c>c</c>", highlightDefault("a bc", style, 3));
 }
 
+TEST_F(HighlighterTest, DefaultHighlighterWithCursorOutOfBounds) {
+  HighlightStyle style;
+  style.selected.Set("<c>", "</c>");
+  EXPECT_EQ("a bc", highlightDefault("a bc", style, 4));
+}
 //------------------------------------------------------------------------------
 // Tests highlighting with the Clang highlighter.
 //------------------------------------------------------------------------------
 
-static std::string highlightC(llvm::StringRef code, HighlightStyle style) {
+static std::string
+highlightC(llvm::StringRef code, HighlightStyle style,
+           llvm::Optional<size_t> cursor = llvm::Optional<size_t>()) {
   HighlighterManager mgr;
   const Highlighter &h = mgr.getHighlighterFor(lldb::eLanguageTypeC, "main.c");
-  return h.Highlight(style, code);
+  return h.Highlight(style, code, cursor);
 }
 
 TEST_F(HighlighterTest, ClangEmptyInput) {
@@ -219,3 +237,67 @@ TEST_F(HighlighterTest, ClangIdentifiers
   EXPECT_EQ(" <id>foo</id> <id>c</id> = <id>bar</id>(); return 1;",
             highlightC(" foo c = bar(); return 1;", s));
 }
+
+TEST_F(HighlighterTest, ClangCursorPos) {
+  HighlightStyle s;
+  s.selected.Set("<c>", "</c>");
+
+  EXPECT_EQ("<c> </c>foo c = bar(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 0));
+  EXPECT_EQ(" <c>foo</c> c = bar(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 1));
+  EXPECT_EQ(" <c>foo</c> c = bar(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 2));
+  EXPECT_EQ(" <c>foo</c> c = bar(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 3));
+  EXPECT_EQ(" foo<c> </c>c = bar(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 4));
+  EXPECT_EQ(" foo <c>c</c> = bar(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 5));
+}
+
+TEST_F(HighlighterTest, ClangCursorPosEndOfLine) {
+  HighlightStyle s;
+  s.selected.Set("<c>", "</c>");
+
+  EXPECT_EQ("f", highlightC("f", s, 1));
+}
+
+TEST_F(HighlighterTest, ClangCursorOutOfBounds) {
+  HighlightStyle s;
+  s.selected.Set("<c>", "</c>");
+  EXPECT_EQ("f", highlightC("f", s, 2));
+  EXPECT_EQ("f", highlightC("f", s, 3));
+  EXPECT_EQ("f", highlightC("f", s, 4));
+}
+
+TEST_F(HighlighterTest, ClangCursorPosBeforeOtherToken) {
+  HighlightStyle s;
+  s.selected.Set("<c>", "</c>");
+  s.identifier.Set("<id>", "</id>");
+
+  EXPECT_EQ("<c> </c><id>foo</id> <id>c</id> = <id>bar</id>(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 0));
+}
+
+TEST_F(HighlighterTest, ClangCursorPosAfterOtherToken) {
+  HighlightStyle s;
+  s.selected.Set("<c>", "</c>");
+  s.identifier.Set("<id>", "</id>");
+
+  EXPECT_EQ(" <id>foo</id><c> </c><id>c</id> = <id>bar</id>(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 4));
+}
+
+TEST_F(HighlighterTest, ClangCursorPosInOtherToken) {
+  HighlightStyle s;
+  s.selected.Set("<c>", "</c>");
+  s.identifier.Set("<id>", "</id>");
+
+  EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 1));
+  EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 2));
+  EXPECT_EQ(" <id><c>foo</c></id> <id>c</id> = <id>bar</id>(); return 1;",
+            highlightC(" foo c = bar(); return 1;", s, 3));
+}




More information about the lldb-commits mailing list