]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/styled_buffer.rs
Rollup merge of #38993 - krdln:patch-1, r=steveklabnik
[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     pub fn copy_tabs(&mut self, row: usize) {
30         if row < self.text.len() {
31             for i in row + 1..self.text.len() {
32                 for j in 0..self.text[i].len() {
33                     if self.text[row].len() > j && self.text[row][j] == '\t' &&
34                        self.text[i][j] == ' ' {
35                         self.text[i][j] = '\t';
36                     }
37                 }
38             }
39         }
40     }
41
42     pub fn render(&mut self) -> Vec<Vec<StyledString>> {
43         let mut output: Vec<Vec<StyledString>> = vec![];
44         let mut styled_vec: Vec<StyledString> = vec![];
45
46         // before we render, do a little patch-up work to support tabs
47         self.copy_tabs(3);
48
49         for (row, row_style) in self.text.iter().zip(&self.styles) {
50             let mut current_style = Style::NoStyle;
51             let mut current_text = String::new();
52
53             for (&c, &s) in row.iter().zip(row_style) {
54                 if s != current_style {
55                     if !current_text.is_empty() {
56                         styled_vec.push(StyledString {
57                             text: current_text,
58                             style: current_style,
59                         });
60                     }
61                     current_style = s;
62                     current_text = String::new();
63                 }
64                 current_text.push(c);
65             }
66             if !current_text.is_empty() {
67                 styled_vec.push(StyledString {
68                     text: current_text,
69                     style: current_style,
70                 });
71             }
72
73             // We're done with the row, push and keep going
74             output.push(styled_vec);
75
76             styled_vec = vec![];
77         }
78
79         output
80     }
81
82     fn ensure_lines(&mut self, line: usize) {
83         while line >= self.text.len() {
84             self.text.push(vec![]);
85             self.styles.push(vec![]);
86         }
87     }
88
89     pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
90         self.ensure_lines(line);
91         if col < self.text[line].len() {
92             self.text[line][col] = chr;
93             self.styles[line][col] = style;
94         } else {
95             let mut i = self.text[line].len();
96             while i < col {
97                 self.text[line].push(' ');
98                 self.styles[line].push(Style::NoStyle);
99                 i += 1;
100             }
101             self.text[line].push(chr);
102             self.styles[line].push(style);
103         }
104     }
105
106     pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
107         let mut n = col;
108         for c in string.chars() {
109             self.putc(line, n, c, style);
110             n += 1;
111         }
112     }
113
114     pub fn set_style(&mut self, line: usize, col: usize, style: Style) {
115         if self.styles.len() > line && self.styles[line].len() > col {
116             self.styles[line][col] = style;
117         }
118     }
119
120     pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
121         self.ensure_lines(line);
122         let string_len = string.len();
123
124         // Push the old content over to make room for new content
125         for _ in 0..string_len {
126             self.styles[line].insert(0, Style::NoStyle);
127             self.text[line].insert(0, ' ');
128         }
129
130         self.puts(line, 0, string, style);
131     }
132
133     pub fn append(&mut self, line: usize, string: &str, style: Style) {
134         if line >= self.text.len() {
135             self.puts(line, 0, string, style);
136         } else {
137             let col = self.text[line].len();
138             self.puts(line, col, string, style);
139         }
140     }
141
142     pub fn num_lines(&self) -> usize {
143         self.text.len()
144     }
145 }