Skip to content

Commit 328da32

Browse files
committed
refactor line handling and remove EOF tracking
1 parent dd71684 commit 328da32

File tree

1 file changed

+46
-101
lines changed

1 file changed

+46
-101
lines changed

src/uu/more/src/more.rs

Lines changed: 46 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)