Skip to content

Commit 5944924

Browse files
committed
Only create the free bar when writing a message
this helps to reduce the flickering
1 parent 7d88cf1 commit 5944924

File tree

1 file changed

+42
-61
lines changed

1 file changed

+42
-61
lines changed

nextest-runner/src/reporter/displayer/progress.rs

Lines changed: 42 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ use crate::{
1313
use iddqd::{IdHashItem, IdHashMap, id_upcast};
1414
use indexmap::IndexSet;
1515
use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle};
16+
use itertools::Itertools as _;
1617
use nextest_metadata::RustBinaryId;
1718
use owo_colors::OwoColorize;
1819
use std::{
19-
collections::VecDeque,
20+
cmp::max,
2021
env, fmt,
2122
io::{self, IsTerminal, Write},
2223
num::NonZero,
@@ -152,19 +153,16 @@ impl SummaryBar {
152153

153154
#[derive(Debug)]
154155
pub(super) struct TestProgressBars {
155-
// A list of currently unused progress bars.
156-
//
157-
// Once a test bar is removed, we add an empty bar, then use it to avoid the
158-
// overall progress bar shifting rapidly up and down.
159-
free_bars: VecDeque<ProgressBar>,
160156
used_bars: IdHashMap<TestProgressBar>,
161157

162158
// Overflow tests in FIFO order (the IndexSet preserves insertion order).
163159
//
164160
// Tests are displayed if they're in used_bars but not in overflow_order.
165161
overflow_queue: IndexSet<(RustBinaryId, String)>,
166162
// Maximum number of tests to display.
167-
max_displayed: MaxProgressRunning,
163+
max_progress_running: MaxProgressRunning,
164+
// Actual maximum number of test displayed
165+
max_displayed: usize,
168166

169167
// Summary bar showing the overflow count. This is Some if the summary bar
170168
// is currently displayed.
@@ -174,12 +172,12 @@ pub(super) struct TestProgressBars {
174172
}
175173

176174
impl TestProgressBars {
177-
fn new(spinner_chars: &'static str, max_displayed: MaxProgressRunning) -> Self {
175+
fn new(spinner_chars: &'static str, max_progress_running: MaxProgressRunning) -> Self {
178176
Self {
179-
free_bars: VecDeque::new(),
180177
used_bars: IdHashMap::new(),
181178
overflow_queue: IndexSet::new(),
182-
max_displayed,
179+
max_progress_running,
180+
max_displayed: 0,
183181
summary_bar: None,
184182
spinner_chars,
185183
}
@@ -231,22 +229,7 @@ impl TestProgressBars {
231229
// multi-progress.
232230
multi.remove(&data.bar);
233231

234-
if self.promote_next_overflow_test(multi) {
235-
// A test was promoted from the overflow queue. The promoted
236-
// test takes this bar's place, so we don't need to add an
237-
// empty bar for spacing.
238-
} else {
239-
// No test was promoted: add an empty bar for spacing.
240-
let free_bar = ProgressBar::hidden();
241-
free_bar.set_style(
242-
ProgressStyle::default_spinner()
243-
.template(" ")
244-
.expect("this template is valid"),
245-
);
246-
let free_bar = multi.add(free_bar);
247-
free_bar.tick();
248-
self.free_bars.push_back(free_bar);
249-
}
232+
self.promote_next_overflow_test(multi);
250233
}
251234

252235
// Update summary bar to reflect the new overflow count.
@@ -295,17 +278,12 @@ impl TestProgressBars {
295278
.len()
296279
.saturating_sub(self.overflow_queue.len());
297280

298-
let should_display = match self.max_displayed {
281+
let should_display = match self.max_progress_running {
299282
MaxProgressRunning::Infinite => true,
300283
MaxProgressRunning::Count(max) => displayed_count < max.get(),
301284
};
302285

303286
let bar = if should_display {
304-
// Remove a free bar if available.
305-
if let Some(free_bar) = self.free_bars.pop_front() {
306-
multi.remove(&free_bar);
307-
}
308-
309287
// Insert the bar at the correct position.
310288
//
311289
// displayed_count doesn't include this test yet, so insert at
@@ -332,14 +310,16 @@ impl TestProgressBars {
332310

333311
// Update the summary bar to reflect the overflow count.
334312
self.update_summary_bar(multi, running_count, styles);
313+
314+
self.max_displayed = max(self.max_displayed, self.len());
335315
}
336316

337317
/// Updates or creates/removes the summary bar showing the overflow count.
338318
fn update_summary_bar(&mut self, multi: &MultiProgress, running_count: usize, styles: &Styles) {
339319
// Use the running count rather than the length of the overflow queue.
340320
// Since tests are added to the queue with a bit of a delay, using the
341321
// running count reduces flickering.
342-
let overflow_count = match self.max_displayed {
322+
let overflow_count = match self.max_progress_running {
343323
MaxProgressRunning::Count(count) => running_count.saturating_sub(count.get()),
344324
MaxProgressRunning::Infinite => {
345325
// No summary bar is displayed in this case.
@@ -352,13 +332,6 @@ impl TestProgressBars {
352332
bar.set_overflow_count(overflow_count, styles);
353333
} else {
354334
// Add a summary bar.
355-
//
356-
// Remove a free bar if available (the summary bar takes its
357-
// place).
358-
if let Some(free_bar) = self.free_bars.pop_front() {
359-
multi.remove(&free_bar);
360-
}
361-
362335
let displayed_count = self
363336
.used_bars
364337
.len()
@@ -375,16 +348,6 @@ impl TestProgressBars {
375348
// The above Option::take removes the summary bar from
376349
// self.summary_bar when the overflow count reaches 0.
377350
multi.remove(&summary_bar.bar);
378-
// Add a free bar for spacing.
379-
let free_bar = ProgressBar::hidden();
380-
free_bar.set_style(
381-
ProgressStyle::default_spinner()
382-
.template(" ")
383-
.expect("this template is valid"),
384-
);
385-
let free_bar = multi.add(free_bar);
386-
free_bar.tick();
387-
self.free_bars.push_back(free_bar);
388351
}
389352
}
390353

@@ -403,12 +366,6 @@ impl TestProgressBars {
403366
.find(|tb| tb.binary_id == test_key.0 && tb.test_name == test_key.1);
404367

405368
if let Some(tb) = tb {
406-
// Remove a free bar if available (we're taking up a display
407-
// slot).
408-
if let Some(free_bar) = self.free_bars.pop_front() {
409-
multi.remove(&free_bar);
410-
}
411-
412369
// Make the bar visible by adding it to the multi-progress.
413370
//
414371
// We've already removed this test from overflow_order, so it's
@@ -443,13 +400,28 @@ impl TestProgressBars {
443400
for tb in &self.used_bars {
444401
tb.bar.finish_and_clear();
445402
}
446-
for bar in &self.free_bars {
447-
bar.finish_and_clear();
448-
}
449403
if let Some(summary_bar) = &self.summary_bar {
450404
summary_bar.bar.finish_and_clear();
451405
}
452406
}
407+
408+
fn len(&self) -> usize {
409+
self.used_bars.len() + self.summary_bar.is_some() as usize
410+
}
411+
412+
fn new_free_bar(&self, multi_progress: &MultiProgress) -> ProgressBar {
413+
// push an bar with as much line as needed to match the max total lines displayed
414+
let missing_lines = self.max_displayed - self.len();
415+
let bar = ProgressBar::hidden();
416+
bar.set_style(
417+
ProgressStyle::default_spinner()
418+
.template(&std::iter::repeat_n(" ", missing_lines).join("\n"))
419+
.expect("this template is valid"),
420+
);
421+
let bar = multi_progress.add(bar);
422+
bar.tick();
423+
bar
424+
}
453425
}
454426

455427
#[derive(Debug)]
@@ -741,8 +713,17 @@ impl ProgressBarState {
741713
// suspend forces a full redraw, so we call it only if there is
742714
// something in the buffer
743715
if !buf.is_empty() {
744-
self.multi_progress
745-
.suspend(|| std::io::stderr().write_all(buf))
716+
let mut free_bar = None;
717+
if let Some(test_bars) = &self.test_bars {
718+
free_bar = Some(test_bars.new_free_bar(&self.multi_progress));
719+
}
720+
let res = self
721+
.multi_progress
722+
.suspend(|| std::io::stderr().write_all(buf));
723+
if let Some(bar) = &free_bar {
724+
self.multi_progress.remove(bar);
725+
}
726+
res
746727
} else {
747728
Ok(())
748729
}

0 commit comments

Comments
 (0)