pretty_print/render/
write_io.rs

1use crate::{Render, RenderAnnotated};
2use alloc::rc::Rc;
3use color_ansi::{AnsiAbility, AnsiStyle, AnsiWriter};
4use core::fmt::{Debug, Formatter};
5use std::io::{Error, ErrorKind, Write};
6/// Represents a terminal writer.
7pub struct TerminalWriter<W> {
8    color_stack: Vec<Rc<AnsiStyle>>,
9    upstream: AnsiWriter<W>,
10}
11
12/// Writes to something implementing `std::io::Write`
13pub struct IoWrite<W> {
14    upstream: W,
15}
16
17impl<W> Debug for IoWrite<W> {
18    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
19        f.debug_struct("IoWrite").finish()
20    }
21}
22
23impl<W> IoWrite<W> {
24    /// Creates a new terminal writer.
25    pub fn new(upstream: W) -> IoWrite<W> {
26        IoWrite { upstream }
27    }
28}
29
30#[cfg(feature = "std")]
31impl<W> Render for IoWrite<W>
32    where
33        W: std::io::Write,
34{
35    type Error = std::io::Error;
36
37    fn write_str(&mut self, s: &str) -> std::io::Result<usize> {
38        self.upstream.write(s.as_bytes())
39    }
40
41    fn write_str_all(&mut self, s: &str) -> std::io::Result<()> {
42        self.upstream.write_all(s.as_bytes())
43    }
44
45    fn fail_doc(&self) -> Self::Error {
46        std::io::Error::new(std::io::ErrorKind::Other, "Document failed to render")
47    }
48}
49
50#[cfg(feature = "std")]
51impl<W> RenderAnnotated for IoWrite<W>
52    where
53        W: std::io::Write,
54{
55    fn push_annotation(&mut self, _: Rc<AnsiStyle>) -> Result<(), Self::Error> {
56        Ok(())
57    }
58
59    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
60        Ok(())
61    }
62}
63
64impl<W> Debug for TerminalWriter<W> {
65    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
66        f.debug_struct("TerminalWriter").finish()
67    }
68}
69
70impl<W: Write> TerminalWriter<W> {
71    /// Creates a new terminal writer.
72    pub fn new(upstream: W) -> Self {
73        TerminalWriter { color_stack: Vec::new(), upstream: AnsiWriter::new(upstream) }
74    }
75    /// Creates a new terminal writer with a specific color.
76    pub fn with_color(mut self, color: AnsiAbility) -> Self {
77        self.upstream.set_ability(color);
78        self
79    }
80}
81
82impl<W> Render for TerminalWriter<W>
83where
84    W: Write,
85{
86    type Error = Error;
87
88    fn write_str(&mut self, s: &str) -> std::io::Result<usize> {
89        self.upstream.write(s.as_bytes())
90    }
91
92    fn write_str_all(&mut self, s: &str) -> std::io::Result<()> {
93        self.upstream.write_all(s.as_bytes())
94    }
95
96    fn fail_doc(&self) -> Self::Error {
97        Error::new(ErrorKind::Other, "Document failed to render")
98    }
99}
100
101impl<W: Write> RenderAnnotated for TerminalWriter<W> {
102    fn push_annotation(&mut self, color: Rc<AnsiStyle>) -> Result<(), Self::Error> {
103        self.color_stack.push(color.clone());
104        self.upstream.set_style(&color)
105    }
106
107    fn pop_annotation(&mut self) -> Result<(), Self::Error> {
108        self.color_stack.pop();
109        match self.color_stack.last() {
110            Some(previous) => self.upstream.set_style(previous),
111            None => self.upstream.reset_style(),
112        }
113    }
114}