Skip to main content

studiole_command/services/
progress_writer.rs

1//! Per-write handle that suspends progress bars during output.
2use indicatif::MultiProgress;
3use std::io::{self, Write};
4
5/// Writer that suspends [`MultiProgress`] bars during each write to `stderr`.
6///
7/// - Produced by [`ProgressWriterFactory::make_writer`]
8/// - Each [`Write::write`] call serializes through [`MultiProgress::suspend`]
9pub struct ProgressWriter<'a> {
10    multi: &'a MultiProgress,
11}
12
13impl<'a> ProgressWriter<'a> {
14    /// Create a new [`ProgressWriter`] that borrows the given [`MultiProgress`].
15    pub(crate) fn new(multi: &'a MultiProgress) -> Self {
16        Self { multi }
17    }
18}
19
20impl Write for ProgressWriter<'_> {
21    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
22        self.multi
23            .suspend(|| io::stderr().lock().write_all(buf))
24            .map(|()| buf.len())
25    }
26    fn flush(&mut self) -> io::Result<()> {
27        self.multi.suspend(|| io::stderr().lock().flush())
28    }
29}
30
31#[cfg(all(test, feature = "server"))]
32mod tests {
33    use super::*;
34    use indicatif::ProgressDrawTarget;
35
36    /// `write` returns the byte count without panicking when the bar is hidden.
37    #[test]
38    fn progress_writer_write() {
39        // Arrange
40        let multi = MultiProgress::with_draw_target(ProgressDrawTarget::hidden());
41        let mut writer = ProgressWriter::new(&multi);
42        // Act
43        let count = writer.write(b"x").expect("write should succeed");
44        // Assert
45        assert_eq!(count, 1);
46    }
47}