diff --git a/Help/release/dev/message-color.rst b/Help/release/dev/message-color.rst new file mode 100644 index 0000000000..4acf15e9ff --- /dev/null +++ b/Help/release/dev/message-color.rst @@ -0,0 +1,4 @@ +message-color +------------- + +* Messages printed to a terminal now may be colored by message type. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c19c154622..bd9e4c2d82 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -638,6 +638,7 @@ set(SRCS cmMathCommand.h cmMessageCommand.cxx cmMessageCommand.h + cmMessageMetadata.h cmOptionCommand.cxx cmOptionCommand.h cmOutputRequiredFilesCommand.cxx diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index a18cbb49bc..adfc8ef774 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -19,6 +19,8 @@ #include "cmWorkingDirectory.h" #include "cmake.h" +struct cmMessageMetadata; + cmCTestBuildAndTestHandler::cmCTestBuildAndTestHandler() { this->BuildTwoConfig = false; @@ -125,7 +127,7 @@ public: : CM(cm) { cmSystemTools::SetMessageCallback( - [&s](const std::string& msg, const char* /*unused*/) { + [&s](const std::string& msg, const cmMessageMetadata& /* unused */) { s += msg; s += "\n"; }); diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 85e256b8bc..1ba45e5f7a 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -19,6 +19,7 @@ #include "cmCursesStandardIncludes.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" // IWYU pragma: keep +#include "cmMessageMetadata.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -181,8 +182,8 @@ int main(int argc, char const* const* argv) return msg; }; cmSystemTools::SetMessageCallback( - [&](const std::string& message, const char* title) { - myform->AddError(cleanMessage(message), title); + [&](const std::string& message, const cmMessageMetadata& md) { + myform->AddError(cleanMessage(message), md.title); }); cmSystemTools::SetStderrCallback([&](const std::string& message) { myform->AddError(cleanMessage(message), ""); diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index a83622afe8..e6faef4703 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -13,6 +13,7 @@ #include "cmExternalMakefileProjectGenerator.h" #include "cmGlobalGenerator.h" +#include "cmMessageMetadata.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -37,8 +38,8 @@ QCMake::QCMake(QObject* p) cmSystemTools::SetRunCommandHideConsole(true); cmSystemTools::SetMessageCallback( - [this](std::string const& msg, const char* title) { - this->messageCallback(msg, title); + [this](std::string const& msg, const cmMessageMetadata& md) { + this->messageCallback(msg, md.title); }); cmSystemTools::SetStdoutCallback( [this](std::string const& msg) { this->stdoutCallback(msg); }); diff --git a/Source/cmMessageMetadata.h b/Source/cmMessageMetadata.h new file mode 100644 index 0000000000..7b56faed7b --- /dev/null +++ b/Source/cmMessageMetadata.h @@ -0,0 +1,11 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmsys/Terminal.h" + +struct cmMessageMetadata +{ + const char* title = nullptr; + int desiredColor = cmsysTerminal_Color_Normal; +}; diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx index af83478a65..1cb638ac25 100644 --- a/Source/cmMessenger.cxx +++ b/Source/cmMessenger.cxx @@ -3,6 +3,7 @@ #include "cmMessenger.h" #include "cmDocumentationFormatter.h" +#include "cmMessageMetadata.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -12,6 +13,8 @@ #include +#include "cmsys/Terminal.h" + MessageType cmMessenger::ConvertMessageType(MessageType t) const { bool warningsAsErrors; @@ -84,6 +87,21 @@ static bool printMessagePreamble(MessageType t, std::ostream& msg) return true; } +static int getMessageColor(MessageType t) +{ + switch (t) { + case MessageType::INTERNAL_ERROR: + case MessageType::FATAL_ERROR: + case MessageType::AUTHOR_ERROR: + return cmsysTerminal_Color_ForegroundRed; + case MessageType::AUTHOR_WARNING: + case MessageType::WARNING: + return cmsysTerminal_Color_ForegroundYellow; + default: + return cmsysTerminal_Color_Normal; + } +} + void printMessageText(std::ostream& msg, std::string const& text) { msg << ":\n"; @@ -120,12 +138,16 @@ void displayMessage(MessageType t, std::ostringstream& msg) #endif // Output the message. + cmMessageMetadata md; + md.desiredColor = getMessageColor(t); if (t == MessageType::FATAL_ERROR || t == MessageType::INTERNAL_ERROR || t == MessageType::DEPRECATION_ERROR || t == MessageType::AUTHOR_ERROR) { cmSystemTools::SetErrorOccured(); - cmSystemTools::Message(msg.str(), "Error"); + md.title = "Error"; + cmSystemTools::Message(msg.str(), md); } else { - cmSystemTools::Message(msg.str(), "Warning"); + md.title = "Warning"; + cmSystemTools::Message(msg.str(), md); } } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 2fba13f436..9b81bf2675 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -19,6 +19,7 @@ #include #include "cmDuration.h" +#include "cmMessageMetadata.h" #include "cmProcessOutput.h" #include "cmRange.h" #include "cmStringAlgorithms.h" @@ -262,9 +263,16 @@ void cmSystemTools::Stdout(const std::string& s) } void cmSystemTools::Message(const std::string& m, const char* title) +{ + cmMessageMetadata md; + md.title = title; + Message(m, md); +} + +void cmSystemTools::Message(const std::string& m, const cmMessageMetadata& md) { if (s_MessageCallback) { - s_MessageCallback(m, title); + s_MessageCallback(m, md); } else { std::cerr << m << std::endl; } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 474f591ef5..5c3b5a9a0a 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -19,6 +19,8 @@ #include "cmDuration.h" #include "cmProcessOutput.h" +struct cmMessageMetadata; + /** \class cmSystemTools * \brief A collection of useful functions for CMake. * @@ -40,7 +42,8 @@ public: /** Map help document name to file name. */ static std::string HelpFileName(cm::string_view); - using MessageCallback = std::function; + using MessageCallback = + std::function; /** * Set the function used by GUIs to display error messages * Function gets passed: message as a const char*, @@ -57,6 +60,7 @@ public: * Display a message. */ static void Message(const std::string& m, const char* title = nullptr); + static void Message(const std::string& m, const cmMessageMetadata& md); using OutputCallback = std::function; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 997d8555e4..d83183f390 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ #include "cmDocumentationEntry.h" // IWYU pragma: keep #include "cmGlobalGenerator.h" #include "cmMakefile.h" +#include "cmMessageMetadata.h" #include "cmProperty.h" #include "cmState.h" #include "cmStateTypes.h" @@ -37,6 +39,7 @@ #endif #include "cmsys/Encoding.hxx" +#include "cmsys/Terminal.h" namespace { #ifndef CMAKE_BOOTSTRAP @@ -147,10 +150,12 @@ std::string cmakemainGetStack(cmake* cm) return msg; } -void cmakemainMessageCallback(const std::string& m, const char* /*unused*/, - cmake* cm) +void cmakemainMessageCallback(const std::string& m, + const cmMessageMetadata& md, cmake* cm) { - std::cerr << m << cmakemainGetStack(cm) << std::endl; + cmsysTerminal_cfprintf(md.desiredColor, stderr, "%s", m.c_str()); + fflush(stderr); // stderr is buffered in some cases. + std::cerr << cmakemainGetStack(cm) << "\n"; } void cmakemainProgressCallback(const std::string& m, float prog, cmake* cm) @@ -343,8 +348,8 @@ int do_cmake(int ac, char const* const* av) cm.SetHomeDirectory(""); cm.SetHomeOutputDirectory(""); cmSystemTools::SetMessageCallback( - [&cm](const std::string& msg, const char* title) { - cmakemainMessageCallback(msg, title, &cm); + [&cm](const std::string& msg, const cmMessageMetadata& md) { + cmakemainMessageCallback(msg, md, &cm); }); cm.SetProgressCallback([&cm](const std::string& msg, float prog) { cmakemainProgressCallback(msg, prog, &cm); @@ -626,8 +631,8 @@ int do_build(int ac, char const* const* av) cmake cm(cmake::RoleInternal, cmState::Project); cmSystemTools::SetMessageCallback( - [&cm](const std::string& msg, const char* title) { - cmakemainMessageCallback(msg, title, &cm); + [&cm](const std::string& msg, const cmMessageMetadata& md) { + cmakemainMessageCallback(msg, md, &cm); }); cm.SetProgressCallback([&cm](const std::string& msg, float prog) { cmakemainProgressCallback(msg, prog, &cm); @@ -859,8 +864,8 @@ int do_install(int ac, char const* const* av) cmake cm(cmake::RoleScript, cmState::Script); cmSystemTools::SetMessageCallback( - [&cm](const std::string& msg, const char* title) { - cmakemainMessageCallback(msg, title, &cm); + [&cm](const std::string& msg, const cmMessageMetadata& md) { + cmakemainMessageCallback(msg, md, &cm); }); cm.SetProgressCallback([&cm](const std::string& msg, float prog) { cmakemainProgressCallback(msg, prog, &cm); @@ -940,8 +945,8 @@ int do_open(int ac, char const* const* av) cmake cm(cmake::RoleInternal, cmState::Unknown); cmSystemTools::SetMessageCallback( - [&cm](const std::string& msg, const char* title) { - cmakemainMessageCallback(msg, title, &cm); + [&cm](const std::string& msg, const cmMessageMetadata& md) { + cmakemainMessageCallback(msg, md, &cm); }); cm.SetProgressCallback([&cm](const std::string& msg, float prog) { cmakemainProgressCallback(msg, prog, &cm);