Skip to content

Commit

Permalink
fix(wincon): Always reset at end of write
Browse files Browse the repository at this point in the history
A lot of the complexity in designing `anstyle-wincon` comes back to the
state tracking inside of it.  This state tracking is to help reduce
redundant calls.  The primary user of this package is only calling it
when the state changes.  However, this does still have a side effect of
back-to-back styles having an extra color write + flush.  In at least my
cases, this isn't too often and ... it is just legacy windows.
  • Loading branch information
epage committed Sep 27, 2023
1 parent 80d10dd commit 23ce8f1
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 38 deletions.
16 changes: 2 additions & 14 deletions crates/anstyle-wincon/src/console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ where
}

/// Close the stream, reporting any errors
#[allow(unused)]
pub fn close(mut self) -> std::io::Result<()> {
self.reset()
Ok(())
}

/// Get the inner writer
#[inline]
pub fn into_inner(mut self) -> S {
let _ = self.reset();
self.stream.take().unwrap()
}
}
Expand All @@ -64,18 +64,6 @@ where
}
}

impl<S> Drop for Console<S>
where
S: crate::WinconStream + std::io::Write,
{
fn drop(&mut self) {
// Otherwise `Console::lock` took it
if self.stream.is_some() {
let _ = self.reset();
}
}
}

impl<S> Console<S>
where
S: crate::WinconStream + std::io::Write,
Expand Down
35 changes: 11 additions & 24 deletions crates/anstyle-wincon/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,15 @@ impl ConsoleState {
bg: Option<anstyle::AnsiColor>,
data: &[u8],
) -> std::io::Result<usize> {
self.apply(stream, fg, bg)?;
let non_default = fg.is_some() || bg.is_some();

if non_default {
self.apply(stream, fg, bg)?;
}
let written = stream.write(data)?;
if non_default {
self.apply(stream, None, None)?;
}
Ok(written)
}

Expand All @@ -160,14 +167,12 @@ impl ConsoleState {
}

#[derive(Default, Clone, Debug)]
pub(crate) struct PassThroughAdapter {
last_fg: Option<anstyle::AnsiColor>,
last_bg: Option<anstyle::AnsiColor>,
}
#[non_exhaustive]
pub(crate) struct PassThroughAdapter {}

impl PassThroughAdapter {
fn new() -> Self {
Default::default()
Self {}
}

fn apply<S: crate::WinconStream + std::io::Write>(
Expand All @@ -176,16 +181,8 @@ impl PassThroughAdapter {
fg: Option<anstyle::AnsiColor>,
bg: Option<anstyle::AnsiColor>,
) -> std::io::Result<()> {
// Avoid writing out no-op resets
if fg == self.last_fg && bg == self.last_bg {
return Ok(());
}

stream.set_colors(fg, bg)?;

self.last_fg = fg;
self.last_bg = bg;

Ok(())
}
}
Expand All @@ -194,17 +191,13 @@ impl PassThroughAdapter {
pub(crate) struct WinconAdapter {
initial_fg: anstyle::AnsiColor,
initial_bg: anstyle::AnsiColor,
last_fg: anstyle::AnsiColor,
last_bg: anstyle::AnsiColor,
}

impl WinconAdapter {
fn new(initial_fg: anstyle::AnsiColor, initial_bg: anstyle::AnsiColor) -> Self {
Self {
initial_fg,
initial_bg,
last_fg: initial_fg,
last_bg: initial_bg,
}
}

Expand All @@ -216,16 +209,10 @@ impl WinconAdapter {
) -> std::io::Result<()> {
let fg = fg.unwrap_or(self.initial_fg);
let bg = bg.unwrap_or(self.initial_bg);
if fg == self.last_fg && bg == self.last_bg {
return Ok(());
}

// Ensure everything is written with the last set of colors before applying the next set
stream.flush()?;

stream.set_colors(Some(fg), Some(bg))?;
self.last_fg = fg;
self.last_bg = bg;

Ok(())
}
Expand Down

0 comments on commit 23ce8f1

Please sign in to comment.