| 1 | //! Adapted from [styled_buffer] | 
| 2 | //! | 
|---|
| 3 | //! [styled_buffer]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_errors/src/styled_buffer.rs | 
|---|
| 4 |  | 
|---|
| 5 | use crate::renderer::stylesheet::Stylesheet; | 
|---|
| 6 | use anstyle::Style; | 
|---|
| 7 | use std::fmt; | 
|---|
| 8 | use std::fmt::Write; | 
|---|
| 9 |  | 
|---|
| 10 | #[ derive(Debug)] | 
|---|
| 11 | pub(crate) struct StyledBuffer { | 
|---|
| 12 | lines: Vec<Vec<StyledChar>>, | 
|---|
| 13 | } | 
|---|
| 14 |  | 
|---|
| 15 | #[ derive(Clone, Copy, Debug, PartialEq)] | 
|---|
| 16 | pub(crate) struct StyledChar { | 
|---|
| 17 | ch: char, | 
|---|
| 18 | style: Style, | 
|---|
| 19 | } | 
|---|
| 20 |  | 
|---|
| 21 | impl StyledChar { | 
|---|
| 22 | pub(crate) const SPACE: Self = StyledChar::new(ch: ' ', Style::new()); | 
|---|
| 23 |  | 
|---|
| 24 | pub(crate) const fn new(ch: char, style: Style) -> StyledChar { | 
|---|
| 25 | StyledChar { ch, style } | 
|---|
| 26 | } | 
|---|
| 27 | } | 
|---|
| 28 |  | 
|---|
| 29 | impl 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 | /// Sets `chr` with `style` for given `line`, `col`. | 
|---|
| 63 | /// If `line` does not exist in our buffer, adds empty lines up to the given | 
|---|
| 64 | /// and fills the last line with unstyled whitespace. | 
|---|
| 65 | 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 | /// Sets `string` with `style` for given `line`, starting from `col`. | 
|---|
| 74 | /// If `line` does not exist in our buffer, adds empty lines up to the given | 
|---|
| 75 | /// and fills the last line with unstyled whitespace. | 
|---|
| 76 | 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 | /// For given `line` inserts `string` with `style` after old content of that line, | 
|---|
| 84 | /// adding lines if needed | 
|---|
| 85 | 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 | } | 
|---|
| 98 |  | 
|---|