summaryrefslogtreecommitdiffstats
path: root/Source/CursesDialog
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CursesDialog')
-rw-r--r--Source/CursesDialog/CMakeLists.txt25
-rw-r--r--Source/CursesDialog/ccmake.cxx24
-rw-r--r--Source/CursesDialog/cmCursesBoolWidget.cxx15
-rw-r--r--Source/CursesDialog/cmCursesColor.cxx29
-rw-r--r--Source/CursesDialog/cmCursesColor.h24
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx26
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.h9
-rw-r--r--Source/CursesDialog/cmCursesMainForm.cxx271
-rw-r--r--Source/CursesDialog/cmCursesMainForm.h25
-rw-r--r--Source/CursesDialog/cmCursesOptionsWidget.cxx10
-rw-r--r--Source/CursesDialog/cmCursesPathWidget.cxx8
-rw-r--r--Source/CursesDialog/cmCursesStringWidget.cxx10
12 files changed, 307 insertions, 169 deletions
diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt
index 7009717..c24ee76 100644
--- a/Source/CursesDialog/CMakeLists.txt
+++ b/Source/CursesDialog/CMakeLists.txt
@@ -5,6 +5,7 @@ add_executable(ccmake
ccmake.cxx
cmCursesBoolWidget.cxx
cmCursesCacheEntryComposite.cxx
+ cmCursesColor.cxx
cmCursesDummyWidget.cxx
cmCursesFilePathWidget.cxx
cmCursesForm.cxx
@@ -17,21 +18,45 @@ add_executable(ccmake
cmCursesWidget.cxx
)
target_include_directories(ccmake PRIVATE ${CURSES_INCLUDE_PATH})
+set(CMAKE_REQUIRED_INCLUDES ${CURSES_INCLUDE_PATH})
target_link_libraries(ccmake CMakeLib)
if(CMAKE_USE_SYSTEM_FORM)
find_path(CURSES_FORM_INCLUDE_DIR NAMES form.h HINTS ${CURSES_INCLUDE_PATH} ${CURSES_INCLUDE_PATH}/ncurses)
if(CURSES_FORM_INCLUDE_DIR)
target_include_directories(ccmake PRIVATE ${CURSES_FORM_INCLUDE_DIR})
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${CURSES_FORM_INCLUDE_DIR})
endif()
target_link_libraries(ccmake
${CURSES_FORM_LIBRARY}
${CURSES_LIBRARY}
)
+ set(CMAKE_REQUIRED_LIBRARIES
+ ${CURSES_FORM_LIBRARY}
+ ${CURSES_LIBRARY}
+ )
if(CURSES_EXTRA_LIBRARY)
target_link_libraries(ccmake ${CURSES_EXTRA_LIBRARY})
+ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CURSES_EXTRA_LIBRARY})
endif()
else()
target_link_libraries(ccmake cmForm)
+ get_target_property(cmFormIncludeDirs cmForm INTERFACE_INCLUDE_DIRECTORIES)
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${cmFormIncludeDirs})
+ get_target_property(cmFormLibraries cmForm INTERFACE_LINK_LIBRARIES)
+ set(CMAKE_REQUIRED_LIBRARIES ${cmFormLibraries})
+endif()
+
+include(CheckSymbolExists)
+check_symbol_exists(use_default_colors
+ "form.h"
+ HAVE_CURSES_USE_DEFAULT_COLORS)
+if(HAVE_CURSES_USE_DEFAULT_COLORS)
+ set_source_files_properties(cmCursesColor.cxx
+ PROPERTIES COMPILE_DEFINITIONS HAVE_CURSES_USE_DEFAULT_COLORS)
+endif()
+
+if(CMake_JOB_POOL_LINK_BIN)
+ set_property(TARGET ccmake PROPERTY JOB_POOL_LINK "link-bin")
endif()
CMake_OPTIONAL_COMPONENT(ccmake)
diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx
index 9e9dfbd..01fce85 100644
--- a/Source/CursesDialog/ccmake.cxx
+++ b/Source/CursesDialog/ccmake.cxx
@@ -9,6 +9,7 @@
#include "cmsys/Encoding.hxx"
+#include "cmCursesColor.h"
#include "cmCursesForm.h"
#include "cmCursesMainForm.h"
#include "cmCursesStandardIncludes.h"
@@ -126,6 +127,7 @@ int main(int argc, char const* const* argv)
noecho(); /* Echo off */
cbreak(); /* nl- or cr not needed */
keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
+ cmCursesColor::InitColors();
signal(SIGWINCH, onsig);
@@ -153,10 +155,28 @@ int main(int argc, char const* const* argv)
return 1;
}
+ /*
+ * The message is stored in a list by the form which will be
+ * joined by '\n' before display.
+ * Removing any trailing '\n' avoid extra empty lines in the final results
+ */
+ auto cleanMessage = [](const std::string& message) -> std::string {
+ auto msg = message;
+ if (!msg.empty() && msg.back() == '\n') {
+ msg.pop_back();
+ }
+ return msg;
+ };
cmSystemTools::SetMessageCallback(
- [myform](const std::string& message, const char* title) {
- myform->AddError(message, title);
+ [&](const std::string& message, const char* title) {
+ myform->AddError(cleanMessage(message), title);
});
+ cmSystemTools::SetStderrCallback([&](const std::string& message) {
+ myform->AddError(cleanMessage(message), "");
+ });
+ cmSystemTools::SetStdoutCallback([&](const std::string& message) {
+ myform->UpdateProgress(cleanMessage(message), -1);
+ });
cmCursesForm::CurrentForm = myform;
diff --git a/Source/CursesDialog/cmCursesBoolWidget.cxx b/Source/CursesDialog/cmCursesBoolWidget.cxx
index 97b0811..c4dbed8 100644
--- a/Source/CursesDialog/cmCursesBoolWidget.cxx
+++ b/Source/CursesDialog/cmCursesBoolWidget.cxx
@@ -4,6 +4,7 @@
#include <string>
+#include "cmCursesColor.h"
#include "cmCursesWidget.h"
#include "cmStateTypes.h"
@@ -12,8 +13,10 @@ cmCursesBoolWidget::cmCursesBoolWidget(int width, int height, int left,
: cmCursesWidget(width, height, left, top)
{
this->Type = cmStateEnums::BOOL;
- set_field_fore(this->Field, A_NORMAL);
- set_field_back(this->Field, A_STANDOUT);
+ if (!cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
field_opts_off(this->Field, O_STATIC);
this->SetValueAsBool(false);
}
@@ -42,8 +45,16 @@ void cmCursesBoolWidget::SetValueAsBool(bool value)
{
if (value) {
this->SetValue("ON");
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOn));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOn));
+ }
} else {
this->SetValue("OFF");
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::BoolOff));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::BoolOff));
+ }
}
}
diff --git a/Source/CursesDialog/cmCursesColor.cxx b/Source/CursesDialog/cmCursesColor.cxx
new file mode 100644
index 0000000..641d48c
--- /dev/null
+++ b/Source/CursesDialog/cmCursesColor.cxx
@@ -0,0 +1,29 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCursesColor.h"
+
+#include "cmCursesStandardIncludes.h"
+
+bool cmCursesColor::HasColors()
+{
+#ifdef HAVE_CURSES_USE_DEFAULT_COLORS
+ return has_colors();
+#else
+ return false;
+#endif
+}
+
+void cmCursesColor::InitColors()
+{
+#ifdef HAVE_CURSES_USE_DEFAULT_COLORS
+ 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);
+ }
+#endif
+}
diff --git a/Source/CursesDialog/cmCursesColor.h b/Source/CursesDialog/cmCursesColor.h
new file mode 100644
index 0000000..78ca52c
--- /dev/null
+++ b/Source/CursesDialog/cmCursesColor.h
@@ -0,0 +1,24 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmCursesColor_h
+#define cmCursesColor_h
+
+class cmCursesColor
+{
+public:
+ enum Color
+ {
+ // Default color is pair 0
+ BoolOff = 1,
+ BoolOn,
+ String,
+ Path,
+ Options
+ };
+
+ static bool HasColors();
+
+ static void InitColors();
+};
+
+#endif // cmCursesColor_h
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index e2d8d06..806e663 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -8,6 +8,7 @@
#include "cmCursesForm.h"
#include "cmCursesMainForm.h"
#include "cmCursesStandardIncludes.h"
+#include "cmStringAlgorithms.h"
#include "cmVersion.h"
inline int ctrl(int z)
@@ -16,14 +17,12 @@ inline int ctrl(int z)
}
cmCursesLongMessageForm::cmCursesLongMessageForm(
- std::vector<std::string> const& messages, const char* title)
+ std::vector<std::string> const& messages, const char* title,
+ ScrollBehavior scrollBehavior)
+ : Scrolling(scrollBehavior)
{
// Append all messages into on big string
- for (std::string const& message : messages) {
- this->Messages += message;
- // Add one blank line after each message
- this->Messages += "\n\n";
- }
+ this->Messages = cmJoin(messages, "\n");
this->Title = title;
this->Fields[0] = nullptr;
this->Fields[1] = nullptr;
@@ -48,7 +47,7 @@ void cmCursesLongMessageForm::UpdateStatusBar()
size = cmCursesMainForm::MAX_WIDTH - 1;
}
strncpy(bar, this->Title.c_str(), size);
- for (size_t i = size - 1; i < cmCursesMainForm::MAX_WIDTH; i++) {
+ for (size_t i = size; i < cmCursesMainForm::MAX_WIDTH; i++) {
bar[i] = ' ';
}
int width;
@@ -89,7 +88,7 @@ void cmCursesLongMessageForm::PrintKeys()
return;
}
char firstLine[512];
- sprintf(firstLine, "Press [e] to exit help");
+ sprintf(firstLine, "Press [e] to exit screen");
char fmt_s[] = "%s";
curses_move(y - 2, 0);
@@ -112,8 +111,6 @@ void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/,
const char* msg = this->Messages.c_str();
- curses_clear();
-
if (this->Fields[0]) {
free_field(this->Fields[0]);
this->Fields[0] = nullptr;
@@ -136,10 +133,13 @@ void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/,
}
i++;
}
- form_driver(this->Form, REQ_BEG_FIELD);
+ if (this->Scrolling == ScrollBehavior::ScrollDown) {
+ form_driver(this->Form, REQ_END_FIELD);
+ } else {
+ form_driver(this->Form, REQ_BEG_FIELD);
+ }
this->UpdateStatusBar();
- this->PrintKeys();
touchwin(stdscr);
refresh();
}
@@ -153,6 +153,7 @@ void cmCursesLongMessageForm::HandleInput()
char debugMessage[128];
for (;;) {
+ this->PrintKeys();
int key = getch();
sprintf(debugMessage, "Message widget handling input, key: %d", key);
@@ -173,7 +174,6 @@ void cmCursesLongMessageForm::HandleInput()
}
this->UpdateStatusBar();
- this->PrintKeys();
touchwin(stdscr);
wrefresh(stdscr);
}
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h
index 42f9c71..88efe62 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.h
+++ b/Source/CursesDialog/cmCursesLongMessageForm.h
@@ -14,8 +14,14 @@
class cmCursesLongMessageForm : public cmCursesForm
{
public:
+ enum class ScrollBehavior
+ {
+ NoScroll,
+ ScrollDown
+ };
+
cmCursesLongMessageForm(std::vector<std::string> const& messages,
- const char* title);
+ const char* title, ScrollBehavior scrollBehavior);
~cmCursesLongMessageForm() override;
cmCursesLongMessageForm(cmCursesLongMessageForm const&) = delete;
@@ -43,6 +49,7 @@ public:
protected:
std::string Messages;
std::string Title;
+ ScrollBehavior Scrolling;
FIELD* Fields[2];
};
diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx
index 6b71e8a..2c92835 100644
--- a/Source/CursesDialog/cmCursesMainForm.cxx
+++ b/Source/CursesDialog/cmCursesMainForm.cxx
@@ -34,6 +34,7 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args,
: Args(std::move(args))
, InitialWidth(initWidth)
{
+ this->HasNonStatusOutputs = false;
this->NumberOfPages = 0;
this->AdvancedMode = false;
this->NumberOfVisibleEntries = 0;
@@ -321,25 +322,25 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */)
} else {
if (this->OkToGenerate) {
sprintf(firstLine,
- "Press [c] to configure Press [g] to generate and exit");
+ " [l] Show log output [c] Configure"
+ " [g] Generate ");
} else {
sprintf(firstLine,
- "Press [c] to configure ");
+ " [l] Show log output [c] Configure"
+ " ");
}
{
const char* toggleKeyInstruction =
- "Press [t] to toggle advanced mode (Currently %s)";
+ " [t] Toggle advanced mode (currently %s)";
sprintf(thirdLine, toggleKeyInstruction,
- this->AdvancedMode ? "On" : "Off");
+ this->AdvancedMode ? "on" : "off");
}
sprintf(secondLine,
- "Press [h] for help "
- "Press [q] to quit without generating");
+ " [h] Help [q] Quit without generating");
}
curses_move(y - 4, 0);
- char fmt[512] =
- "Press [enter] to edit option Press [d] to delete an entry";
+ char fmt[512] = "Keys: [enter] Edit an entry [d] Delete an entry";
if (process) {
memset(fmt, ' ', 57);
}
@@ -364,7 +365,7 @@ void cmCursesMainForm::PrintKeys(int process /* = 0 */)
// Print the key of the current entry and the CMake version
// on the status bar. Designed for a width of 80 chars.
-void cmCursesMainForm::UpdateStatusBar(const char* message)
+void cmCursesMainForm::UpdateStatusBar(cm::optional<std::string> message)
{
int x;
int y;
@@ -385,119 +386,91 @@ void cmCursesMainForm::UpdateStatusBar(const char* message)
return;
}
- // Get the key of the current entry
- FIELD* cur = current_field(this->Form);
- int findex = field_index(cur);
- cmCursesWidget* lbl = nullptr;
- if (findex >= 0) {
- lbl = reinterpret_cast<cmCursesWidget*>(
- field_userptr(this->Fields[findex - 2]));
- }
- char help[128] = "";
- const char* curField = "";
- if (lbl) {
- curField = lbl->GetValue();
+ // Find the current label index
+ // Field are grouped by 3, the label should be 2 less than the current index
+ using size_type = decltype(this->Fields)::size_type;
+ size_type currentLabelIndex = field_index(current_field(this->Form)) - 2;
+
+ // Use the status message if any, otherwise join the key and help string
+ std::string bar;
+ if (message) {
+ bar = *message;
+ } else {
+ // Get the key of the current entry
+ cmCursesWidget* labelWidget = reinterpret_cast<cmCursesWidget*>(
+ field_userptr(this->Fields[currentLabelIndex]));
+ std::string labelValue = labelWidget->GetValue();
+ bar = labelValue + ": ";
// Get the help string of the current entry
// and add it to the help string
- const char* existingValue =
- this->CMakeInstance->GetState()->GetCacheEntryValue(curField);
+ auto cmakeState = this->CMakeInstance->GetState();
+ const char* existingValue = cmakeState->GetCacheEntryValue(labelValue);
if (existingValue) {
- const char* hs = this->CMakeInstance->GetState()->GetCacheEntryProperty(
- curField, "HELPSTRING");
- if (hs) {
- strncpy(help, hs, 127);
- help[127] = '\0';
- } else {
- help[0] = 0;
+ auto help = cmakeState->GetCacheEntryProperty(labelValue, "HELPSTRING");
+ if (help) {
+ bar += help;
}
- } else {
- sprintf(help, " ");
}
}
+ // Pad with spaces to erase any previous text,
+ // or truncate as necessary to fit the screen
+ bar.resize(x, ' ');
+ curses_move(y - 5, 0);
+ attron(A_STANDOUT);
+ char fmt_s[] = "%s";
+ printw(fmt_s, bar.c_str());
+ attroff(A_STANDOUT);
- // Join the key, help string and pad with spaces
- // (or truncate) as necessary
- char bar[cmCursesMainForm::MAX_WIDTH];
- size_t curFieldLen = strlen(curField);
- size_t helpLen = strlen(help);
-
- size_t width = std::min<size_t>(x, cmCursesMainForm::MAX_WIDTH);
-
- if (message) {
- curField = message;
- curFieldLen = strlen(message);
- strncpy(bar, curField, width);
- if (curFieldLen < width) {
- memset(bar + curFieldLen, ' ', width - curFieldLen);
- }
- } else {
- strncpy(bar, curField, width);
- if (curFieldLen < width) {
- bar[curFieldLen] = ':';
- bar[curFieldLen + 1] = ' ';
- strncpy(bar + curFieldLen + 2, help, width - curFieldLen - 2);
- if (curFieldLen + helpLen + 2 < width) {
- memset(bar + curFieldLen + helpLen + 2, ' ',
- width - (curFieldLen + helpLen + 2));
- }
- }
+ // Highlight the current label, reset others
+ // Fields are grouped by 3, the first one being the label
+ // so start at 0 and move up by 3 avoiding the last null entry
+ for (size_type index = 0; index < this->Fields.size() - 1; index += 3) {
+ bool currentLabel = index == currentLabelIndex;
+ set_field_fore(this->Fields[index], currentLabel ? A_STANDOUT : A_NORMAL);
}
- bar[width] = '\0';
-
- // Display CMake version info on the next line
+ // Display CMake version under the status bar
// We want to display this on the right
- char version[cmCursesMainForm::MAX_WIDTH];
- char vertmp[128];
- sprintf(vertmp, "CMake Version %s", cmVersion::GetCMakeVersion());
- size_t sideSpace = (width - strlen(vertmp));
- memset(version, ' ', sideSpace);
- sprintf(version + sideSpace, "%s", vertmp);
- version[width] = '\0';
-
- // Now print both lines
- char fmt_s[] = "%s";
- curses_move(y - 5, 0);
- attron(A_STANDOUT);
- printw(fmt_s, bar);
- attroff(A_STANDOUT);
- curses_move(y - 4, 0);
- printw(fmt_s, version);
+ std::string version = "CMake Version ";
+ version += cmVersion::GetCMakeVersion();
+ version.resize(std::min<std::string::size_type>(x, version.size()));
+ curses_move(y - 4, x - static_cast<int>(version.size()));
+ printw(fmt_s, version.c_str());
+
pos_form_cursor(this->Form);
}
void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog)
{
- char tmp[1024];
- const char* cmsg = tmp;
if (prog >= 0) {
- sprintf(tmp, "%s %i%%", msg.c_str(), static_cast<int>(100 * prog));
+ constexpr int progressBarWidth = 40;
+ int progressBarCompleted = static_cast<int>(progressBarWidth * prog);
+ int percentCompleted = static_cast<int>(100 * prog);
+ this->LastProgress = (percentCompleted < 100 ? " " : "");
+ this->LastProgress += (percentCompleted < 10 ? " " : "");
+ this->LastProgress += std::to_string(percentCompleted) + "% [";
+ this->LastProgress.append(progressBarCompleted, '#');
+ this->LastProgress.append(progressBarWidth - progressBarCompleted, ' ');
+ this->LastProgress += "] " + msg + "...";
} else {
- cmsg = msg.c_str();
+ this->Outputs.emplace_back(msg);
}
- this->UpdateStatusBar(cmsg);
- this->PrintKeys(1);
- curses_move(1, 1);
- touchwin(stdscr);
- refresh();
+
+ this->DisplayOutputs();
}
int cmCursesMainForm::Configure(int noconfigure)
{
- int xi;
- int yi;
- getmaxyx(stdscr, yi, xi);
-
- curses_move(1, 1);
- this->UpdateStatusBar("Configuring, please wait...");
- this->PrintKeys(1);
- touchwin(stdscr);
- refresh();
- this->CMakeInstance->SetProgressCallback(
- [this](const std::string& msg, float prog) {
- this->UpdateProgress(msg, prog);
- });
+ this->ResetOutputs();
+
+ if (noconfigure == 0) {
+ this->UpdateProgress("Configuring", 0);
+ this->CMakeInstance->SetProgressCallback(
+ [this](const std::string& msg, float prog) {
+ this->UpdateProgress(msg, prog);
+ });
+ }
// always save the current gui values to disk
this->FillCacheManagerFromUI();
@@ -505,9 +478,6 @@ int cmCursesMainForm::Configure(int noconfigure)
this->CMakeInstance->GetHomeOutputDirectory());
this->LoadCache(nullptr);
- // Get rid of previous errors
- this->Errors = std::vector<std::string>();
-
// run the generate process
this->OkToGenerate = true;
int retVal;
@@ -524,7 +494,7 @@ int cmCursesMainForm::Configure(int noconfigure)
keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
- if (retVal != 0 || !this->Errors.empty()) {
+ if (retVal != 0 || this->HasNonStatusOutputs) {
// see if there was an error
if (cmSystemTools::GetErrorOccuredFlag()) {
this->OkToGenerate = false;
@@ -532,11 +502,13 @@ int cmCursesMainForm::Configure(int noconfigure)
int xx;
int yy;
getmaxyx(stdscr, yy, xx);
- cmCursesLongMessageForm* msgs =
- new cmCursesLongMessageForm(this->Errors,
- cmSystemTools::GetErrorOccuredFlag()
- ? "Errors occurred during the last pass."
- : "CMake produced the following output.");
+ const char* title = "Configure produced the following output";
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ title = "Configure failed with the following output";
+ }
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Outputs, title,
+ cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
// reset error condition
cmSystemTools::ResetErrorOccuredFlag();
CurrentForm = msgs;
@@ -547,11 +519,13 @@ int cmCursesMainForm::Configure(int noconfigure)
if (retVal == -2) {
return retVal;
}
- CurrentForm = this;
- this->Render(1, 1, xx, yy);
}
this->InitializeUI();
+ CurrentForm = this;
+ int xi;
+ int yi;
+ getmaxyx(stdscr, yi, xi);
this->Render(1, 1, xi, yi);
return 0;
@@ -559,30 +533,21 @@ int cmCursesMainForm::Configure(int noconfigure)
int cmCursesMainForm::Generate()
{
- int xi;
- int yi;
- getmaxyx(stdscr, yi, xi);
+ this->ResetOutputs();
- curses_move(1, 1);
- this->UpdateStatusBar("Generating, please wait...");
- this->PrintKeys(1);
- touchwin(stdscr);
- refresh();
+ this->UpdateProgress("Generating", 0);
this->CMakeInstance->SetProgressCallback(
[this](const std::string& msg, float prog) {
this->UpdateProgress(msg, prog);
});
- // Get rid of previous errors
- this->Errors = std::vector<std::string>();
-
// run the generate process
int retVal = this->CMakeInstance->Generate();
this->CMakeInstance->SetProgressCallback(nullptr);
keypad(stdscr, true); /* Use key symbols as KEY_DOWN */
- if (retVal != 0 || !this->Errors.empty()) {
+ if (retVal != 0 || this->HasNonStatusOutputs) {
// see if there was an error
if (cmSystemTools::GetErrorOccuredFlag()) {
this->OkToGenerate = false;
@@ -592,12 +557,13 @@ int cmCursesMainForm::Generate()
int xx;
int yy;
getmaxyx(stdscr, yy, xx);
- const char* title = "Messages during last pass.";
+ const char* title = "Generate produced the following output";
if (cmSystemTools::GetErrorOccuredFlag()) {
- title = "Errors occurred during the last pass.";
+ title = "Generate failed with the following output";
}
- cmCursesLongMessageForm* msgs =
- new cmCursesLongMessageForm(this->Errors, title);
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->Outputs, title,
+ cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
CurrentForm = msgs;
msgs->Render(1, 1, xx, yy);
msgs->HandleInput();
@@ -606,11 +572,13 @@ int cmCursesMainForm::Generate()
if (retVal == -2) {
return retVal;
}
- CurrentForm = this;
- this->Render(1, 1, xx, yy);
}
this->InitializeUI();
+ CurrentForm = this;
+ int xi;
+ int yi;
+ getmaxyx(stdscr, yi, xi);
this->Render(1, 1, xi, yi);
return 0;
@@ -619,7 +587,9 @@ int cmCursesMainForm::Generate()
void cmCursesMainForm::AddError(const std::string& message,
const char* /*unused*/)
{
- this->Errors.emplace_back(message);
+ this->Outputs.emplace_back(message);
+ this->HasNonStatusOutputs = true;
+ this->DisplayOutputs();
}
void cmCursesMainForm::RemoveEntry(const char* value)
@@ -704,7 +674,7 @@ void cmCursesMainForm::HandleInput()
this->PrintKeys();
if (this->SearchMode) {
std::string searchstr = "Search: " + this->SearchString;
- this->UpdateStatusBar(searchstr.c_str());
+ this->UpdateStatusBar(searchstr);
this->PrintKeys(1);
curses_move(y - 5, static_cast<unsigned int>(searchstr.size()));
// curses_move(1,1);
@@ -848,8 +818,9 @@ void cmCursesMainForm::HandleInput()
this->HelpMessage[1] = "";
}
- cmCursesLongMessageForm* msgs =
- new cmCursesLongMessageForm(this->HelpMessage, "Help.");
+ cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
+ this->HelpMessage, "Help",
+ cmCursesLongMessageForm::ScrollBehavior::NoScroll);
CurrentForm = msgs;
msgs->Render(1, 1, x, y);
msgs->HandleInput();
@@ -861,7 +832,8 @@ void cmCursesMainForm::HandleInput()
else if (key == 'l') {
getmaxyx(stdscr, y, x);
cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(
- this->Errors, "Errors occurred during the last pass.");
+ this->Outputs, "CMake produced the following output",
+ cmCursesLongMessageForm::ScrollBehavior::NoScroll);
CurrentForm = msgs;
msgs->Render(1, 1, x, y);
msgs->HandleInput();
@@ -1007,15 +979,6 @@ void cmCursesMainForm::JumpToCacheEntry(const char* astr)
} else {
form_driver(this->Form, REQ_NEXT_FIELD);
}
- /*
- char buffer[1024];
- sprintf(buffer, "Line: %d != %d / %d\n", findex, idx,
- this->NumberOfVisibleEntries);
- touchwin(stdscr);
- refresh();
- this->UpdateStatusBar( buffer );
- usleep(100000);
- */
cur = current_field(this->Form);
findex = field_index(cur);
if (findex == start_index) {
@@ -1024,6 +987,28 @@ void cmCursesMainForm::JumpToCacheEntry(const char* astr)
}
}
+void cmCursesMainForm::ResetOutputs()
+{
+ this->LogForm.reset();
+ this->Outputs.clear();
+ this->HasNonStatusOutputs = false;
+ this->LastProgress.clear();
+}
+
+void cmCursesMainForm::DisplayOutputs()
+{
+ int xi;
+ int yi;
+ getmaxyx(stdscr, yi, xi);
+
+ auto newLogForm = new cmCursesLongMessageForm(
+ this->Outputs, this->LastProgress.c_str(),
+ cmCursesLongMessageForm::ScrollBehavior::ScrollDown);
+ CurrentForm = newLogForm;
+ this->LogForm.reset(newLogForm);
+ this->LogForm->Render(1, 1, xi, yi);
+}
+
const char* cmCursesMainForm::s_ConstHelpMessage =
"CMake is used to configure and generate build files for software projects. "
"The basic steps for configuring a project with ccmake are as follows:\n\n"
@@ -1080,7 +1065,7 @@ const char* cmCursesMainForm::s_ConstHelpMessage =
" c : process the configuration files with the current options\n"
" g : generate build files and exit, only available when there are no "
"new options and no errors have been detected during last configuration.\n"
- " l : shows last errors\n"
+ " l : shows cmake output\n"
" d : delete an option\n"
" t : toggles advanced mode. In normal mode, only the most important "
"options are shown. In advanced mode, all options are shown. We recommend "
diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h
index b8769b7..b7c204d 100644
--- a/Source/CursesDialog/cmCursesMainForm.h
+++ b/Source/CursesDialog/cmCursesMainForm.h
@@ -10,12 +10,15 @@
#include <string>
#include <vector>
+#include <cm/optional>
+
#include "cmCursesCacheEntryComposite.h"
#include "cmCursesForm.h"
#include "cmCursesStandardIncludes.h"
#include "cmStateTypes.h"
class cmake;
+class cmCursesLongMessageForm;
/** \class cmCursesMainForm
* \brief The main page of ccmake
@@ -66,8 +69,8 @@ public:
* exception is during a resize. The optional argument specifies the
* string to be displayed in the status bar.
*/
- void UpdateStatusBar() override { this->UpdateStatusBar(nullptr); }
- virtual void UpdateStatusBar(const char* message);
+ void UpdateStatusBar() override { this->UpdateStatusBar(cm::nullopt); }
+ void UpdateStatusBar(cm::optional<std::string> message);
/**
* Display current commands and their keys on the toolbar. This
@@ -122,10 +125,24 @@ protected:
// Jump to the cache entry whose name matches the string.
void JumpToCacheEntry(const char* str);
+ // Clear and reset the output log and state
+ void ResetOutputs();
+
+ // Display the current progress and output
+ void DisplayOutputs();
+
// Copies of cache entries stored in the user interface
std::vector<cmCursesCacheEntryComposite> Entries;
- // Errors produced during last run of cmake
- std::vector<std::string> Errors;
+
+ // The form used to display logs during processing
+ std::unique_ptr<cmCursesLongMessageForm> LogForm;
+ // Output produced by the last pass
+ std::vector<std::string> Outputs;
+ // Did the last pass produced outputs of interest (errors, warnings, ...)
+ bool HasNonStatusOutputs;
+ // Last progress bar
+ std::string LastProgress;
+
// Command line arguments to be passed to cmake each time
// it is run
std::vector<std::string> Args;
diff --git a/Source/CursesDialog/cmCursesOptionsWidget.cxx b/Source/CursesDialog/cmCursesOptionsWidget.cxx
index eb773ad..a15241f 100644
--- a/Source/CursesDialog/cmCursesOptionsWidget.cxx
+++ b/Source/CursesDialog/cmCursesOptionsWidget.cxx
@@ -2,6 +2,7 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmCursesOptionsWidget.h"
+#include "cmCursesColor.h"
#include "cmCursesWidget.h"
#include "cmStateTypes.h"
@@ -15,8 +16,13 @@ cmCursesOptionsWidget::cmCursesOptionsWidget(int width, int height, int left,
// there is no option type, and string type causes ccmake to cast
// the widget into a string widget at some point. BOOL is safe for
// now.
- set_field_fore(this->Field, A_NORMAL);
- set_field_back(this->Field, A_STANDOUT);
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Options));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Options));
+ } else {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
field_opts_off(this->Field, O_STATIC);
}
diff --git a/Source/CursesDialog/cmCursesPathWidget.cxx b/Source/CursesDialog/cmCursesPathWidget.cxx
index bb3808e..8ed42de 100644
--- a/Source/CursesDialog/cmCursesPathWidget.cxx
+++ b/Source/CursesDialog/cmCursesPathWidget.cxx
@@ -4,6 +4,7 @@
#include <vector>
+#include "cmCursesColor.h"
#include "cmCursesMainForm.h"
#include "cmCursesStringWidget.h"
#include "cmStateTypes.h"
@@ -16,6 +17,13 @@ cmCursesPathWidget::cmCursesPathWidget(int width, int height, int left,
this->Type = cmStateEnums::PATH;
this->Cycle = false;
this->CurrentIndex = 0;
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::Path));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::Path));
+ } else {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
}
void cmCursesPathWidget::OnType(int& key, cmCursesMainForm* fm, WINDOW* w)
diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx
index 6296af2..c629478 100644
--- a/Source/CursesDialog/cmCursesStringWidget.cxx
+++ b/Source/CursesDialog/cmCursesStringWidget.cxx
@@ -4,6 +4,7 @@
#include <cstdio>
+#include "cmCursesColor.h"
#include "cmCursesForm.h"
#include "cmCursesMainForm.h"
#include "cmCursesStandardIncludes.h"
@@ -21,8 +22,13 @@ cmCursesStringWidget::cmCursesStringWidget(int width, int height, int left,
{
this->InEdit = false;
this->Type = cmStateEnums::STRING;
- set_field_fore(this->Field, A_NORMAL);
- set_field_back(this->Field, A_STANDOUT);
+ if (cmCursesColor::HasColors()) {
+ set_field_fore(this->Field, COLOR_PAIR(cmCursesColor::String));
+ set_field_back(this->Field, COLOR_PAIR(cmCursesColor::String));
+ } else {
+ set_field_fore(this->Field, A_NORMAL);
+ set_field_back(this->Field, A_STANDOUT);
+ }
field_opts_off(this->Field, O_STATIC);
}