@@ -458,8 +458,8 @@ struct Pager<'a> {
458458 line_positions : Vec < u64 > ,
459459 // The number of rows that fit on the screen
460460 content_rows : usize ,
461- eof_reached : bool ,
462461 next_file : Option < & ' a str > ,
462+ line_count : usize ,
463463 silent : bool ,
464464 squeeze : bool ,
465465}
@@ -471,17 +471,31 @@ impl<'a> Pager<'a> {
471471 next_file : Option < & ' a str > ,
472472 options : & Options ,
473473 ) -> Self {
474- let reader = Box :: new ( BufReader :: new ( file) ) ;
474+ let mut reader = Box :: new ( BufReader :: new ( file) ) ;
475475 let content_rows = rows. saturating_sub ( 1 ) as usize ;
476+ let mut line_positions = vec ! [ 0 ] ;
477+ let mut line_count = 0 ;
478+
479+ let mut line = String :: new ( ) ;
480+ while let Ok ( bytes) = reader. read_line ( & mut line) {
481+ if bytes == 0 {
482+ break ; // EOF
483+ }
484+ line_count += 1 ;
485+ line_positions. push ( reader. stream_position ( ) . unwrap ( ) ) ;
486+ line. clear ( ) ;
487+ }
488+
489+ reader. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
476490
477491 Self {
478492 reader,
479493 upper_mark : options. from_line ,
480494 visible_lines : VecDeque :: with_capacity ( content_rows) ,
481- line_positions : vec ! [ 0 ] ,
495+ line_positions,
482496 content_rows,
483- eof_reached : false ,
484497 next_file,
498+ line_count,
485499 silent : options. silent ,
486500 squeeze : options. squeeze ,
487501 }
@@ -508,11 +522,6 @@ impl<'a> Pager<'a> {
508522 return Ok ( Some ( line_num) ) ;
509523 }
510524
511- // Record this line position for later seeking
512- if self . line_positions . len ( ) <= line_num + 1 {
513- self . line_positions . push ( self . reader . stream_position ( ) ?) ;
514- }
515-
516525 line. clear ( ) ;
517526 line_num += 1 ;
518527 }
@@ -522,26 +531,20 @@ impl<'a> Pager<'a> {
522531 }
523532
524533 fn should_close ( & mut self ) -> bool {
525- // Return true when we've reached EOF and don't have enough lines to fill the screen
526- self . eof_reached && self . visible_lines . len ( ) < self . content_rows
534+ self . upper_mark
535+ . saturating_add ( self . content_rows )
536+ . ge ( & self . line_count )
527537 }
528538
529539 fn page_down ( & mut self ) {
530- if self . eof_reached
531- && self . upper_mark + self . visible_lines . len ( ) >= self . line_positions . len ( ) - 1
532- {
533- return ;
534- }
535-
536- self . upper_mark = self . upper_mark . saturating_add ( self . content_rows ) ;
537-
538- // Check if we have any lines to reuse
539- if !self . visible_lines . is_empty ( ) {
540- let lines_to_drop = self . content_rows . min ( self . visible_lines . len ( ) ) ;
541- self . visible_lines . drain ( ..lines_to_drop) ;
540+ // If the next page down position __after redraw__ is greater than the total line count,
541+ // the upper mark must not grow past top of the screen at the end of the open file.
542+ if self . upper_mark . saturating_add ( self . content_rows * 2 ) >= self . line_count {
543+ self . upper_mark = self . line_count - self . content_rows ;
542544 } else {
543- self . visible_lines . clear ( ) ;
545+ self . upper_mark = self . upper_mark . saturating_add ( self . content_rows ) ;
544546 }
547+ self . visible_lines . clear ( ) ;
545548 }
546549
547550 fn page_up ( & mut self ) {
@@ -554,27 +557,21 @@ impl<'a> Pager<'a> {
554557 self . upper_mark = self . upper_mark . saturating_sub ( self . content_rows ) ;
555558
556559 // If we're moving up by less than a full page, we can reuse some lines
557- if old_upper_mark - self . upper_mark < self . content_rows {
558- let lines_to_keep = self . content_rows - ( old_upper_mark - self . upper_mark ) ;
559- if lines_to_keep > 0 && lines_to_keep < self . visible_lines . len ( ) {
560+ let lines_to_keep = self
561+ . content_rows
562+ . saturating_sub ( old_upper_mark - self . upper_mark ) ;
563+ if lines_to_keep > 0 {
564+ if lines_to_keep < self . visible_lines . len ( ) {
560565 self . visible_lines . truncate ( lines_to_keep) ;
561566 } else {
562567 self . visible_lines . clear ( ) ;
563568 }
564569 } else {
565570 self . visible_lines . clear ( ) ;
566571 }
567-
568- self . eof_reached = false ;
569572 }
570573
571574 fn next_line ( & mut self ) {
572- if self . eof_reached
573- && self . upper_mark + self . visible_lines . len ( ) >= self . line_positions . len ( ) - 1
574- {
575- return ;
576- }
577-
578575 self . upper_mark = self . upper_mark . saturating_add ( 1 ) ;
579576
580577 if !self . visible_lines . is_empty ( ) {
@@ -599,8 +596,6 @@ impl<'a> Pager<'a> {
599596 }
600597 }
601598 }
602-
603- self . eof_reached = false ;
604599 }
605600
606601 // TODO: Deal with column size changes.
@@ -612,7 +607,10 @@ impl<'a> Pager<'a> {
612607
613608 fn draw ( & mut self , stdout : & mut std:: io:: Stdout , wrong_key : Option < char > ) -> UResult < ( ) > {
614609 self . draw_lines ( stdout) ?;
615- self . draw_prompt ( stdout, wrong_key) ?;
610+ let lower_mark = self
611+ . line_count
612+ . min ( self . upper_mark . saturating_add ( self . content_rows ) ) ;
613+ self . draw_prompt ( stdout, lower_mark, wrong_key) ;
616614 stdout. flush ( ) . unwrap ( ) ;
617615 Ok ( ( ) )
618616 }
@@ -627,22 +625,14 @@ impl<'a> Pager<'a> {
627625 Ok ( ( ) )
628626 }
629627
630- fn draw_prompt ( & self , stdout : & mut Stdout , wrong_key : Option < char > ) -> UResult < ( ) > {
631- let status_inner = if self . eof_reached && self . visible_lines . len ( ) < self . content_rows {
628+ fn draw_prompt ( & self , stdout : & mut Stdout , lower_mark : usize , wrong_key : Option < char > ) {
629+ let status_inner = if lower_mark == self . line_count {
632630 format ! ( "Next file: {}" , self . next_file. unwrap_or_default( ) )
633631 } else {
634- let percentage = if self . line_positions . len ( ) <= 1 {
635- 0
636- } else {
637- let current_pos = self . line_positions [ self . upper_mark ] ;
638- let last_known_pos = * self . line_positions . last ( ) . unwrap_or ( & 0 ) ;
639- if last_known_pos == 0 {
640- 0
641- } else {
642- ( current_pos as f64 / last_known_pos as f64 * 100.0 ) . round ( ) as u16
643- }
644- } ;
645- format ! ( "{}%" , percentage)
632+ format ! (
633+ "{}%" ,
634+ ( lower_mark as f64 / self . line_count as f64 * 100.0 ) . round( ) as u16
635+ )
646636 } ;
647637
648638 let status = format ! ( "--More--({status_inner})" ) ;
@@ -663,7 +653,6 @@ impl<'a> Pager<'a> {
663653 Attribute :: Reset
664654 )
665655 . unwrap ( ) ;
666- Ok ( ( ) )
667656 }
668657
669658 fn load_visible_lines ( & mut self ) -> UResult < ( ) > {
@@ -674,17 +663,8 @@ impl<'a> Pager<'a> {
674663 while self . visible_lines . len ( ) < self . content_rows {
675664 line. clear ( ) ;
676665 match self . reader . read_line ( & mut line) ? {
677- 0 => {
678- self . eof_reached = true ;
679- break ;
680- }
666+ 0 => break ,
681667 _ => {
682- // Cache position and handle line
683- let current_pos = self . reader . stream_position ( ) ?;
684- let line_index = self . upper_mark + self . visible_lines . len ( ) ;
685- if self . line_positions . len ( ) <= line_index + 1 {
686- self . line_positions . push ( current_pos) ;
687- }
688668 if !self . should_squeeze_line ( & line) {
689669 self . visible_lines . push_back ( std:: mem:: take ( & mut line) ) ;
690670 }
@@ -701,17 +681,8 @@ impl<'a> Pager<'a> {
701681 for _ in 0 ..lines_needed {
702682 line. clear ( ) ;
703683 match self . reader . read_line ( & mut line) ? {
704- 0 => {
705- self . eof_reached = true ;
706- break ;
707- }
684+ 0 => break ,
708685 _ => {
709- // Cache position and handle line
710- let current_pos = self . reader . stream_position ( ) ?;
711- let line_index = self . upper_mark + self . visible_lines . len ( ) ;
712- if self . line_positions . len ( ) <= line_index + 1 {
713- self . line_positions . push ( current_pos) ;
714- }
715686 if !self . should_squeeze_line ( & line) {
716687 self . visible_lines . push_back ( std:: mem:: take ( & mut line) ) ;
717688 }
@@ -724,34 +695,8 @@ impl<'a> Pager<'a> {
724695 }
725696
726697 fn seek_to_line ( & mut self , line_number : usize ) -> UResult < ( ) > {
727- if line_number < self . line_positions . len ( ) {
728- let pos = self . line_positions [ line_number] ;
729- self . reader . seek ( SeekFrom :: Start ( pos) ) ?;
730- return Ok ( ( ) ) ;
731- }
732-
733- let start_line = self . line_positions . len ( ) - 1 ;
734- let start_pos = self . line_positions [ start_line] ;
735- self . reader . seek ( SeekFrom :: Start ( start_pos) ) ?;
736-
737- let mut line = String :: new ( ) ;
738- for current_line in start_line..line_number {
739- match self . reader . read_line ( & mut line) ? {
740- 0 => {
741- self . eof_reached = true ;
742- return Ok ( ( ) ) ;
743- }
744- _ => {
745- // Cache this position for future seeks
746- let next_pos = self . reader . stream_position ( ) ?;
747- if self . line_positions . len ( ) <= current_line + 1 {
748- self . line_positions . push ( next_pos) ;
749- }
750- line. clear ( ) ;
751- }
752- }
753- }
754-
698+ let pos = self . line_positions [ line_number] ;
699+ self . reader . seek ( SeekFrom :: Start ( pos) ) ?;
755700 Ok ( ( ) )
756701 }
757702
0 commit comments