| 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 | |
| 13 | use snippet::{Style, StyledString}; |
| 14 | |
| 15 | #[derive (Debug)] |
| 16 | pub struct StyledBuffer { |
| 17 | text: Vec<Vec<char>>, |
| 18 | styles: Vec<Vec<Style>>, |
| 19 | } |
| 20 | |
| 21 | impl 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 | } |
| 140 | |