Răsfoiți Sursa

ccmake: Improve coloring, allow customization

Change the default color for strings from BLUE (which is nearly
illegible on any terminals using the standard color palette which has
been around since at least CGA, almost 40 years ago) to CYAN. Add
ability to customize the colors via an environment variable (inspired by
LS_COLORS and using similar syntax).

Fixes: #20596
Matthew Woehlke 5 ani în urmă
părinte
comite
671fe28313

+ 34 - 0
Help/envvar/CCMAKE_COLORS.rst

@@ -0,0 +1,34 @@
+CCMAKE_COLORS
+-------------
+
+Determines what colors are used by the CMake curses interface,
+when run on a terminal that supports colors.
+The syntax follows the same conventions as ``LS_COLORS``;
+that is, a list of key/value pairs separated by ``:``.
+
+Keys are a single letter corresponding to a CMake cache variable type:
+
+- ``s``: A ``STRING``.
+- ``p``: A ``FILEPATH``.
+- ``c``: A value which has an associated list of choices.
+- ``y``: A ``BOOL`` which has a true-like value (e.g. ``ON``, ``YES``).
+- ``n``: A ``BOOL`` which has a false-like value (e.g. ``OFF``, ``NO``).
+
+Values are an integer number that specifies what color to use.
+``0`` is black (you probably don't want to use that).
+Others are determined by your terminal's color support.
+Most (color) terminals will support at least 8 or 16 colors.
+Some will support up to 256 colors. The colors will likely match
+`this chart <https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg>`_,
+although the first 16 colors may match the original
+`CGA color palette <https://en.wikipedia.org/wiki/Color_Graphics_Adapter#Color_palette>`_.
+(Many modern terminal emulators also allow their color palette,
+at least for the first 16 colors, to be configured by the user.)
+
+Note that fairly minimal checking is done for bad colors
+(although a value higher than what curses believes your terminal supports
+will be silently ignored) or bad syntax.
+
+For example::
+
+  CCMAKE_COLORS='s=39:p=220:c=207:n=196:y=46'

+ 8 - 0
Help/manual/cmake-env-variables.7.rst

@@ -80,3 +80,11 @@ Environment Variables for CTest
    /envvar/CTEST_PROGRESS_OUTPUT
    /envvar/CTEST_USE_LAUNCHERS_DEFAULT
    /envvar/DASHBOARD_TEST_FROM_CTEST
+
+Environment Variables for the CMake curses interface
+====================================================
+
+.. toctree::
+   :maxdepth: 1
+
+   /envvar/CCMAKE_COLORS

+ 5 - 0
Help/release/dev/ccmake-custom-colors.rst

@@ -0,0 +1,5 @@
+ccmake-custom-colors
+--------------------
+
+* :manual:`ccmake(1)` learned to read a :envvar:`CCMAKE_COLORS`
+  environment variable to customize colors.

+ 54 - 5
Source/CursesDialog/cmCursesColor.cxx

@@ -2,6 +2,12 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmCursesColor.h"
 
+#include <cctype>
+#include <cstdlib>
+#include <cstring>
+#include <unordered_map>
+#include <utility>
+
 #include "cmCursesStandardIncludes.h"
 
 bool cmCursesColor::HasColors()
@@ -19,11 +25,54 @@ void cmCursesColor::InitColors()
   if (HasColors()) {
     start_color();
     use_default_colors();
-    init_pair(cmCursesColor::BoolOff, COLOR_RED, -1);
-    init_pair(cmCursesColor::BoolOn, COLOR_GREEN, -1);
-    init_pair(cmCursesColor::String, COLOR_BLUE, -1);
-    init_pair(cmCursesColor::Path, COLOR_YELLOW, -1);
-    init_pair(cmCursesColor::Choice, COLOR_MAGENTA, -1);
+    init_pair(BoolOff, GetColor('N', COLOR_RED), -1);
+    init_pair(BoolOn, GetColor('Y', COLOR_GREEN), -1);
+    init_pair(String, GetColor('S', COLOR_CYAN), -1);
+    init_pair(Path, GetColor('P', COLOR_YELLOW), -1);
+    init_pair(Choice, GetColor('C', COLOR_MAGENTA), -1);
   }
 #endif
 }
+
+short cmCursesColor::GetColor(char id, short fallback)
+{
+  static bool initialized = false;
+  static std::unordered_map<char, short> env;
+
+  if (!initialized) {
+    if (auto* v = getenv("CCMAKE_COLORS")) {
+      while (v[0] && v[1] && v[1] == '=') {
+        auto const n = std::toupper(*v);
+
+        char buffer[12];
+        memset(buffer, 0, sizeof(buffer));
+
+        if (auto* const e = strchr(v, ':')) {
+          if (static_cast<size_t>(e - v) > sizeof(buffer)) {
+            break;
+          }
+
+          strncpy(buffer, v + 2, static_cast<size_t>(e - v - 2));
+          v = e + 1;
+        } else {
+          auto const l = strlen(v);
+          if (l > sizeof(buffer)) {
+            break;
+          }
+
+          strncpy(buffer, v + 2, l - 2);
+          v += l;
+        }
+
+        auto const c = atoi(buffer);
+        if (c && c < COLORS) {
+          env.emplace(n, static_cast<short>(c));
+        }
+      }
+    }
+    initialized = true;
+  }
+
+  auto const iter = env.find(id);
+  return (iter == env.end() ? fallback : iter->second);
+}

+ 3 - 0
Source/CursesDialog/cmCursesColor.h

@@ -19,6 +19,9 @@ public:
   static bool HasColors();
 
   static void InitColors();
+
+protected:
+  static short GetColor(char id, short fallback);
 };
 
 #endif // cmCursesColor_h