swc_common/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
13use super::snippet::{Style, StyledString};
14
15#[derive(Debug)]
16pub struct StyledBuffer {
17    text: Vec<Vec<char>>,
18    styles: Vec<Vec<Style>>,
19}
20
21impl StyledBuffer {
22    pub fn new() -> StyledBuffer {
23        StyledBuffer {
24            text: Vec::new(),
25            styles: Vec::new(),
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::new();
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::new();
52        let mut styled_vec: Vec<StyledString> = Vec::new();
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::new();
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::new());
93            self.styles.push(Vec::new());
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(
149        &mut self,
150        line: usize,
151        col_start: usize,
152        col_end: usize,
153        style: Style,
154        overwrite: bool,
155    ) {
156        for col in col_start..col_end {
157            self.set_style(line, col, style, overwrite);
158        }
159    }
160
161    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
162        if let Some(ref mut line) = self.styles.get_mut(line) {
163            if let Some(s) = line.get_mut(col) {
164                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
165                    *s = style;
166                }
167            }
168        }
169    }
170}