1- use std:: io:: { self , BufRead , Write } ;
2-
31use crate :: assets:: HighlightingAssets ;
42use crate :: config:: { Config , VisibleLines } ;
53#[ cfg( feature = "git" ) ]
@@ -10,11 +8,14 @@ use crate::input::{Input, InputReader, OpenedInput};
108use crate :: lessopen:: LessOpenPreprocessor ;
119#[ cfg( feature = "git" ) ]
1210use crate :: line_range:: LineRange ;
13- use crate :: line_range:: { LineRanges , RangeCheckResult } ;
11+ use crate :: line_range:: { LineRanges , MaxBufferedLineNumber , RangeCheckResult } ;
1412use crate :: output:: { OutputHandle , OutputType } ;
1513#[ cfg( feature = "paging" ) ]
1614use crate :: paging:: PagingMode ;
1715use crate :: printer:: { InteractivePrinter , Printer , SimplePrinter } ;
16+ use std:: collections:: VecDeque ;
17+ use std:: io:: { self , BufRead , Write } ;
18+ use std:: mem;
1819
1920use clircle:: { Clircle , Identifier } ;
2021
@@ -238,20 +239,63 @@ impl Controller<'_> {
238239 reader : & mut InputReader ,
239240 line_ranges : & LineRanges ,
240241 ) -> 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 ;
244250 let mut first_range: bool = true ;
245251 let mut mid_range: bool = false ;
246252
247253 let style_snip = self . config . style_components . snip ( ) ;
248254
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) {
251295 RangeCheckResult :: BeforeOrBetweenRanges => {
252296 // Call the printer in case we need to call the syntax highlighter
253297 // 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 ) ?;
255299 mid_range = false ;
256300 }
257301
@@ -266,15 +310,12 @@ impl Controller<'_> {
266310 }
267311 }
268312
269- printer. print_line ( false , writer, line_number , & line_buffer ) ?;
313+ printer. print_line ( false , writer, line_nr , & line , max_buffered_line_number ) ?;
270314 }
271315 RangeCheckResult :: AfterLastRange => {
272316 break ;
273317 }
274318 }
275-
276- line_number += 1 ;
277- line_buffer. clear ( ) ;
278319 }
279320 Ok ( ( ) )
280321 }
0 commit comments