]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/styled_buffer.rs
Auto merge of #55318 - Aaron1011:fix/final-auto-trait-resolve, r=nikomatsakis
[rust.git] / src / librustc_errors / styled_buffer.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Code for creating styled buffers
12
13 use snippet::{Style, StyledString};
14
15 #[derive(Debug)]
16 pub struct StyledBuffer {
17     text: Vec<Vec<char>>,
18     styles: Vec<Vec<Style>>,
19 }
20
21 impl StyledBuffer {
22     pub fn new() -> StyledBuffer {
23         StyledBuffer {
24             text: vec![],
25             styles: vec![],
26         }
27     }
28
29     fn replace_tabs(&mut self) {
30         for (line_pos, line) in self.text.iter_mut().enumerate() {
31             let mut tab_pos = vec![];
32             for (pos, c) in line.iter().enumerate() {
33                 if *c == '\t' {
34                     tab_pos.push(pos);
35                 }
36             }
37             // start with the tabs at the end of the line to replace them with 4 space chars
38             for pos in tab_pos.iter().rev() {
39                 assert_eq!(line.remove(*pos), '\t');
40                 // fix the position of the style to match up after replacing the tabs
41                 let s = self.styles[line_pos].remove(*pos);
42                 for _ in 0..4 {
43                     line.insert(*pos, ' ');
44                     self.styles[line_pos].insert(*pos, s);
45                 }
46             }
47         }
48     }
49
50     pub fn render(&mut self) -> Vec<Vec<StyledString>> {
51         let mut output: Vec<Vec<StyledString>> = vec![];
52         let mut styled_vec: Vec<StyledString> = vec![];
53
54         // before we render, replace tabs with spaces
55         self.replace_tabs();
56
57         for (row, row_style) in self.text.iter().zip(&self.styles) {
58             let mut current_style = Style::NoStyle;
59             let mut current_text = String::new();
60
61             for (&c, &s) in row.iter().zip(row_style) {
62                 if s != current_style {
63                     if !current_text.is_empty() {
64                         styled_vec.push(StyledString {
65                             text: current_text,
66                             style: current_style,
67                         });
68                     }
69                     current_style = s;
70                     current_text = String::new();
71                 }
72                 current_text.push(c);
73             }
74             if !current_text.is_empty() {
75                 styled_vec.push(StyledString {
76                     text: current_text,
77                     style: current_style,
78                 });
79             }
80
81             // We're done with the row, push and keep going
82             output.push(styled_vec);
83
84             styled_vec = vec![];
85         }
86
87         output
88     }
89
90     fn ensure_lines(&mut self, line: usize) {
91         while line >= self.text.len() {
92             self.text.push(vec![]);
93             self.styles.push(vec![]);
94         }
95     }
96
97     pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
98         self.ensure_lines(line);
99         if col < self.text[line].len() {
100             self.text[line][col] = chr;
101             self.styles[line][col] = style;
102         } else {
103             let mut i = self.text[line].len();
104             while i < col {
105                 self.text[line].push(' ');
106                 self.styles[line].push(Style::NoStyle);
107                 i += 1;
108             }
109             self.text[line].push(chr);
110             self.styles[line].push(style);
111         }
112     }
113
114     pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
115         let mut n = col;
116         for c in string.chars() {
117             self.putc(line, n, c, style);
118             n += 1;
119         }
120     }
121
122     pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
123         self.ensure_lines(line);
124         let string_len = string.len();
125
126         // Push the old content over to make room for new content
127         for _ in 0..string_len {
128             self.styles[line].insert(0, Style::NoStyle);
129             self.text[line].insert(0, ' ');
130         }
131
132         self.puts(line, 0, string, style);
133     }
134
135     pub fn append(&mut self, line: usize, string: &str, style: Style) {
136         if line >= self.text.len() {
137             self.puts(line, 0, string, style);
138         } else {
139             let col = self.text[line].len();
140             self.puts(line, col, string, style);
141         }
142     }
143
144     pub fn num_lines(&self) -> usize {
145         self.text.len()
146     }
147
148     pub fn set_style_range(&mut self,
149                            line: usize,
150                            col_start: usize,
151                            col_end: usize,
152                            style: Style,
153                            overwrite: bool) {
154         for col in col_start..col_end {
155             self.set_style(line, col, style, overwrite);
156         }
157     }
158
159     pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
160         if let Some(ref mut line) = self.styles.get_mut(line) {
161             if let Some(s) = line.get_mut(col) {
162                 if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
163                     *s = style;
164                 }
165             }
166         }
167     }
168 }