[llvm] r367649 - Improve raw_ostream so that you can "write" colors using operator<<

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 1 21:48:30 PDT 2019


Author: ruiu
Date: Thu Aug  1 21:48:30 2019
New Revision: 367649

URL: http://llvm.org/viewvc/llvm-project?rev=367649&view=rev
Log:
Improve raw_ostream so that you can "write" colors using operator<<

1. raw_ostream supports ANSI colors so that you can write messages to
the termina with colors. Previously, in order to change and reset
color, you had to call `changeColor` and `resetColor` functions,
respectively.

So, if you print out "error: " in red, for example, you had to do
something like this:

  OS.changeColor(raw_ostream::RED);
  OS << "error: ";
  OS.resetColor();

With this patch, you can write the same code as follows:

  OS << raw_ostream::RED << "error: " << raw_ostream::RESET;

2. Add a boolean flag to raw_ostream so that you can disable colored
output. If you disable colors, changeColor, operator<<(Color),
resetColor and other color-related functions have no effect.

Most LLVM tools automatically prints out messages using colors, and
you can disable it by passing a flag such as `--disable-colors`.
This new flag makes it easy to write code that works that way.

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

Modified:
    llvm/trunk/include/llvm/Support/FormattedStream.h
    llvm/trunk/include/llvm/Support/WithColor.h
    llvm/trunk/include/llvm/Support/raw_ostream.h
    llvm/trunk/lib/Support/WithColor.cpp
    llvm/trunk/lib/Support/raw_ostream.cpp
    llvm/trunk/tools/llvm-cov/CoverageReport.cpp
    llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
    llvm/trunk/tools/llvm-cov/RenderingSupport.h
    llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp
    llvm/trunk/tools/llvm-cov/llvm-cov.cpp
    llvm/trunk/tools/llvm-mca/Views/TimelineView.cpp
    llvm/trunk/utils/FileCheck/FileCheck.cpp

Modified: llvm/trunk/include/llvm/Support/FormattedStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FormattedStream.h?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FormattedStream.h (original)
+++ llvm/trunk/include/llvm/Support/FormattedStream.h Thu Aug  1 21:48:30 2019
@@ -121,8 +121,8 @@ public:
     return *this;
   }
 
-  raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override {
-    TheStream->changeColor(Color, Bold, BG);
+  raw_ostream &changeColor(Color C, bool Bold, bool BG) override {
+    TheStream->changeColor(C, Bold, BG);
     return *this;
   }
 

Modified: llvm/trunk/include/llvm/Support/WithColor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/WithColor.h?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/WithColor.h (original)
+++ llvm/trunk/include/llvm/Support/WithColor.h Thu Aug  1 21:48:30 2019
@@ -53,8 +53,7 @@ public:
   /// @param BG If true, change the background, default: change foreground
   /// @param DisableColors Whether to ignore color changes regardless of -color
   /// and support in OS
-  WithColor(raw_ostream &OS,
-            raw_ostream::Colors Color = raw_ostream::SAVEDCOLOR,
+  WithColor(raw_ostream &OS, raw_ostream::Color Color = raw_ostream::SAVEDCOLOR,
             bool Bold = false, bool BG = false, bool DisableColors = false)
       : OS(OS), DisableColors(DisableColors) {
     changeColor(Color, Bold, BG);
@@ -102,7 +101,7 @@ public:
   /// change only the bold attribute, and keep colors untouched
   /// @param Bold Bold/brighter text, default false
   /// @param BG If true, change the background, default: change foreground
-  WithColor &changeColor(raw_ostream::Colors Color, bool Bold = false,
+  WithColor &changeColor(raw_ostream::Color Color, bool Bold = false,
                          bool BG = false);
 
   /// Reset the colors to terminal defaults. Call this when you are done

Modified: llvm/trunk/include/llvm/Support/raw_ostream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/raw_ostream.h?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/raw_ostream.h (original)
+++ llvm/trunk/include/llvm/Support/raw_ostream.h Thu Aug  1 21:48:30 2019
@@ -72,7 +72,7 @@ private:
 
 public:
   // color order matches ANSI escape sequence, don't change
-  enum Colors {
+  enum class Color {
     BLACK = 0,
     RED,
     GREEN,
@@ -81,9 +81,21 @@ public:
     MAGENTA,
     CYAN,
     WHITE,
-    SAVEDCOLOR
+    SAVEDCOLOR,
+    RESET,
   };
 
+  static const Color BLACK = Color::BLACK;
+  static const Color RED = Color::RED;
+  static const Color GREEN = Color::GREEN;
+  static const Color YELLOW = Color::YELLOW;
+  static const Color BLUE = Color::BLUE;
+  static const Color MAGENTA = Color::MAGENTA;
+  static const Color CYAN = Color::CYAN;
+  static const Color WHITE = Color::WHITE;
+  static const Color SAVEDCOLOR = Color::SAVEDCOLOR;
+  static const Color RESET = Color::RESET;
+
   explicit raw_ostream(bool unbuffered = false)
       : BufferMode(unbuffered ? Unbuffered : InternalBuffer) {
     // Start out ready to flush.
@@ -214,6 +226,9 @@ public:
   /// Output \p N in hexadecimal, without any prefix or padding.
   raw_ostream &write_hex(unsigned long long N);
 
+  // Change the foreground color of text.
+  raw_ostream &operator<<(Color C);
+
   /// Output a formatted UUID with dash separators.
   using uuid_t = uint8_t[16];
   raw_ostream &write_uuid(const uuid_t UUID);
@@ -248,15 +263,14 @@ public:
 
   /// Changes the foreground color of text that will be output from this point
   /// forward.
-  /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+  /// @param C ANSI color to use, the special SAVEDCOLOR can be used to
   /// change only the bold attribute, and keep colors untouched
   /// @param Bold bold/brighter text, default false
   /// @param BG if true change the background, default: change foreground
   /// @returns itself so it can be used within << invocations
-  virtual raw_ostream &changeColor(enum Colors Color,
-                                   bool Bold = false,
+  virtual raw_ostream &changeColor(Color C, bool Bold = false,
                                    bool BG = false) {
-    (void)Color;
+    (void)C;
     (void)Bold;
     (void)BG;
     return *this;
@@ -277,6 +291,11 @@ public:
   /// This function determines if this stream is displayed and supports colors.
   virtual bool has_colors() const { return is_displayed(); }
 
+  // Enable or disable colors. Once disable_colors() is called,
+  // changeColor() has no effect until enable_colors() is called.
+  virtual void enable_colors() {}
+  virtual void disable_colors() {}
+
   //===--------------------------------------------------------------------===//
   // Subclass Interface
   //===--------------------------------------------------------------------===//
@@ -368,6 +387,8 @@ class raw_fd_ostream : public raw_pwrite
 
   bool SupportsSeeking;
 
+  bool ColorEnabled;
+
 #ifdef _WIN32
   /// True if this fd refers to a Windows console device. Mintty and other
   /// terminal emulators are TTYs, but they are not consoles.
@@ -432,8 +453,8 @@ public:
   /// to the offset specified from the beginning of the file.
   uint64_t seek(uint64_t off);
 
-  raw_ostream &changeColor(enum Colors colors, bool bold=false,
-                           bool bg=false) override;
+  raw_ostream &changeColor(Color C, bool bold = false,
+                           bool bg = false) override;
   raw_ostream &resetColor() override;
 
   raw_ostream &reverseColor() override;
@@ -442,6 +463,10 @@ public:
 
   bool has_colors() const override;
 
+  void enable_colors() override { ColorEnabled = true; }
+
+  void disable_colors() override { ColorEnabled = false; }
+
   std::error_code error() const { return EC; }
 
   /// Return the value of the flag in this raw_fd_ostream indicating whether an

Modified: llvm/trunk/lib/Support/WithColor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/WithColor.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/lib/Support/WithColor.cpp (original)
+++ llvm/trunk/lib/Support/WithColor.cpp Thu Aug  1 21:48:30 2019
@@ -22,6 +22,8 @@ WithColor::WithColor(raw_ostream &OS, Hi
     : OS(OS), DisableColors(DisableColors) {
   // Detect color from terminal type unless the user passed the --color option.
   if (colorsEnabled()) {
+    OS.enable_colors();
+
     switch (Color) {
     case HighlightColor::Address:
       OS.changeColor(raw_ostream::YELLOW);
@@ -104,10 +106,9 @@ bool WithColor::colorsEnabled() {
   return UseColor == cl::BOU_TRUE;
 }
 
-WithColor &WithColor::changeColor(raw_ostream::Colors Color, bool Bold,
-                                  bool BG) {
+WithColor &WithColor::changeColor(raw_ostream::Color C, bool Bold, bool BG) {
   if (colorsEnabled())
-    OS.changeColor(Color, Bold, BG);
+    OS.changeColor(C, Bold, BG);
   return *this;
 }
 

Modified: llvm/trunk/lib/Support/raw_ostream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/raw_ostream.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/lib/Support/raw_ostream.cpp (original)
+++ llvm/trunk/lib/Support/raw_ostream.cpp Thu Aug  1 21:48:30 2019
@@ -65,6 +65,17 @@
 
 using namespace llvm;
 
+const raw_ostream::Color raw_ostream::BLACK;
+const raw_ostream::Color raw_ostream::RED;
+const raw_ostream::Color raw_ostream::GREEN;
+const raw_ostream::Color raw_ostream::YELLOW;
+const raw_ostream::Color raw_ostream::BLUE;
+const raw_ostream::Color raw_ostream::MAGENTA;
+const raw_ostream::Color raw_ostream::CYAN;
+const raw_ostream::Color raw_ostream::WHITE;
+const raw_ostream::Color raw_ostream::SAVEDCOLOR;
+const raw_ostream::Color raw_ostream::RESET;
+
 raw_ostream::~raw_ostream() {
   // raw_ostream's subclasses should take care to flush the buffer
   // in their destructors.
@@ -133,6 +144,14 @@ raw_ostream &raw_ostream::write_hex(unsi
   return *this;
 }
 
+raw_ostream &raw_ostream::operator<<(Color C) {
+  if (C == Color::RESET)
+    resetColor();
+  else
+    changeColor(C);
+  return *this;
+}
+
 raw_ostream &raw_ostream::write_uuid(const uuid_t UUID) {
   for (int Idx = 0; Idx < 16; ++Idx) {
     *this << format("%02" PRIX32, UUID[Idx]);
@@ -552,8 +571,9 @@ raw_fd_ostream::raw_fd_ostream(StringRef
 /// FD is the file descriptor that this writes to.  If ShouldClose is true, this
 /// closes the file when the stream is destroyed.
 raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
-    : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
-  if (FD < 0 ) {
+    : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose),
+      ColorEnabled(sys::Process::FileDescriptorHasColors(fd)) {
+  if (FD < 0) {
     ShouldClose = false;
     return;
   }
@@ -782,13 +802,16 @@ size_t raw_fd_ostream::preferred_buffer_
 #endif
 }
 
-raw_ostream &raw_fd_ostream::changeColor(enum Colors colors, bool bold,
-                                         bool bg) {
+raw_ostream &raw_fd_ostream::changeColor(Color color, bool bold, bool bg) {
+  if (!ColorEnabled)
+    return *this;
+
   if (sys::Process::ColorNeedsFlush())
     flush();
   const char *colorcode =
-    (colors == SAVEDCOLOR) ? sys::Process::OutputBold(bg)
-    : sys::Process::OutputColor(colors, bold, bg);
+      (color == Color::SAVEDCOLOR)
+          ? sys::Process::OutputBold(bg)
+          : sys::Process::OutputColor(static_cast<char>(color), bold, bg);
   if (colorcode) {
     size_t len = strlen(colorcode);
     write(colorcode, len);
@@ -799,6 +822,9 @@ raw_ostream &raw_fd_ostream::changeColor
 }
 
 raw_ostream &raw_fd_ostream::resetColor() {
+  if (!ColorEnabled)
+    return *this;
+
   if (sys::Process::ColorNeedsFlush())
     flush();
   const char *colorcode = sys::Process::ResetColor();
@@ -812,6 +838,9 @@ raw_ostream &raw_fd_ostream::resetColor(
 }
 
 raw_ostream &raw_fd_ostream::reverseColor() {
+  if (!ColorEnabled)
+    return *this;
+
   if (sys::Process::ColorNeedsFlush())
     flush();
   const char *colorcode = sys::Process::OutputReverse();

Modified: llvm/trunk/tools/llvm-cov/CoverageReport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageReport.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageReport.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CoverageReport.cpp Thu Aug  1 21:48:30 2019
@@ -111,7 +111,7 @@ void renderDivider(ArrayRef<size_t> Colu
 /// Return the color which correponds to the coverage percentage of a
 /// certain metric.
 template <typename T>
-raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
+raw_ostream::Color determineCoveragePercentageColor(const T &Info) {
   if (Info.isFullyCovered())
     return raw_ostream::GREEN;
   return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW

Modified: llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageViewOptions.h?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageViewOptions.h (original)
+++ llvm/trunk/tools/llvm-cov/CoverageViewOptions.h Thu Aug  1 21:48:30 2019
@@ -46,7 +46,7 @@ struct CoverageViewOptions {
 
   /// Change the output's stream color if the colors are enabled.
   ColoredRawOstream colored_ostream(raw_ostream &OS,
-                                    raw_ostream::Colors Color) const {
+                                    raw_ostream::Color Color) const {
     return llvm::colored_ostream(OS, Color, Colors);
   }
 

Modified: llvm/trunk/tools/llvm-cov/RenderingSupport.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/RenderingSupport.h?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/RenderingSupport.h (original)
+++ llvm/trunk/tools/llvm-cov/RenderingSupport.h Thu Aug  1 21:48:30 2019
@@ -47,7 +47,7 @@ inline raw_ostream &operator<<(const Col
 /// Change the color of the output stream if the `IsColorUsed` flag
 /// is true. Returns an object that resets the color when destroyed.
 inline ColoredRawOstream colored_ostream(raw_ostream &OS,
-                                         raw_ostream::Colors Color,
+                                         raw_ostream::Color Color,
                                          bool IsColorUsed = true,
                                          bool Bold = false, bool BG = false) {
   if (IsColorUsed)

Modified: llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp (original)
+++ llvm/trunk/tools/llvm-cov/SourceCoverageViewText.cpp Thu Aug  1 21:48:30 2019
@@ -101,7 +101,7 @@ void SourceCoverageViewText::renderLine(
   auto *WrappedSegment = LCS.getWrappedSegment();
   CoverageSegmentArray Segments = LCS.getLineSegments();
 
-  Optional<raw_ostream::Colors> Highlight;
+  Optional<raw_ostream::Color> Highlight;
   SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
 
   // The first segment overlaps from a previous line, so we treat it specially.

Modified: llvm/trunk/tools/llvm-cov/llvm-cov.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/llvm-cov.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/llvm-cov.cpp (original)
+++ llvm/trunk/tools/llvm-cov/llvm-cov.cpp Thu Aug  1 21:48:30 2019
@@ -83,13 +83,10 @@ int main(int argc, const char **argv) {
     }
   }
 
-  if (argc > 1) {
-    if (sys::Process::StandardErrHasColors())
-      errs().changeColor(raw_ostream::RED);
-    errs() << "Unrecognized command: " << argv[1] << ".\n\n";
-    if (sys::Process::StandardErrHasColors())
-      errs().resetColor();
-  }
+  if (argc > 1)
+    errs() << raw_ostream::RED << "Unrecognized command: " << argv[1] << ".\n\n"
+           << raw_ostream::RESET;
+
   helpMain(argc, argv);
   return 1;
 }

Modified: llvm/trunk/tools/llvm-mca/Views/TimelineView.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Views/TimelineView.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Views/TimelineView.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Views/TimelineView.cpp Thu Aug  1 21:48:30 2019
@@ -103,8 +103,8 @@ void TimelineView::onEvent(const HWInstr
     LastCycle = std::max(LastCycle, CurrentCycle);
 }
 
-static raw_ostream::Colors chooseColor(unsigned CumulativeCycles,
-                                       unsigned Executions, int BufferSize) {
+static raw_ostream::Color chooseColor(unsigned CumulativeCycles,
+                                      unsigned Executions, int BufferSize) {
   if (CumulativeCycles && BufferSize < 0)
     return raw_ostream::MAGENTA;
   unsigned Size = static_cast<unsigned>(BufferSize);
@@ -120,7 +120,7 @@ static void tryChangeColor(raw_ostream &
   if (!OS.has_colors())
     return;
 
-  raw_ostream::Colors Color = chooseColor(Cycles, Executions, BufferSize);
+  raw_ostream::Color Color = chooseColor(Cycles, Executions, BufferSize);
   if (Color == raw_ostream::SAVEDCOLOR) {
     OS.resetColor();
     return;

Modified: llvm/trunk/utils/FileCheck/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/FileCheck/FileCheck.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- llvm/trunk/utils/FileCheck/FileCheck.cpp (original)
+++ llvm/trunk/utils/FileCheck/FileCheck.cpp Thu Aug  1 21:48:30 2019
@@ -138,12 +138,11 @@ struct MarkerStyle {
   /// The starting char (before tildes) for marking the line.
   char Lead;
   /// What color to use for this annotation.
-  raw_ostream::Colors Color;
+  raw_ostream::Color Color;
   /// A note to follow the marker, or empty string if none.
   std::string Note;
   MarkerStyle() {}
-  MarkerStyle(char Lead, raw_ostream::Colors Color,
-              const std::string &Note = "")
+  MarkerStyle(char Lead, raw_ostream::Color Color, const std::string &Note = "")
       : Lead(Lead), Color(Color), Note(Note) {}
 };
 




More information about the llvm-commits mailing list