tari_log4rs/encode/writer/
ansi.rs

1//! The ANSI writer.
2//!
3//! Requires the `ansi_writer` feature.
4
5use crate::encode::{self, Color, Style};
6use std::{fmt, io};
7
8/// An `encode::Write`r that wraps an `io::Write`r, emitting ANSI escape codes
9/// for text style.
10#[derive(Clone, Eq, PartialEq, Hash, Debug)]
11pub struct AnsiWriter<W>(pub W);
12
13impl<W: io::Write> io::Write for AnsiWriter<W> {
14    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
15        self.0.write(buf)
16    }
17
18    fn flush(&mut self) -> io::Result<()> {
19        self.0.flush()
20    }
21
22    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
23        self.0.write_all(buf)
24    }
25
26    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
27        self.0.write_fmt(fmt)
28    }
29}
30
31impl<W: io::Write> encode::Write for AnsiWriter<W> {
32    fn set_style(&mut self, style: &Style) -> io::Result<()> {
33        let mut buf = [0; 12];
34        buf[0] = b'\x1b';
35        buf[1] = b'[';
36        buf[2] = b'0';
37        let mut idx = 3;
38
39        if let Some(text) = style.text {
40            buf[idx] = b';';
41            buf[idx + 1] = b'3';
42            buf[idx + 2] = color_byte(text);
43            idx += 3;
44        }
45
46        if let Some(background) = style.background {
47            buf[idx] = b';';
48            buf[idx + 1] = b'4';
49            buf[idx + 2] = color_byte(background);
50            idx += 3;
51        }
52
53        if let Some(intense) = style.intense {
54            buf[idx] = b';';
55            if intense {
56                buf[idx + 1] = b'1';
57                idx += 2;
58            } else {
59                buf[idx + 1] = b'2';
60                buf[idx + 2] = b'2';
61                idx += 3;
62            }
63        }
64        buf[idx] = b'm';
65        self.0.write_all(&buf[..=idx])
66    }
67}
68
69fn color_byte(c: Color) -> u8 {
70    match c {
71        Color::Black => b'0',
72        Color::Red => b'1',
73        Color::Green => b'2',
74        Color::Yellow => b'3',
75        Color::Blue => b'4',
76        Color::Magenta => b'5',
77        Color::Cyan => b'6',
78        Color::White => b'7',
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use std::io::{self, Write};
85
86    use super::*;
87    use crate::encode::{Color, Style, Write as EncodeWrite};
88
89    #[test]
90    fn basic() {
91        let stdout = io::stdout();
92        let mut w = AnsiWriter(stdout.lock());
93
94        w.write_all(b"normal ").unwrap();
95        w.set_style(
96            Style::new()
97                .text(Color::Red)
98                .background(Color::Blue)
99                .intense(true),
100        )
101        .unwrap();
102        w.write_all(b"styled").unwrap();
103        w.set_style(Style::new().text(Color::Green)).unwrap();
104        w.write_all(b" styled2").unwrap();
105        w.set_style(&Style::new()).unwrap();
106        w.write_all(b" normal\n").unwrap();
107        w.flush().unwrap();
108    }
109}