]>
Commit | Line | Data |
---|---|---|
5bcae85e SL |
1 | // Code for creating styled buffers |
2 | ||
9fa01778 | 3 | use crate::snippet::{Style, StyledString}; |
5bcae85e SL |
4 | |
5 | #[derive(Debug)] | |
6 | pub struct StyledBuffer { | |
7 | text: Vec<Vec<char>>, | |
8 | styles: Vec<Vec<Style>>, | |
9 | } | |
10 | ||
11 | impl StyledBuffer { | |
12 | pub fn new() -> StyledBuffer { | |
13 | StyledBuffer { | |
14 | text: vec![], | |
15 | styles: vec![], | |
16 | } | |
17 | } | |
18 | ||
ea8adc8c | 19 | fn replace_tabs(&mut self) { |
ff7c6d11 XL |
20 | for (line_pos, line) in self.text.iter_mut().enumerate() { |
21 | let mut tab_pos = vec![]; | |
22 | for (pos, c) in line.iter().enumerate() { | |
ea8adc8c | 23 | if *c == '\t' { |
ff7c6d11 XL |
24 | tab_pos.push(pos); |
25 | } | |
26 | } | |
27 | // start with the tabs at the end of the line to replace them with 4 space chars | |
28 | for pos in tab_pos.iter().rev() { | |
29 | assert_eq!(line.remove(*pos), '\t'); | |
30 | // fix the position of the style to match up after replacing the tabs | |
31 | let s = self.styles[line_pos].remove(*pos); | |
32 | for _ in 0..4 { | |
33 | line.insert(*pos, ' '); | |
34 | self.styles[line_pos].insert(*pos, s); | |
5bcae85e SL |
35 | } |
36 | } | |
37 | } | |
38 | } | |
39 | ||
40 | pub fn render(&mut self) -> Vec<Vec<StyledString>> { | |
41 | let mut output: Vec<Vec<StyledString>> = vec![]; | |
42 | let mut styled_vec: Vec<StyledString> = vec![]; | |
43 | ||
ea8adc8c XL |
44 | // before we render, replace tabs with spaces |
45 | self.replace_tabs(); | |
5bcae85e SL |
46 | |
47 | for (row, row_style) in self.text.iter().zip(&self.styles) { | |
48 | let mut current_style = Style::NoStyle; | |
49 | let mut current_text = String::new(); | |
50 | ||
51 | for (&c, &s) in row.iter().zip(row_style) { | |
52 | if s != current_style { | |
53 | if !current_text.is_empty() { | |
54 | styled_vec.push(StyledString { | |
55 | text: current_text, | |
56 | style: current_style, | |
57 | }); | |
58 | } | |
59 | current_style = s; | |
60 | current_text = String::new(); | |
61 | } | |
62 | current_text.push(c); | |
63 | } | |
64 | if !current_text.is_empty() { | |
65 | styled_vec.push(StyledString { | |
66 | text: current_text, | |
67 | style: current_style, | |
68 | }); | |
69 | } | |
70 | ||
71 | // We're done with the row, push and keep going | |
72 | output.push(styled_vec); | |
73 | ||
74 | styled_vec = vec![]; | |
75 | } | |
76 | ||
77 | output | |
78 | } | |
79 | ||
80 | fn ensure_lines(&mut self, line: usize) { | |
81 | while line >= self.text.len() { | |
82 | self.text.push(vec![]); | |
83 | self.styles.push(vec![]); | |
84 | } | |
85 | } | |
86 | ||
87 | pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) { | |
88 | self.ensure_lines(line); | |
89 | if col < self.text[line].len() { | |
90 | self.text[line][col] = chr; | |
91 | self.styles[line][col] = style; | |
92 | } else { | |
93 | let mut i = self.text[line].len(); | |
94 | while i < col { | |
95 | self.text[line].push(' '); | |
96 | self.styles[line].push(Style::NoStyle); | |
97 | i += 1; | |
98 | } | |
99 | self.text[line].push(chr); | |
100 | self.styles[line].push(style); | |
101 | } | |
102 | } | |
103 | ||
104 | pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) { | |
105 | let mut n = col; | |
106 | for c in string.chars() { | |
107 | self.putc(line, n, c, style); | |
108 | n += 1; | |
109 | } | |
110 | } | |
111 | ||
5bcae85e SL |
112 | pub fn prepend(&mut self, line: usize, string: &str, style: Style) { |
113 | self.ensure_lines(line); | |
114 | let string_len = string.len(); | |
115 | ||
116 | // Push the old content over to make room for new content | |
117 | for _ in 0..string_len { | |
118 | self.styles[line].insert(0, Style::NoStyle); | |
119 | self.text[line].insert(0, ' '); | |
120 | } | |
121 | ||
122 | self.puts(line, 0, string, style); | |
123 | } | |
124 | ||
125 | pub fn append(&mut self, line: usize, string: &str, style: Style) { | |
126 | if line >= self.text.len() { | |
127 | self.puts(line, 0, string, style); | |
128 | } else { | |
129 | let col = self.text[line].len(); | |
130 | self.puts(line, col, string, style); | |
131 | } | |
132 | } | |
133 | ||
134 | pub fn num_lines(&self) -> usize { | |
135 | self.text.len() | |
136 | } | |
2c00a5a8 XL |
137 | |
138 | pub fn set_style_range(&mut self, | |
139 | line: usize, | |
140 | col_start: usize, | |
141 | col_end: usize, | |
142 | style: Style, | |
143 | overwrite: bool) { | |
144 | for col in col_start..col_end { | |
145 | self.set_style(line, col, style, overwrite); | |
146 | } | |
147 | } | |
148 | ||
149 | pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) { | |
150 | if let Some(ref mut line) = self.styles.get_mut(line) { | |
151 | if let Some(s) = line.get_mut(col) { | |
152 | if *s == Style::NoStyle || *s == Style::Quotation || overwrite { | |
153 | *s = style; | |
154 | } | |
155 | } | |
156 | } | |
157 | } | |
5bcae85e | 158 | } |