https://github.com/nabijaczleweli created https://github.com/llvm/llvm-project/pull/83060
 `CLANG_HIGHLIGHT_COLORS=on` is equivalent to unset, and enables the default. `CLANG_HIGHLIGHT_COLORS=off` (or `=no`, or anything to that effect) disables highlighting altogether. `CLANG_HIGHLIGHT_COLORS=comment=red` highlights comments in red, and the rest as-default. `CLANG_HIGHLIGHT_COLORS=comment=blue,literal=bright-magenta,keyword=no` highlights comments in blue, literals in bright magenta, and doesn't highlight keywords. Also documentation because the original didn't have it. From 81b1327c3b5104b0c053fd1ee8e8773925efb8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= <nabijaczlew...@nabijaczleweli.xyz> Date: Mon, 26 Feb 2024 21:58:24 +0100 Subject: [PATCH] [clang][Diagnostics] Add CLANG_HIGHLIGHT_COLORS= to configure syntax highlighting in diagnostics (#82945) CLANG_HIGHLIGHT_COLORS=on is equivalent to unset, and enables the default. CLANG_HIGHLIGHT_COLORS=off (or =no, or anything to that effect) disables highlighting altogether. CLANG_HIGHLIGHT_COLORS=comment=red highlights comments in red, and the rest as-default. CLANG_HIGHLIGHT_COLORS=comment=blue,literal=bright-magenta,keyword=no highlights comments in blue, literals in bright magenta, and doesn't highlight keywords. Fixes: 718aac9f7a19227b5c5ec85819a3a5ae24ce32e1 --- clang/docs/UsersManual.rst | 11 +++++++ clang/lib/Frontend/TextDiagnostic.cpp | 43 ++++++++++++++++++++----- llvm/include/llvm/Support/raw_ostream.h | 2 ++ llvm/lib/Support/raw_ostream.cpp | 39 ++++++++++++++++++++++ 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 7391e4cf3a9aeb..e268fb73159f12 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -256,6 +256,17 @@ output format of the diagnostics that it generates. defined and ``-fcolor-diagnostics`` is passed on the command line, Clang will honor the command line argument. + Additionally, if enabled, Clang will semantically highlight the code + the diagnostics pertain to. The ``CLANG_HIGHLIGHT_COLORS`` environment + variable controls this behaviour: + if unset or set to "on", code is highlighted normally. + If set to "off" or "no", highlighting is disabled. + Otherwise, a comma-separated, `token=color` list may be given, + where `token`s may be ``comment``, ``literal``, or ``keyword``, + and `color`s may be ``{bright-,}black,red,green,yellow,blue,magenta,cyan,white``. + If an unknown `color` is given, it's disabled. For example, a valid spec may be + ``CLANG_HIGHLIGHT_COLORS=comment=blue,literal=bright-magenta,keyword=no``. + .. option:: -fansi-escape-codes Controls whether ANSI escape codes are used instead of the Windows Console diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index 10240d7ee6f2e6..3fc528c39ce752 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -24,6 +24,7 @@ #include <optional> using namespace clang; +using namespace std::literals; static const enum raw_ostream::Colors noteColor = raw_ostream::CYAN; static const enum raw_ostream::Colors remarkColor = @@ -46,9 +47,31 @@ static const enum raw_ostream::Colors savedColor = // is already taken for 'note'. Green is already used to underline // source ranges. White and black are bad because of the usual // terminal backgrounds. Which leaves us only with TWO options. -static constexpr raw_ostream::Colors CommentColor = raw_ostream::YELLOW; -static constexpr raw_ostream::Colors LiteralColor = raw_ostream::GREEN; -static constexpr raw_ostream::Colors KeywordColor = raw_ostream::BLUE; +static std::optional<raw_ostream::Colors> CommentColor = raw_ostream::YELLOW; +static std::optional<raw_ostream::Colors> LiteralColor = raw_ostream::GREEN; +static std::optional<raw_ostream::Colors> KeywordColor = raw_ostream::BLUE; + +static __attribute__((constructor)) void loadHighlightColors() { + auto cfg = std::getenv("CLANG_HIGHLIGHT_COLORS"); + if (!cfg || cfg == "on"sv) + return; + + if (!std::strchr(cfg, '=')) { + CommentColor = LiteralColor = KeywordColor = {}; + return; + } + + const char *const tokens[]{"comment", "literal", "keyword", nullptr}; + std::optional<raw_ostream::Colors> *const colors[]{ + &CommentColor, &LiteralColor, &KeywordColor}; + for (char *value; *cfg;) { + auto idx = getsubopt(&cfg, const_cast<char *const *>(tokens), &value); + if (idx == -1 || !value) + continue; + + *colors[idx] = raw_ostream::parse_color(value); + } +} /// Add highlights to differences in template strings. static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, @@ -1138,7 +1161,7 @@ highlightLines(StringRef FileData, unsigned StartLineNumber, std::make_unique<SmallVector<TextDiagnostic::StyleRange>[]>( EndLineNumber - StartLineNumber + 1); - if (!PP || !ShowColors) + if (!PP || !ShowColors || (!CommentColor && !LiteralColor && !KeywordColor)) return SnippetRanges; // Might cause emission of another diagnostic. @@ -1164,6 +1187,10 @@ highlightLines(StringRef FileData, unsigned StartLineNumber, auto appendStyle = [PP, &LangOpts](SmallVector<TextDiagnostic::StyleRange> &Vec, const Token &T, unsigned Start, unsigned Length) -> void { + auto setColor = [&](auto && color) { + if (color) + Vec.emplace_back(Start, Start + Length, *color); + }; if (T.is(tok::raw_identifier)) { StringRef RawIdent = T.getRawIdentifier(); // Special case true/false/nullptr/... literals, since they will otherwise @@ -1183,18 +1210,18 @@ highlightLines(StringRef FileData, unsigned StartLineNumber, .Case("__FUNCTION__", true) .Case("__FUNCSIG__", true) .Default(false)) { - Vec.emplace_back(Start, Start + Length, LiteralColor); + setColor(LiteralColor); } else { const IdentifierInfo *II = PP->getIdentifierInfo(RawIdent); assert(II); if (II->isKeyword(LangOpts)) - Vec.emplace_back(Start, Start + Length, KeywordColor); + setColor(KeywordColor); } } else if (tok::isLiteral(T.getKind())) { - Vec.emplace_back(Start, Start + Length, LiteralColor); + setColor(LiteralColor); } else { assert(T.is(tok::comment)); - Vec.emplace_back(Start, Start + Length, CommentColor); + setColor(CommentColor); } }; diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h index 696290a5d99cf5..61cb6d09abe24a 100644 --- a/llvm/include/llvm/Support/raw_ostream.h +++ b/llvm/include/llvm/Support/raw_ostream.h @@ -133,6 +133,8 @@ class raw_ostream { static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR; static constexpr Colors RESET = Colors::RESET; + static std::optional<Colors> parse_color(const std::string_view &name) noexcept; + explicit raw_ostream(bool unbuffered = false, OStreamKind K = OStreamKind::OK_OStream) : Kind(K), BufferMode(unbuffered ? BufferKind::Unbuffered diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp index c7064d2dfedc56..27031c962f068f 100644 --- a/llvm/lib/Support/raw_ostream.cpp +++ b/llvm/lib/Support/raw_ostream.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/NativeFormatting.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" +#include <string_view> #include <algorithm> #include <cerrno> #include <cstdio> @@ -62,6 +63,7 @@ #endif using namespace llvm; +using namespace std::literals; constexpr raw_ostream::Colors raw_ostream::BLACK; constexpr raw_ostream::Colors raw_ostream::RED; @@ -74,6 +76,43 @@ constexpr raw_ostream::Colors raw_ostream::WHITE; constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR; constexpr raw_ostream::Colors raw_ostream::RESET; +std::optional<raw_ostream::Colors> raw_ostream::parse_color(const std::string_view &name) noexcept { + if(name == "black"sv) + return Colors::BLACK; + else if(name == "red"sv) + return Colors::RED; + else if(name == "green"sv) + return Colors::GREEN; + else if(name == "yellow"sv) + return Colors::YELLOW; + else if(name == "blue"sv) + return Colors::BLUE; + else if(name == "magenta"sv) + return Colors::MAGENTA; + else if(name == "cyan"sv) + return Colors::CYAN; + else if(name == "white"sv) + return Colors::WHITE; + else if(name == "bright-black"sv) + return Colors::BRIGHT_BLACK; + else if(name == "bright-red"sv) + return Colors::BRIGHT_RED; + else if(name == "bright-green"sv) + return Colors::BRIGHT_GREEN; + else if(name == "bright-yellow"sv) + return Colors::BRIGHT_YELLOW; + else if(name == "bright-blue"sv) + return Colors::BRIGHT_BLUE; + else if(name == "bright-magenta"sv) + return Colors::BRIGHT_MAGENTA; + else if(name == "bright-cyan"sv) + return Colors::BRIGHT_CYAN; + else if(name == "bright-white"sv) + return Colors::BRIGHT_WHITE; + else + return std::nullopt; +} + raw_ostream::~raw_ostream() { // raw_ostream's subclasses should take care to flush the buffer // in their destructors. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits