From 3300070cc2e7cadcb0fe2a77d67d2099bf22e7ba Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Wed, 23 Oct 2019 16:32:31 +0200 Subject: ccmake: Display an ASCII progress bar in the status bar The status bar is now only used to display the progress. The status log are not shown anymore since for the most cases they went by too quickly to be read. As for cases when a process is long enough to display and read a log, it would probably be a previous unrelated message. --- Source/CursesDialog/cmCursesMainForm.cxx | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 6b71e8a..3f7ee89 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -469,14 +469,18 @@ void cmCursesMainForm::UpdateStatusBar(const char* message) 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(100 * prog)); - } else { - cmsg = msg.c_str(); + constexpr int progressBarWidth = 40; + int progressBarCompleted = static_cast(progressBarWidth * prog); + int percentCompleted = static_cast(100 * prog); + std::string status = (percentCompleted < 100 ? " " : ""); + status += (percentCompleted < 10 ? " " : ""); + status += std::to_string(percentCompleted) + "% ["; + status.append(progressBarCompleted, '#'); + status.append(progressBarWidth - progressBarCompleted, ' '); + status += "] " + msg + "..."; + this->UpdateStatusBar(status.c_str()); } - this->UpdateStatusBar(cmsg); this->PrintKeys(1); curses_move(1, 1); touchwin(stdscr); @@ -489,11 +493,7 @@ int cmCursesMainForm::Configure(int noconfigure) int yi; getmaxyx(stdscr, yi, xi); - curses_move(1, 1); - this->UpdateStatusBar("Configuring, please wait..."); - this->PrintKeys(1); - touchwin(stdscr); - refresh(); + this->UpdateProgress("Configuring", 0); this->CMakeInstance->SetProgressCallback( [this](const std::string& msg, float prog) { this->UpdateProgress(msg, prog); @@ -563,11 +563,7 @@ int cmCursesMainForm::Generate() int yi; getmaxyx(stdscr, yi, xi); - 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); -- cgit v0.12 From c168e789dfeeb4e0bd5db96bb17e682a9fd92b1f Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Wed, 23 Oct 2019 17:07:15 +0200 Subject: ccmake: Use the error display for all the logs --- Source/CursesDialog/cmCursesLongMessageForm.cxx | 7 ++--- Source/CursesDialog/cmCursesMainForm.cxx | 41 +++++++++++++++---------- Source/CursesDialog/cmCursesMainForm.h | 11 +++++-- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index e2d8d06..4ff3fe4 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) @@ -19,11 +20,7 @@ cmCursesLongMessageForm::cmCursesLongMessageForm( std::vector const& messages, const char* title) { // 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; diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 3f7ee89..c76cc42 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -34,6 +34,7 @@ cmCursesMainForm::cmCursesMainForm(std::vector args, : Args(std::move(args)) , InitialWidth(initWidth) { + this->HasNonStatusOutputs = false; this->NumberOfPages = 0; this->AdvancedMode = false; this->NumberOfVisibleEntries = 0; @@ -480,6 +481,8 @@ void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog) status.append(progressBarWidth - progressBarCompleted, ' '); status += "] " + msg + "..."; this->UpdateStatusBar(status.c_str()); + } else { + this->Outputs.emplace_back(msg); } this->PrintKeys(1); curses_move(1, 1); @@ -505,8 +508,7 @@ int cmCursesMainForm::Configure(int noconfigure) this->CMakeInstance->GetHomeOutputDirectory()); this->LoadCache(nullptr); - // Get rid of previous errors - this->Errors = std::vector(); + this->ResetOutputs(); // run the generate process this->OkToGenerate = true; @@ -524,7 +526,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 +534,12 @@ int cmCursesMainForm::Configure(int noconfigure) int xx; int yy; getmaxyx(stdscr, yy, xx); + const char* title = "Configure produced the following output."; + if (cmSystemTools::GetErrorOccuredFlag()) { + title = "Configure failed with the following output."; + } cmCursesLongMessageForm* msgs = - new cmCursesLongMessageForm(this->Errors, - cmSystemTools::GetErrorOccuredFlag() - ? "Errors occurred during the last pass." - : "CMake produced the following output."); + new cmCursesLongMessageForm(this->Outputs, title); // reset error condition cmSystemTools::ResetErrorOccuredFlag(); CurrentForm = msgs; @@ -569,8 +572,7 @@ int cmCursesMainForm::Generate() this->UpdateProgress(msg, prog); }); - // Get rid of previous errors - this->Errors = std::vector(); + this->ResetOutputs(); // run the generate process int retVal = this->CMakeInstance->Generate(); @@ -578,7 +580,7 @@ int cmCursesMainForm::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; @@ -588,12 +590,12 @@ 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); + new cmCursesLongMessageForm(this->Outputs, title); CurrentForm = msgs; msgs->Render(1, 1, xx, yy); msgs->HandleInput(); @@ -615,7 +617,8 @@ 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; } void cmCursesMainForm::RemoveEntry(const char* value) @@ -857,7 +860,7 @@ 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."); CurrentForm = msgs; msgs->Render(1, 1, x, y); msgs->HandleInput(); @@ -1020,6 +1023,12 @@ void cmCursesMainForm::JumpToCacheEntry(const char* astr) } } +void cmCursesMainForm::ResetOutputs() +{ + this->Outputs.clear(); + this->HasNonStatusOutputs = false; +} + 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" @@ -1076,7 +1085,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..c6a0262 100644 --- a/Source/CursesDialog/cmCursesMainForm.h +++ b/Source/CursesDialog/cmCursesMainForm.h @@ -122,10 +122,17 @@ 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(); + // Copies of cache entries stored in the user interface std::vector Entries; - // Errors produced during last run of cmake - std::vector Errors; + + // Output produced by the last pass + std::vector Outputs; + // Did the last pass produced outputs of interest (errors, warnings, ...) + bool HasNonStatusOutputs; + // Command line arguments to be passed to cmake each time // it is run std::vector Args; -- cgit v0.12 From 1d0e557aed926d4d11cc5cf579363bb7be058688 Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Fri, 25 Oct 2019 14:53:10 +0200 Subject: ccmake: Display output during configure and generate --- Source/CursesDialog/cmCursesLongMessageForm.cxx | 13 +++++- Source/CursesDialog/cmCursesLongMessageForm.h | 4 ++ Source/CursesDialog/cmCursesMainForm.cxx | 58 ++++++++++++++++--------- Source/CursesDialog/cmCursesMainForm.h | 8 ++++ 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index 4ff3fe4..d980d81 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.cxx +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -136,7 +136,6 @@ void cmCursesLongMessageForm::Render(int /*left*/, int /*top*/, int /*width*/, form_driver(this->Form, REQ_BEG_FIELD); this->UpdateStatusBar(); - this->PrintKeys(); touchwin(stdscr); refresh(); } @@ -150,6 +149,7 @@ void cmCursesLongMessageForm::HandleInput() char debugMessage[128]; for (;;) { + this->PrintKeys(); int key = getch(); sprintf(debugMessage, "Message widget handling input, key: %d", key); @@ -170,7 +170,16 @@ void cmCursesLongMessageForm::HandleInput() } this->UpdateStatusBar(); - this->PrintKeys(); + touchwin(stdscr); + wrefresh(stdscr); + } +} + +void cmCursesLongMessageForm::ScrollDown() +{ + if (this->Form) { + form_driver(this->Form, REQ_END_FIELD); + this->UpdateStatusBar(); touchwin(stdscr); wrefresh(stdscr); } diff --git a/Source/CursesDialog/cmCursesLongMessageForm.h b/Source/CursesDialog/cmCursesLongMessageForm.h index 42f9c71..dde5bff 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.h +++ b/Source/CursesDialog/cmCursesLongMessageForm.h @@ -26,6 +26,10 @@ public: void HandleInput() override; // Description: + // Scroll down to the end of the content + void ScrollDown(); + + // Description: // Display form. Use a window of size width x height, starting // at top, left. void Render(int left, int top, int width, int height) override; diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index c76cc42..ba238eb 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -474,20 +474,17 @@ void cmCursesMainForm::UpdateProgress(const std::string& msg, float prog) constexpr int progressBarWidth = 40; int progressBarCompleted = static_cast(progressBarWidth * prog); int percentCompleted = static_cast(100 * prog); - std::string status = (percentCompleted < 100 ? " " : ""); - status += (percentCompleted < 10 ? " " : ""); - status += std::to_string(percentCompleted) + "% ["; - status.append(progressBarCompleted, '#'); - status.append(progressBarWidth - progressBarCompleted, ' '); - status += "] " + msg + "..."; - this->UpdateStatusBar(status.c_str()); + 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 { this->Outputs.emplace_back(msg); } - this->PrintKeys(1); - curses_move(1, 1); - touchwin(stdscr); - refresh(); + + this->DisplayOutputs(); } int cmCursesMainForm::Configure(int noconfigure) @@ -496,11 +493,15 @@ int cmCursesMainForm::Configure(int noconfigure) int yi; getmaxyx(stdscr, yi, xi); - this->UpdateProgress("Configuring", 0); - 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(); @@ -508,8 +509,6 @@ int cmCursesMainForm::Configure(int noconfigure) this->CMakeInstance->GetHomeOutputDirectory()); this->LoadCache(nullptr); - this->ResetOutputs(); - // run the generate process this->OkToGenerate = true; int retVal; @@ -544,6 +543,7 @@ int cmCursesMainForm::Configure(int noconfigure) cmSystemTools::ResetErrorOccuredFlag(); CurrentForm = msgs; msgs->Render(1, 1, xx, yy); + msgs->ScrollDown(); msgs->HandleInput(); // If they typed the wrong source directory, we report // an error and exit @@ -566,14 +566,14 @@ int cmCursesMainForm::Generate() int yi; getmaxyx(stdscr, yi, xi); + this->ResetOutputs(); + this->UpdateProgress("Generating", 0); this->CMakeInstance->SetProgressCallback( [this](const std::string& msg, float prog) { this->UpdateProgress(msg, prog); }); - this->ResetOutputs(); - // run the generate process int retVal = this->CMakeInstance->Generate(); @@ -598,6 +598,7 @@ int cmCursesMainForm::Generate() new cmCursesLongMessageForm(this->Outputs, title); CurrentForm = msgs; msgs->Render(1, 1, xx, yy); + msgs->ScrollDown(); msgs->HandleInput(); // If they typed the wrong source directory, we report // an error and exit @@ -619,6 +620,7 @@ void cmCursesMainForm::AddError(const std::string& message, { this->Outputs.emplace_back(message); this->HasNonStatusOutputs = true; + this->DisplayOutputs(); } void cmCursesMainForm::RemoveEntry(const char* value) @@ -1025,8 +1027,24 @@ 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()); + CurrentForm = newLogForm; + this->LogForm.reset(newLogForm); + this->LogForm->Render(1, 1, xi, yi); + this->LogForm->ScrollDown(); } const char* cmCursesMainForm::s_ConstHelpMessage = diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h index c6a0262..598fbdf 100644 --- a/Source/CursesDialog/cmCursesMainForm.h +++ b/Source/CursesDialog/cmCursesMainForm.h @@ -16,6 +16,7 @@ #include "cmStateTypes.h" class cmake; +class cmCursesLongMessageForm; /** \class cmCursesMainForm * \brief The main page of ccmake @@ -125,13 +126,20 @@ protected: // 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 Entries; + // The form used to display logs during processing + std::unique_ptr LogForm; // Output produced by the last pass std::vector 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 -- cgit v0.12 From 66d969fcc490f09297714e98d7285512fd8d91e1 Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Fri, 25 Oct 2019 13:13:14 +0200 Subject: ccmake: Don't overwrite the last character of the title --- Source/CursesDialog/cmCursesLongMessageForm.cxx | 2 +- Source/CursesDialog/cmCursesMainForm.cxx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx index d980d81..41fceee 100644 --- a/Source/CursesDialog/cmCursesLongMessageForm.cxx +++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx @@ -45,7 +45,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; diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index ba238eb..972509f 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -533,9 +533,9 @@ int cmCursesMainForm::Configure(int noconfigure) int xx; int yy; getmaxyx(stdscr, yy, xx); - const char* title = "Configure produced the following output."; + const char* title = "Configure produced the following output"; if (cmSystemTools::GetErrorOccuredFlag()) { - title = "Configure failed with the following output."; + title = "Configure failed with the following output"; } cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(this->Outputs, title); @@ -590,9 +590,9 @@ int cmCursesMainForm::Generate() int xx; int yy; getmaxyx(stdscr, yy, xx); - const char* title = "Generate produced the following output."; + const char* title = "Generate produced the following output"; if (cmSystemTools::GetErrorOccuredFlag()) { - title = "Generate failed with the following output."; + title = "Generate failed with the following output"; } cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm(this->Outputs, title); @@ -850,7 +850,7 @@ void cmCursesMainForm::HandleInput() } cmCursesLongMessageForm* msgs = - new cmCursesLongMessageForm(this->HelpMessage, "Help."); + new cmCursesLongMessageForm(this->HelpMessage, "Help"); CurrentForm = msgs; msgs->Render(1, 1, x, y); msgs->HandleInput(); @@ -862,7 +862,7 @@ void cmCursesMainForm::HandleInput() else if (key == 'l') { getmaxyx(stdscr, y, x); cmCursesLongMessageForm* msgs = new cmCursesLongMessageForm( - this->Outputs, "CMake produced the following output."); + this->Outputs, "CMake produced the following output"); CurrentForm = msgs; msgs->Render(1, 1, x, y); msgs->HandleInput(); -- cgit v0.12 From 2086da1713f7c1626c45565c01bc6cd7967a7e25 Mon Sep 17 00:00:00 2001 From: Sylvain Joubert Date: Fri, 25 Oct 2019 15:16:04 +0200 Subject: ccmake: Add output and progress bar release note --- Help/release/dev/ccmake_progress_bar_and_log_display.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Help/release/dev/ccmake_progress_bar_and_log_display.rst diff --git a/Help/release/dev/ccmake_progress_bar_and_log_display.rst b/Help/release/dev/ccmake_progress_bar_and_log_display.rst new file mode 100644 index 0000000..5c67c7d --- /dev/null +++ b/Help/release/dev/ccmake_progress_bar_and_log_display.rst @@ -0,0 +1,6 @@ +ccmake_progress_bar_and_log_display +----------------------------------- + +* :manual:`ccmake(1)` now displays messages and a progress bar during + configure and generate. It will keep the output displayed if any + errors or warnings occurred. -- cgit v0.12