about summary refs log tree commit diff
path: root/compiler/rustc_errors/src/styled_buffer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors/src/styled_buffer.rs')
-rw-r--r--compiler/rustc_errors/src/styled_buffer.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs
new file mode 100644
index 00000000000..f2d255d7d95
--- /dev/null
+++ b/compiler/rustc_errors/src/styled_buffer.rs
@@ -0,0 +1,151 @@
+// Code for creating styled buffers
+
+use crate::snippet::{Style, StyledString};
+
+#[derive(Debug)]
+pub struct StyledBuffer {
+    text: Vec<Vec<char>>,
+    styles: Vec<Vec<Style>>,
+}
+
+impl StyledBuffer {
+    pub fn new() -> StyledBuffer {
+        StyledBuffer { text: vec![], styles: vec![] }
+    }
+
+    fn replace_tabs(&mut self) {
+        for (line_pos, line) in self.text.iter_mut().enumerate() {
+            let mut tab_pos = vec![];
+            for (pos, c) in line.iter().enumerate() {
+                if *c == '\t' {
+                    tab_pos.push(pos);
+                }
+            }
+            // start with the tabs at the end of the line to replace them with 4 space chars
+            for pos in tab_pos.iter().rev() {
+                assert_eq!(line.remove(*pos), '\t');
+                // fix the position of the style to match up after replacing the tabs
+                let s = self.styles[line_pos].remove(*pos);
+                for _ in 0..4 {
+                    line.insert(*pos, ' ');
+                    self.styles[line_pos].insert(*pos, s);
+                }
+            }
+        }
+    }
+
+    pub fn render(&mut self) -> Vec<Vec<StyledString>> {
+        let mut output: Vec<Vec<StyledString>> = vec![];
+        let mut styled_vec: Vec<StyledString> = vec![];
+
+        // before we render, replace tabs with spaces
+        self.replace_tabs();
+
+        for (row, row_style) in self.text.iter().zip(&self.styles) {
+            let mut current_style = Style::NoStyle;
+            let mut current_text = String::new();
+
+            for (&c, &s) in row.iter().zip(row_style) {
+                if s != current_style {
+                    if !current_text.is_empty() {
+                        styled_vec.push(StyledString { text: current_text, style: current_style });
+                    }
+                    current_style = s;
+                    current_text = String::new();
+                }
+                current_text.push(c);
+            }
+            if !current_text.is_empty() {
+                styled_vec.push(StyledString { text: current_text, style: current_style });
+            }
+
+            // We're done with the row, push and keep going
+            output.push(styled_vec);
+
+            styled_vec = vec![];
+        }
+
+        output
+    }
+
+    fn ensure_lines(&mut self, line: usize) {
+        while line >= self.text.len() {
+            self.text.push(vec![]);
+            self.styles.push(vec![]);
+        }
+    }
+
+    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
+        self.ensure_lines(line);
+        if col < self.text[line].len() {
+            self.text[line][col] = chr;
+            self.styles[line][col] = style;
+        } else {
+            let mut i = self.text[line].len();
+            while i < col {
+                self.text[line].push(' ');
+                self.styles[line].push(Style::NoStyle);
+                i += 1;
+            }
+            self.text[line].push(chr);
+            self.styles[line].push(style);
+        }
+    }
+
+    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
+        let mut n = col;
+        for c in string.chars() {
+            self.putc(line, n, c, style);
+            n += 1;
+        }
+    }
+
+    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
+        self.ensure_lines(line);
+        let string_len = string.chars().count();
+
+        // Push the old content over to make room for new content
+        for _ in 0..string_len {
+            self.styles[line].insert(0, Style::NoStyle);
+            self.text[line].insert(0, ' ');
+        }
+
+        self.puts(line, 0, string, style);
+    }
+
+    pub fn append(&mut self, line: usize, string: &str, style: Style) {
+        if line >= self.text.len() {
+            self.puts(line, 0, string, style);
+        } else {
+            let col = self.text[line].len();
+            self.puts(line, col, string, style);
+        }
+    }
+
+    pub fn num_lines(&self) -> usize {
+        self.text.len()
+    }
+
+    pub fn set_style_range(
+        &mut self,
+        line: usize,
+        col_start: usize,
+        col_end: usize,
+        style: Style,
+        overwrite: bool,
+    ) {
+        for col in col_start..col_end {
+            self.set_style(line, col, style, overwrite);
+        }
+    }
+
+    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
+        if let Some(ref mut line) = self.styles.get_mut(line) {
+            if let Some(s) = line.get_mut(col) {
+                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
+                    *s = style;
+                }
+            }
+        }
+    }
+}