diff options
| -rw-r--r-- | lldb/include/lldb/Core/Debugger.h | 4 | ||||
| -rw-r--r-- | lldb/include/lldb/Core/Highlighter.h | 19 | ||||
| -rw-r--r-- | lldb/include/lldb/Core/SourceManager.h | 2 | ||||
| -rw-r--r-- | lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py | 5 | ||||
| -rw-r--r-- | lldb/source/Core/Debugger.cpp | 19 | ||||
| -rw-r--r-- | lldb/source/Core/Highlighter.cpp | 32 | ||||
| -rw-r--r-- | lldb/source/Core/SourceManager.cpp | 95 | ||||
| -rw-r--r-- | lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp | 16 | ||||
| -rw-r--r-- | lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h | 1 | ||||
| -rw-r--r-- | lldb/unittests/Language/Highlighting/HighlighterTest.cpp | 100 | 
10 files changed, 188 insertions, 105 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 69b4d8f072b..3da8ea14825 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -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; diff --git a/lldb/include/lldb/Core/Highlighter.h b/lldb/include/lldb/Core/Highlighter.h index 85e54506278..220557c1f03 100644 --- a/lldb/include/lldb/Core/Highlighter.h +++ b/lldb/include/lldb/Core/Highlighter.h @@ -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 diff --git a/lldb/include/lldb/Core/SourceManager.h b/lldb/include/lldb/Core/SourceManager.h index ef652531244..06ff74bd276 100644 --- a/lldb/include/lldb/Core/SourceManager.h +++ b/lldb/include/lldb/Core/SourceManager.h @@ -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 ®ex, uint32_t start_line, diff --git a/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py b/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py index dc43cd0815a..ea822decdb6 100644 --- a/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py +++ b/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py @@ -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.""" diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 763c89e6f04..692856f17bf 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -177,9 +177,6 @@ OptionEnumValueElement g_language_enumerators[] = {  // 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::GetStopShowColumn() const {        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 { diff --git a/lldb/source/Core/Highlighter.cpp b/lldb/source/Core/Highlighter.cpp index 53aa16df36b..c7dd0db8364 100644 --- a/lldb/source/Core/Highlighter.cpp +++ b/lldb/source/Core/Highlighter.cpp @@ -25,11 +25,28 @@ void HighlightStyle::ColorStyle::Set(llvm::StringRef prefix,    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(lldb::LanguageType language_type,    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();  } diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp index c14b72250e7..413505d3ba8 100644 --- a/lldb/source/Core/SourceManager.cpp +++ b/lldb/source/Core/SourceManager.cpp @@ -127,11 +127,6 @@ static bool should_show_stop_column_with_ansi(DebuggerSP debugger_sp) {    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::DisplaySourceLinesWithLineNumbersUsingLastFile(        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::DisplaySourceLines(uint32_t line, uint32_t column,    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::DisplaySourceLines(uint32_t line, uint32_t column,        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())) diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp index 442d4cf53e3..50824d72d65 100644 --- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp +++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp @@ -130,6 +130,7 @@ determineClangStyle(const ClangHighlighter &highlighter,  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 HighlightStyle &options,    // 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 HighlightStyle &options,      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 diff --git a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h index 78971932054..6390c3249ca 100644 --- a/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h +++ b/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h @@ -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 diff --git a/lldb/unittests/Language/Highlighting/HighlighterTest.cpp b/lldb/unittests/Language/Highlighting/HighlighterTest.cpp index 8e9a2ea4e6c..ea1f6376cb7 100644 --- a/lldb/unittests/Language/Highlighting/HighlighterTest.cpp +++ b/lldb/unittests/Language/Highlighting/HighlighterTest.cpp @@ -99,31 +99,49 @@ TEST_F(HighlighterTest, FallbackHighlighter) {    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)); +}  | 

