From ff95ad5b9a79f967b78a890ed66dcf08b86d727f Mon Sep 17 00:00:00 2001 From: Thomas Otto Date: Tue, 3 Oct 2023 14:50:45 +0200 Subject: [PATCH] Repair --default-language, and highlight using full filename Fixed that the "txt" fallback was used instead of --default-language And when looking for syntax highlighting, keep the filename around as long as possible. Using simple custom logic (filename > 4) a Makefile can be highlighted with make syntax, but a 'cc' or 'ini' file does not get treated like a *.cc or *.ini file. Currently the underlying highlighting lib syntect and the sublime syntax definitions can not make this distinction (). --- src/cli.rs | 8 +- src/config.rs | 5 +- src/handlers/blame.rs | 10 +-- src/handlers/diff_header.rs | 73 ++++++++--------- src/handlers/git_show_file.rs | 4 +- src/handlers/grep.rs | 8 +- src/options/set.rs | 2 +- src/paint.rs | 49 +++++++---- src/subcommands/show_colors.rs | 2 +- src/tests/ansi_test_utils.rs | 12 ++- src/tests/test_example_diffs.rs | 58 ++++++++++++- src/utils/process.rs | 141 ++++++++++++++------------------ 12 files changed, 206 insertions(+), 166 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 4cddd6fb9..723ea42c0 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -287,12 +287,12 @@ pub struct Opt { /// For more control, see the style options and --syntax-theme. pub dark: bool, - #[arg(long = "default-language", value_name = "LANG")] + #[arg(long = "default-language", value_name = "LANG", default_value = "txt")] /// Default language used for syntax highlighting. /// - /// Used when the language cannot be inferred from a filename. It will typically make sense to - /// set this in per-repository git config (.git/config) - pub default_language: Option, + /// Used as a fallback when the language cannot be inferred from a filename. It will + /// typically make sense to set this in the per-repository config file '.git/config'. + pub default_language: String, /// Detect whether or not the terminal is dark or light by querying for its colors. /// diff --git a/src/config.rs b/src/config.rs index 7d3d442d0..767892890 100644 --- a/src/config.rs +++ b/src/config.rs @@ -31,6 +31,9 @@ use crate::wrapping::WrapConfig; pub const INLINE_SYMBOL_WIDTH_1: usize = 1; +// Used if an invalid default-language was specified. +pub const SYNTAX_FALLBACK_LANG: &str = "txt"; + #[cfg_attr(test, derive(Clone))] pub struct Config { pub available_terminal_width: usize, @@ -49,7 +52,7 @@ pub struct Config { pub cwd_of_user_shell_process: Option, pub cwd_relative_to_repo_root: Option, pub decorations_width: cli::Width, - pub default_language: Option, + pub default_language: String, pub diff_stat_align_width: usize, pub error_exit_code: i32, pub file_added_label: String, diff --git a/src/handlers/blame.rs b/src/handlers/blame.rs index e8c2e435a..fc3d6d1cb 100644 --- a/src/handlers/blame.rs +++ b/src/handlers/blame.rs @@ -77,13 +77,9 @@ impl<'a> StateMachine<'a> { // Emit syntax-highlighted code if matches!(self.state, State::Unknown) { - if let Some(lang) = utils::process::git_blame_filename_extension() - .as_ref() - .or(self.config.default_language.as_ref()) - { - self.painter.set_syntax(Some(lang)); - self.painter.set_highlighter(); - } + self.painter + .set_syntax(utils::process::git_blame_filename().as_deref()); + self.painter.set_highlighter(); } self.state = State::Blame(key); self.painter.syntax_highlight_and_paint_line( diff --git a/src/handlers/diff_header.rs b/src/handlers/diff_header.rs index 3c71a61a3..11b8b8e14 100644 --- a/src/handlers/diff_header.rs +++ b/src/handlers/diff_header.rs @@ -95,10 +95,10 @@ impl<'a> StateMachine<'a> { if self.source == Source::DiffUnified { self.state = State::DiffHeader(DiffType::Unified); self.painter - .set_syntax(get_file_extension_from_marker_line(&self.line)); + .set_syntax(get_filename_from_marker_line(&self.line)); } else { self.painter - .set_syntax(get_file_extension_from_diff_header_line_file_path( + .set_syntax(get_filename_from_diff_header_line_file_path( &self.minus_file, )); } @@ -129,7 +129,7 @@ impl<'a> StateMachine<'a> { .unwrap_or(path_or_mode); self.plus_file_event = file_event; self.painter - .set_syntax(get_file_extension_from_diff_header_line_file_path( + .set_syntax(get_filename_from_diff_header_line_file_path( &self.plus_file, )); self.current_file_pair = Some((self.minus_file.clone(), self.plus_file.clone())); @@ -300,30 +300,23 @@ pub fn write_generic_diff_header_header_line( #[allow(clippy::tabs_in_doc_comments)] /// Given input like -/// "--- one.rs 2019-11-20 06:16:08.000000000 +0100" -/// Return "rs" -fn get_file_extension_from_marker_line(line: &str) -> Option<&str> { +/// "--- a/zero/one.rs 2019-11-20 06:16:08.000000000 +0100" +/// Return "one.rs" +fn get_filename_from_marker_line(line: &str) -> Option<&str> { line.split('\t') .next() .and_then(|column| column.split(' ').nth(1)) - .and_then(|file| file.split('.').last()) + .and_then(get_filename_from_diff_header_line_file_path) } -fn get_file_extension_from_diff_header_line_file_path(path: &str) -> Option<&str> { - if path.is_empty() || path == "/dev/null" { - None - } else { - get_extension(path).map(|ex| ex.trim()) - } -} - -/// Attempt to parse input as a file path and return extension as a &str. -pub fn get_extension(s: &str) -> Option<&str> { - let path = Path::new(s); - path.extension() - .and_then(|e| e.to_str()) - // E.g. 'Makefile' is the file name and also the extension - .or_else(|| path.file_name().and_then(|s| s.to_str())) +fn get_filename_from_diff_header_line_file_path(path: &str) -> Option<&str> { + Path::new(path).file_name().and_then(|filename| { + if path != "/dev/null" { + filename.to_str() + } else { + None + } + }) } fn parse_diff_header_line(line: &str, git_diff_name: bool) -> (String, FileEvent) { @@ -477,51 +470,49 @@ mod tests { use super::*; #[test] - fn test_get_file_extension_from_marker_line() { + fn test_get_filename_from_marker_line() { assert_eq!( - get_file_extension_from_marker_line( - "--- src/one.rs 2019-11-20 06:47:56.000000000 +0100" - ), - Some("rs") + get_filename_from_marker_line("--- src/one.rs 2019-11-20 06:47:56.000000000 +0100"), + Some("one.rs") ); } #[test] - fn test_get_file_extension_from_diff_header_line() { + fn test_get_filename_from_diff_header_line() { assert_eq!( - get_file_extension_from_diff_header_line_file_path("a/src/parse.rs"), - Some("rs") + get_filename_from_diff_header_line_file_path("a/src/parse.rs"), + Some("parse.rs") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("b/src/pa rse.rs"), - Some("rs") + get_filename_from_diff_header_line_file_path("b/src/pa rse.rs"), + Some("pa rse.rs") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("src/pa rse.rs"), - Some("rs") + get_filename_from_diff_header_line_file_path("src/pa rse.rs"), + Some("pa rse.rs") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("wat hello.rs"), - Some("rs") + get_filename_from_diff_header_line_file_path("wat hello.rs"), + Some("wat hello.rs") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("/dev/null"), + get_filename_from_diff_header_line_file_path("/dev/null"), None ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("Dockerfile"), + get_filename_from_diff_header_line_file_path("Dockerfile"), Some("Dockerfile") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("Makefile"), + get_filename_from_diff_header_line_file_path("Makefile"), Some("Makefile") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("a/src/Makefile"), + get_filename_from_diff_header_line_file_path("a/src/Makefile"), Some("Makefile") ); assert_eq!( - get_file_extension_from_diff_header_line_file_path("src/Makefile"), + get_filename_from_diff_header_line_file_path("src/Makefile"), Some("Makefile") ); } diff --git a/src/handlers/git_show_file.rs b/src/handlers/git_show_file.rs index a9e1358ea..ff670eb9a 100644 --- a/src/handlers/git_show_file.rs +++ b/src/handlers/git_show_file.rs @@ -9,11 +9,11 @@ impl<'a> StateMachine<'a> { self.painter.emit()?; let mut handled_line = false; if matches!(self.state, State::Unknown) { - if let process::CallingProcess::GitShow(_, Some(extension)) = + if let process::CallingProcess::GitShow(_, Some(filename)) = &*process::calling_process() { self.state = State::GitShowFile; - self.painter.set_syntax(Some(extension)); + self.painter.set_syntax(Some(filename)); } else { return Ok(handled_line); } diff --git a/src/handlers/grep.rs b/src/handlers/grep.rs index b7f2dc530..63cc1a3ef 100644 --- a/src/handlers/grep.rs +++ b/src/handlers/grep.rs @@ -132,12 +132,8 @@ impl<'a> StateMachine<'a> { self.painter.set_highlighter() } if new_path { - if let Some(lang) = handlers::diff_header::get_extension(&grep_line.path) - .or(self.config.default_language.as_deref()) - { - self.painter.set_syntax(Some(lang)); - self.painter.set_highlighter(); - } + self.painter.set_syntax(Some(grep_line.path.as_ref())); + self.painter.set_highlighter(); } match &self.state { State::Grep(GrepType::Ripgrep, _, _, _) => { diff --git a/src/options/set.rs b/src/options/set.rs index cfb42987b..5c8e1b431 100644 --- a/src/options/set.rs +++ b/src/options/set.rs @@ -735,7 +735,7 @@ pub mod tests { assert_eq!(opt.commit_decoration_style, "black black"); assert_eq!(opt.commit_style, "black black"); assert!(!opt.dark); - assert_eq!(opt.default_language, Some("rs".to_owned())); + assert_eq!(opt.default_language, "rs".to_owned()); // TODO: should set_options not be called on any feature flags? // assert_eq!(opt.diff_highlight, true); // assert_eq!(opt.diff_so_fancy, true); diff --git a/src/paint.rs b/src/paint.rs index ee2fefec6..4b487ea38 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -70,9 +70,7 @@ pub enum StyleSectionSpecifier<'l> { impl<'p> Painter<'p> { pub fn new(writer: &'p mut dyn Write, config: &'p config::Config) -> Self { - let default_syntax = - Self::get_syntax(&config.syntax_set, None, config.default_language.as_deref()); - + let default_syntax = Self::get_syntax(&config.syntax_set, None, &config.default_language); let panel_width_fix = ansifill::UseFullPanelWidth::new(config); let line_numbers_data = if config.line_numbers { @@ -104,27 +102,50 @@ impl<'p> Painter<'p> { } } - pub fn set_syntax(&mut self, extension: Option<&str>) { + pub fn set_syntax(&mut self, filename: Option<&str>) { self.syntax = Painter::get_syntax( &self.config.syntax_set, - extension, - self.config.default_language.as_deref(), + filename, + &self.config.default_language, ); } fn get_syntax<'a>( syntax_set: &'a SyntaxSet, - extension: Option<&str>, - fallback_extension: Option<&str>, + filename: Option<&str>, + fallback: &str, ) -> &'a SyntaxReference { - for extension in [extension, fallback_extension].iter().flatten() { - if let Some(syntax) = syntax_set.find_syntax_by_extension(extension) { - return syntax; + if let Some(filename) = filename { + let path = std::path::Path::new(filename); + let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + let extension = path.extension().and_then(|x| x.to_str()).unwrap_or(""); + + // Like syntect's `find_syntax_for_file`, without inspecting the file content, plus: + // If the file has NO extension then look up the whole filename as a + // syntax definition (if it is longer than 4 bytes). + // This means file formats like Makefile/Dockerfile/Rakefile etc. will get highlighted, + // but 1-4 short filenames will not -- even if they, as a whole, match an extension: + // 'rs' will not get highlighted, while 'x.rs' will. + if !extension.is_empty() || file_name.len() > 4 { + if let Some(syntax) = syntax_set + .find_syntax_by_extension(file_name) + .or_else(|| syntax_set.find_syntax_by_extension(extension)) + { + return syntax; + } } } - syntax_set - .find_syntax_by_extension("txt") - .unwrap_or_else(|| delta_unreachable("Failed to find any language syntax definitions.")) + + // Nothing found, try the user provided fallback, or the internal fallback. + if let Some(syntax) = syntax_set.find_syntax_for_file(fallback).unwrap_or(None) { + syntax + } else { + syntax_set + .find_syntax_by_extension(config::SYNTAX_FALLBACK_LANG) + .unwrap_or_else(|| { + delta_unreachable("Failed to find any language syntax definitions.") + }) + } } pub fn set_highlighter(&mut self) { diff --git a/src/subcommands/show_colors.rs b/src/subcommands/show_colors.rs index 8ad9fc35e..2898dd975 100644 --- a/src/subcommands/show_colors.rs +++ b/src/subcommands/show_colors.rs @@ -28,7 +28,7 @@ pub fn show_colors() -> std::io::Result<()> { let writer = output_type.handle().unwrap(); let mut painter = paint::Painter::new(writer, &config); - painter.set_syntax(Some("ts")); + painter.set_syntax(Some("a.ts")); painter.set_highlighter(); let title_style = ansi_term::Style::new().bold(); diff --git a/src/tests/ansi_test_utils.rs b/src/tests/ansi_test_utils.rs index 5e60223ba..8ccd12968 100644 --- a/src/tests/ansi_test_utils.rs +++ b/src/tests/ansi_test_utils.rs @@ -122,15 +122,19 @@ pub mod ansi_test_utils { line_number: usize, substring_begin: usize, expected_substring: &str, - language_extension: &str, + filename_for_highlighting: &str, state: State, config: &Config, ) { + assert!( + filename_for_highlighting.contains("."), + "expecting filename, not just a file extension" + ); let line = output.lines().nth(line_number).unwrap(); let substring_end = substring_begin + expected_substring.len(); let substring = &ansi::strip_ansi_codes(line)[substring_begin..substring_end]; assert_eq!(substring, expected_substring); - let painted_substring = paint_line(substring, language_extension, state, config); + let painted_substring = paint_line(substring, filename_for_highlighting, state, config); // remove trailing newline appended by paint::paint_lines. assert!(line.contains(painted_substring.trim_end())); } @@ -163,7 +167,7 @@ pub mod ansi_test_utils { pub fn paint_line( line: &str, - language_extension: &str, + filename_for_highlighting: &str, state: State, config: &Config, ) -> String { @@ -174,7 +178,7 @@ pub mod ansi_test_utils { is_syntax_highlighted: true, ..Style::new() }; - painter.set_syntax(Some(language_extension)); + painter.set_syntax(Some(filename_for_highlighting)); painter.set_highlighter(); let lines = vec![(line.to_string(), state)]; let syntax_style_sections = paint::get_syntax_style_sections_for_lines( diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs index 104807a7e..50a4fd1d1 100644 --- a/src/tests/test_example_diffs.rs +++ b/src/tests/test_example_diffs.rs @@ -111,7 +111,7 @@ mod tests { 12, 1, " rsync -avu --delete $src/ $dst", - "bash", + "abc.bash", State::HunkZero(DiffType::Unified, None), &config, ); @@ -126,17 +126,49 @@ mod tests { "bash", ]); let output = integration_test_utils::run_delta(MODIFIED_BASH_AND_CSHARP_FILES, &config); + eprintln!("{}", &output); ansi_test_utils::assert_line_has_syntax_highlighted_substring( &output, 19, 1, " static void Main(string[] args)", - "cs", + "abc.cs", State::HunkZero(DiffType::Unified, None), &config, ); } + #[test] + fn test_full_filename_used_to_detect_language() { + let config = integration_test_utils::make_config_from_args(&[ + "--color-only", + "--default-language", + "txt", + ]); + let output = integration_test_utils::run_delta(MODIFIED_DOCKER_AND_RS_FILES, &config); + let ansi = ansi::explain_ansi(&output, false); + + // Ensure presence and absence of highlighting. Do not use `assert_line_has_syntax_highlighted_substring` + // because it uses the same code path as the one to be tested here. + let expected = r"(normal)diff --git a/Dockerfile b/Dockerfile +index 0123456..1234567 100644 +--- a/Dockerfile ++++ b/Dockerfile +@@ -0,0 +2 @@ +(normal 22)+(204)FROM(231) foo(normal) +(normal 22)+(203)COPY(231) bar baz(normal) +diff --git a/rs b/rs +index 0123456..1234567 100644 +--- a/rs ++++ b/rs +@@ -0,0 +2 @@ +(normal 22)+(231)fn foobar() -> i8 {(normal) +(normal 22)+(231) 8(normal) +(normal 22)+(231)}(normal) +"; + assert_eq!(expected, ansi); + } + #[test] fn test_diff_unified_two_files() { let config = @@ -1461,7 +1493,7 @@ src/align.rs:71: impl<'a> Alignment<'a> { │ 11, 4, "impl<'a> Alignment<'a> { ", - "rs", + "a.rs", State::HunkHeader( DiffType::Unified, ParsedHunkHeader::default(), @@ -1797,7 +1829,7 @@ src/align.rs:71: impl<'a> Alignment<'a> { │ 12, 1, " for (i, x_i) in self.x.iter().enumerate() {", - "rs", + "align.rs", State::HunkZero(DiffType::Unified, None), &config, ); @@ -2167,6 +2199,24 @@ index 2e73468..8d8b89d 100644 } "; + const MODIFIED_DOCKER_AND_RS_FILES: &str = "\ +diff --git a/Dockerfile b/Dockerfile +index 0123456..1234567 100644 +--- a/Dockerfile ++++ b/Dockerfile +@@ -0,0 +2 @@ ++FROM foo ++COPY bar baz +diff --git a/rs b/rs +index 0123456..1234567 100644 +--- a/rs ++++ b/rs +@@ -0,0 +2 @@ ++fn foobar() -> i8 { ++ 8 ++} +"; + const RENAMED_FILE_INPUT: &str = "\ commit 1281650789680f1009dfff2497d5ccfbe7b96526 Author: Dan Davison diff --git a/src/utils/process.rs b/src/utils/process.rs index 1876d679e..ab7a7e48b 100644 --- a/src/utils/process.rs +++ b/src/utils/process.rs @@ -10,7 +10,7 @@ pub type DeltaPid = u32; #[derive(Clone, Debug, PartialEq, Eq)] pub enum CallingProcess { GitDiff(CommandLine), - GitShow(CommandLine, Option), // element 2 is file extension + GitShow(CommandLine, Option), // element 2 is filename GitLog(CommandLine), GitReflog(CommandLine), GitGrep(CommandLine), @@ -110,11 +110,11 @@ pub enum ProcessArgs { OtherProcess, } -pub fn git_blame_filename_extension() -> Option { - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension) +pub fn git_blame_filename() -> Option { + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename) } -pub fn guess_git_blame_filename_extension(args: &[String]) -> ProcessArgs { +pub fn guess_git_blame_filename(args: &[String]) -> ProcessArgs { let all_args = args.iter().map(|s| s.as_str()); // See git(1) and git-blame(1). Some arguments separate their parameter with space or '=', e.g. @@ -126,10 +126,15 @@ pub fn guess_git_blame_filename_extension(args: &[String]) -> ProcessArgs match last_arg.split('.').last() { - Some(arg) => ProcessArgs::Args(arg.to_string()), - None => ProcessArgs::ArgError, - }, + [git, "blame", .., last_arg] if is_git_binary(git) => { + match Path::new(last_arg) + .file_name() + .map(|filename| filename.to_string_lossy().to_string()) + { + Some(filename) => ProcessArgs::Args(filename), + None => ProcessArgs::ArgError, + } + } [git, "blame"] if is_git_binary(git) => ProcessArgs::ArgError, _ => ProcessArgs::OtherProcess, } @@ -158,17 +163,17 @@ pub fn describe_calling_process(args: &[String]) -> ProcessArgs } Some("show") => { let command_line = parse_command_line(args); - let extension = if let Some(last_arg) = &command_line.last_arg { + let filename = if let Some(last_arg) = &command_line.last_arg { match last_arg.split_once(':') { - Some((_, suffix)) => { - suffix.split('.').last().map(|s| s.to_string()) - } + Some((_, filename)) => Path::new(filename) + .file_name() + .map(|f| f.to_string_lossy().to_string()), None => None, } } else { None }; - ProcessArgs::Args(CallingProcess::GitShow(command_line, extension)) + ProcessArgs::Args(CallingProcess::GitShow(command_line, filename)) } Some("log") => { ProcessArgs::Args(CallingProcess::GitLog(parse_command_line(args))) @@ -682,17 +687,14 @@ pub mod tests { } #[test] - fn test_guess_git_blame_filename_extension() { + fn test_guess_git_blame_filename() { use ProcessArgs::Args; fn make_string_vec(args: &[&str]) -> Vec { args.iter().map(|&x| x.to_owned()).collect::>() } let args = make_string_vec(&["git", "blame", "hello", "world.txt"]); - assert_eq!( - guess_git_blame_filename_extension(&args), - Args("txt".into()) - ); + assert_eq!(guess_git_blame_filename(&args), Args("world.txt".into())); let args = make_string_vec(&[ "git", @@ -704,46 +706,31 @@ pub mod tests { "--date", "now", ]); - assert_eq!( - guess_git_blame_filename_extension(&args), - Args("txt".into()) - ); + assert_eq!(guess_git_blame_filename(&args), Args("hello.txt".into())); let args = make_string_vec(&["git", "blame", "-s", "-f", "--", "hello.txt"]); - assert_eq!( - guess_git_blame_filename_extension(&args), - Args("txt".into()) - ); + assert_eq!(guess_git_blame_filename(&args), Args("hello.txt".into())); let args = make_string_vec(&["git", "blame", "--", "--not.an.argument"]); assert_eq!( - guess_git_blame_filename_extension(&args), - Args("argument".into()) + guess_git_blame_filename(&args), + Args("--not.an.argument".into()) ); let args = make_string_vec(&["foo", "bar", "-a", "--123", "not.git"]); - assert_eq!( - guess_git_blame_filename_extension(&args), - ProcessArgs::OtherProcess - ); + assert_eq!(guess_git_blame_filename(&args), ProcessArgs::OtherProcess); let args = make_string_vec(&["git", "blame", "--help.txt"]); - assert_eq!( - guess_git_blame_filename_extension(&args), - ProcessArgs::ArgError - ); + assert_eq!(guess_git_blame_filename(&args), ProcessArgs::ArgError); let args = make_string_vec(&["git", "-c", "a=b", "blame", "main.rs"]); - assert_eq!(guess_git_blame_filename_extension(&args), Args("rs".into())); + assert_eq!(guess_git_blame_filename(&args), Args("main.rs".into())); let args = make_string_vec(&["git", "blame", "README"]); - assert_eq!( - guess_git_blame_filename_extension(&args), - Args("README".into()) - ); + assert_eq!(guess_git_blame_filename(&args), Args("README".into())); let args = make_string_vec(&["git", "blame", ""]); - assert_eq!(guess_git_blame_filename_extension(&args), Args("".into())); + assert_eq!(guess_git_blame_filename(&args), ProcessArgs::ArgError); } #[derive(Debug, Default)] @@ -830,27 +817,22 @@ pub mod tests { { let _args = FakeParentArgs::once("git blame hello"); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), Some("hello".into()) ); } { let _args = FakeParentArgs::once("git blame world.txt"); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), - Some("txt".into()) + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), + Some("world.txt".into()) ); } { let _args = FakeParentArgs::for_scope("git blame hello world.txt"); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), - Some("txt".into()) - ); - - assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), - Some("txt".into()) + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), + Some("world.txt".into()) ); } } @@ -860,11 +842,11 @@ pub mod tests { fn test_process_testing_assert() { let _args = FakeParentArgs::once("git blame do.not.panic"); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), - Some("panic".into()) + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), + Some("do.not.panic".into()) ); - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension); + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename); } #[test] @@ -886,12 +868,12 @@ pub mod tests { fn test_process_testing_n_times_panic() { let _args = FakeParentArgs::with(&["git blame once", "git blame twice"]); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), Some("once".into()) ); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), Some("twice".into()) ); } @@ -907,7 +889,7 @@ pub mod tests { fn test_process_testing_n_times_underused() { let _args = FakeParentArgs::with(&["git blame once", "git blame twice"]); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), Some("once".into()) ); } @@ -918,11 +900,11 @@ pub mod tests { fn test_process_testing_n_times_overused() { let _args = FakeParentArgs::with(&["git blame once"]); assert_eq!( - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension), + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename), Some("once".into()) ); // ignored: dropping causes a panic while panicking, so can't test - calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename_extension); + calling_process_cmdline(ProcInfo::new(), guess_git_blame_filename); } #[test] @@ -934,7 +916,7 @@ pub mod tests { (5, 100, "delta", Some(4)), ]); assert_eq!( - calling_process_cmdline(two_trees, guess_git_blame_filename_extension), + calling_process_cmdline(two_trees, guess_git_blame_filename), None ); } @@ -943,7 +925,7 @@ pub mod tests { fn test_process_blame_info_with_parent() { let no_processes = MockProcInfo::with(&[]); assert_eq!( - calling_process_cmdline(no_processes, guess_git_blame_filename_extension), + calling_process_cmdline(no_processes, guess_git_blame_filename), None ); @@ -953,8 +935,8 @@ pub mod tests { (4, 100, "delta", Some(3)), ]); assert_eq!( - calling_process_cmdline(parent, guess_git_blame_filename_extension), - Some("txt".into()) + calling_process_cmdline(parent, guess_git_blame_filename), + Some("hello.txt".into()) ); let grandparent = MockProcInfo::with(&[ @@ -964,8 +946,8 @@ pub mod tests { (5, 100, "delta", Some(4)), ]); assert_eq!( - calling_process_cmdline(grandparent, guess_git_blame_filename_extension), - Some("rs".into()) + calling_process_cmdline(grandparent, guess_git_blame_filename), + Some("main.rs".into()) ); } @@ -978,8 +960,8 @@ pub mod tests { (5, 100, "delta", Some(3)), ]); assert_eq!( - calling_process_cmdline(sibling, guess_git_blame_filename_extension), - Some("rs".into()) + calling_process_cmdline(sibling, guess_git_blame_filename), + Some("main.rs".into()) ); let indirect_sibling = MockProcInfo::with(&[ @@ -996,8 +978,8 @@ pub mod tests { (20, 100, "delta", Some(5)), ]); assert_eq!( - calling_process_cmdline(indirect_sibling, guess_git_blame_filename_extension), - Some("abc".into()) + calling_process_cmdline(indirect_sibling, guess_git_blame_filename), + Some("main.abc".into()) ); let indirect_sibling2 = MockProcInfo::with(&[ @@ -1009,8 +991,8 @@ pub mod tests { (20, 100, "delta", Some(5)), ]); assert_eq!( - calling_process_cmdline(indirect_sibling2, guess_git_blame_filename_extension), - Some("def".into()) + calling_process_cmdline(indirect_sibling2, guess_git_blame_filename), + Some("main.def".into()) ); // 3 blame processes, 2 with matching start times, pick the one with lower @@ -1028,11 +1010,8 @@ pub mod tests { (20, 100, "delta", Some(5)), ]); assert_eq!( - calling_process_cmdline( - indirect_sibling_start_times, - guess_git_blame_filename_extension - ), - Some("this".into()) + calling_process_cmdline(indirect_sibling_start_times, guess_git_blame_filename), + Some("main.this".into()) ); } @@ -1122,7 +1101,7 @@ pub mod tests { for (command, expected_extension) in [ ( "/usr/local/bin/git show --abbrev-commit -w 775c3b84:./src/hello.rs", - "rs", + "hello.rs", ), ( "/usr/local/bin/git show --abbrev-commit -w HEAD~1:Makefile", @@ -1130,7 +1109,7 @@ pub mod tests { ), ( "git -c x.y=z show --abbrev-commit -w 775c3b84:./src/hello.bye.R", - "R", + "hello.bye.R", ), ] { let parent = MockProcInfo::with(&[ @@ -1138,12 +1117,12 @@ pub mod tests { (3, 100, command, Some(2)), (4, 100, "delta", Some(3)), ]); - if let Some(CallingProcess::GitShow(cmd_line, ext)) = + if let Some(CallingProcess::GitShow(cmd_line, filename)) = calling_process_cmdline(parent, describe_calling_process) { assert_eq!(cmd_line.long_options, set(&["--abbrev-commit"])); assert_eq!(cmd_line.short_options, set(&["-w"])); - assert_eq!(ext, Some(expected_extension.to_string())); + assert_eq!(filename, Some(expected_extension.to_string())); } else { unreachable!(); }