Browse Source

Merge topic 'ccmake-custom-colors'

671fe28313 ccmake: Improve coloring, allow customization
f56a695440 ccmake: Rename cmCursesColor::{Options => Choice}

Acked-by: Kitware Robot <[email protected]>
Merge-request: !4629
Brad King 5 years ago
parent
commit
0e3a2d9b16

+ 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::Options, 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);
+}

+ 4 - 1
Source/CursesDialog/cmCursesColor.h

@@ -13,12 +13,15 @@ public:
     BoolOn,
     String,
     Path,
-    Options
+    Choice
   };
 
   static bool HasColors();
 
   static void InitColors();
+
+protected:
+  static short GetColor(char id, short fallback);
 };
 
 #endif // cmCursesColor_h

+ 2 - 2
Source/CursesDialog/cmCursesOptionsWidget.cxx

@@ -17,8 +17,8 @@ cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left,
   // the widget into a string widget at some point.  BOOL is safe for
   // now.
   if (cmCursesColor::HasColors()) {
-    set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Options));
-    set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Options));
+    set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Choice));
+    set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Choice));
   } else {
     set_field_fore(this->Field, A_NORMAL);
     set_field_back(this->Field, A_STANDOUT);