From fe16f7533deb55e83ed0d736e1cd826ad8ae7522 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Thu, 20 May 2021 10:37:21 -0400 Subject: Emit description of file mode change (#605) Fixes #583 --- src/delta.rs | 41 +++++++++++++++++++++++++--------- src/parse.rs | 49 ++++++++++++++++++++++++++++++++--------- src/tests/test_example_diffs.rs | 14 ++++++++++++ 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/delta.rs b/src/delta.rs index 56114f76..cfafe3dc 100644 --- a/src/delta.rs +++ b/src/delta.rs @@ -62,7 +62,9 @@ struct StateMachine<'a> { source: Source, minus_file: String, plus_file: String, - file_event: parse::FileEvent, + minus_file_event: parse::FileEvent, + plus_file_event: parse::FileEvent, + file_paths_from_diff_line: (Option, Option), painter: Painter<'a>, config: &'a Config, @@ -91,7 +93,9 @@ impl<'a> StateMachine<'a> { source: Source::Unknown, minus_file: "".to_string(), plus_file: "".to_string(), - file_event: parse::FileEvent::NoEvent, + minus_file_event: parse::FileEvent::NoEvent, + plus_file_event: parse::FileEvent::NoEvent, + file_paths_from_diff_line: (None, None), current_file_pair: None, handled_file_meta_header_line_file_pair: None, painter: Painter::new(writer, config), @@ -122,13 +126,15 @@ impl<'a> StateMachine<'a> { } else if (self.state == State::FileMeta || self.source == Source::DiffUnified) && (line.starts_with("--- ") || line.starts_with("rename from ") - || line.starts_with("copy from ")) + || line.starts_with("copy from ") + || line.starts_with("old mode ")) { self.handle_file_meta_minus_line()? } else if (self.state == State::FileMeta || self.source == Source::DiffUnified) && (line.starts_with("+++ ") || line.starts_with("rename to ") - || line.starts_with("copy to ")) + || line.starts_with("copy to ") + || line.starts_with("new mode ")) { self.handle_file_meta_plus_line()? } else if line.starts_with("@@") { @@ -253,13 +259,14 @@ impl<'a> StateMachine<'a> { self.painter.paint_buffered_minus_and_plus_lines(); self.state = State::FileMeta; self.handled_file_meta_header_line_file_pair = None; + self.file_paths_from_diff_line = parse::get_file_paths_from_diff_line(&self.line); Ok(false) } fn handle_file_meta_minus_line(&mut self) -> std::io::Result { let mut handled_line = false; - let parsed_file_meta_line = parse::parse_file_meta_line( + let (path_or_mode, file_event) = parse::parse_file_meta_line( &self.line, self.source == Source::GitDiff, if self.config.relative_paths { @@ -268,8 +275,14 @@ impl<'a> StateMachine<'a> { None }, ); - self.minus_file = parsed_file_meta_line.0; - self.file_event = parsed_file_meta_line.1; + // In the case of ModeChange only, the file path is taken from the diff + // --git line (since that is the only place the file path occurs); + // otherwise it is taken from the --- / +++ line. + self.minus_file = match (&file_event, &self.file_paths_from_diff_line) { + (parse::FileEvent::ModeChange(_), (Some(file), _)) => file.clone(), + _ => path_or_mode, + }; + self.minus_file_event = file_event; if self.source == Source::DiffUnified { self.state = State::FileMeta; @@ -300,7 +313,7 @@ impl<'a> StateMachine<'a> { fn handle_file_meta_plus_line(&mut self) -> std::io::Result { let mut handled_line = false; - let parsed_file_meta_line = parse::parse_file_meta_line( + let (path_or_mode, file_event) = parse::parse_file_meta_line( &self.line, self.source == Source::GitDiff, if self.config.relative_paths { @@ -309,7 +322,14 @@ impl<'a> StateMachine<'a> { None }, ); - self.plus_file = parsed_file_meta_line.0; + // In the case of ModeChange only, the file path is taken from the diff + // --git line (since that is the only place the file path occurs); + // otherwise it is taken from the --- / +++ line. + self.plus_file = match (&file_event, &self.file_paths_from_diff_line) { + (parse::FileEvent::ModeChange(_), (_, Some(file))) => file.clone(), + _ => path_or_mode, + }; + self.plus_file_event = file_event; self.painter .set_syntax(parse::get_file_extension_from_file_meta_line_file_path( &self.plus_file, @@ -344,7 +364,8 @@ impl<'a> StateMachine<'a> { &self.minus_file, &self.plus_file, comparing, - &self.file_event, + &self.minus_file_event, + &self.plus_file_event, self.config, ); // FIXME: no support for 'raw' diff --git a/src/parse.rs b/src/parse.rs index ab51702e..3329248b 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -25,6 +25,7 @@ pub enum FileEvent { Change, Copy, Rename, + ModeChange(String), NoEvent, } @@ -33,7 +34,7 @@ pub fn parse_file_meta_line( git_diff_name: bool, relative_path_base: Option<&str>, ) -> (String, FileEvent) { - let (mut path, file_event) = match line { + let (mut path_or_mode, file_event) = match line { line if line.starts_with("--- ") || line.starts_with("+++ ") => { let offset = 4; let file = _parse_file_path(&line[offset..], git_diff_name); @@ -51,18 +52,35 @@ pub fn parse_file_meta_line( line if line.starts_with("copy to ") => { (line[8..].to_string(), FileEvent::Copy) // "copy to ".len() } + line if line.starts_with("old mode ") => { + ("".to_string(), FileEvent::ModeChange(line[9..].to_string())) // "old mode ".len() + } + line if line.starts_with("new mode ") => { + ("".to_string(), FileEvent::ModeChange(line[9..].to_string())) // "new mode ".len() + } _ => ("".to_string(), FileEvent::NoEvent), }; if let Some(base) = relative_path_base { - if let Some(relative_path) = pathdiff::diff_paths(&path, base) { + if let FileEvent::ModeChange(_) = file_event { + } else if let Some(relative_path) = pathdiff::diff_paths(&path_or_mode, base) { if let Some(relative_path) = relative_path.to_str() { - path = relative_path.to_owned(); + path_or_mode = relative_path.to_owned(); } } } - (path, file_event) + (path_or_mode, file_event) +} + +/// Given input like "diff --git a/src/main.rs b/src/main.rs" +/// return (Some("src/main.rs"), Some("src/main.rs")) +pub fn get_file_paths_from_diff_line(line: &str) -> (Option, Option) { + let mut iter = line.split(' ').skip(2); + ( + iter.next().map(|s| _parse_file_path(&s[2..], true)), + iter.next().map(|s| _parse_file_path(&s[2..], true)), + ) } fn _parse_file_path(s: &str, git_diff_name: bool) -> String { @@ -117,7 +135,8 @@ pub fn get_file_change_description_from_file_paths( minus_file: &str, plus_file: &str, comparing: bool, - file_event: &FileEvent, + minus_file_event: &FileEvent, + plus_file_event: &FileEvent, config: &Config, ) -> String { if comparing { @@ -137,23 +156,33 @@ pub fn get_file_change_description_from_file_paths( Cow::from(file) } }; - match (minus_file, plus_file) { - (minus_file, plus_file) if minus_file == plus_file => format!( + match (minus_file, plus_file, minus_file_event, plus_file_event) { + ( + minus_file, + plus_file, + FileEvent::ModeChange(old_mode), + FileEvent::ModeChange(new_mode), + ) if minus_file == plus_file => { + format!("{}: {} ⟶ {}", plus_file, old_mode, new_mode) + } + (minus_file, plus_file, _, _) if minus_file == plus_file => format!( "{}{}", format_label(&config.file_modified_label), format_file(minus_file) ), - (minus_file, "/dev/null") => format!( + (minus_file, "/dev/null", _, _) => format!( "{}{}", format_label(&config.file_removed_label), format_file(minus_file) ), - ("/dev/null", plus_file) => format!( + ("/dev/null", plus_file, _, _) => format!( "{}{}", format_label(&config.file_added_label), format_file(plus_file) ), - (minus_file, plus_file) => format!( + // minus_file_event == plus_file_event, except in the ModeChange + // case above. + (minus_file, plus_file, file_event, _) => format!( "{}{} ⟶ {}", format_label(match file_event { FileEvent::Rename => &config.file_renamed_label, diff --git a/src/tests/test_example_diffs.rs b/src/tests/test_example_diffs.rs index de35535a..a4d0b854 100644 --- a/src/tests/test_example_diffs.rs +++ b/src/tests/test_example_diffs.rs @@ -1569,6 +1569,14 @@ src/align.rs:71: impl<'a> Alignment<'a> { │ )); } + #[test] + fn test_file_mode_change() { + let config = integration_test_utils::make_config_from_args(&[]); + let output = integration_test_utils::run_delta(GIT_DIFF_FILE_MODE_CHANGE, &config); + let output = strip_ansi_codes(&output); + assert!(output.contains(r"src/delta.rs: 100644 ⟶ 100755")); + } + const GIT_DIFF_SINGLE_HUNK: &str = "\ commit 94907c0f136f46dc46ffae2dc92dca9af7eb7c2e Author: Dan Davison @@ -2172,4 +2180,10 @@ Date: Sun Nov 1 15:28:53 2020 -0500 \ No newline at end of file +] "#; + + const GIT_DIFF_FILE_MODE_CHANGE: &str = " +diff --git a/src/delta.rs b/src/delta.rs +old mode 100644 +new mode 100755 +"; } -- cgit v1.2.3