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
This commit is contained in:
@@ -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<char> 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];
|
||||
|
||||
Reference in New Issue
Block a user