1
0
mirror of https://github.com/sharkdp/bat.git synced 2025-10-01 09:32:27 +01:00

Add a "builtin" pager using the Minus crate

This commit is contained in:
Daniel Waechter
2024-09-05 18:27:29 -04:00
committed by Academician
parent 929669728c
commit a470cebf32
9 changed files with 257 additions and 22 deletions

View File

@@ -16,7 +16,7 @@ use std::io::{BufReader, Write};
use std::path::Path;
use std::process;
use bat::output::{OutputHandle, OutputType};
use bat::output::OutputType;
use bat::theme::DetectColorScheme;
use nu_ansi_term::Color::Green;
use nu_ansi_term::Style;
@@ -229,10 +229,7 @@ pub fn list_themes(
)?;
config.theme = theme.to_string();
Controller::new(&config, &assets)
.run(
vec![theme_preview_file()],
Some(OutputHandle::IoWrite(&mut writer)),
)
.run(vec![theme_preview_file()], Some(&mut writer))
.ok();
writeln!(writer)?;
} else if config.loop_through {

View File

@@ -36,14 +36,18 @@ impl Controller<'_> {
}
}
pub fn run(&self, inputs: Vec<Input>, output_handle: Option<OutputHandle<'_>>) -> Result<bool> {
pub fn run(
&self,
inputs: Vec<Input>,
output_handle: Option<&mut OutputHandle<'_>>,
) -> Result<bool> {
self.run_with_error_handler(inputs, output_handle, default_error_handler)
}
pub fn run_with_error_handler(
&self,
inputs: Vec<Input>,
output_handle: Option<OutputHandle<'_>>,
output_handle: Option<&mut OutputHandle<'_>>,
mut handle_error: impl FnMut(&Error, &mut dyn Write),
) -> Result<bool> {
let mut output_type;
@@ -88,7 +92,7 @@ impl Controller<'_> {
let mut writer = match output_handle {
Some(OutputHandle::FmtWrite(w)) => OutputHandle::FmtWrite(w),
Some(OutputHandle::IoWrite(w)) => OutputHandle::IoWrite(w),
None => OutputHandle::IoWrite(output_type.handle()?),
None => output_type.handle()?,
};
let mut no_errors: bool = true;
let stderr = io::stderr();

View File

@@ -28,6 +28,9 @@ pub enum Error {
InvalidPagerValueBat,
#[error("{0}")]
Msg(String),
#[cfg(feature = "paging")]
#[error(transparent)]
MinusError(#[from] ::minus::MinusError),
#[cfg(feature = "lessopen")]
#[error(transparent)]
VarError(#[from] ::std::env::VarError),

View File

@@ -1,7 +1,9 @@
use std::fmt;
use std::io::{self, Write};
use std::io;
#[cfg(feature = "paging")]
use std::process::Child;
#[cfg(feature = "paging")]
use std::thread::{spawn, JoinHandle};
use crate::error::*;
#[cfg(feature = "paging")]
@@ -11,6 +13,36 @@ use crate::paging::PagingMode;
#[cfg(feature = "paging")]
use crate::wrapping::WrappingMode;
#[cfg(feature = "paging")]
pub struct BuiltinPager {
pager: minus::Pager,
handle: Option<JoinHandle<Result<()>>>,
}
#[cfg(feature = "paging")]
impl BuiltinPager {
fn new() -> Self {
let pager = minus::Pager::new();
let handle = {
let pager = pager.clone();
Some(spawn(move || {
minus::dynamic_paging(pager).map_err(Error::from)
}))
};
Self { pager, handle }
}
}
#[cfg(feature = "paging")]
impl std::fmt::Debug for BuiltinPager {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BuiltinPager")
//.field("pager", &self.pager) /// minus::Pager doesn't implement fmt::Debug
.field("handle", &self.handle)
.finish()
}
}
#[cfg(feature = "paging")]
#[derive(Debug, PartialEq)]
enum SingleScreenAction {
@@ -22,6 +54,8 @@ enum SingleScreenAction {
pub enum OutputType {
#[cfg(feature = "paging")]
Pager(Child),
#[cfg(feature = "paging")]
BuiltinPager(BuiltinPager),
Stdout(io::Stdout),
}
@@ -64,6 +98,10 @@ impl OutputType {
return Err(Error::InvalidPagerValueBat);
}
if pager.kind == PagerKind::Builtin {
return Ok(OutputType::BuiltinPager(BuiltinPager::new()));
}
let resolved_path = match grep_cli::resolve_binary(&pager.bin) {
Ok(path) => path,
Err(_) => {
@@ -138,7 +176,7 @@ impl OutputType {
#[cfg(feature = "paging")]
pub(crate) fn is_pager(&self) -> bool {
matches!(self, OutputType::Pager(_))
matches!(self, OutputType::Pager(_) | OutputType::BuiltinPager(_))
}
#[cfg(not(feature = "paging"))]
@@ -146,14 +184,18 @@ impl OutputType {
false
}
pub fn handle(&mut self) -> Result<&mut dyn Write> {
pub fn handle<'a>(&'a mut self) -> Result<OutputHandle<'a>> {
Ok(match *self {
#[cfg(feature = "paging")]
OutputType::Pager(ref mut command) => command
.stdin
.as_mut()
.ok_or("Could not open stdin for pager")?,
OutputType::Stdout(ref mut handle) => handle,
OutputType::Pager(ref mut command) => OutputHandle::IoWrite(
command
.stdin
.as_mut()
.ok_or("Could not open stdin for pager")?,
),
#[cfg(feature = "paging")]
OutputType::BuiltinPager(ref mut pager) => OutputHandle::FmtWrite(&mut pager.pager),
OutputType::Stdout(ref mut handle) => OutputHandle::IoWrite(handle),
})
}
}
@@ -161,8 +203,16 @@ impl OutputType {
#[cfg(feature = "paging")]
impl Drop for OutputType {
fn drop(&mut self) {
if let OutputType::Pager(ref mut command) = *self {
let _ = command.wait();
match *self {
OutputType::Pager(ref mut command) => {
let _ = command.wait();
}
OutputType::BuiltinPager(ref mut pager) => {
if pager.handle.is_some() {
let _ = pager.handle.take().unwrap().join().unwrap();
}
}
OutputType::Stdout(_) => (),
}
}
}

View File

@@ -32,6 +32,9 @@ pub(crate) enum PagerKind {
/// most
Most,
/// builtin
Builtin,
/// A pager we don't know about
Unknown,
}
@@ -40,6 +43,10 @@ impl PagerKind {
fn from_bin(bin: &str) -> PagerKind {
use std::path::Path;
if bin == "builtin" {
return PagerKind::Builtin;
}
// Set to `less` by default on most Linux distros.
let pager_bin = Path::new(bin).file_stem();

View File

@@ -328,7 +328,7 @@ impl<'a> PrettyPrinter<'a> {
if let Some(mut w) = writer {
controller.run(
inputs.into_iter().map(|i| i.into()).collect(),
Some(OutputHandle::FmtWrite(&mut w)),
Some(&mut OutputHandle::FmtWrite(&mut w)),
)
} else {
controller.run(inputs.into_iter().map(|i| i.into()).collect(), None)