1
1
// Code for creating styled buffers
2
2
3
3
use crate :: snippet:: { Style , StyledString } ;
4
- use std:: iter;
5
4
6
5
#[ derive( Debug ) ]
7
6
pub 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
+ }
10
22
}
11
23
12
24
impl StyledBuffer {
13
25
pub fn new ( ) -> StyledBuffer {
14
- StyledBuffer { text : vec ! [ ] , styles : vec ! [ ] }
26
+ StyledBuffer { lines : vec ! [ ] }
15
27
}
16
28
29
+ /// Returns content of `StyledBuffer` splitted by lines and line styles
17
30
pub fn render ( & self ) -> Vec < Vec < StyledString > > {
18
31
// 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' ) ) ) ;
20
33
21
34
let mut output: Vec < Vec < StyledString > > = vec ! [ ] ;
22
35
let mut styled_vec: Vec < StyledString > = vec ! [ ] ;
23
36
24
- for ( row , row_style ) in iter :: zip ( & self . text , & self . styles ) {
37
+ for styled_line in & self . lines {
25
38
let mut current_style = Style :: NoStyle ;
26
39
let mut current_text = String :: new ( ) ;
27
40
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 {
30
43
if !current_text. is_empty ( ) {
31
44
styled_vec. push ( StyledString { text : current_text, style : current_style } ) ;
32
45
}
33
- current_style = s ;
46
+ current_style = sc . style ;
34
47
current_text = String :: new ( ) ;
35
48
}
36
- current_text. push ( c ) ;
49
+ current_text. push ( sc . chr ) ;
37
50
}
38
51
if !current_text. is_empty ( ) {
39
52
styled_vec. push ( StyledString { text : current_text, style : current_style } ) ;
@@ -49,29 +62,25 @@ impl StyledBuffer {
49
62
}
50
63
51
64
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 ( ) ) ;
55
67
}
56
68
}
57
69
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.
58
73
pub fn putc ( & mut self , line : usize , col : usize , chr : char , style : Style ) {
59
74
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 ) ;
72
77
}
78
+ self . lines [ line] [ col] = StyledChar :: new ( chr, style) ;
73
79
}
74
80
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.
75
84
pub fn puts ( & mut self , line : usize , col : usize , string : & str , style : Style ) {
76
85
let mut n = col;
77
86
for c in string. chars ( ) {
@@ -80,32 +89,40 @@ impl StyledBuffer {
80
89
}
81
90
}
82
91
92
+ /// For given `line` inserts `string` with `style` before old content of that line,
93
+ /// adding lines if needed
83
94
pub fn prepend ( & mut self , line : usize , string : & str , style : Style ) {
84
95
self . ensure_lines ( line) ;
85
96
let string_len = string. chars ( ) . count ( ) ;
86
97
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
+ }
91
103
}
92
104
93
105
self . puts ( line, 0 , string, style) ;
94
106
}
95
107
108
+ /// For given `line` inserts `string` with `style` after old content of that line,
109
+ /// adding lines if needed
96
110
pub fn append ( & mut self , line : usize , string : & str , style : Style ) {
97
- if line >= self . text . len ( ) {
111
+ if line >= self . lines . len ( ) {
98
112
self . puts ( line, 0 , string, style) ;
99
113
} else {
100
- let col = self . text [ line] . len ( ) ;
114
+ let col = self . lines [ line] . len ( ) ;
101
115
self . puts ( line, col, string, style) ;
102
116
}
103
117
}
104
118
105
119
pub fn num_lines ( & self ) -> usize {
106
- self . text . len ( )
120
+ self . lines . len ( )
107
121
}
108
122
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`
109
126
pub fn set_style_range (
110
127
& mut self ,
111
128
line : usize ,
@@ -119,10 +136,13 @@ impl StyledBuffer {
119
136
}
120
137
}
121
138
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`
122
142
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 {
126
146
* s = style;
127
147
}
128
148
}
0 commit comments