From 9df5236c468839ead6627131886f3d1153035bf3 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 27 Aug 2024 13:43:50 +0200 Subject: [PATCH] progress-bar: Only write when truly updated --- src/libmain/progress-bar.cc | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc index bb4c52ef7..d864d9473 100644 --- a/src/libmain/progress-bar.cc +++ b/src/libmain/progress-bar.cc @@ -75,6 +75,9 @@ private: bool active = true; bool paused = false; bool haveUpdate = true; + + /** Helps avoid unnecessary redraws, see `draw()` */ + std::string lastOutput; }; Sync state_; @@ -360,6 +363,31 @@ public: } 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 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 & output) { auto nextWakeup = std::chrono::milliseconds::max(); @@ -412,7 +440,7 @@ public: auto width = getWindowSize().second; if (width <= 0) width = std::numeric_limits::max(); - writeToStderr("\r" + filterANSIEscapes(line, false, width) + ANSI_NORMAL + "\e[K"); + output = "\r" + filterANSIEscapes(line, false, width) + ANSI_NORMAL + "\e[K"; return nextWakeup; }