diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f531f1dd..0d33c072e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ visible. Improved colours on terminals with light coloured backgrounds. +### Command Line Interface + +Added a `--width` option which allows overriding `DFT_WIDTH`, and is +more discoverable. + ## 0.17 (released 25 January 2022) ### Diffing diff --git a/src/main.rs b/src/main.rs index 422db35ff..ea1b625ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,6 +64,12 @@ use crate::{ extern crate pretty_env_logger; +/// Choose the display width: try to autodetect, or fall back to a +/// sensible default. +fn detect_display_width() -> usize { + term_size::dimensions().map(|(w, _)| w).unwrap_or(80) +} + fn configure_color() { if atty::is(Stream::Stdout) || env::var("GIT_PAGER_IN_USE").is_ok() { // Always enable colour if stdout is a TTY or if the git pager is active. @@ -76,6 +82,7 @@ fn configure_color() { enum Mode { Diff { + display_width: usize, display_path: String, lhs_path: String, rhs_path: String, @@ -111,6 +118,15 @@ fn app() -> clap::App<'static> { "Parse a single file with tree-sitter and display the tree-sitter parse tree.", ), ) + .arg( + Arg::new("width") + .long("width") + .takes_value(true) + .value_name("COLUMNS") + .help("Use this many columns when calculating line wrapping. Overrides $DFT_WIDTH if present. If not specified, difftastic will detect the terminal width.") + .validator(|s| s.parse::()) + .required(false), + ) .arg( Arg::new("paths") .multiple_values(true) @@ -171,7 +187,22 @@ fn parse_args() -> Mode { ), }; + let display_width = if let Some(arg_width) = matches.value_of("width") { + let width = arg_width + .parse::() + .expect("Already validated by clap"); + width + } else { + let env_width = if let Ok(env_width) = env::var("DFT_WIDTH") { + env_width.parse::().ok() + } else { + None + }; + env_width.unwrap_or_else(detect_display_width) + }; + Mode::Diff { + display_width, display_path, lhs_path, rhs_path, @@ -233,20 +264,22 @@ fn main() { } } Mode::Diff { + display_width, display_path, lhs_path, rhs_path, + .. } => { let lhs_path = Path::new(&lhs_path); let rhs_path = Path::new(&rhs_path); if lhs_path.is_dir() && rhs_path.is_dir() { for diff_result in diff_directories(lhs_path, rhs_path) { - print_diff_result(&diff_result); + print_diff_result(display_width, &diff_result); } } else { let diff_result = diff_file(&display_path, lhs_path, rhs_path); - print_diff_result(&diff_result); + print_diff_result(display_width, &diff_result); } } }; @@ -368,7 +401,7 @@ fn diff_directories(lhs_dir: &Path, rhs_dir: &Path) -> Vec { res } -fn print_diff_result(summary: &DiffResult) { +fn print_diff_result(display_width: usize, summary: &DiffResult) { if summary.binary { println!("{}", style::header(&summary.path, 1, 1, "binary")); return; @@ -415,6 +448,7 @@ fn print_diff_result(summary: &DiffResult) { "{}", side_by_side::display_hunks( &hunks, + display_width, &summary.path, &lang_name, &summary.lhs_src, @@ -444,4 +478,10 @@ mod tests { fn test_app() { app().debug_assert(); } + + #[test] + fn test_detect_display_width() { + // Basic smoke test. + assert!(detect_display_width() > 10); + } } diff --git a/src/side_by_side.rs b/src/side_by_side.rs index 558c5d0ab..2a85ed785 100644 --- a/src/side_by_side.rs +++ b/src/side_by_side.rs @@ -4,7 +4,6 @@ use colored::{Color, Colorize}; use std::{ cmp::max, collections::{HashMap, HashSet}, - env, }; use crate::{ @@ -18,19 +17,6 @@ use crate::{ const SPACER: &str = " "; -/// Choose the display width: honour environment variables, then try -/// to autodetect, or fall back to a sensible default. -fn display_width() -> usize { - // TODO: document in manual. - if let Ok(s) = env::var("DFT_WIDTH") { - if let Ok(i) = s.parse::() { - return i; - } - } - - term_size::dimensions().map(|(w, _)| w).unwrap_or(80) -} - /// Split `s` by newlines. Always returns a non-empty vec. /// /// This differs from `str::lines`, which considers `""` to be zero @@ -241,6 +227,7 @@ fn highlight_as_novel( pub fn display_hunks( hunks: &[Hunk], + display_width: usize, display_path: &str, lang_name: &str, lhs_src: &str, @@ -282,7 +269,7 @@ pub fn display_hunks( let no_rhs_changes = hunk.lines.iter().all(|(_, r)| r.is_none()); let same_lines = aligned_lines.iter().all(|(l, r)| l == r); - let widths = Widths::new(display_width(), &aligned_lines, &lhs_lines, &rhs_lines); + let widths = Widths::new(display_width, &aligned_lines, &lhs_lines, &rhs_lines); for (lhs_line_num, rhs_line_num) in aligned_lines { let lhs_line_novel = highlight_as_novel( lhs_line_num, @@ -440,12 +427,6 @@ mod tests { assert_eq!(widths.rhs_line_nums, 3); } - #[test] - fn test_display_width() { - // Basic smoke test. - assert!(display_width() > 10); - } - #[test] fn test_display_single_column() { // Basic smoke test. @@ -511,6 +492,7 @@ mod tests { // Simple smoke test. display_hunks( &hunks, + 80, "foo.el", "Emacs Lisp", "foo",