diff --git a/Cargo.lock b/Cargo.lock index 647a026..33e0760 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,6 +269,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + [[package]] name = "errno" version = "0.3.14" @@ -279,6 +290,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -343,6 +364,7 @@ dependencies = [ "gleisbau", "itertools", "lazy_static", + "pager", "platform-dirs", "regex", "serde", @@ -582,6 +604,16 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "pager" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2599211a5c97fbbb1061d3dc751fa15f404927e4846e07c643287d6d1f462880" +dependencies = [ + "errno 0.2.8", + "libc", +] + [[package]] name = "parking_lot" version = "0.12.5" @@ -715,7 +747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", - "errno", + "errno 0.3.14", "libc", "linux-raw-sys", "windows-sys", @@ -810,7 +842,7 @@ version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ - "errno", + "errno 0.3.14", "libc", ] diff --git a/Cargo.toml b/Cargo.toml index c4b8c87..e8c0fce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,4 @@ crossterm = {version = "0.29", optional = false} chrono = {version = "0.4", optional = false} textwrap = {version = "0.16", default-features = false, optional = false, features = ["unicode-width"]} gleisbau = "0.7.5" +pager = "0.16.1" diff --git a/src/main.rs b/src/main.rs index 44193fb..5151607 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,8 +23,9 @@ use gleisbau::settings::{ }; use itertools::enumerate; use platform_dirs::AppDirs; -use std::path::PathBuf; use std::borrow::Borrow; +use std::io::IsTerminal; +use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; use std::time::Instant; @@ -56,6 +57,7 @@ fn from_args() -> Result<(), String> { ses.svg, ses.commit_limit, ses.refspecs, + ses.pager, ) } @@ -134,6 +136,13 @@ fn match_args() -> ArgMatches { .required(false) .num_args(1), ) + .arg( + Arg::new("no-pager") + .long("no-pager") + .help("Use no pager (print everything at once without prompt).") + .required(false) + .num_args(0), + ) .arg( Arg::new("refspecs") .help( @@ -210,6 +219,11 @@ fn configure_session(ses: &mut Session, matches: &ArgMatches) -> Result("no-pager") + .map(|b| !*b) + .unwrap_or(true); + Ok(run_application) } @@ -225,6 +239,7 @@ struct Session { pub svg: bool, pub commit_limit: Option, pub refspecs: Vec, + pub pager: bool, } impl Session { @@ -241,6 +256,8 @@ impl Session { svg: false, commit_limit: None, refspecs: Vec::new(), + + pager: true, } } } @@ -620,6 +637,7 @@ fn run( svg: bool, max_commits: Option, refspecs: Vec, + pager: bool, ) -> Result<(), String> { let now = Instant::now(); let mut graph_builder = GraphBuilder::new() @@ -665,6 +683,13 @@ fn run( if svg { println!("{}", print_svg(&graph, settings)?); } else { + if pager && should_page() { + let pager_command = git_pager(); + + let mut pager = pager::Pager::with_pager(&pager_command); + pager.setup(); + } + let (g_lines, t_lines, _indices) = print_unicode(&graph, settings)?; print_unpaged(&g_lines, &t_lines); }; @@ -682,6 +707,32 @@ fn run( Ok(()) } +fn git_pager() -> String { + std::env::var("GIT_PAGER") + .ok() + .or_else(|| { + std::process::Command::new("git") + .args(["config", "--get", "core.pager"]) + .output() + .ok() + .filter(|o| o.status.success()) + .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned()) + .filter(|s| !s.is_empty()) + }) + .or_else(|| std::env::var("PAGER").ok()) + .unwrap_or_else(|| "less".to_owned()) +} + +fn should_page() -> bool { + if !std::io::stdout().is_terminal() { + return false; + } + + let (width, height) = crossterm::terminal::size().unwrap_or((80, 24)); + + width > 0 && height > 0 +} + /// Print the graph, un-paged. fn print_unpaged(graph_lines: &[String], text_lines: &[String]) { for (g_line, t_line) in graph_lines.iter().zip(text_lines.iter()) {