progress-bar: Only write when truly updated

This commit is contained in:
Robert Hensing 2024-08-27 13:43:50 +02:00
parent cb4b9be458
commit 9df5236c46

View file

@ -75,6 +75,9 @@ private:
bool active = true; bool active = true;
bool paused = false; bool paused = false;
bool haveUpdate = true; bool haveUpdate = true;
/** Helps avoid unnecessary redraws, see `draw()` */
std::string lastOutput;
}; };
Sync<State> state_; Sync<State> state_;
@ -360,6 +363,31 @@ public:
} }
std::chrono::milliseconds draw(State & state) std::chrono::milliseconds draw(State & state)
{
// Call draw() and render if the output has changed.
// Excessive redrawing is noticable on slow terminals, and it interferes
// with text selection in some terminals, including libvte-based terminal
// emulators.
std::optional<std::string> newOutput;
auto nextWakeup = draw(state, newOutput);
{
auto state(state_.lock());
if (newOutput && *newOutput != state->lastOutput) {
writeToStderr(*newOutput);
state->lastOutput = std::move(*newOutput);
}
}
return nextWakeup;
}
/**
* @param output[out] `nullopt` if nothing is to be drawn. Otherwise, a
* string of ANSI terminal output that can be used to
* render the progress bar.
*/
std::chrono::milliseconds draw(State & state, std::optional<std::string> & output)
{ {
auto nextWakeup = std::chrono::milliseconds::max(); auto nextWakeup = std::chrono::milliseconds::max();
@ -412,7 +440,7 @@ public:
auto width = getWindowSize().second; auto width = getWindowSize().second;
if (width <= 0) width = std::numeric_limits<decltype(width)>::max(); if (width <= 0) width = std::numeric_limits<decltype(width)>::max();
writeToStderr("\r" + filterANSIEscapes(line, false, width) + ANSI_NORMAL + "\e[K"); output = "\r" + filterANSIEscapes(line, false, width) + ANSI_NORMAL + "\e[K";
return nextWakeup; return nextWakeup;
} }