11// Code for creating styled buffers
22
33use crate :: snippet:: { Style , StyledString } ;
4- use std:: iter;
54
65#[ derive( Debug ) ]
76pub struct StyledBuffer {
8- text : Vec < Vec < char > > ,
9- styles : Vec < Vec < Style > > ,
7+ lines : Vec < Vec < StyledChar > > ,
8+ }
9+
10+ #[ derive( Debug , Clone ) ]
11+ struct StyledChar {
12+ chr : char ,
13+ style : Style ,
14+ }
15+
16+ impl StyledChar {
17+ const SPACE : Self = StyledChar :: new ( ' ' , Style :: NoStyle ) ;
18+
19+ const fn new ( chr : char , style : Style ) -> Self {
20+ StyledChar { chr, style }
21+ }
1022}
1123
1224impl StyledBuffer {
1325 pub fn new ( ) -> StyledBuffer {
14- StyledBuffer { text : vec ! [ ] , styles : vec ! [ ] }
26+ StyledBuffer { lines : vec ! [ ] }
1527 }
1628
29+ /// Returns content of `StyledBuffer` splitted by lines and line styles
1730 pub fn render ( & self ) -> Vec < Vec < StyledString > > {
1831 // Tabs are assumed to have been replaced by spaces in calling code.
19- debug_assert ! ( self . text . iter( ) . all( |r| !r. contains ( & '\t' ) ) ) ;
32+ debug_assert ! ( self . lines . iter( ) . all( |r| !r. iter ( ) . any ( |sc| sc . chr == '\t' ) ) ) ;
2033
2134 let mut output: Vec < Vec < StyledString > > = vec ! [ ] ;
2235 let mut styled_vec: Vec < StyledString > = vec ! [ ] ;
2336
24- for ( row , row_style ) in iter :: zip ( & self . text , & self . styles ) {
37+ for styled_line in & self . lines {
2538 let mut current_style = Style :: NoStyle ;
2639 let mut current_text = String :: new ( ) ;
2740
28- for ( & c , & s ) in iter :: zip ( row , row_style ) {
29- if s != current_style {
41+ for sc in styled_line {
42+ if sc . style != current_style {
3043 if !current_text. is_empty ( ) {
3144 styled_vec. push ( StyledString { text : current_text, style : current_style } ) ;
3245 }
33- current_style = s ;
46+ current_style = sc . style ;
3447 current_text = String :: new ( ) ;
3548 }
36- current_text. push ( c ) ;
49+ current_text. push ( sc . chr ) ;
3750 }
3851 if !current_text. is_empty ( ) {
3952 styled_vec. push ( StyledString { text : current_text, style : current_style } ) ;
@@ -49,29 +62,25 @@ impl StyledBuffer {
4962 }
5063
5164 fn ensure_lines ( & mut self , line : usize ) {
52- while line >= self . text . len ( ) {
53- self . text . push ( vec ! [ ] ) ;
54- self . styles . push ( vec ! [ ] ) ;
65+ if line >= self . lines . len ( ) {
66+ self . lines . resize ( line + 1 , Vec :: new ( ) ) ;
5567 }
5668 }
5769
70+ /// Sets `chr` with `style` for given `line`, `col`.
71+ /// If `line` does not exist in our buffer, adds empty lines up to the given
72+ /// and fills the last line with unstyled whitespace.
5873 pub fn putc ( & mut self , line : usize , col : usize , chr : char , style : Style ) {
5974 self . ensure_lines ( line) ;
60- if col < self . text [ line] . len ( ) {
61- self . text [ line] [ col] = chr;
62- self . styles [ line] [ col] = style;
63- } else {
64- let mut i = self . text [ line] . len ( ) ;
65- while i < col {
66- self . text [ line] . push ( ' ' ) ;
67- self . styles [ line] . push ( Style :: NoStyle ) ;
68- i += 1 ;
69- }
70- self . text [ line] . push ( chr) ;
71- self . styles [ line] . push ( style) ;
75+ if col >= self . lines [ line] . len ( ) {
76+ self . lines [ line] . resize ( col + 1 , StyledChar :: SPACE ) ;
7277 }
78+ self . lines [ line] [ col] = StyledChar :: new ( chr, style) ;
7379 }
7480
81+ /// Sets `string` with `style` for given `line`, starting from `col`.
82+ /// If `line` does not exist in our buffer, adds empty lines up to the given
83+ /// and fills the last line with unstyled whitespace.
7584 pub fn puts ( & mut self , line : usize , col : usize , string : & str , style : Style ) {
7685 let mut n = col;
7786 for c in string. chars ( ) {
@@ -80,32 +89,40 @@ impl StyledBuffer {
8089 }
8190 }
8291
92+ /// For given `line` inserts `string` with `style` before old content of that line,
93+ /// adding lines if needed
8394 pub fn prepend ( & mut self , line : usize , string : & str , style : Style ) {
8495 self . ensure_lines ( line) ;
8596 let string_len = string. chars ( ) . count ( ) ;
8697
87- // Push the old content over to make room for new content
88- for _ in 0 ..string_len {
89- self . styles [ line] . insert ( 0 , Style :: NoStyle ) ;
90- self . text [ line] . insert ( 0 , ' ' ) ;
98+ if !self . lines [ line] . is_empty ( ) {
99+ // Push the old content over to make room for new content
100+ for _ in 0 ..string_len {
101+ self . lines [ line] . insert ( 0 , StyledChar :: SPACE ) ;
102+ }
91103 }
92104
93105 self . puts ( line, 0 , string, style) ;
94106 }
95107
108+ /// For given `line` inserts `string` with `style` after old content of that line,
109+ /// adding lines if needed
96110 pub fn append ( & mut self , line : usize , string : & str , style : Style ) {
97- if line >= self . text . len ( ) {
111+ if line >= self . lines . len ( ) {
98112 self . puts ( line, 0 , string, style) ;
99113 } else {
100- let col = self . text [ line] . len ( ) ;
114+ let col = self . lines [ line] . len ( ) ;
101115 self . puts ( line, col, string, style) ;
102116 }
103117 }
104118
105119 pub fn num_lines ( & self ) -> usize {
106- self . text . len ( )
120+ self . lines . len ( )
107121 }
108122
123+ /// Set `style` for `line`, `col_start..col_end` range if:
124+ /// 1. That line and column range exist in `StyledBuffer`
125+ /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
109126 pub fn set_style_range (
110127 & mut self ,
111128 line : usize ,
@@ -119,10 +136,13 @@ impl StyledBuffer {
119136 }
120137 }
121138
139+ /// Set `style` for `line`, `col` if:
140+ /// 1. That line and column exist in `StyledBuffer`
141+ /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
122142 pub fn set_style ( & mut self , line : usize , col : usize , style : Style , overwrite : bool ) {
123- if let Some ( ref mut line) = self . styles . get_mut ( line) {
124- if let Some ( s ) = line. get_mut ( col) {
125- if * s == Style :: NoStyle || * s == Style :: Quotation || overwrite {
143+ if let Some ( ref mut line) = self . lines . get_mut ( line) {
144+ if let Some ( StyledChar { style : s , .. } ) = line. get_mut ( col) {
145+ if overwrite || * s == Style :: NoStyle || * s == Style :: Quotation {
126146 * s = style;
127147 }
128148 }
0 commit comments