codemap_diagnostic/
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 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![],
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 prepend(&mut self, line: usize, string: &str, style: Style) {
115        self.ensure_lines(line);
116        let string_len = string.len();
117
118        // Push the old content over to make room for new content
119        for _ in 0..string_len {
120            self.styles[line].insert(0, Style::NoStyle);
121            self.text[line].insert(0, ' ');
122        }
123
124        self.puts(line, 0, string, style);
125    }
126
127    pub fn append(&mut self, line: usize, string: &str, style: Style) {
128        if line >= self.text.len() {
129            self.puts(line, 0, string, style);
130        } else {
131            let col = self.text[line].len();
132            self.puts(line, col, string, style);
133        }
134    }
135
136    pub fn num_lines(&self) -> usize {
137        self.text.len()
138    }
139}