summaryrefslogtreecommitdiff
path: root/vendor/anstream/src/auto.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/anstream/src/auto.rs')
-rw-r--r--vendor/anstream/src/auto.rs263
1 files changed, 263 insertions, 0 deletions
diff --git a/vendor/anstream/src/auto.rs b/vendor/anstream/src/auto.rs
new file mode 100644
index 0000000..7aaac6a
--- /dev/null
+++ b/vendor/anstream/src/auto.rs
@@ -0,0 +1,263 @@
+use crate::stream::AsLockedWrite;
+use crate::stream::RawStream;
+#[cfg(feature = "auto")]
+use crate::ColorChoice;
+use crate::StripStream;
+#[cfg(all(windows, feature = "wincon"))]
+use crate::WinconStream;
+
+/// [`std::io::Write`] that adapts ANSI escape codes to the underlying `Write`s capabilities
+#[derive(Debug)]
+pub struct AutoStream<S: RawStream> {
+ inner: StreamInner<S>,
+}
+
+#[derive(Debug)]
+enum StreamInner<S: RawStream> {
+ PassThrough(S),
+ Strip(StripStream<S>),
+ #[cfg(all(windows, feature = "wincon"))]
+ Wincon(WinconStream<S>),
+}
+
+impl<S> AutoStream<S>
+where
+ S: RawStream,
+{
+ /// Runtime control over styling behavior
+ #[cfg(feature = "auto")]
+ #[inline]
+ pub fn new(raw: S, choice: ColorChoice) -> Self {
+ match choice {
+ ColorChoice::Auto => Self::auto(raw),
+ ColorChoice::AlwaysAnsi => Self::always_ansi(raw),
+ ColorChoice::Always => Self::always(raw),
+ ColorChoice::Never => Self::never(raw),
+ }
+ }
+
+ /// Auto-adapt for the stream's capabilities
+ #[cfg(feature = "auto")]
+ #[inline]
+ pub fn auto(raw: S) -> Self {
+ let choice = Self::choice(&raw);
+ debug_assert_ne!(choice, ColorChoice::Auto);
+ Self::new(raw, choice)
+ }
+
+ /// Report the desired choice for the given stream
+ #[cfg(feature = "auto")]
+ pub fn choice(raw: &S) -> ColorChoice {
+ choice(raw)
+ }
+
+ /// Force ANSI escape codes to be passed through as-is, no matter what the inner `Write`
+ /// supports.
+ #[inline]
+ pub fn always_ansi(raw: S) -> Self {
+ #[cfg(feature = "auto")]
+ {
+ if raw.is_terminal() {
+ let _ = anstyle_query::windows::enable_ansi_colors();
+ }
+ }
+ Self::always_ansi_(raw)
+ }
+
+ #[inline]
+ fn always_ansi_(raw: S) -> Self {
+ let inner = StreamInner::PassThrough(raw);
+ AutoStream { inner }
+ }
+
+ /// Force color, no matter what the inner `Write` supports.
+ #[inline]
+ pub fn always(raw: S) -> Self {
+ if cfg!(windows) {
+ #[cfg(feature = "auto")]
+ let use_wincon = raw.is_terminal()
+ && !anstyle_query::windows::enable_ansi_colors().unwrap_or(true)
+ && !anstyle_query::term_supports_ansi_color();
+ #[cfg(not(feature = "auto"))]
+ let use_wincon = true;
+ if use_wincon {
+ Self::wincon(raw).unwrap_or_else(|raw| Self::always_ansi_(raw))
+ } else {
+ Self::always_ansi_(raw)
+ }
+ } else {
+ Self::always_ansi(raw)
+ }
+ }
+
+ /// Only pass printable data to the inner `Write`.
+ #[inline]
+ pub fn never(raw: S) -> Self {
+ let inner = StreamInner::Strip(StripStream::new(raw));
+ AutoStream { inner }
+ }
+
+ #[inline]
+ fn wincon(raw: S) -> Result<Self, S> {
+ #[cfg(all(windows, feature = "wincon"))]
+ {
+ Ok(Self {
+ inner: StreamInner::Wincon(WinconStream::new(raw)),
+ })
+ }
+ #[cfg(not(all(windows, feature = "wincon")))]
+ {
+ Err(raw)
+ }
+ }
+
+ /// Get the wrapped [`RawStream`]
+ #[inline]
+ pub fn into_inner(self) -> S {
+ match self.inner {
+ StreamInner::PassThrough(w) => w,
+ StreamInner::Strip(w) => w.into_inner(),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => w.into_inner(),
+ }
+ }
+
+ #[inline]
+ pub fn is_terminal(&self) -> bool {
+ match &self.inner {
+ StreamInner::PassThrough(w) => w.is_terminal(),
+ StreamInner::Strip(w) => w.is_terminal(),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(_) => true, // its only ever a terminal
+ }
+ }
+
+ /// Prefer [`AutoStream::choice`]
+ ///
+ /// This doesn't report what is requested but what is currently active.
+ #[inline]
+ #[cfg(feature = "auto")]
+ pub fn current_choice(&self) -> ColorChoice {
+ match &self.inner {
+ StreamInner::PassThrough(_) => ColorChoice::AlwaysAnsi,
+ StreamInner::Strip(_) => ColorChoice::Never,
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(_) => ColorChoice::Always,
+ }
+ }
+}
+
+#[cfg(feature = "auto")]
+fn choice(raw: &dyn RawStream) -> ColorChoice {
+ let choice = ColorChoice::global();
+ match choice {
+ ColorChoice::Auto => {
+ let clicolor = anstyle_query::clicolor();
+ let clicolor_enabled = clicolor.unwrap_or(false);
+ let clicolor_disabled = !clicolor.unwrap_or(true);
+ if raw.is_terminal()
+ && !anstyle_query::no_color()
+ && !clicolor_disabled
+ && (anstyle_query::term_supports_color()
+ || clicolor_enabled
+ || anstyle_query::is_ci())
+ || anstyle_query::clicolor_force()
+ {
+ ColorChoice::Always
+ } else {
+ ColorChoice::Never
+ }
+ }
+ ColorChoice::AlwaysAnsi | ColorChoice::Always | ColorChoice::Never => choice,
+ }
+}
+
+impl AutoStream<std::io::Stdout> {
+ /// Get exclusive access to the `AutoStream`
+ ///
+ /// Why?
+ /// - Faster performance when writing in a loop
+ /// - Avoid other threads interleaving output with the current thread
+ #[inline]
+ pub fn lock(self) -> AutoStream<std::io::StdoutLock<'static>> {
+ let inner = match self.inner {
+ StreamInner::PassThrough(w) => StreamInner::PassThrough(w.lock()),
+ StreamInner::Strip(w) => StreamInner::Strip(w.lock()),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => StreamInner::Wincon(w.lock()),
+ };
+ AutoStream { inner }
+ }
+}
+
+impl AutoStream<std::io::Stderr> {
+ /// Get exclusive access to the `AutoStream`
+ ///
+ /// Why?
+ /// - Faster performance when writing in a loop
+ /// - Avoid other threads interleaving output with the current thread
+ #[inline]
+ pub fn lock(self) -> AutoStream<std::io::StderrLock<'static>> {
+ let inner = match self.inner {
+ StreamInner::PassThrough(w) => StreamInner::PassThrough(w.lock()),
+ StreamInner::Strip(w) => StreamInner::Strip(w.lock()),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => StreamInner::Wincon(w.lock()),
+ };
+ AutoStream { inner }
+ }
+}
+
+impl<S> std::io::Write for AutoStream<S>
+where
+ S: RawStream + AsLockedWrite,
+{
+ // Must forward all calls to ensure locking happens appropriately
+ #[inline]
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ match &mut self.inner {
+ StreamInner::PassThrough(w) => w.as_locked_write().write(buf),
+ StreamInner::Strip(w) => w.write(buf),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => w.write(buf),
+ }
+ }
+ #[inline]
+ fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
+ match &mut self.inner {
+ StreamInner::PassThrough(w) => w.as_locked_write().write_vectored(bufs),
+ StreamInner::Strip(w) => w.write_vectored(bufs),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => w.write_vectored(bufs),
+ }
+ }
+ // is_write_vectored: nightly only
+ #[inline]
+ fn flush(&mut self) -> std::io::Result<()> {
+ match &mut self.inner {
+ StreamInner::PassThrough(w) => w.as_locked_write().flush(),
+ StreamInner::Strip(w) => w.flush(),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => w.flush(),
+ }
+ }
+ #[inline]
+ fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
+ match &mut self.inner {
+ StreamInner::PassThrough(w) => w.as_locked_write().write_all(buf),
+ StreamInner::Strip(w) => w.write_all(buf),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => w.write_all(buf),
+ }
+ }
+ // write_all_vectored: nightly only
+ #[inline]
+ fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> {
+ match &mut self.inner {
+ StreamInner::PassThrough(w) => w.as_locked_write().write_fmt(args),
+ StreamInner::Strip(w) => w.write_fmt(args),
+ #[cfg(all(windows, feature = "wincon"))]
+ StreamInner::Wincon(w) => w.write_fmt(args),
+ }
+ }
+}