annotate_snippets/renderer/
styled_buffer.rs1use crate::renderer::stylesheet::Stylesheet;
6use anstyle::Style;
7use std::fmt;
8use std::fmt::Write;
9
10#[derive(Debug)]
11pub(crate) struct StyledBuffer {
12 lines: Vec<Vec<StyledChar>>,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq)]
16pub(crate) struct StyledChar {
17 ch: char,
18 style: Style,
19}
20
21impl StyledChar {
22 pub(crate) const SPACE: Self = StyledChar::new(' ', Style::new());
23
24 pub(crate) const fn new(ch: char, style: Style) -> StyledChar {
25 StyledChar { ch, style }
26 }
27}
28
29impl StyledBuffer {
30 pub(crate) fn new() -> StyledBuffer {
31 StyledBuffer { lines: vec![] }
32 }
33
34 fn ensure_lines(&mut self, line: usize) {
35 if line >= self.lines.len() {
36 self.lines.resize(line + 1, Vec::new());
37 }
38 }
39
40 pub(crate) fn render(&self, stylesheet: &Stylesheet) -> Result<String, fmt::Error> {
41 let mut str = String::new();
42 for (i, line) in self.lines.iter().enumerate() {
43 let mut current_style = stylesheet.none;
44 for ch in line {
45 if ch.style != current_style {
46 if !line.is_empty() {
47 write!(str, "{}", current_style.render_reset())?;
48 }
49 current_style = ch.style;
50 write!(str, "{}", current_style.render())?;
51 }
52 write!(str, "{}", ch.ch)?;
53 }
54 write!(str, "{}", current_style.render_reset())?;
55 if i != self.lines.len() - 1 {
56 writeln!(str)?;
57 }
58 }
59 Ok(str)
60 }
61
62 pub(crate) fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
66 self.ensure_lines(line);
67 if col >= self.lines[line].len() {
68 self.lines[line].resize(col + 1, StyledChar::SPACE);
69 }
70 self.lines[line][col] = StyledChar::new(chr, style);
71 }
72
73 pub(crate) fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
77 let mut n = col;
78 for c in string.chars() {
79 self.putc(line, n, c, style);
80 n += 1;
81 }
82 }
83 pub(crate) fn append(&mut self, line: usize, string: &str, style: Style) {
86 if line >= self.lines.len() {
87 self.puts(line, 0, string, style);
88 } else {
89 let col = self.lines[line].len();
90 self.puts(line, col, string, style);
91 }
92 }
93
94 pub(crate) fn num_lines(&self) -> usize {
95 self.lines.len()
96 }
97}