Skip to content

Commit

Permalink
MultiProgressBar now buffers the output text to a single write
Browse files Browse the repository at this point in the history
This is to avoid multiple small writes to the terminal, which can cause flickering.
  • Loading branch information
Giedriusj1 committed Nov 6, 2024
1 parent d4c7414 commit 6ad9ec4
Showing 1 changed file with 22 additions and 13 deletions.
35 changes: 22 additions & 13 deletions libdnf5-cli/progressbar/multi_progress_bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,22 @@ std::size_t MultiProgressBar::get_total_num_of_bars() const noexcept {
std::ostream & operator<<(std::ostream & stream, MultiProgressBar & mbar) {
const bool is_interactive{tty::is_interactive()};

// We'll buffer the output text to a single string and print it all at once.
// This is to avoid multiple writes to the terminal, which can cause flickering.
static std::ostringstream text_buffer;
text_buffer.str("");
text_buffer.clear();

if (is_interactive && mbar.num_of_lines_to_clear > 0) {
stream << tty::clear_line;
text_buffer << tty::clear_line;
for (std::size_t i = 1; i < mbar.num_of_lines_to_clear; i++) {
stream << tty::cursor_up << tty::clear_line;
text_buffer << tty::cursor_up << tty::clear_line;
}
stream << "\r";
text_buffer << "\r";
} else if (mbar.line_printed) {
stream << std::endl;
text_buffer << std::endl;
}

mbar.num_of_lines_to_clear = 0;
mbar.line_printed = false;

Expand All @@ -124,8 +131,8 @@ std::ostream & operator<<(std::ostream & stream, MultiProgressBar & mbar) {
}
bar->set_number(numbers.back());
numbers.pop_back();
stream << *bar;
stream << std::endl;
text_buffer << *bar;
text_buffer << std::endl;
mbar.bars_done.push_back(bar);
// TODO(dmach): use iterator
mbar.bars_todo.erase(mbar.bars_todo.begin() + static_cast<int>(i));
Expand All @@ -148,9 +155,9 @@ std::ostream & operator<<(std::ostream & stream, MultiProgressBar & mbar) {
continue;
}
if (mbar.line_printed) {
stream << std::endl;
text_buffer << std::endl;
}
stream << *bar;
text_buffer << *bar;
mbar.line_printed = true;
mbar.num_of_lines_to_clear++;
mbar.num_of_lines_to_clear += bar->get_messages().size();
Expand Down Expand Up @@ -178,12 +185,12 @@ std::ostream & operator<<(std::ostream & stream, MultiProgressBar & mbar) {

if ((mbar.bars_all.size() >= mbar.total_bar_visible_limit) && (is_interactive || mbar.bars_todo.empty())) {
if (mbar.line_printed) {
stream << std::endl;
text_buffer << std::endl;
}
// print divider
int terminal_width = tty::get_width();
stream << std::string(static_cast<std::size_t>(terminal_width), '-');
stream << std::endl;
text_buffer << std::string(static_cast<std::size_t>(terminal_width), '-');
text_buffer << std::endl;

// print Total progress bar
mbar.total.set_number(static_cast<int>(mbar.bars_done.size()));
Expand All @@ -196,11 +203,13 @@ std::ostream & operator<<(std::ostream & stream, MultiProgressBar & mbar) {
mbar.total.set_state(ProgressBarState::SUCCESS);
}

stream << mbar.total;
stream << std::endl;
text_buffer << mbar.total;
text_buffer << std::endl;
mbar.num_of_lines_to_clear += 3;
}

stream << text_buffer.str(); // Single syscall to output all commands

return stream;
}

Expand Down

0 comments on commit 6ad9ec4

Please sign in to comment.