teemperor updated this revision to Diff 157702.
teemperor added a comment.
- Removed extra semicolons that slipped in somehow.
https://reviews.llvm.org/D49334
Files:
include/lldb/Core/Debugger.h
include/lldb/Core/Highlighter.h
include/lldb/Target/Language.h
packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
source/Core/CMakeLists.txt
source/Core/Debugger.cpp
source/Core/Highlighter.cpp
source/Core/SourceManager.cpp
source/Plugins/Language/CMakeLists.txt
source/Plugins/Language/CPlusPlus/CMakeLists.txt
source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
source/Plugins/Language/ClangCommon/CMakeLists.txt
source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
source/Plugins/Language/ClangCommon/ClangHighlighter.h
source/Plugins/Language/Go/GoLanguage.cpp
source/Plugins/Language/Go/GoLanguage.h
source/Plugins/Language/Java/JavaLanguage.cpp
source/Plugins/Language/Java/JavaLanguage.h
source/Plugins/Language/OCaml/OCamlLanguage.cpp
source/Plugins/Language/OCaml/OCamlLanguage.h
source/Plugins/Language/ObjC/CMakeLists.txt
source/Plugins/Language/ObjC/ObjCLanguage.cpp
source/Plugins/Language/ObjC/ObjCLanguage.h
source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt
source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h
source/Target/Language.cpp
unittests/Language/CMakeLists.txt
unittests/Language/Highlighting/CMakeLists.txt
unittests/Language/Highlighting/HighlighterTest.cpp
Index: unittests/Language/Highlighting/HighlighterTest.cpp
===================================================================
--- /dev/null
+++ unittests/Language/Highlighting/HighlighterTest.cpp
@@ -0,0 +1,221 @@
+//===-- HighlighterTest.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Core/Highlighter.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/Go/GoLanguage.h"
+#include "Plugins/Language/Java/JavaLanguage.h"
+#include "Plugins/Language/OCaml/OCamlLanguage.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+#include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h"
+
+using namespace lldb_private;
+
+namespace {
+class HighlighterTest : public testing::Test {
+public:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+};
+} // namespace
+
+void HighlighterTest::SetUpTestCase() {
+ // The HighlighterManager uses the language plugins under the hood, so we
+ // have to initialize them here for our test process.
+ CPlusPlusLanguage::Initialize();
+ GoLanguage::Initialize();
+ JavaLanguage::Initialize();
+ ObjCLanguage::Initialize();
+ ObjCPlusPlusLanguage::Initialize();
+ OCamlLanguage::Initialize();
+}
+
+void HighlighterTest::TearDownTestCase() {
+ CPlusPlusLanguage::Terminate();
+ GoLanguage::Terminate();
+ JavaLanguage::Terminate();
+ ObjCLanguage::Terminate();
+ ObjCPlusPlusLanguage::Terminate();
+ OCamlLanguage::Terminate();
+}
+
+static std::string getName(lldb::LanguageType type) {
+ HighlighterManager m;
+ return m.getHighlighterFor(type, "").GetName().str();
+}
+
+static std::string getName(llvm::StringRef path) {
+ HighlighterManager m;
+ return m.getHighlighterFor(lldb::eLanguageTypeUnknown, path).GetName().str();
+}
+
+TEST_F(HighlighterTest, HighlighterSelectionType) {
+ EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus), "clang");
+ EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_03), "clang");
+ EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_11), "clang");
+ EXPECT_EQ(getName(lldb::eLanguageTypeC_plus_plus_14), "clang");
+ EXPECT_EQ(getName(lldb::eLanguageTypeObjC), "clang");
+ EXPECT_EQ(getName(lldb::eLanguageTypeObjC_plus_plus), "clang");
+
+ EXPECT_EQ(getName(lldb::eLanguageTypeUnknown), "none");
+ EXPECT_EQ(getName(lldb::eLanguageTypeJulia), "none");
+ EXPECT_EQ(getName(lldb::eLanguageTypeJava), "none");
+ EXPECT_EQ(getName(lldb::eLanguageTypeHaskell), "none");
+}
+
+TEST_F(HighlighterTest, HighlighterSelectionPath) {
+ EXPECT_EQ(getName("myfile.cc"), "clang");
+ EXPECT_EQ(getName("moo.cpp"), "clang");
+ EXPECT_EQ(getName("mar.cxx"), "clang");
+ EXPECT_EQ(getName("foo.C"), "clang");
+ EXPECT_EQ(getName("bar.CC"), "clang");
+ EXPECT_EQ(getName("a/dir.CC"), "clang");
+ EXPECT_EQ(getName("/a/dir.hpp"), "clang");
+ EXPECT_EQ(getName("header.h"), "clang");
+
+ EXPECT_EQ(getName(""), "none");
+ EXPECT_EQ(getName("/dev/null"), "none");
+ EXPECT_EQ(getName("Factory.java"), "none");
+ EXPECT_EQ(getName("poll.py"), "none");
+ EXPECT_EQ(getName("reducer.hs"), "none");
+}
+
+TEST_F(HighlighterTest, FallbackHighlighter) {
+ HighlighterManager mgr;
+ const Highlighter &h =
+ mgr.getHighlighterFor(lldb::eLanguageTypePascal83, "foo.pas");
+
+ HighlightStyle style;
+ style.identifier.Set("[", "]");
+ style.semicolons.Set("<", ">");
+
+ const char *code = "program Hello;";
+ std::string output = h.Highlight(style, code);
+
+ EXPECT_STREQ(output.c_str(), code);
+}
+
+TEST_F(HighlighterTest, DefaultHighlighter) {
+ HighlighterManager mgr;
+ const Highlighter &h = mgr.getHighlighterFor(lldb::eLanguageTypeC, "main.c");
+
+ HighlightStyle style;
+
+ const char *code = "int my_main() { return 22; } \n";
+ std::string output = h.Highlight(style, code);
+
+ EXPECT_STREQ(output.c_str(), code);
+}
+
+//------------------------------------------------------------------------------
+// Tests highlighting with the Clang highlighter.
+//------------------------------------------------------------------------------
+
+static std::string highlightC(llvm::StringRef code, HighlightStyle style) {
+ HighlighterManager mgr;
+ const Highlighter &h = mgr.getHighlighterFor(lldb::eLanguageTypeC, "main.c");
+ return h.Highlight(style, code);
+}
+
+TEST_F(HighlighterTest, ClangEmptyInput) {
+ HighlightStyle s;
+ EXPECT_EQ("", highlightC("", s));
+}
+
+TEST_F(HighlighterTest, ClangScalarLiterals) {
+ HighlightStyle s;
+ s.scalar_literal.Set("<scalar>", "</scalar>");
+
+ EXPECT_EQ(" int i = <scalar>22</scalar>;", highlightC(" int i = 22;", s));
+}
+
+TEST_F(HighlighterTest, ClangStringLiterals) {
+ HighlightStyle s;
+ s.string_literal.Set("<str>", "</str>");
+
+ EXPECT_EQ("const char *f = 22 + <str>\"foo\"</str>;",
+ highlightC("const char *f = 22 + \"foo\";", s));
+}
+
+TEST_F(HighlighterTest, ClangUnterminatedString) {
+ HighlightStyle s;
+ s.string_literal.Set("<str>", "</str>");
+
+ EXPECT_EQ(" f = \"", highlightC(" f = \"", s));
+}
+
+TEST_F(HighlighterTest, Keywords) {
+ HighlightStyle s;
+ s.keyword.Set("<k>", "</k>");
+
+ EXPECT_EQ(" <k>return</k> 1; ", highlightC(" return 1; ", s));
+}
+
+TEST_F(HighlighterTest, Colons) {
+ HighlightStyle s;
+ s.colon.Set("<c>", "</c>");
+
+ EXPECT_EQ("foo<c>:</c><c>:</c>bar<c>:</c>", highlightC("foo::bar:", s));
+}
+
+TEST_F(HighlighterTest, ClangBraces) {
+ HighlightStyle s;
+ s.braces.Set("<b>", "</b>");
+
+ EXPECT_EQ("a<b>{</b><b>}</b>", highlightC("a{}", s));
+}
+
+TEST_F(HighlighterTest, ClangSquareBrackets) {
+ HighlightStyle s;
+ s.square_brackets.Set("<sb>", "</sb>");
+
+ EXPECT_EQ("a<sb>[</sb><sb>]</sb>", highlightC("a[]", s));
+}
+
+TEST_F(HighlighterTest, ClangCommas) {
+ HighlightStyle s;
+ s.comma.Set("<comma>", "</comma>");
+
+ EXPECT_EQ(" bool f = foo()<comma>,</comma> 1;",
+ highlightC(" bool f = foo(), 1;", s));
+}
+
+TEST_F(HighlighterTest, ClangPPDirectives) {
+ HighlightStyle s;
+ s.pp_directive.Set("<pp>", "</pp>");
+
+ EXPECT_EQ("<pp>#</pp><pp>include</pp><pp> </pp><pp>\"foo\"</pp><pp> </pp>//c",
+ highlightC("#include \"foo\" //c", s));
+}
+
+TEST_F(HighlighterTest, ClangComments) {
+ HighlightStyle s;
+ s.comment.Set("<cc>", "</cc>");
+
+ EXPECT_EQ(" <cc>/*com */</cc> <cc>// com /*n*/</cc>",
+ highlightC(" /*com */ // com /*n*/", s));
+}
+
+TEST_F(HighlighterTest, ClangOperators) {
+ HighlightStyle s;
+ s.operators.Set("[", "]");
+
+ EXPECT_EQ(" 1[+]2[/]a[*]f[&]x[|][~]l", highlightC(" 1+2/a*f&x|~l", s));
+}
+
+TEST_F(HighlighterTest, ClangIdentifiers) {
+ HighlightStyle s;
+ s.identifier.Set("<id>", "</id>");
+
+ EXPECT_EQ(" <id>foo</id> <id>c</id> = <id>bar</id>(); return 1;",
+ highlightC(" foo c = bar(); return 1;", s));
+}
Index: unittests/Language/Highlighting/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/Language/Highlighting/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_lldb_unittest(HighlighterTests
+ HighlighterTest.cpp
+
+ LINK_LIBS
+ lldbPluginCPlusPlusLanguage
+ lldbPluginObjCLanguage
+ lldbPluginObjCPlusPlusLanguage
+ lldbPluginJavaLanguage
+ lldbPluginOCamlLanguage
+ lldbPluginGoLanguage
+ )
Index: unittests/Language/CMakeLists.txt
===================================================================
--- unittests/Language/CMakeLists.txt
+++ unittests/Language/CMakeLists.txt
@@ -1 +1,2 @@
add_subdirectory(CPlusPlus)
+add_subdirectory(Highlighting)
Index: source/Target/Language.cpp
===================================================================
--- source/Target/Language.cpp
+++ source/Target/Language.cpp
@@ -77,7 +77,39 @@
return nullptr;
}
+Language *Language::FindPlugin(llvm::StringRef file_path) {
+ Language *result = nullptr;
+ ForEach([&result, file_path](Language *language) {
+ if (language->IsSourceFile(file_path)) {
+ result = language;
+ return false;
+ }
+ return true;
+ });
+ return result;
+}
+
+Language *Language::FindPlugin(LanguageType language,
+ llvm::StringRef file_path) {
+ Language *result = FindPlugin(language);
+ // Finding a language by file path is slower, we so we use this as the
+ // fallback.
+ if (!result)
+ result = FindPlugin(file_path);
+ return result;
+}
+
void Language::ForEach(std::function<bool(Language *)> callback) {
+ // If we want to iterate over all languages, we first have to complete the
+ // LanguagesMap.
+ static llvm::once_flag g_initialize;
+ llvm::call_once(g_initialize, [] {
+ for (unsigned lang = eLanguageTypeUnknown; lang < eNumLanguageTypes;
+ ++lang) {
+ FindPlugin(static_cast<lldb::LanguageType>(lang));
+ }
+ });
+
std::lock_guard<std::mutex> guard(GetLanguagesMutex());
LanguagesMap &map(GetLanguagesMap());
for (const auto &entry : map) {
Index: source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h
===================================================================
--- source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h
+++ source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h
@@ -14,12 +14,15 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
+#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
#include "lldb/Target/Language.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class ObjCPlusPlusLanguage : public Language {
+ ClangHighlighter m_highlighter;
+
public:
ObjCPlusPlusLanguage() = default;
@@ -29,6 +32,10 @@
return lldb::eLanguageTypeObjC_plus_plus;
}
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
+ const Highlighter *GetHighlighter() const override { return &m_highlighter; }
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
Index: source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
===================================================================
--- source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
+++ source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp
@@ -16,6 +16,15 @@
using namespace lldb;
using namespace lldb_private;
+bool ObjCPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".h", ".mm"};
+ for (auto suffix : suffixes) {
+ if (file_path.endswith_lower(suffix))
+ return true;
+ }
+ return false;
+}
+
void ObjCPlusPlusLanguage::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), "Objective-C++ Language",
CreateInstance);
Index: source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt
===================================================================
--- source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt
+++ source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt
@@ -1,7 +1,8 @@
add_lldb_library(lldbPluginObjCPlusPlusLanguage PLUGIN
ObjCPlusPlusLanguage.cpp
-
+
LINK_LIBS
lldbCore
lldbTarget
+ lldbPluginClangCommon
)
Index: source/Plugins/Language/ObjC/ObjCLanguage.h
===================================================================
--- source/Plugins/Language/ObjC/ObjCLanguage.h
+++ source/Plugins/Language/ObjC/ObjCLanguage.h
@@ -17,13 +17,16 @@
// Other libraries and framework includes
// Project includes
+#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
#include "lldb/Target/Language.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class ObjCLanguage : public Language {
+ ClangHighlighter m_highlighter;
+
public:
class MethodName {
public:
@@ -121,6 +124,10 @@
bool IsNilReference(ValueObject &valobj) override;
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
+ const Highlighter *GetHighlighter() const override { return &m_highlighter; }
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
Index: source/Plugins/Language/ObjC/ObjCLanguage.cpp
===================================================================
--- source/Plugins/Language/ObjC/ObjCLanguage.cpp
+++ source/Plugins/Language/ObjC/ObjCLanguage.cpp
@@ -1102,3 +1102,12 @@
bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0;
return canReadValue && isZero;
}
+
+bool ObjCLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".h", ".m", ".M"};
+ for (auto suffix : suffixes) {
+ if (file_path.endswith_lower(suffix))
+ return true;
+ }
+ return false;
+}
Index: source/Plugins/Language/ObjC/CMakeLists.txt
===================================================================
--- source/Plugins/Language/ObjC/CMakeLists.txt
+++ source/Plugins/Language/ObjC/CMakeLists.txt
@@ -31,6 +31,7 @@
lldbTarget
lldbUtility
lldbPluginAppleObjCRuntime
+ lldbPluginClangCommon
EXTRA_CXXFLAGS ${EXTRA_CXXFLAGS}
)
Index: source/Plugins/Language/OCaml/OCamlLanguage.h
===================================================================
--- source/Plugins/Language/OCaml/OCamlLanguage.h
+++ source/Plugins/Language/OCaml/OCamlLanguage.h
@@ -31,6 +31,8 @@
return lldb::eLanguageTypeOCaml;
}
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
static void Initialize();
static void Terminate();
Index: source/Plugins/Language/OCaml/OCamlLanguage.cpp
===================================================================
--- source/Plugins/Language/OCaml/OCamlLanguage.cpp
+++ source/Plugins/Language/OCaml/OCamlLanguage.cpp
@@ -28,6 +28,15 @@
using namespace lldb;
using namespace lldb_private;
+bool OCamlLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".ml", ".mli"};
+ for (auto suffix : suffixes) {
+ if (file_path.endswith_lower(suffix))
+ return true;
+ }
+ return false;
+}
+
void OCamlLanguage::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), "OCaml Language",
CreateInstance);
Index: source/Plugins/Language/Java/JavaLanguage.h
===================================================================
--- source/Plugins/Language/Java/JavaLanguage.h
+++ source/Plugins/Language/Java/JavaLanguage.h
@@ -45,6 +45,8 @@
bool IsNilReference(ValueObject &valobj) override;
lldb::TypeCategoryImplSP GetFormatters() override;
+
+ bool IsSourceFile(llvm::StringRef file_path) const override;
};
} // namespace lldb_private
Index: source/Plugins/Language/Java/JavaLanguage.cpp
===================================================================
--- source/Plugins/Language/Java/JavaLanguage.cpp
+++ source/Plugins/Language/Java/JavaLanguage.cpp
@@ -99,3 +99,7 @@
});
return g_category;
}
+
+bool JavaLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ return file_path.endswith(".java");
+}
Index: source/Plugins/Language/Go/GoLanguage.h
===================================================================
--- source/Plugins/Language/Go/GoLanguage.h
+++ source/Plugins/Language/Go/GoLanguage.h
@@ -39,6 +39,8 @@
HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics() override;
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
Index: source/Plugins/Language/Go/GoLanguage.cpp
===================================================================
--- source/Plugins/Language/Go/GoLanguage.cpp
+++ source/Plugins/Language/Go/GoLanguage.cpp
@@ -125,3 +125,7 @@
return g_formatters;
}
+
+bool GoLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ return file_path.endswith(".go");
+}
Index: source/Plugins/Language/ClangCommon/ClangHighlighter.h
===================================================================
--- /dev/null
+++ source/Plugins/Language/ClangCommon/ClangHighlighter.h
@@ -0,0 +1,42 @@
+//===-- ClangHighlighter.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ClangHighlighter_h_
+#define liblldb_ClangHighlighter_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/StringSet.h"
+
+// Project includes
+#include "lldb/Core/Highlighter.h"
+
+namespace lldb_private {
+
+class ClangHighlighter : public Highlighter {
+ llvm::StringSet<> keywords;
+
+public:
+ ClangHighlighter();
+ llvm::StringRef GetName() const override { return "clang"; }
+
+ std::size_t Highlight(const HighlightStyle &options, llvm::StringRef line,
+ llvm::StringRef previous_lines,
+ Stream &s) const override;
+
+ /// Returns true if the given string represents a keywords in any Clang
+ /// supported language.
+ bool isKeyword(llvm::StringRef token) const;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangHighlighter_h_
Index: source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
===================================================================
--- /dev/null
+++ source/Plugins/Language/ClangCommon/ClangHighlighter.cpp
@@ -0,0 +1,227 @@
+//===-- ClangHighlighter.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangHighlighter.h"
+
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/AnsiTerminal.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace lldb_private;
+
+bool ClangHighlighter::isKeyword(llvm::StringRef token) const {
+ return keywords.find(token) != keywords.end();
+}
+
+ClangHighlighter::ClangHighlighter() {
+#define KEYWORD(X, N) keywords.insert(#X);
+#include "clang/Basic/TokenKinds.def"
+}
+
+/// Determines which style should be applied to the given token.
+/// \param highlighter
+/// The current highlighter that should use the style.
+/// \param token
+/// The current token.
+/// \param tok_str
+/// The string in the source code the token represents.
+/// \param options
+/// The style we use for coloring the source code.
+/// \param in_pp_directive
+/// If we are currently in a preprocessor directive. NOTE: This is
+/// passed by reference and will be updated if the current token starts
+/// or ends a preprocessor directive.
+/// \return
+/// The ColorStyle that should be applied to the token.
+static HighlightStyle::ColorStyle
+determineClangStyle(const ClangHighlighter &highlighter,
+ const clang::Token &token, llvm::StringRef tok_str,
+ const HighlightStyle &options, bool &in_pp_directive) {
+ using namespace clang;
+
+ if (token.is(tok::comment)) {
+ // If we were in a preprocessor directive before, we now left it.
+ in_pp_directive = false;
+ return options.comment;
+ } else if (in_pp_directive || token.getKind() == tok::hash) {
+ // Let's assume that the rest of the line is a PP directive.
+ in_pp_directive = true;
+ // Preprocessor directives are hard to match, so we have to hack this in.
+ return options.pp_directive;
+ } else if (tok::isStringLiteral(token.getKind()))
+ return options.string_literal;
+ else if (tok::isLiteral(token.getKind()))
+ return options.scalar_literal;
+ else if (highlighter.isKeyword(tok_str))
+ return options.keyword;
+ else
+ switch (token.getKind()) {
+ case tok::raw_identifier:
+ case tok::identifier:
+ return options.identifier;
+ case tok::l_brace:
+ case tok::r_brace:
+ return options.braces;
+ case tok::l_square:
+ case tok::r_square:
+ return options.square_brackets;
+ case tok::l_paren:
+ case tok::r_paren:
+ return options.parentheses;
+ case tok::comma:
+ return options.comma;
+ case tok::coloncolon:
+ case tok::colon:
+ return options.colon;
+
+ case tok::amp:
+ case tok::ampamp:
+ case tok::ampequal:
+ case tok::star:
+ case tok::starequal:
+ case tok::plus:
+ case tok::plusplus:
+ case tok::plusequal:
+ case tok::minus:
+ case tok::arrow:
+ case tok::minusminus:
+ case tok::minusequal:
+ case tok::tilde:
+ case tok::exclaim:
+ case tok::exclaimequal:
+ case tok::slash:
+ case tok::slashequal:
+ case tok::percent:
+ case tok::percentequal:
+ case tok::less:
+ case tok::lessless:
+ case tok::lessequal:
+ case tok::lesslessequal:
+ case tok::spaceship:
+ case tok::greater:
+ case tok::greatergreater:
+ case tok::greaterequal:
+ case tok::greatergreaterequal:
+ case tok::caret:
+ case tok::caretequal:
+ case tok::pipe:
+ case tok::pipepipe:
+ case tok::pipeequal:
+ case tok::question:
+ case tok::equal:
+ case tok::equalequal:
+ return options.operators;
+ default:
+ break;
+ }
+ return HighlightStyle::ColorStyle();
+}
+
+std::size_t ClangHighlighter::Highlight(const HighlightStyle &options,
+ llvm::StringRef line,
+ llvm::StringRef previous_lines,
+ Stream &result) const {
+ using namespace clang;
+
+ std::size_t written_bytes = 0;
+
+ FileSystemOptions file_opts;
+ FileManager file_mgr(file_opts);
+
+ unsigned line_number = previous_lines.count('\n') + 1U;
+
+ // Let's build the actual source code Clang needs and setup some utility
+ // objects.
+ std::string full_source = previous_lines.str() + line.str();
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
+ llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
+ new DiagnosticOptions());
+ DiagnosticsEngine diags(diag_ids, diags_opts);
+ clang::SourceManager SM(diags, file_mgr);
+ auto buf = llvm::MemoryBuffer::getMemBuffer(full_source);
+
+ FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get());
+
+ // Let's just enable the latest ObjC and C++ which should get most tokens
+ // right.
+ LangOptions Opts;
+ Opts.ObjC2 = true;
+ Opts.CPlusPlus17 = true;
+ Opts.LineComment = true;
+
+ Lexer lex(FID, buf.get(), SM, Opts);
+ // The lexer should keep whitespace around.
+ lex.SetKeepWhitespaceMode(true);
+
+ // Keeps track if we have entered a PP directive.
+ bool in_pp_directive = false;
+
+ // True once we actually lexed the user provided line.
+ bool found_user_line = false;
+
+ Token token;
+ bool exit = false;
+ while (!exit) {
+ // Returns true if this is the last token we get from the lexer.
+ exit = lex.LexFromRawLexer(token);
+
+ bool invalid = false;
+ unsigned current_line_number =
+ SM.getSpellingLineNumber(token.getLocation(), &invalid);
+ if (current_line_number != line_number)
+ continue;
+ found_user_line = true;
+
+ // We don't need to print any tokens without a spelling line number.
+ if (invalid)
+ continue;
+
+ // Same as above but with the column number.
+ invalid = false;
+ unsigned start = SM.getSpellingColumnNumber(token.getLocation(), &invalid);
+ if (invalid)
+ continue;
+ // Column numbers start at 1, but indexes in our string start at 0.
+ --start;
+
+ // Annotations don't have a length, so let's skip them.
+ if (token.isAnnotation())
+ continue;
+
+ // Extract the token string from our source code.
+ llvm::StringRef tok_str = line.substr(start, token.getLength());
+
+ // If the token is just an empty string, we can skip all the work below.
+ if (tok_str.empty())
+ continue;
+
+ // See how we are supposed to highlight this token.
+ HighlightStyle::ColorStyle color =
+ determineClangStyle(*this, token, tok_str, options, in_pp_directive);
+
+ written_bytes += color.Apply(result, tok_str);
+ }
+
+ // If we went over the whole file but couldn't find our own file, then
+ // somehow our setup was wrong. When we're in release mode we just give the
+ // user the normal line and pretend we don't know how to highlight it. In
+ // debug mode we bail out with an assert as this should never happen.
+ if (!found_user_line) {
+ result << line;
+ written_bytes += line.size();
+ assert(false && "We couldn't find the user line in the input file?");
+ }
+
+ return written_bytes;
+}
Index: source/Plugins/Language/ClangCommon/CMakeLists.txt
===================================================================
--- /dev/null
+++ source/Plugins/Language/ClangCommon/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbPluginClangCommon PLUGIN
+ ClangHighlighter.cpp
+
+ LINK_LIBS
+ lldbCore
+ lldbUtility
+ LINK_COMPONENTS
+ Support
+)
Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
===================================================================
--- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -19,13 +19,16 @@
#include "llvm/ADT/StringRef.h"
// Project includes
+#include "Plugins/Language/ClangCommon/ClangHighlighter.h"
#include "lldb/Target/Language.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class CPlusPlusLanguage : public Language {
+ ClangHighlighter m_highlighter;
+
public:
class MethodName {
public:
@@ -90,6 +93,10 @@
HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics() override;
+ bool IsSourceFile(llvm::StringRef file_path) const override;
+
+ const Highlighter *GetHighlighter() const override { return &m_highlighter; }
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
Index: source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
===================================================================
--- source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1002,3 +1002,16 @@
return g_formatters;
}
+
+bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const {
+ const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c",
+ ".h", ".hh", ".hpp", ".hxx", ".h++"};
+ for (auto suffix : suffixes) {
+ if (file_path.endswith_lower(suffix))
+ return true;
+ }
+
+ // Check if we're in a STL path (where the files usually have no extension
+ // that we could check for.
+ return file_path.contains("/usr/include/c++/");
+}
Index: source/Plugins/Language/CPlusPlus/CMakeLists.txt
===================================================================
--- source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -24,6 +24,8 @@
lldbSymbol
lldbTarget
lldbUtility
+ lldbPluginClangCommon
+
LINK_COMPONENTS
Support
)
Index: source/Plugins/Language/CMakeLists.txt
===================================================================
--- source/Plugins/Language/CMakeLists.txt
+++ source/Plugins/Language/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(ClangCommon)
add_subdirectory(CPlusPlus)
add_subdirectory(Go)
add_subdirectory(Java)
Index: source/Core/SourceManager.cpp
===================================================================
--- source/Core/SourceManager.cpp
+++ source/Core/SourceManager.cpp
@@ -13,6 +13,7 @@
#include "lldb/Core/AddressRange.h" // for AddressRange
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatEntity.h" // for FormatEntity
+#include "lldb/Core/Highlighter.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h" // for ModuleList
#include "lldb/Host/FileSystem.h"
@@ -103,6 +104,18 @@
return file_sp;
}
+static bool should_highlight_source(DebuggerSP debugger_sp) {
+ if (!debugger_sp)
+ return false;
+
+ // We don't use ANSI stop column formatting if the debugger doesn't think it
+ // should be using color.
+ if (!debugger_sp->GetUseColor())
+ return false;
+
+ return debugger_sp->GetHighlightSource();
+}
+
static bool should_show_stop_column_with_ansi(DebuggerSP debugger_sp) {
// We don't use ANSI stop column formatting if we can't lookup values from
// the debugger.
@@ -114,6 +127,11 @@
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.
@@ -515,6 +533,16 @@
if (!m_data_sp)
return 0;
+ std::string previous_content;
+
+ 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 uint32_t start_line =
line <= context_before ? 1 : line - context_before;
const uint32_t start_line_offset = GetLineOffset(start_line);
@@ -530,10 +558,19 @@
size_t count = end_line_offset - start_line_offset;
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;
- if (column && (column < count)) {
- auto debugger_sp = m_debugger_wp.lock();
+ auto debugger_sp = m_debugger_wp.lock();
+ if (should_highlight_source(debugger_sp)) {
+ bytes_written +=
+ 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.
@@ -581,10 +618,10 @@
// If we didn't end up displaying the line with ANSI codes for whatever
// reason, display it now sans codes.
if (!displayed_line)
- bytes_written = s->Write(cstr, count);
+ bytes_written = s->PutCString(ref);
// Ensure we get an end of line character one way or another.
- if (!is_newline_char(cstr[count - 1]))
+ if (!is_newline_char(ref.back()))
bytes_written += s->EOL();
}
return bytes_written;
Index: source/Core/Highlighter.cpp
===================================================================
--- /dev/null
+++ source/Core/Highlighter.cpp
@@ -0,0 +1,68 @@
+//===-- Highlighter.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Highlighter.h"
+
+#include "lldb/Target/Language.h"
+#include "lldb/Utility/AnsiTerminal.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb_private;
+
+std::size_t HighlightStyle::ColorStyle::Apply(Stream &s,
+ llvm::StringRef value) const {
+ s << m_prefix << value << m_suffix;
+ // Calculate how many bytes we have written.
+ return m_prefix.size() + value.size() + m_suffix.size();
+}
+
+void HighlightStyle::ColorStyle::Set(llvm::StringRef prefix,
+ llvm::StringRef suffix) {
+ m_prefix = lldb_utility::ansi::FormatAnsiTerminalCodes(prefix);
+ m_suffix = lldb_utility::ansi::FormatAnsiTerminalCodes(suffix);
+}
+
+std::size_t 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;
+ return line.size();
+}
+
+static HighlightStyle::ColorStyle GetColor(const char *c) {
+ return HighlightStyle::ColorStyle(c, "${ansi.normal}");
+}
+
+HighlightStyle HighlightStyle::MakeVimStyle() {
+ HighlightStyle result;
+ result.comment = GetColor("${ansi.fg.purple}");
+ result.scalar_literal = GetColor("${ansi.fg.red}");
+ result.keyword = GetColor("${ansi.fg.green}");
+ return result;
+}
+
+const Highlighter &
+HighlighterManager::getHighlighterFor(lldb::LanguageType language_type,
+ llvm::StringRef path) const {
+ Language *language = lldb_private::Language::FindPlugin(language_type, path);
+ if (language && language->GetHighlighter())
+ return *language->GetHighlighter();
+ return m_no_highlighter;
+}
+
+std::string Highlighter::Highlight(const HighlightStyle &options,
+ llvm::StringRef line,
+ llvm::StringRef previous_lines) const {
+ StreamString s;
+ Highlight(options, line, previous_lines, s);
+ s.Flush();
+ return s.GetString().str();
+}
Index: source/Core/Debugger.cpp
===================================================================
--- source/Core/Debugger.cpp
+++ source/Core/Debugger.cpp
@@ -233,6 +233,8 @@
nullptr,
"The number of sources lines to display that come before the "
"current source line when displaying a stopped context."},
+ {"highlight-source", OptionValue::eTypeBoolean, true, true, nullptr,
+ nullptr, "If true, LLDB will highlight the displayed source code."},
{"stop-show-column", OptionValue::eTypeEnum, false,
eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values,
"If true, LLDB will use the column information from the debug info to "
@@ -296,6 +298,7 @@
ePropertyStopDisassemblyDisplay,
ePropertyStopLineCountAfter,
ePropertyStopLineCountBefore,
+ ePropertyHighlightSource,
ePropertyStopShowColumn,
ePropertyStopShowColumnAnsiPrefix,
ePropertyStopShowColumnAnsiSuffix,
@@ -470,6 +473,12 @@
return ret;
}
+bool Debugger::GetHighlightSource() const {
+ const uint32_t idx = ePropertyHighlightSource;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value);
+}
+
StopShowColumn Debugger::GetStopShowColumn() const {
const uint32_t idx = ePropertyStopShowColumn;
return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration(
Index: source/Core/CMakeLists.txt
===================================================================
--- source/Core/CMakeLists.txt
+++ source/Core/CMakeLists.txt
@@ -25,6 +25,7 @@
FileLineResolver.cpp
FileSpecList.cpp
FormatEntity.cpp
+ Highlighter.cpp
IOHandler.cpp
Listener.cpp
Mangled.cpp
Index: packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
===================================================================
--- packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
+++ packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
@@ -22,6 +22,8 @@
# return re.compile(r"\[4m%s\[0m" % inner_regex_text)
return "4.+\033\\[4m%s\033\\[0m" % inner_regex_text
+def ansi_color_surround_regex(inner_regex_text):
+ return "\033\\[3[0-7]m%s\033\\[0m" % inner_regex_text
class SourceManagerTestCase(TestBase):
@@ -47,7 +49,7 @@
# the character column after the initial whitespace.
return len(stop_line) - len(stop_line.lstrip()) + 1
- def do_display_source_python_api(self, use_color, column_marker_regex):
+ def do_display_source_python_api(self, use_color, needle_regex, highlight_source=False):
self.build()
exe = self.getBuildArtifact("a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
@@ -69,6 +71,9 @@
# Setup whether we should use ansi escape sequences, including color
# and styles such as underline.
self.dbg.SetUseColor(use_color)
+ # Disable syntax highlighting if needed.
+
+ self.runCmd("settings set highlight-source " + str(highlight_source).lower())
filespec = lldb.SBFileSpec(self.file, False)
source_mgr = self.dbg.GetSourceManager()
@@ -87,10 +92,10 @@
# => 4 printf("Hello world.\n"); // Set break point at this line.
# 5 return 0;
# 6 }
- self.expect(stream.GetData(), "Source code displayed correctly",
+ self.expect(stream.GetData(), "Source code displayed correctly:\n" + stream.GetData(),
exe=False,
patterns=['=> %d.*Hello world' % self.line,
- column_marker_regex])
+ needle_regex])
# Boundary condition testings for SBStream(). LLDB should not crash!
stream.Print(None)
@@ -111,6 +116,24 @@
underline_regex = ansi_underline_surround_regex(r".")
self.do_display_source_python_api(use_color, underline_regex)
+ @add_test_categories(['pyapi'])
+ def test_display_source_python_ansi_terminal_syntax_highlighting(self):
+ """Test display of source using the SBSourceManager API and check for
+ the syntax highlighted output"""
+ use_color = True
+ syntax_highlighting = True;
+
+ # Just pick 'int' as something that should be colored.
+ color_regex = ansi_color_surround_regex("int")
+ self.do_display_source_python_api(use_color, color_regex, syntax_highlighting)
+
+ # Same for 'char'.
+ color_regex = ansi_color_surround_regex("char")
+ 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)
+
def test_move_and_then_display_source(self):
"""Test that target.source-map settings work by moving main.c to hidden/main.c."""
self.build()
Index: include/lldb/Target/Language.h
===================================================================
--- include/lldb/Target/Language.h
+++ include/lldb/Target/Language.h
@@ -20,6 +20,7 @@
// Other libraries and framework includes
// Project includes
+#include "lldb/Core/Highlighter.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
#include "lldb/DataFormatters/FormatClasses.h"
@@ -152,13 +153,24 @@
static Language *FindPlugin(lldb::LanguageType language);
+ /// Returns the Language associated with the given file path or a nullptr
+ /// if there is no known language.
+ static Language *FindPlugin(llvm::StringRef file_path);
+
+ static Language *FindPlugin(lldb::LanguageType language,
+ llvm::StringRef file_path);
+
// return false from callback to stop iterating
static void ForEach(std::function<bool(Language *)> callback);
virtual lldb::LanguageType GetLanguageType() const = 0;
virtual bool IsTopLevelFunction(Function &function);
+ virtual bool IsSourceFile(llvm::StringRef file_path) const = 0;
+
+ virtual const Highlighter *GetHighlighter() const { return nullptr; }
+
virtual lldb::TypeCategoryImplSP GetFormatters();
virtual HardcodedFormatters::HardcodedFormatFinder GetHardcodedFormats();
Index: include/lldb/Core/Highlighter.h
===================================================================
--- /dev/null
+++ include/lldb/Core/Highlighter.h
@@ -0,0 +1,159 @@
+//===-- Highlighter.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Highlighter_h_
+#define liblldb_Highlighter_h_
+
+#include <utility>
+#include <vector>
+
+#include "lldb/Utility/Stream.h"
+#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// Represents style that the highlighter should apply to the given source code.
+/// Stores information about how every kind of token should be annotated.
+//----------------------------------------------------------------------
+struct HighlightStyle {
+
+ //----------------------------------------------------------------------
+ /// A pair of strings that should be placed around a certain token. Usually
+ /// stores color codes in these strings (the suffix string is often used for
+ /// resetting the terminal attributes back to normal).
+ //----------------------------------------------------------------------
+ class ColorStyle {
+ std::string m_prefix;
+ std::string m_suffix;
+
+ public:
+ ColorStyle() = default;
+ ColorStyle(llvm::StringRef prefix, llvm::StringRef suffix) {
+ Set(prefix, suffix);
+ }
+
+ /// Applies this style to the given value.
+ /// \param s
+ /// The stream to which the result should be appended.
+ /// \param value
+ /// The value that we should place our strings around.
+ /// \return
+ /// The number of bytes that have been written to the given stream.
+ std::size_t Apply(Stream &s, llvm::StringRef value) const;
+
+ /// Sets the prefix and suffix strings.
+ /// @param prefix
+ /// @param suffix
+ void Set(llvm::StringRef prefix, llvm::StringRef suffix);
+ };
+
+ /// Matches identifiers to variable or functions.
+ ColorStyle identifier;
+ /// Matches any string or character literals in the language: "foo" or 'f'
+ ColorStyle string_literal;
+ /// Matches scalar value literals like '42' or '0.1'.
+ ColorStyle scalar_literal;
+ /// Matches all reserved keywords in the language.
+ ColorStyle keyword;
+ /// Matches any comments in the language.
+ ColorStyle comment;
+ /// Matches commas: ','
+ ColorStyle comma;
+ /// Matches one colon: ':'
+ ColorStyle colon;
+ /// Matches any semicolon: ';'
+ ColorStyle semicolons;
+ /// Matches operators like '+', '-', '%', '&', '='
+ ColorStyle operators;
+
+ /// Matches '{' or '}'
+ ColorStyle braces;
+ /// Matches '[' or ']'
+ ColorStyle square_brackets;
+ /// Matches '(' or ')'
+ ColorStyle parentheses;
+
+ //-----------------------------------------------------------------------
+ // C language specific options
+ //-----------------------------------------------------------------------
+
+ /// Matches directives to a preprocessor (if the language has any).
+ ColorStyle pp_directive;
+
+ /// Returns a HighlightStyle that is based on vim's default highlight style.
+ static HighlightStyle MakeVimStyle();
+};
+
+//----------------------------------------------------------------------
+/// Annotates source code with color attributes.
+//----------------------------------------------------------------------
+class Highlighter {
+public:
+ Highlighter() = default;
+ virtual ~Highlighter() = default;
+ DISALLOW_COPY_AND_ASSIGN(Highlighter);
+
+ /// Returns a human readable name for the selected highlighter.
+ virtual llvm::StringRef GetName() const = 0;
+
+ /// Highlights the given line
+ /// \param options
+ /// \param line
+ /// The user supplied line that needs to be highlighted.
+ /// \param previous_lines
+ /// Any previous lines the user has written which we should only use
+ /// for getting the context of the Highlighting right.
+ /// \param s
+ /// The stream to which the highlighted version of the user string should
+ /// be written.
+ /// \return
+ /// The number of bytes that have been written to the stream.
+ virtual std::size_t Highlight(const HighlightStyle &options,
+ llvm::StringRef line,
+ 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::StringRef previous_lines = "") const;
+};
+
+/// A default highlighter that does nothing. Used as a fallback.
+class NoHighlighter : public Highlighter {
+public:
+ llvm::StringRef GetName() const override { return "none"; }
+
+ std::size_t Highlight(const HighlightStyle &options, llvm::StringRef line,
+ llvm::StringRef previous_lines,
+ Stream &s) const override;
+};
+
+/// Manages the available highlighters.
+class HighlighterManager {
+ NoHighlighter m_no_highlighter;
+
+public:
+ /// Queries all known highlighter for one that can highlight some source code.
+ /// \param language_type
+ /// The language type that the caller thinks the source code was given in.
+ /// \param path
+ /// The path to the file the source code is from. Used as a fallback when
+ /// the user can't provide a language.
+ /// \return
+ /// The highlighter that wants to highlight the source code. Could be an
+ /// empty highlighter that does nothing.
+ const Highlighter &getHighlighterFor(lldb::LanguageType language_type,
+ llvm::StringRef path) const;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Highlighter_h_
Index: include/lldb/Core/Debugger.h
===================================================================
--- include/lldb/Core/Debugger.h
+++ include/lldb/Core/Debugger.h
@@ -272,6 +272,8 @@
bool SetUseColor(bool use_color);
+ bool GetHighlightSource() const;
+
lldb::StopShowColumn GetStopShowColumn() const;
const FormatEntity::Entry *GetStopShowColumnAnsiPrefix() const;
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits