Skip to content

Commit

Permalink
Output paths relative to current working directory
Browse files Browse the repository at this point in the history
Fixes #552
  • Loading branch information
dandavison committed Apr 24, 2021
1 parent 9f2f44d commit 6c0538d
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 19 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ console = "0.14.1"
dirs-next = "2.0.0"
itertools = "0.10.0"
lazy_static = "1.4"
pathdiff = "0.2.0"
regex = "1.4.6"
shell-words = "1.0.0"
structopt = "0.3.21"
Expand Down
2 changes: 2 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub struct Config {
pub background_color_extends_to_terminal_width: bool,
pub commit_style: Style,
pub color_only: bool,
pub cwd_relative_to_repo_root: Option<String>,
pub decorations_width: cli::Width,
pub error_exit_code: i32,
pub file_added_label: String,
Expand Down Expand Up @@ -182,6 +183,7 @@ impl From<cli::Opt> for Config {
.background_color_extends_to_terminal_width,
commit_style,
color_only: opt.color_only,
cwd_relative_to_repo_root: std::env::var("GIT_PREFIX").ok(),
decorations_width: opt.computed.decorations_width,
error_exit_code: 2, // Use 2 for error because diff uses 0 and 1 for non-error.
file_added_label,
Expand Down
30 changes: 26 additions & 4 deletions src/delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ impl<'a> StateMachine<'a> {

let mut handled_line = if line.starts_with("commit ") {
self.handle_commit_meta_header_line()?
} else if self.state == State::CommitMeta && line.starts_with(" ") {
self.handle_diff_stat_line()?
} else if line.starts_with("diff ") {
self.handle_file_meta_diff_line()?
} else if (self.state == State::FileMeta || self.source == Source::DiffUnified)
Expand Down Expand Up @@ -226,6 +228,20 @@ impl<'a> StateMachine<'a> {
Ok(())
}

fn handle_diff_stat_line(&mut self) -> std::io::Result<bool> {
let mut handled_line = false;
if let Some(cwd) = self.config.cwd_relative_to_repo_root.as_deref() {
if let Some(replacement_line) =
parse::relativize_path_in_diff_stat_line(&self.raw_line, cwd)
{
self.painter.emit()?;
writeln!(self.painter.writer, "{}", replacement_line)?;
handled_line = true
}
}
Ok(handled_line)
}

#[allow(clippy::unnecessary_wraps)]
fn handle_file_meta_diff_line(&mut self) -> std::io::Result<bool> {
self.painter.paint_buffered_minus_and_plus_lines();
Expand All @@ -237,8 +253,11 @@ impl<'a> StateMachine<'a> {
fn handle_file_meta_minus_line(&mut self) -> std::io::Result<bool> {
let mut handled_line = false;

let parsed_file_meta_line =
parse::parse_file_meta_line(&self.line, self.source == Source::GitDiff);
let parsed_file_meta_line = parse::parse_file_meta_line(
&self.line,
self.source == Source::GitDiff,
self.config.cwd_relative_to_repo_root.as_deref(),
);
self.minus_file = parsed_file_meta_line.0;
self.file_event = parsed_file_meta_line.1;

Expand Down Expand Up @@ -271,8 +290,11 @@ impl<'a> StateMachine<'a> {

fn handle_file_meta_plus_line(&mut self) -> std::io::Result<bool> {
let mut handled_line = false;
let parsed_file_meta_line =
parse::parse_file_meta_line(&self.line, self.source == Source::GitDiff);
let parsed_file_meta_line = parse::parse_file_meta_line(
&self.line,
self.source == Source::GitDiff,
self.config.cwd_relative_to_repo_root.as_deref(),
);
self.plus_file = parsed_file_meta_line.0;
self.painter
.set_syntax(parse::get_file_extension_from_file_meta_line_file_path(
Expand Down
105 changes: 90 additions & 15 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ pub enum FileEvent {
NoEvent,
}

pub fn parse_file_meta_line(line: &str, git_diff_name: bool) -> (String, FileEvent) {
match line {
pub fn parse_file_meta_line(
line: &str,
git_diff_name: bool,
cwd_relative_to_repo_root: Option<&str>,
) -> (String, FileEvent) {
let (mut path, file_event) = match line {
line if line.starts_with("--- ") || line.starts_with("+++ ") => {
let offset = 4;
let file = match &line[offset..] {
Expand All @@ -56,7 +60,44 @@ pub fn parse_file_meta_line(line: &str, git_diff_name: bool) -> (String, FileEve
(line[8..].to_string(), FileEvent::Copy) // "copy to ".len()
}
_ => ("".to_string(), FileEvent::NoEvent),
};

if let Some(cwd) = cwd_relative_to_repo_root {
if let Some(relative_path) = pathdiff::diff_paths(&path, cwd) {
if let Some(relative_path) = relative_path.to_str() {
path = relative_path.to_owned();
}
}
}

(path, file_event)
}

// A regex to capture the path, and the content from the pipe onwards, in lines
// like these:
// " src/delta.rs | 14 ++++++++++----"
// " src/config.rs | 2 ++"
lazy_static! {
static ref DIFF_STAT_LINE_REGEX: Regex =
Regex::new(r" ([^\| ][^\|]+[^\| ]) +(\| +[0-9]+ .+)").unwrap();
}

pub fn relativize_path_in_diff_stat_line(
line: &str,
cwd_relative_to_repo_root: &str,
) -> Option<String> {
if let Some(caps) = DIFF_STAT_LINE_REGEX.captures(line) {
let path_relative_to_repo_root = caps.get(1).unwrap().as_str();
if let Some(relative_path) =
pathdiff::diff_paths(path_relative_to_repo_root, cwd_relative_to_repo_root)
{
if let Some(relative_path) = relative_path.to_str() {
let suffix = caps.get(2).unwrap().as_str();
return Some(format!(" {:<30}{}", relative_path, suffix,));
}
}
}
return None;
}

pub fn get_file_extension_from_file_meta_line_file_path(path: &str) -> Option<&str> {
Expand Down Expand Up @@ -245,45 +286,45 @@ mod tests {
#[test]
fn test_get_file_path_from_git_file_meta_line() {
assert_eq!(
parse_file_meta_line("--- /dev/null", true),
parse_file_meta_line("--- /dev/null", true, None),
("/dev/null".to_string(), FileEvent::Change)
);
for prefix in &DIFF_PREFIXES {
assert_eq!(
parse_file_meta_line(&format!("--- {}src/delta.rs", prefix), true),
parse_file_meta_line(&format!("--- {}src/delta.rs", prefix), true, None),
("src/delta.rs".to_string(), FileEvent::Change)
);
}
assert_eq!(
parse_file_meta_line("--- src/delta.rs", true),
parse_file_meta_line("--- src/delta.rs", true, None),
("src/delta.rs".to_string(), FileEvent::Change)
);
assert_eq!(
parse_file_meta_line("+++ src/delta.rs", true),
parse_file_meta_line("+++ src/delta.rs", true, None),
("src/delta.rs".to_string(), FileEvent::Change)
);
}

#[test]
fn test_get_file_path_from_git_file_meta_line_containing_spaces() {
assert_eq!(
parse_file_meta_line("+++ a/my src/delta.rs", true),
parse_file_meta_line("+++ a/my src/delta.rs", true, None),
("my src/delta.rs".to_string(), FileEvent::Change)
);
assert_eq!(
parse_file_meta_line("+++ my src/delta.rs", true),
parse_file_meta_line("+++ my src/delta.rs", true, None),
("my src/delta.rs".to_string(), FileEvent::Change)
);
assert_eq!(
parse_file_meta_line("+++ a/src/my delta.rs", true),
parse_file_meta_line("+++ a/src/my delta.rs", true, None),
("src/my delta.rs".to_string(), FileEvent::Change)
);
assert_eq!(
parse_file_meta_line("+++ a/my src/my delta.rs", true),
parse_file_meta_line("+++ a/my src/my delta.rs", true, None),
("my src/my delta.rs".to_string(), FileEvent::Change)
);
assert_eq!(
parse_file_meta_line("+++ b/my src/my enough/my delta.rs", true),
parse_file_meta_line("+++ b/my src/my enough/my delta.rs", true, None),
(
"my src/my enough/my delta.rs".to_string(),
FileEvent::Change
Expand All @@ -294,27 +335,27 @@ mod tests {
#[test]
fn test_get_file_path_from_git_file_meta_line_rename() {
assert_eq!(
parse_file_meta_line("rename from nospace/file2.el", true),
parse_file_meta_line("rename from nospace/file2.el", true, None),
("nospace/file2.el".to_string(), FileEvent::Rename)
);
}

#[test]
fn test_get_file_path_from_git_file_meta_line_rename_containing_spaces() {
assert_eq!(
parse_file_meta_line("rename from with space/file1.el", true),
parse_file_meta_line("rename from with space/file1.el", true, None),
("with space/file1.el".to_string(), FileEvent::Rename)
);
}

#[test]
fn test_parse_file_meta_line() {
assert_eq!(
parse_file_meta_line("--- src/delta.rs", false),
parse_file_meta_line("--- src/delta.rs", false, None),
("src/delta.rs".to_string(), FileEvent::Change)
);
assert_eq!(
parse_file_meta_line("+++ src/delta.rs", false),
parse_file_meta_line("+++ src/delta.rs", false, None),
("src/delta.rs".to_string(), FileEvent::Change)
);
}
Expand Down Expand Up @@ -369,4 +410,38 @@ mod tests {
assert_eq!(line_numbers_and_hunk_lengths[1], (358, 15),);
assert_eq!(line_numbers_and_hunk_lengths[2], (358, 16),);
}

#[test]
fn test_relative_path() {
for (path, cwd_relative_to_repo_root, expected) in &[
("file.rs", "", "file.rs"),
("file.rs", "a/", "../file.rs"),
("a/file.rs", "a/", "file.rs"),
("a/b/file.rs", "a", "b/file.rs"),
("c/d/file.rs", "a/b/", "../../c/d/file.rs"),
] {
assert_eq!(
pathdiff::diff_paths(path, cwd_relative_to_repo_root),
Some(expected.into())
)
}
}

#[test]
fn test_diff_stat_line_regex_1() {
let caps = DIFF_STAT_LINE_REGEX.captures(" src/delta.rs | 14 ++++++++++----");
assert!(caps.is_some());
let caps = caps.unwrap();
assert_eq!(caps.get(1).unwrap().as_str(), "src/delta.rs");
assert_eq!(caps.get(2).unwrap().as_str(), "| 14 ++++++++++----");
}

#[test]
fn test_diff_stat_line_regex_2() {
let caps = DIFF_STAT_LINE_REGEX.captures(" src/config.rs | 2 ++");
assert!(caps.is_some());
let caps = caps.unwrap();
assert_eq!(caps.get(1).unwrap().as_str(), "src/config.rs");
assert_eq!(caps.get(2).unwrap().as_str(), "| 2 ++");
}
}

0 comments on commit 6c0538d

Please sign in to comment.