]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_errors/src/styled_buffer.rs
New upstream version 1.48.0~beta.8+dfsg1
[rustc.git] / compiler / rustc_errors / src / styled_buffer.rs
1 // Code for creating styled buffers
2
3 use crate::snippet::{Style, StyledString};
4
5 #[derive(Debug)]
6 pub struct StyledBuffer {
7 text: Vec<Vec<char>>,
8 styles: Vec<Vec<Style>>,
9 }
10
11 impl StyledBuffer {
12 pub fn new() -> StyledBuffer {
13 StyledBuffer { text: vec![], styles: vec![] }
14 }
15
16 fn replace_tabs(&mut self) {
17 for (line_pos, line) in self.text.iter_mut().enumerate() {
18 let mut tab_pos = vec![];
19 for (pos, c) in line.iter().enumerate() {
20 if *c == '\t' {
21 tab_pos.push(pos);
22 }
23 }
24 // start with the tabs at the end of the line to replace them with 4 space chars
25 for pos in tab_pos.iter().rev() {
26 assert_eq!(line.remove(*pos), '\t');
27 // fix the position of the style to match up after replacing the tabs
28 let s = self.styles[line_pos].remove(*pos);
29 for _ in 0..4 {
30 line.insert(*pos, ' ');
31 self.styles[line_pos].insert(*pos, s);
32 }
33 }
34 }
35 }
36
37 pub fn render(&mut self) -> Vec<Vec<StyledString>> {
38 let mut output: Vec<Vec<StyledString>> = vec![];
39 let mut styled_vec: Vec<StyledString> = vec![];
40
41 // before we render, replace tabs with spaces
42 self.replace_tabs();
43
44 for (row, row_style) in self.text.iter().zip(&self.styles) {
45 let mut current_style = Style::NoStyle;
46 let mut current_text = String::new();
47
48 for (&c, &s) in row.iter().zip(row_style) {
49 if s != current_style {
50 if !current_text.is_empty() {
51 styled_vec.push(StyledString { text: current_text, style: current_style });
52 }
53 current_style = s;
54 current_text = String::new();
55 }
56 current_text.push(c);
57 }
58 if !current_text.is_empty() {
59 styled_vec.push(StyledString { text: current_text, style: current_style });
60 }
61
62 // We're done with the row, push and keep going
63 output.push(styled_vec);
64
65 styled_vec = vec![];
66 }
67
68 output
69 }
70
71 fn ensure_lines(&mut self, line: usize) {
72 while line >= self.text.len() {
73 self.text.push(vec![]);
74 self.styles.push(vec![]);
75 }
76 }
77
78 pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
79 self.ensure_lines(line);
80 if col < self.text[line].len() {
81 self.text[line][col] = chr;
82 self.styles[line][col] = style;
83 } else {
84 let mut i = self.text[line].len();
85 while i < col {
86 self.text[line].push(' ');
87 self.styles[line].push(Style::NoStyle);
88 i += 1;
89 }
90 self.text[line].push(chr);
91 self.styles[line].push(style);
92 }
93 }
94
95 pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
96 let mut n = col;
97 for c in string.chars() {
98 self.putc(line, n, c, style);
99 n += 1;
100 }
101 }
102
103 pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
104 self.ensure_lines(line);
105 let string_len = string.chars().count();
106
107 // Push the old content over to make room for new content
108 for _ in 0..string_len {
109 self.styles[line].insert(0, Style::NoStyle);
110 self.text[line].insert(0, ' ');
111 }
112
113 self.puts(line, 0, string, style);
114 }
115
116 pub fn append(&mut self, line: usize, string: &str, style: Style) {
117 if line >= self.text.len() {
118 self.puts(line, 0, string, style);
119 } else {
120 let col = self.text[line].len();
121 self.puts(line, col, string, style);
122 }
123 }
124
125 pub fn num_lines(&self) -> usize {
126 self.text.len()
127 }
128
129 pub fn set_style_range(
130 &mut self,
131 line: usize,
132 col_start: usize,
133 col_end: usize,
134 style: Style,
135 overwrite: bool,
136 ) {
137 for col in col_start..col_end {
138 self.set_style(line, col, style, overwrite);
139 }
140 }
141
142 pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
143 if let Some(ref mut line) = self.styles.get_mut(line) {
144 if let Some(s) = line.get_mut(col) {
145 if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
146 *s = style;
147 }
148 }
149 }
150 }
151 }