about summary refs log tree commit diff
path: root/compiler/rustc_errors/src/styled_buffer.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-19 08:28:03 +0000
committerbors <bors@rust-lang.org>2024-05-19 08:28:03 +0000
commit9f4b6517208d77556a919789ed285e0c6f67bbb5 (patch)
treeed59ba0a778df31624015f2719f19f215d36e429 /compiler/rustc_errors/src/styled_buffer.rs
parent143661a7f0df8b456f9caffbb1fabafcd4407db0 (diff)
parentc944b01b81abe1f28f3f8dd9bf883bd66facc7de (diff)
downloadrust-9f4b6517208d77556a919789ed285e0c6f67bbb5.tar.gz
rust-9f4b6517208d77556a919789ed285e0c6f67bbb5.zip
Auto merge of #17259 - lnicola:sync-from-rust, r=lnicola
internal: Sync from downstream
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..9aa14e1f214
--- /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 {
+    lines: Vec<Vec<StyledChar>>,
+}
+
+#[derive(Debug, Clone)]
+struct StyledChar {
+    chr: char,
+    style: Style,
+}
+
+impl StyledChar {
+    const SPACE: Self = StyledChar::new(' ', Style::NoStyle);
+
+    const fn new(chr: char, style: Style) -> Self {
+        StyledChar { chr, style }
+    }
+}
+
+impl StyledBuffer {
+    pub fn new() -> StyledBuffer {
+        StyledBuffer { lines: vec![] }
+    }
+
+    /// Returns content of `StyledBuffer` split by lines and line styles
+    pub fn render(&self) -> Vec<Vec<StyledString>> {
+        // Tabs are assumed to have been replaced by spaces in calling code.
+        debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
+
+        let mut output: Vec<Vec<StyledString>> = vec![];
+        let mut styled_vec: Vec<StyledString> = vec![];
+
+        for styled_line in &self.lines {
+            let mut current_style = Style::NoStyle;
+            let mut current_text = String::new();
+
+            for sc in styled_line {
+                if sc.style != current_style {
+                    if !current_text.is_empty() {
+                        styled_vec.push(StyledString { text: current_text, style: current_style });
+                    }
+                    current_style = sc.style;
+                    current_text = String::new();
+                }
+                current_text.push(sc.chr);
+            }
+            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) {
+        if line >= self.lines.len() {
+            self.lines.resize(line + 1, Vec::new());
+        }
+    }
+
+    /// Sets `chr` with `style` for given `line`, `col`.
+    /// If `line` does not exist in our buffer, adds empty lines up to the given
+    /// and fills the last line with unstyled whitespace.
+    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
+        self.ensure_lines(line);
+        if col >= self.lines[line].len() {
+            self.lines[line].resize(col + 1, StyledChar::SPACE);
+        }
+        self.lines[line][col] = StyledChar::new(chr, style);
+    }
+
+    /// Sets `string` with `style` for given `line`, starting from `col`.
+    /// If `line` does not exist in our buffer, adds empty lines up to the given
+    /// and fills the last line with unstyled whitespace.
+    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;
+        }
+    }
+
+    /// For given `line` inserts `string` with `style` before old content of that line,
+    /// adding lines if needed
+    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
+        self.ensure_lines(line);
+        let string_len = string.chars().count();
+
+        if !self.lines[line].is_empty() {
+            // Push the old content over to make room for new content
+            for _ in 0..string_len {
+                self.lines[line].insert(0, StyledChar::SPACE);
+            }
+        }
+
+        self.puts(line, 0, string, style);
+    }
+
+    /// For given `line` inserts `string` with `style` after old content of that line,
+    /// adding lines if needed
+    pub fn append(&mut self, line: usize, string: &str, style: Style) {
+        if line >= self.lines.len() {
+            self.puts(line, 0, string, style);
+        } else {
+            let col = self.lines[line].len();
+            self.puts(line, col, string, style);
+        }
+    }
+
+    pub fn num_lines(&self) -> usize {
+        self.lines.len()
+    }
+
+    /// Set `style` for `line`, `col_start..col_end` range if:
+    /// 1. That line and column range exist in `StyledBuffer`
+    /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
+    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);
+        }
+    }
+
+    /// Set `style` for `line`, `col` if:
+    /// 1. That line and column exist in `StyledBuffer`
+    /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
+    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
+        if let Some(ref mut line) = self.lines.get_mut(line) {
+            if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
+                if overwrite || matches!(s, Style::NoStyle | Style::Quotation) {
+                    *s = style;
+                }
+            }
+        }
+    }
+}