1
- use std:: io:: { self , BufRead , Write } ;
2
-
3
1
use crate :: assets:: HighlightingAssets ;
4
2
use crate :: config:: { Config , VisibleLines } ;
5
3
#[ cfg( feature = "git" ) ]
@@ -10,11 +8,14 @@ use crate::input::{Input, InputReader, OpenedInput};
10
8
use crate :: lessopen:: LessOpenPreprocessor ;
11
9
#[ cfg( feature = "git" ) ]
12
10
use crate :: line_range:: LineRange ;
13
- use crate :: line_range:: { LineRanges , RangeCheckResult } ;
11
+ use crate :: line_range:: { LineRanges , MaxBufferedLineNumber , RangeCheckResult } ;
14
12
use crate :: output:: { OutputHandle , OutputType } ;
15
13
#[ cfg( feature = "paging" ) ]
16
14
use crate :: paging:: PagingMode ;
17
15
use crate :: printer:: { InteractivePrinter , Printer , SimplePrinter } ;
16
+ use std:: collections:: VecDeque ;
17
+ use std:: io:: { self , BufRead , Write } ;
18
+ use std:: mem;
18
19
19
20
use clircle:: { Clircle , Identifier } ;
20
21
@@ -238,20 +239,63 @@ impl Controller<'_> {
238
239
reader : & mut InputReader ,
239
240
line_ranges : & LineRanges ,
240
241
) -> Result < ( ) > {
241
- let mut line_buffer = Vec :: new ( ) ;
242
- let mut line_number: usize = 1 ;
243
-
242
+ let mut current_line_buffer: Vec < u8 > = Vec :: new ( ) ;
243
+ let mut current_line_number: usize = 1 ;
244
+ // Buffer needs to be 1 greater than the offset to have a look-ahead line for EOF
245
+ let buffer_size: usize = line_ranges. largest_offset_from_end ( ) + 1 ;
246
+ // Buffers multiple line data and line number
247
+ let mut buffered_lines: VecDeque < ( Vec < u8 > , usize ) > = VecDeque :: with_capacity ( buffer_size) ;
248
+
249
+ let mut reached_eof: bool = false ;
244
250
let mut first_range: bool = true ;
245
251
let mut mid_range: bool = false ;
246
252
247
253
let style_snip = self . config . style_components . snip ( ) ;
248
254
249
- while reader. read_line ( & mut line_buffer) ? {
250
- match line_ranges. check ( line_number) {
255
+ loop {
256
+ if reached_eof && buffered_lines. is_empty ( ) {
257
+ // Done processing all lines
258
+ break ;
259
+ }
260
+ if !reached_eof {
261
+ if reader. read_line ( & mut current_line_buffer) ? {
262
+ // Fill the buffer
263
+ buffered_lines
264
+ . push_back ( ( mem:: take ( & mut current_line_buffer) , current_line_number) ) ;
265
+ current_line_number += 1 ;
266
+ } else {
267
+ // No more data to read
268
+ reached_eof = true ;
269
+ }
270
+ }
271
+
272
+ if buffered_lines. len ( ) < buffer_size && !reached_eof {
273
+ // The buffer needs to be completely filled first
274
+ continue ;
275
+ }
276
+
277
+ let Some ( ( line, line_nr) ) = buffered_lines. pop_front ( ) else {
278
+ break ;
279
+ } ;
280
+
281
+ // Determine if the last line number in the buffer is the last line of the file or
282
+ // just a line somewhere in the file
283
+ let max_buffered_line_number = buffered_lines
284
+ . back ( )
285
+ . map ( |( _, max_line_number) | {
286
+ if reached_eof {
287
+ MaxBufferedLineNumber :: Final ( * max_line_number)
288
+ } else {
289
+ MaxBufferedLineNumber :: Tentative ( * max_line_number)
290
+ }
291
+ } )
292
+ . unwrap_or ( MaxBufferedLineNumber :: Final ( line_nr) ) ;
293
+
294
+ match line_ranges. check ( line_nr, max_buffered_line_number) {
251
295
RangeCheckResult :: BeforeOrBetweenRanges => {
252
296
// Call the printer in case we need to call the syntax highlighter
253
297
// for this line. However, set `out_of_range` to `true`.
254
- printer. print_line ( true , writer, line_number , & line_buffer ) ?;
298
+ printer. print_line ( true , writer, line_nr , & line , max_buffered_line_number ) ?;
255
299
mid_range = false ;
256
300
}
257
301
@@ -266,15 +310,12 @@ impl Controller<'_> {
266
310
}
267
311
}
268
312
269
- printer. print_line ( false , writer, line_number , & line_buffer ) ?;
313
+ printer. print_line ( false , writer, line_nr , & line , max_buffered_line_number ) ?;
270
314
}
271
315
RangeCheckResult :: AfterLastRange => {
272
316
break ;
273
317
}
274
318
}
275
-
276
- line_number += 1 ;
277
- line_buffer. clear ( ) ;
278
319
}
279
320
Ok ( ( ) )
280
321
}
0 commit comments