1
0
mirror of https://github.com/sharkdp/bat.git synced 2025-09-03 03:42:26 +01:00

Support relative negative line ranges

This commit is contained in:
Alex Jesipow
2024-08-10 10:37:19 +02:00
parent 018a482621
commit 569286055c
7 changed files with 578 additions and 84 deletions

View File

@@ -1,5 +1,3 @@
use std::io::{self, BufRead, Write};
use crate::assets::HighlightingAssets;
use crate::config::{Config, VisibleLines};
#[cfg(feature = "git")]
@@ -10,11 +8,14 @@ use crate::input::{Input, InputReader, OpenedInput};
use crate::lessopen::LessOpenPreprocessor;
#[cfg(feature = "git")]
use crate::line_range::LineRange;
use crate::line_range::{LineRanges, RangeCheckResult};
use crate::line_range::{LineRanges, MaxBufferedLineNumber, RangeCheckResult};
use crate::output::OutputType;
#[cfg(feature = "paging")]
use crate::paging::PagingMode;
use crate::printer::{InteractivePrinter, OutputHandle, Printer, SimplePrinter};
use std::collections::VecDeque;
use std::io::{self, BufRead, Write};
use std::mem;
use clircle::{Clircle, Identifier};
@@ -241,20 +242,63 @@ impl<'b> Controller<'b> {
reader: &mut InputReader,
line_ranges: &LineRanges,
) -> Result<()> {
let mut line_buffer = Vec::new();
let mut line_number: usize = 1;
let mut current_line_buffer: Vec<u8> = Vec::new();
let mut current_line_number: usize = 1;
// Buffer needs to be 1 greater than the offset to have a look-ahead line for EOF
let buffer_size: usize = line_ranges.largest_offset_from_end() + 1;
// Buffers multiple line data and line number
let mut buffered_lines: VecDeque<(Vec<u8>, usize)> = VecDeque::with_capacity(buffer_size);
let mut reached_eof: bool = false;
let mut first_range: bool = true;
let mut mid_range: bool = false;
let style_snip = self.config.style_components.snip();
while reader.read_line(&mut line_buffer)? {
match line_ranges.check(line_number) {
loop {
if reached_eof && buffered_lines.is_empty() {
// Done processing all lines
break;
}
if !reached_eof {
if reader.read_line(&mut current_line_buffer)? {
// Fill the buffer
buffered_lines
.push_back((mem::take(&mut current_line_buffer), current_line_number));
current_line_number += 1;
} else {
// No more data to read
reached_eof = true;
}
}
if buffered_lines.len() < buffer_size && !reached_eof {
// The buffer needs to be completely filled first
continue;
}
let Some((line, line_nr)) = buffered_lines.pop_front() else {
break;
};
// Determine if the last line number in the buffer is the last line of the file or
// just a line somewhere in the file
let max_buffered_line_number = buffered_lines
.back()
.map(|(_, max_line_number)| {
if reached_eof {
MaxBufferedLineNumber::Final(*max_line_number)
} else {
MaxBufferedLineNumber::Tentative(*max_line_number)
}
})
.unwrap_or(MaxBufferedLineNumber::Final(line_nr));
match line_ranges.check(line_nr, max_buffered_line_number) {
RangeCheckResult::BeforeOrBetweenRanges => {
// Call the printer in case we need to call the syntax highlighter
// for this line. However, set `out_of_range` to `true`.
printer.print_line(true, writer, line_number, &line_buffer)?;
printer.print_line(true, writer, line_nr, &line, max_buffered_line_number)?;
mid_range = false;
}
@@ -269,15 +313,12 @@ impl<'b> Controller<'b> {
}
}
printer.print_line(false, writer, line_number, &line_buffer)?;
printer.print_line(false, writer, line_nr, &line, max_buffered_line_number)?;
}
RangeCheckResult::AfterLastRange => {
break;
}
}
line_number += 1;
line_buffer.clear();
}
Ok(())
}