rustc_errors/
styled_buffer.rs
1use crate::snippet::{Style, StyledString};
4
5#[derive(Debug)]
6pub(crate) struct StyledBuffer {
7 lines: Vec<Vec<StyledChar>>,
8}
9
10#[derive(Debug, Clone)]
11struct StyledChar {
12 chr: char,
13 style: Style,
14}
15
16impl StyledChar {
17 const SPACE: Self = StyledChar::new(' ', Style::NoStyle);
18
19 const fn new(chr: char, style: Style) -> Self {
20 StyledChar { chr, style }
21 }
22}
23
24impl StyledBuffer {
25 pub(crate) fn new() -> StyledBuffer {
26 StyledBuffer { lines: vec![] }
27 }
28
29 pub(crate) fn render(&self) -> Vec<Vec<StyledString>> {
31 debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
33
34 let mut output: Vec<Vec<StyledString>> = vec![];
35 let mut styled_vec: Vec<StyledString> = vec![];
36
37 for styled_line in &self.lines {
38 let mut current_style = Style::NoStyle;
39 let mut current_text = String::new();
40
41 for sc in styled_line {
42 if sc.style != current_style {
43 if !current_text.is_empty() {
44 styled_vec.push(StyledString { text: current_text, style: current_style });
45 }
46 current_style = sc.style;
47 current_text = String::new();
48 }
49 current_text.push(sc.chr);
50 }
51 if !current_text.is_empty() {
52 styled_vec.push(StyledString { text: current_text, style: current_style });
53 }
54
55 output.push(styled_vec);
57
58 styled_vec = vec![];
59 }
60
61 output
62 }
63
64 fn ensure_lines(&mut self, line: usize) {
65 if line >= self.lines.len() {
66 self.lines.resize(line + 1, Vec::new());
67 }
68 }
69
70 pub(crate) fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
74 self.ensure_lines(line);
75 if col >= self.lines[line].len() {
76 self.lines[line].resize(col + 1, StyledChar::SPACE);
77 }
78 self.lines[line][col] = StyledChar::new(chr, style);
79 }
80
81 pub(crate) fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
85 let mut n = col;
86 for c in string.chars() {
87 self.putc(line, n, c, style);
88 n += 1;
89 }
90 }
91
92 pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) {
93 if start == end {
94 return;
95 }
96 if start > self.lines[line].len() || end > self.lines[line].len() {
97 return;
98 }
99 let _ = self.lines[line].drain(start..(end - string.chars().count()));
100 for (i, c) in string.chars().enumerate() {
101 self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber);
102 }
103 }
104
105 pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) {
108 self.ensure_lines(line);
109 let string_len = string.chars().count();
110
111 if !self.lines[line].is_empty() {
112 for _ in 0..string_len {
114 self.lines[line].insert(0, StyledChar::SPACE);
115 }
116 }
117
118 self.puts(line, 0, string, style);
119 }
120
121 pub(crate) fn append(&mut self, line: usize, string: &str, style: Style) {
124 if line >= self.lines.len() {
125 self.puts(line, 0, string, style);
126 } else {
127 let col = self.lines[line].len();
128 self.puts(line, col, string, style);
129 }
130 }
131
132 pub(crate) fn num_lines(&self) -> usize {
133 self.lines.len()
134 }
135
136 pub(crate) fn set_style_range(
140 &mut self,
141 line: usize,
142 col_start: usize,
143 col_end: usize,
144 style: Style,
145 overwrite: bool,
146 ) {
147 for col in col_start..col_end {
148 self.set_style(line, col, style, overwrite);
149 }
150 }
151
152 fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
156 if let Some(ref mut line) = self.lines.get_mut(line) {
157 if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
158 if overwrite || matches!(s, Style::NoStyle | Style::Quotation) {
159 *s = style;
160 }
161 }
162 }
163 }
164}