1+ use std:: mem:: replace;
2+
13use alacritty_terminal:: index:: { Column , Line , Point } ;
24use alacritty_terminal:: term:: cell:: Flags ;
35use alacritty_terminal:: term:: color:: Rgb ;
46use alacritty_terminal:: term:: search:: Match ;
57
68use crate :: display:: content:: { RenderableCell , RenderableContent } ;
79
8- #[ derive( Debug ) ]
10+ #[ derive( Debug , Default , Clone , Copy ) ]
911struct RunStart {
1012 line : usize ,
1113 column : Column ,
@@ -16,14 +18,25 @@ struct RunStart {
1618}
1719
1820impl RunStart {
21+ fn new ( cell : & RenderableCell ) -> Self {
22+ Self {
23+ line : cell. point . line ,
24+ column : cell. point . column ,
25+ fg : cell. fg ,
26+ bg : cell. bg ,
27+ bg_alpha : cell. bg_alpha ,
28+ flags : cell. flags ,
29+ }
30+ }
31+
1932 /// Compare cell and check if it belongs to the same run.
2033 #[ inline]
2134 fn belongs_to_text_run ( & self , render_cell : & RenderableCell ) -> bool {
2235 self . line == render_cell. point . line
2336 && self . fg == render_cell. fg
24- && self . bg == render_cell. bg
25- && ( self . bg_alpha - render_cell. bg_alpha ) . abs ( ) < std:: f32:: EPSILON
2637 && self . flags == render_cell. flags
38+ && self . bg == render_cell. bg
39+ && ( self . bg_alpha - render_cell. bg_alpha ) . abs ( ) < f32:: EPSILON
2740 }
2841}
2942
@@ -80,7 +93,7 @@ impl TextRun {
8093 Point { line : self . line , column : self . span . 1 }
8194 }
8295
83- /// Iterates over each RenderableCell in column range [run.0, run.1]
96+ /// Iterates over each RenderableCell in column range ` [run.0, run.1]`
8497 pub fn cells ( & self ) -> impl Iterator < Item = RenderableCell > + ' _ {
8598 let step = if self . flags . contains ( Flags :: WIDE_CHAR ) { 2 } else { 1 } ;
8699 let ( Column ( start) , Column ( end) ) = self . span ;
@@ -89,14 +102,24 @@ impl TextRun {
89102 }
90103}
91104
92- type IsWide = bool ;
93- type LatestCol = ( Column , IsWide ) ;
105+ #[ derive( Default , Clone , Copy ) ]
106+ pub struct LatestCol {
107+ column : Column ,
108+ is_wide : bool ,
109+ }
110+
111+ impl LatestCol {
112+ #[ inline]
113+ fn new ( cell : & RenderableCell ) -> Self {
114+ Self { column : cell. point . column , is_wide : cell. flags . contains ( Flags :: WIDE_CHAR ) }
115+ }
116+ }
94117
95118/// Wraps an Iterator<Item=RenderableCell> and produces TextRuns to represent batches of cells
96119pub struct TextRunIter < I > {
97120 iter : I ,
98- run_start : Option < RunStart > ,
99- latest_col : Option < LatestCol > ,
121+ run_start : RunStart ,
122+ latest_col : LatestCol ,
100123 display_offset : usize ,
101124 hint : Option < Match > ,
102125 vi_hint : Option < Match > ,
@@ -107,12 +130,12 @@ pub struct TextRunIter<I> {
107130type TextRunIterFromContent < ' a , ' c > =
108131 TextRunIter < std:: iter:: Filter < & ' a mut RenderableContent < ' c > , fn ( & RenderableCell ) -> bool > > ;
109132
110- impl < I > TextRunIter < I > {
111- pub fn from_content < ' a , ' c > (
133+ impl < ' a , ' c > TextRunIterFromContent < ' a , ' c > {
134+ pub fn from_content (
112135 content : & ' a mut RenderableContent < ' c > ,
113136 hint : Option < Match > ,
114137 vi_hint : Option < Match > ,
115- ) -> TextRunIterFromContent < ' a , ' c > {
138+ ) -> Self {
116139 fn check ( cell : & RenderableCell ) -> bool {
117140 !cell. flags . contains ( Flags :: WIDE_CHAR_SPACER )
118141 }
@@ -130,41 +153,60 @@ where
130153 I : Iterator < Item = RenderableCell > ,
131154{
132155 pub fn new (
133- iter : I ,
156+ mut iter : I ,
134157 hint : Option < Match > ,
135158 vi_hint : Option < Match > ,
136159 display_offset : usize ,
137160 ) -> Self {
138- TextRunIter {
139- iter,
140- latest_col : None ,
141- display_offset,
142- run_start : None ,
143- buffer_text : String :: new ( ) ,
144- buffer_zero_width : Vec :: new ( ) ,
145- hint,
146- vi_hint,
161+ if let Some ( cell) = iter. next ( ) {
162+ let latest_col = LatestCol :: new ( & cell) ;
163+ let run_start = RunStart :: new ( & cell) ;
164+ let buffer_text = cell. character . to_string ( ) ;
165+ let buffer_zero_width = vec ! [ cell. zerowidth] ;
166+
167+ TextRunIter {
168+ iter,
169+ run_start,
170+ latest_col,
171+ display_offset,
172+ hint,
173+ vi_hint,
174+ buffer_text,
175+ buffer_zero_width,
176+ }
177+ } else {
178+ // There are no cells in the grid. This rarely happens.
179+ #[ cold]
180+ #[ inline]
181+ fn dummy < I > ( iter : I ) -> TextRunIter < I > {
182+ TextRunIter {
183+ iter,
184+ run_start : RunStart :: default ( ) ,
185+ latest_col : LatestCol :: default ( ) ,
186+ display_offset : 0 ,
187+ hint : None ,
188+ vi_hint : None ,
189+ buffer_text : String :: new ( ) ,
190+ buffer_zero_width : Vec :: new ( ) ,
191+ }
192+ }
193+
194+ dummy ( iter)
147195 }
148196 }
149197}
150198impl < I > TextRunIter < I > {
151199 /// Check if the cell belongs to this text run. Returns `true` if it does not belong.
152200 fn cell_does_not_belong_to_run ( & self , render_cell : & RenderableCell ) -> bool {
153- self . run_start
154- . as_ref ( )
155- . map ( |run_start| !run_start. belongs_to_text_run ( render_cell) )
156- . unwrap_or_default ( )
201+ !self . run_start . belongs_to_text_run ( render_cell)
157202 }
158203
159204 /// Check if the column is not adjacent to the latest column.
160- fn is_col_not_adjacent ( & self , column : Column ) -> bool {
161- self . latest_col
162- . as_ref ( )
163- . map ( |& ( col, is_wide) | {
164- let width = if is_wide { 2 } else { 1 } ;
165- col + width != column && column + width != col
166- } )
167- . unwrap_or_default ( )
205+ fn is_col_not_adjacent ( & self , col : Column ) -> bool {
206+ let LatestCol { column, is_wide } = self . latest_col ;
207+
208+ let width = if is_wide { 2 } else { 1 } ;
209+ col + width != column && column + width != col
168210 }
169211
170212 /// Check if current run ends at incoming RenderableCell
@@ -184,7 +226,8 @@ impl<I> TextRunIter<I> {
184226 /// Empty out pending buffer producing owned collections that can be moved into a TextRun
185227 fn drain_buffer ( & mut self ) -> TextRunContent {
186228 use std:: mem:: take;
187- let text = take ( & mut self . buffer_text ) ;
229+ let text = self . buffer_text . clone ( ) ;
230+ self . buffer_text . clear ( ) ;
188231 let zero_widths = take ( & mut self . buffer_zero_width ) ;
189232
190233 TextRunContent { text, zero_widths }
@@ -204,40 +247,28 @@ impl<I> TextRunIter<I> {
204247
205248 /// Start a new run by setting latest_col, run_start, and buffering content of rc
206249 /// Returns the previous runs run_start and latest_col data if available.
207- fn start_run ( & mut self , render_cell : RenderableCell ) -> ( Option < RunStart > , Option < LatestCol > ) {
208- let latest = self
209- . latest_col
210- . replace ( ( render_cell. point . column , render_cell. flags . contains ( Flags :: WIDE_CHAR ) ) ) ;
211- let start = self . run_start . replace ( RunStart {
212- line : render_cell. point . line ,
213- column : render_cell. point . column ,
214- fg : render_cell. fg ,
215- bg : render_cell. bg ,
216- bg_alpha : render_cell. bg_alpha ,
217- flags : render_cell. flags ,
218- } ) ;
250+ fn start_run ( & mut self , render_cell : RenderableCell ) -> ( RunStart , LatestCol ) {
251+ let prev_start = replace ( & mut self . run_start , RunStart :: new ( & render_cell) ) ;
252+ let prev_latest = replace ( & mut self . latest_col , LatestCol :: new ( & render_cell) ) ;
253+
219254 self . buffer_content ( render_cell) ;
220- ( start, latest)
255+
256+ ( prev_start, prev_latest)
221257 }
222258
223259 /// Create a run of chars from the current state of the `TextRunIter`.
224260 /// This is a destructive operation, the iterator will be in a new run state after it's
225261 /// completion.
226- fn produce_char_run ( & mut self , render_cell : RenderableCell ) -> Option < TextRun > {
262+ fn produce_char_run ( & mut self , render_cell : RenderableCell ) -> TextRun {
227263 let prev_buffer = self . drain_buffer ( ) ;
228- let ( start_opt, latest_col_opt) = self . start_run ( render_cell) ;
229- let start = start_opt?;
230- let latest_col = latest_col_opt?;
231- Some ( Self :: build_text_run ( start, latest_col, prev_buffer) )
264+ let ( start, latest_col) = self . start_run ( render_cell) ;
265+
266+ Self :: build_text_run ( start, latest_col, prev_buffer)
232267 }
233268
234269 /// Build a TextRun instance from passed state of TextRunIter
235- fn build_text_run (
236- start : RunStart ,
237- ( latest, is_wide) : LatestCol ,
238- content : TextRunContent ,
239- ) -> TextRun {
240- let end_column = if is_wide { latest + 1 } else { latest } ;
270+ fn build_text_run ( start : RunStart , latest_col : LatestCol , content : TextRunContent ) -> TextRun {
271+ let end_column = latest_col. column + latest_col. is_wide as usize ;
241272 TextRun {
242273 line : start. line ,
243274 span : ( start. column , end_column) ,
@@ -257,46 +288,28 @@ where
257288 type Item = TextRun ;
258289
259290 fn next ( & mut self ) -> Option < Self :: Item > {
260- let mut output = None ;
261291 while let Some ( mut render_cell) = self . iter . next ( ) {
262292 if self . is_hinted ( render_cell. point ) {
263293 render_cell. flags . insert ( Flags :: UNDERLINE ) ;
264294 }
265- if self . latest_col . is_none ( ) || self . run_start . is_none ( ) {
266- // Initial state, this is should only be hit on the first next() call of
267- // iterator
268-
269- self . run_start = Some ( RunStart {
270- line : render_cell. point . line ,
271- column : render_cell. point . column ,
272- fg : render_cell. fg ,
273- bg : render_cell. bg ,
274- bg_alpha : render_cell. bg_alpha ,
275- flags : render_cell. flags ,
276- } ) ;
277- } else if self . is_end_of_run ( & render_cell) {
295+ if self . is_end_of_run ( & render_cell) {
278296 // If we find a run break,
279297 // return what we have so far and start a new run.
280- output = self . produce_char_run ( render_cell) ;
281- break ;
298+ return Some ( self . produce_char_run ( render_cell) ) ;
282299 }
283300
284301 // Build up buffer and track the latest column we've seen
285- self . latest_col =
286- Some ( ( render_cell. point . column , render_cell. flags . contains ( Flags :: WIDE_CHAR ) ) ) ;
302+ self . latest_col = LatestCol :: new ( & render_cell) ;
287303 self . buffer_content ( render_cell) ;
288304 }
305+
289306 // Check for any remaining buffered content and return it as a text run.
290307 // This is a destructive operation, it will return None after it excutes once.
291- output. or_else ( || {
292- if !self . buffer_text . is_empty ( ) || !self . buffer_zero_width . is_empty ( ) {
293- let start = self . run_start . take ( ) ?;
294- let latest_col = self . latest_col . take ( ) ?;
295- // Save leftover buffer and empty it
296- Some ( Self :: build_text_run ( start, latest_col, self . drain_buffer ( ) ) )
297- } else {
298- None
299- }
300- } )
308+ if !self . buffer_text . is_empty ( ) || !self . buffer_zero_width . is_empty ( ) {
309+ // Save leftover buffer and empty it
310+ Some ( Self :: build_text_run ( self . run_start , self . latest_col , self . drain_buffer ( ) ) )
311+ } else {
312+ None
313+ }
301314 }
302315}
0 commit comments