]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/styled_buffer.rs
Clean up E0207 explanation
[rust.git] / src / librustc_errors / 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 }