summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Core/Debugger.h4
-rw-r--r--lldb/include/lldb/Core/Highlighter.h19
-rw-r--r--lldb/include/lldb/Core/SourceManager.h2
-rw-r--r--lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py5
-rw-r--r--lldb/source/Core/Debugger.cpp19
-rw-r--r--lldb/source/Core/Highlighter.cpp32
-rw-r--r--lldb/source/Core/SourceManager.cpp95
-rw-r--r--lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp16
-rw-r--r--lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.h1
-rw-r--r--lldb/unittests/Language/Highlighting/HighlighterTest.cpp100
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 &regex, 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));
+}
OpenPOWER on IntegriCloud