From a13521bb1f31e03227b4c3ff22e234329500a690 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Sat, 8 Mar 2025 15:01:37 +0100 Subject: [PATCH] libmain/progress-bar: implement synchronized updates If tearing occurs while the progress bar is rendering, flickering can occur. This is particularly visible in multiline mode. Use the synchronized updates specification [1] to make updates atomic on supported terminal emulators. On unsupported terminals, the escape sequences should be ignored, leaving the behaviour effectively unchanged (but there's nothing we could do better in this situation). [1] https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec Change-Id: Ic91ca40422c73ac9f9e088c7cb78c1b8c28adc4e --- lix/libmain/progress-bar.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lix/libmain/progress-bar.cc b/lix/libmain/progress-bar.cc index 02fd4766a..1323c2900 100644 --- a/lix/libmain/progress-bar.cc +++ b/lix/libmain/progress-bar.cc @@ -320,6 +320,9 @@ void ProgressBar::update(State & state) void ProgressBar::eraseProgressDisplay(State & state) { + if (state.paused == 0) { + writeLogsToStderr("\e[?2026h"); // begin synchronized update + } if (printMultiline && (state.lastLines >= 1)) { // FIXME: make sure this works on windows writeLogsToStderr(fmt("\e[G\e[%dF\e[J", state.lastLines)); @@ -414,6 +417,8 @@ std::chrono::milliseconds ProgressBar::restoreProgressDisplay(State & state) } } + writeLogsToStderr("\e[?2026l"); // end synchronized update + return nextWakeup; } @@ -548,8 +553,10 @@ std::optional ProgressBar::ask(std::string_view msg) auto state(state_.lock()); if (state->paused > 0 || !isatty(STDIN_FILENO)) return {}; eraseProgressDisplay(*state); + writeLogsToStderr("\e[?2026l"); // end synchronized update std::cerr << msg; auto s = trim(readLine(STDIN_FILENO)); + writeLogsToStderr("\e[?2026h"); // begin synchronized update if (s.size() != 1) return {}; restoreProgressDisplay(*state); return s[0];