2022-11-26 23:57:50 +00:00
|
|
|
|
// Copyright 2022 The Jujutsu Authors
|
2022-03-31 05:36:05 +00:00
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
diff: add option to display complex color-words diffs without inlining
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
2024-08-14 08:47:11 +00:00
|
|
|
|
use indoc::indoc;
|
2023-08-31 04:17:50 +00:00
|
|
|
|
use itertools::Itertools;
|
2022-03-31 05:36:05 +00:00
|
|
|
|
|
2024-08-22 18:18:15 +00:00
|
|
|
|
use crate::common::escaped_fake_diff_editor_path;
|
|
|
|
|
use crate::common::strip_last_line;
|
|
|
|
|
use crate::common::TestEnvironment;
|
2022-03-31 05:36:05 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_basic() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo\n").unwrap();
|
2024-08-14 14:20:17 +00:00
|
|
|
|
std::fs::write(repo_path.join("file2"), "1\n2\n3\n4\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
std::fs::remove_file(repo_path.join("file1")).unwrap();
|
2024-08-14 14:20:17 +00:00
|
|
|
|
std::fs::write(repo_path.join("file2"), "1\n5\n3\n").unwrap();
|
2022-03-31 05:36:05 +00:00
|
|
|
|
std::fs::write(repo_path.join("file3"), "foo\n").unwrap();
|
2024-08-14 14:20:17 +00:00
|
|
|
|
std::fs::write(repo_path.join("file4"), "1\n2\n3\n4\n").unwrap();
|
2022-03-31 05:36:05 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file2:
|
2024-08-14 14:20:17 +00:00
|
|
|
|
1 1: 1
|
|
|
|
|
2 2: 25
|
|
|
|
|
3 3: 3
|
|
|
|
|
4 : 4
|
2024-08-06 18:04:58 +00:00
|
|
|
|
Modified regular file file3 (file1 => file3):
|
2024-08-14 14:20:17 +00:00
|
|
|
|
Modified regular file file4 (file2 => file4):
|
2022-03-31 05:36:05 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2024-03-02 00:57:43 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--context=0"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file2:
|
2024-08-14 14:20:17 +00:00
|
|
|
|
1 1: 1
|
|
|
|
|
2 2: 25
|
|
|
|
|
3 3: 3
|
|
|
|
|
4 : 4
|
2024-08-06 18:04:58 +00:00
|
|
|
|
Modified regular file file3 (file1 => file3):
|
2024-08-14 14:20:17 +00:00
|
|
|
|
Modified regular file file4 (file2 => file4):
|
2024-03-02 00:57:43 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2024-06-25 08:56:58 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--color=debug"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-10 21:38:22 +00:00
|
|
|
|
[38;5;3m<<diff header::Modified regular file file2:>>[39m
|
2024-08-14 14:20:17 +00:00
|
|
|
|
[38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: 1>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: >>[4m[38;5;1m<<diff removed token::2>>[38;5;2m<<diff added token::5>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 3>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: 3>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 4>>[39m<<diff:: : >>[4m[38;5;1m<<diff removed token::4>>[24m[39m
|
2024-08-06 18:04:58 +00:00
|
|
|
|
[38;5;3m<<diff header::Modified regular file file3 (file1 => file3):>>[39m
|
2024-08-14 14:20:17 +00:00
|
|
|
|
[38;5;3m<<diff header::Modified regular file file4 (file2 => file4):>>[39m
|
2024-06-25 08:56:58 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2022-03-31 05:36:05 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
M file2
|
2024-08-09 00:00:50 +00:00
|
|
|
|
R {file1 => file3}
|
2024-08-14 14:20:17 +00:00
|
|
|
|
C {file2 => file4}
|
2022-03-31 05:36:05 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2021-09-16 05:46:54 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--types"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-08-14 13:30:31 +00:00
|
|
|
|
FF file2
|
|
|
|
|
FF {file1 => file3}
|
2024-08-14 14:20:17 +00:00
|
|
|
|
FF {file2 => file4}
|
2024-08-14 13:30:31 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--types", "glob:file[12]"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2021-09-16 05:46:54 +00:00
|
|
|
|
F- file1
|
|
|
|
|
FF file2
|
|
|
|
|
"###);
|
|
|
|
|
|
2024-08-14 14:20:17 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "file1"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
deleted file mode 100644
|
|
|
|
|
index 257cc5642c..0000000000
|
|
|
|
|
--- a/file1
|
|
|
|
|
+++ /dev/null
|
|
|
|
|
@@ -1,1 +1,0 @@
|
|
|
|
|
-foo
|
2024-08-14 14:20:17 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2022-03-31 05:36:05 +00:00
|
|
|
|
diff --git a/file2 b/file2
|
2024-08-14 14:20:17 +00:00
|
|
|
|
index 94ebaf9001..1ffc51b472 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/file2
|
|
|
|
|
+++ b/file2
|
2024-08-14 14:20:17 +00:00
|
|
|
|
@@ -1,4 +1,3 @@
|
|
|
|
|
1
|
|
|
|
|
-2
|
|
|
|
|
+5
|
|
|
|
|
3
|
|
|
|
|
-4
|
|
|
|
|
diff --git a/file1 b/file3
|
|
|
|
|
rename from file1
|
|
|
|
|
rename to file3
|
|
|
|
|
diff --git a/file2 b/file4
|
|
|
|
|
copy from file2
|
|
|
|
|
copy to file4
|
2022-03-31 05:36:05 +00:00
|
|
|
|
"###);
|
2022-12-13 12:24:24 +00:00
|
|
|
|
|
2024-03-02 00:57:43 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--context=0"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file2 b/file2
|
2024-08-14 14:20:17 +00:00
|
|
|
|
index 94ebaf9001..1ffc51b472 100644
|
2024-03-02 00:57:43 +00:00
|
|
|
|
--- a/file2
|
|
|
|
|
+++ b/file2
|
2024-08-14 14:20:17 +00:00
|
|
|
|
@@ -2,1 +2,1 @@
|
|
|
|
|
-2
|
|
|
|
|
+5
|
|
|
|
|
@@ -4,1 +4,0 @@
|
|
|
|
|
-4
|
|
|
|
|
diff --git a/file1 b/file3
|
|
|
|
|
rename from file1
|
|
|
|
|
rename to file3
|
|
|
|
|
diff --git a/file2 b/file4
|
|
|
|
|
copy from file2
|
|
|
|
|
copy to file4
|
2024-03-02 00:57:43 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2024-06-25 08:56:58 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--color=debug"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-07-10 21:38:22 +00:00
|
|
|
|
[1m<<diff file_header::diff --git a/file2 b/file2>>[0m
|
2024-08-14 14:20:17 +00:00
|
|
|
|
[1m<<diff file_header::index 94ebaf9001..1ffc51b472 100644>>[0m
|
2024-07-10 21:38:22 +00:00
|
|
|
|
[1m<<diff file_header::--- a/file2>>[0m
|
|
|
|
|
[1m<<diff file_header::+++ b/file2>>[0m
|
2024-08-14 14:20:17 +00:00
|
|
|
|
[38;5;6m<<diff hunk_header::@@ -1,4 +1,3 @@>>[39m
|
|
|
|
|
<<diff context:: 1>>
|
|
|
|
|
[38;5;1m<<diff removed::->>[4m<<diff removed token::2>>[24m<<diff removed::>>[39m
|
|
|
|
|
[38;5;2m<<diff added::+>>[4m<<diff added token::5>>[24m<<diff added::>>[39m
|
|
|
|
|
<<diff context:: 3>>
|
|
|
|
|
[38;5;1m<<diff removed::->>[4m<<diff removed token::4>>[24m[39m
|
|
|
|
|
[1m<<diff file_header::diff --git a/file1 b/file3>>[0m
|
|
|
|
|
[1m<<diff file_header::rename from file1>>[0m
|
|
|
|
|
[1m<<diff file_header::rename to file3>>[0m
|
|
|
|
|
[1m<<diff file_header::diff --git a/file2 b/file4>>[0m
|
|
|
|
|
[1m<<diff file_header::copy from file2>>[0m
|
|
|
|
|
[1m<<diff file_header::copy to file4>>[0m
|
2024-06-25 08:56:58 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2022-12-13 12:24:24 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
M file2
|
2024-08-09 00:00:50 +00:00
|
|
|
|
R {file1 => file3}
|
2024-08-14 14:20:17 +00:00
|
|
|
|
C {file2 => file4}
|
2022-12-13 12:24:24 +00:00
|
|
|
|
diff --git a/file2 b/file2
|
2024-08-14 14:20:17 +00:00
|
|
|
|
index 94ebaf9001..1ffc51b472 100644
|
2022-12-13 12:24:24 +00:00
|
|
|
|
--- a/file2
|
|
|
|
|
+++ b/file2
|
2024-08-14 14:20:17 +00:00
|
|
|
|
@@ -1,4 +1,3 @@
|
|
|
|
|
1
|
|
|
|
|
-2
|
|
|
|
|
+5
|
|
|
|
|
3
|
|
|
|
|
-4
|
|
|
|
|
diff --git a/file1 b/file3
|
|
|
|
|
rename from file1
|
|
|
|
|
rename to file3
|
|
|
|
|
diff --git a/file2 b/file4
|
|
|
|
|
copy from file2
|
|
|
|
|
copy to file4
|
2022-12-13 12:24:24 +00:00
|
|
|
|
"###);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-08-14 14:20:17 +00:00
|
|
|
|
file2 | 3 +--
|
2024-08-09 00:00:50 +00:00
|
|
|
|
{file1 => file3} | 0
|
2024-08-14 14:20:17 +00:00
|
|
|
|
{file2 => file4} | 0
|
|
|
|
|
3 files changed, 1 insertion(+), 2 deletions(-)
|
2023-08-13 19:30:57 +00:00
|
|
|
|
"###);
|
2024-04-09 07:35:23 +00:00
|
|
|
|
|
2024-04-14 02:33:55 +00:00
|
|
|
|
// Filter by glob pattern
|
2024-07-23 10:16:22 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-s", "glob:file[12]"]);
|
2024-04-14 02:33:55 +00:00
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-08-09 00:00:50 +00:00
|
|
|
|
D file1
|
2024-04-14 02:33:55 +00:00
|
|
|
|
M file2
|
|
|
|
|
"###);
|
|
|
|
|
|
2024-04-09 07:35:23 +00:00
|
|
|
|
// Unmatched paths should generate warnings
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(
|
|
|
|
|
test_env.env_root(),
|
|
|
|
|
&[
|
|
|
|
|
"diff",
|
|
|
|
|
"-Rrepo",
|
|
|
|
|
"-s",
|
|
|
|
|
"repo", // matches directory
|
|
|
|
|
"repo/file1", // deleted in to_tree, but exists in from_tree
|
|
|
|
|
"repo/x",
|
|
|
|
|
"repo/y/z",
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout.replace('\\', "/"), @r###"
|
|
|
|
|
M repo/file2
|
2024-08-09 00:00:50 +00:00
|
|
|
|
R repo/{file1 => file3}
|
2024-08-14 14:20:17 +00:00
|
|
|
|
C repo/{file2 => file4}
|
2024-04-09 07:35:23 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(stderr.replace('\\', "/"), @r###"
|
|
|
|
|
Warning: No matching entries for paths: repo/x, repo/y/z
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Unmodified paths shouldn't generate warnings
|
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["diff", "-s", "--from=@", "file2"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @"");
|
|
|
|
|
insta::assert_snapshot!(stderr, @"");
|
2022-03-31 05:36:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-12 15:07:59 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_empty() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-08-12 15:07:59 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "").unwrap();
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Added regular file file1:
|
|
|
|
|
(empty)
|
|
|
|
|
"###);
|
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2023-08-12 15:07:59 +00:00
|
|
|
|
std::fs::remove_file(repo_path.join("file1")).unwrap();
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Removed regular file file1:
|
|
|
|
|
(empty)
|
|
|
|
|
"###);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
file1 | 0
|
|
|
|
|
1 file changed, 0 insertions(+), 0 deletions(-)
|
|
|
|
|
"###);
|
2023-08-12 15:07:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-14 11:12:12 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_file_mode() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
// Test content+mode/mode-only changes of empty/non-empty files:
|
|
|
|
|
// - file1: ("", x) -> ("2", n) empty, content+mode
|
|
|
|
|
// - file2: ("1", x) -> ("1", n) non-empty, mode-only
|
|
|
|
|
// - file3: ("1", n) -> ("2", x) non-empty, content+mode
|
|
|
|
|
// - file4: ("", n) -> ("", x) empty, mode-only
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "1\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3"), "1\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file4"), "").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["file", "chmod", "x", "file1", "file2"]);
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "2\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3"), "2\n").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["file", "chmod", "n", "file1", "file2"]);
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["file", "chmod", "x", "file3", "file4"]);
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::remove_file(repo_path.join("file1")).unwrap();
|
|
|
|
|
std::fs::remove_file(repo_path.join("file2")).unwrap();
|
|
|
|
|
std::fs::remove_file(repo_path.join("file3")).unwrap();
|
|
|
|
|
std::fs::remove_file(repo_path.join("file4")).unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@--"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Added executable file file1:
|
|
|
|
|
(empty)
|
|
|
|
|
Added executable file file2:
|
|
|
|
|
1: 1
|
|
|
|
|
Added regular file file3:
|
|
|
|
|
1: 1
|
|
|
|
|
Added regular file file4:
|
|
|
|
|
(empty)
|
|
|
|
|
"###);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@-"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Executable file became non-executable at file1:
|
|
|
|
|
1: 2
|
|
|
|
|
Executable file became non-executable at file2:
|
|
|
|
|
Non-executable file became executable at file3:
|
|
|
|
|
1 1: 12
|
|
|
|
|
Non-executable file became executable at file4:
|
|
|
|
|
"###);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Removed regular file file1:
|
|
|
|
|
1 : 2
|
|
|
|
|
Removed regular file file2:
|
|
|
|
|
1 : 1
|
|
|
|
|
Removed executable file file3:
|
|
|
|
|
1 : 2
|
|
|
|
|
Removed executable file file4:
|
|
|
|
|
(empty)
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@--", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
new file mode 100755
|
|
|
|
|
index 0000000000..e69de29bb2
|
|
|
|
|
diff --git a/file2 b/file2
|
|
|
|
|
new file mode 100755
|
|
|
|
|
index 0000000000..d00491fd7e
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/file2
|
|
|
|
|
@@ -1,0 +1,1 @@
|
|
|
|
|
+1
|
|
|
|
|
diff --git a/file3 b/file3
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000000..d00491fd7e
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/file3
|
|
|
|
|
@@ -1,0 +1,1 @@
|
|
|
|
|
+1
|
|
|
|
|
diff --git a/file4 b/file4
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000000..e69de29bb2
|
|
|
|
|
"###);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@-", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
old mode 100755
|
|
|
|
|
new mode 100644
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index e69de29bb2..0cfbf08886
|
2024-07-14 11:12:12 +00:00
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,0 +1,1 @@
|
|
|
|
|
+2
|
|
|
|
|
diff --git a/file2 b/file2
|
|
|
|
|
old mode 100755
|
|
|
|
|
new mode 100644
|
|
|
|
|
diff --git a/file3 b/file3
|
|
|
|
|
old mode 100644
|
|
|
|
|
new mode 100755
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index d00491fd7e..0cfbf08886
|
2024-07-14 11:12:12 +00:00
|
|
|
|
--- a/file3
|
|
|
|
|
+++ b/file3
|
|
|
|
|
@@ -1,1 +1,1 @@
|
|
|
|
|
-1
|
|
|
|
|
+2
|
|
|
|
|
diff --git a/file4 b/file4
|
|
|
|
|
old mode 100644
|
|
|
|
|
new mode 100755
|
|
|
|
|
"###);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "-r@", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
deleted file mode 100644
|
|
|
|
|
index 0cfbf08886..0000000000
|
|
|
|
|
--- a/file1
|
|
|
|
|
+++ /dev/null
|
|
|
|
|
@@ -1,1 +1,0 @@
|
|
|
|
|
-2
|
|
|
|
|
diff --git a/file2 b/file2
|
|
|
|
|
deleted file mode 100644
|
|
|
|
|
index d00491fd7e..0000000000
|
|
|
|
|
--- a/file2
|
|
|
|
|
+++ /dev/null
|
|
|
|
|
@@ -1,1 +1,0 @@
|
|
|
|
|
-1
|
|
|
|
|
diff --git a/file3 b/file3
|
|
|
|
|
deleted file mode 100755
|
|
|
|
|
index 0cfbf08886..0000000000
|
|
|
|
|
--- a/file3
|
|
|
|
|
+++ /dev/null
|
|
|
|
|
@@ -1,1 +1,0 @@
|
|
|
|
|
-2
|
|
|
|
|
diff --git a/file4 b/file4
|
|
|
|
|
deleted file mode 100755
|
|
|
|
|
index e69de29bb2..0000000000
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 05:46:54 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_types() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
let file_path = repo_path.join("foo");
|
|
|
|
|
|
|
|
|
|
// Missing
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=missing"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
|
|
|
|
|
// Normal file
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=file"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
std::fs::write(&file_path, "foo").unwrap();
|
|
|
|
|
|
|
|
|
|
// Conflict (add/add)
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=conflict"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
std::fs::write(&file_path, "foo").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
std::fs::write(&file_path, "bar").unwrap();
|
2024-04-28 16:58:46 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["squash", r#"--into=description("conflict")"#]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
{
|
|
|
|
|
use std::os::unix::fs::PermissionsExt;
|
2023-05-01 02:58:55 +00:00
|
|
|
|
use std::path::PathBuf;
|
2021-09-16 05:46:54 +00:00
|
|
|
|
|
|
|
|
|
// Executable
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=executable"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
std::fs::write(&file_path, "foo").unwrap();
|
|
|
|
|
std::fs::set_permissions(&file_path, std::fs::Permissions::from_mode(0o755)).unwrap();
|
|
|
|
|
|
|
|
|
|
// Symlink
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()", "-m=symlink"]);
|
2021-09-16 05:46:54 +00:00
|
|
|
|
std::os::unix::fs::symlink(PathBuf::from("."), &file_path).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let diff = |from: &str, to: &str| {
|
|
|
|
|
test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&[
|
|
|
|
|
"diff",
|
|
|
|
|
"--types",
|
2024-10-02 19:48:42 +00:00
|
|
|
|
&format!(r#"--from=description("{from}")"#),
|
|
|
|
|
&format!(r#"--to=description("{to}")"#),
|
2021-09-16 05:46:54 +00:00
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
insta::assert_snapshot!(diff("missing", "file"), @r###"
|
|
|
|
|
-F foo
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(diff("file", "conflict"), @r###"
|
|
|
|
|
FC foo
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(diff("conflict", "missing"), @r###"
|
|
|
|
|
C- foo
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
{
|
|
|
|
|
insta::assert_snapshot!(diff("symlink", "file"), @r###"
|
|
|
|
|
LF foo
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(diff("missing", "executable"), @r###"
|
|
|
|
|
-F foo
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 17:19:51 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_name_only() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::write(repo_path.join("deleted"), "d").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("modified"), "m").unwrap();
|
|
|
|
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--name-only"]), @r###"
|
|
|
|
|
deleted
|
|
|
|
|
modified
|
|
|
|
|
"###);
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-mfirst"]);
|
|
|
|
|
std::fs::remove_file(repo_path.join("deleted")).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("modified"), "mod").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("added"), "add").unwrap();
|
|
|
|
|
std::fs::create_dir(repo_path.join("sub")).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("sub/added"), "sub/add").unwrap();
|
|
|
|
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", "--name-only"]).replace('\\', "/"),
|
|
|
|
|
@r###"
|
|
|
|
|
added
|
|
|
|
|
deleted
|
|
|
|
|
modified
|
|
|
|
|
sub/added
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-11 04:11:58 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_bad_args() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-03-11 04:11:58 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
2021-09-16 05:46:54 +00:00
|
|
|
|
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["diff", "-s", "--types"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2023-03-17 23:14:20 +00:00
|
|
|
|
error: the argument '--summary' cannot be used with '--types'
|
2021-09-16 05:46:54 +00:00
|
|
|
|
|
|
|
|
|
Usage: jj diff --summary [PATHS]...
|
|
|
|
|
|
2023-03-17 23:14:20 +00:00
|
|
|
|
For more information, try '--help'.
|
2021-09-16 05:46:54 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
2023-03-11 04:11:58 +00:00
|
|
|
|
let stderr = test_env.jj_cmd_cli_error(&repo_path, &["diff", "--color-words", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stderr, @r###"
|
2023-03-17 23:14:20 +00:00
|
|
|
|
error: the argument '--color-words' cannot be used with '--git'
|
2023-03-11 04:11:58 +00:00
|
|
|
|
|
|
|
|
|
Usage: jj diff --color-words [PATHS]...
|
|
|
|
|
|
2023-03-17 23:14:20 +00:00
|
|
|
|
For more information, try '--help'.
|
2023-03-11 04:11:58 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-31 05:36:05 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_relative_paths() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::create_dir_all(repo_path.join("dir1").join("subdir1")).unwrap();
|
|
|
|
|
std::fs::create_dir(repo_path.join("dir2")).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo1\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("dir1").join("file2"), "foo2\n").unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join("dir1").join("subdir1").join("file3"),
|
|
|
|
|
"foo3\n",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("dir2").join("file4"), "foo4\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "bar1\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("dir1").join("file2"), "bar2\n").unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join("dir1").join("subdir1").join("file3"),
|
|
|
|
|
"bar3\n",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("dir2").join("file4"), "bar4\n").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path.join("dir1"), &["diff"]);
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file2:
|
|
|
|
|
1 1: foo2bar2
|
|
|
|
|
Modified regular file subdir1/file3:
|
|
|
|
|
1 1: foo3bar3
|
|
|
|
|
Modified regular file ../dir2/file4:
|
|
|
|
|
1 1: foo4bar4
|
|
|
|
|
Modified regular file ../file1:
|
|
|
|
|
1 1: foo1bar1
|
|
|
|
|
"###);
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file2:
|
|
|
|
|
1 1: foo2bar2
|
|
|
|
|
Modified regular file subdir1\file3:
|
|
|
|
|
1 1: foo3bar3
|
|
|
|
|
Modified regular file ..\dir2\file4:
|
|
|
|
|
1 1: foo4bar4
|
|
|
|
|
Modified regular file ..\file1:
|
|
|
|
|
1 1: foo1bar1
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path.join("dir1"), &["diff", "-s"]);
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
M file2
|
|
|
|
|
M subdir1/file3
|
|
|
|
|
M ../dir2/file4
|
|
|
|
|
M ../file1
|
|
|
|
|
"###);
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
M file2
|
|
|
|
|
M subdir1\file3
|
|
|
|
|
M ..\dir2\file4
|
|
|
|
|
M ..\file1
|
|
|
|
|
"###);
|
|
|
|
|
|
2021-09-16 05:46:54 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path.join("dir1"), &["diff", "--types"]);
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
FF file2
|
|
|
|
|
FF subdir1/file3
|
|
|
|
|
FF ../dir2/file4
|
|
|
|
|
FF ../file1
|
|
|
|
|
"###);
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
FF file2
|
|
|
|
|
FF subdir1\file3
|
|
|
|
|
FF ..\dir2\file4
|
|
|
|
|
FF ..\file1
|
|
|
|
|
"###);
|
|
|
|
|
|
2022-03-31 05:36:05 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path.join("dir1"), &["diff", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/dir1/file2 b/dir1/file2
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index 54b060eee9..1fe912cdd8 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/dir1/file2
|
|
|
|
|
+++ b/dir1/file2
|
|
|
|
|
@@ -1,1 +1,1 @@
|
|
|
|
|
-foo2
|
|
|
|
|
+bar2
|
|
|
|
|
diff --git a/dir1/subdir1/file3 b/dir1/subdir1/file3
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index c1ec6c6f12..f3c8b75ec6 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/dir1/subdir1/file3
|
|
|
|
|
+++ b/dir1/subdir1/file3
|
|
|
|
|
@@ -1,1 +1,1 @@
|
|
|
|
|
-foo3
|
|
|
|
|
+bar3
|
|
|
|
|
diff --git a/dir2/file4 b/dir2/file4
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index a0016dbc4c..17375f7a12 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/dir2/file4
|
|
|
|
|
+++ b/dir2/file4
|
|
|
|
|
@@ -1,1 +1,1 @@
|
|
|
|
|
-foo4
|
|
|
|
|
+bar4
|
|
|
|
|
diff --git a/file1 b/file1
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index 1715acd6a5..05c4fe6772 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,1 +1,1 @@
|
|
|
|
|
-foo1
|
|
|
|
|
+bar1
|
|
|
|
|
"###);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path.join("dir1"), &["diff", "--stat"]);
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2023-08-31 04:47:30 +00:00
|
|
|
|
file2 | 2 +-
|
|
|
|
|
subdir1/file3 | 2 +-
|
|
|
|
|
../dir2/file4 | 2 +-
|
|
|
|
|
../file1 | 2 +-
|
|
|
|
|
4 files changed, 4 insertions(+), 4 deletions(-)
|
2023-08-13 19:30:57 +00:00
|
|
|
|
"###);
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2023-08-31 04:47:30 +00:00
|
|
|
|
file2 | 2 +-
|
|
|
|
|
subdir1\file3 | 2 +-
|
|
|
|
|
..\dir2\file4 | 2 +-
|
|
|
|
|
..\file1 | 2 +-
|
|
|
|
|
4 files changed, 4 insertions(+), 4 deletions(-)
|
2023-08-13 19:30:57 +00:00
|
|
|
|
"###);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 00:38:44 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_hunks() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
// Test added, removed, inserted, and modified lines. The modified line
|
|
|
|
|
// contains unchanged words.
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "foo\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3"), "foo\nbaz qux blah blah\n").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3"), "foo\nbar\nbaz quux blah blah\n").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1: foo
|
|
|
|
|
Modified regular file file2:
|
|
|
|
|
1 : foo
|
|
|
|
|
Modified regular file file3:
|
|
|
|
|
1 1: foo
|
|
|
|
|
2: bar
|
|
|
|
|
2 3: baz quxquux blah blah
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--color=debug"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
[38;5;3m<<diff header::Modified regular file file1:>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::foo>>[24m[39m
|
|
|
|
|
[38;5;3m<<diff header::Modified regular file file2:>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: : >>[4m[38;5;1m<<diff removed token::foo>>[24m[39m
|
|
|
|
|
[38;5;3m<<diff header::Modified regular file file3:>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: foo>>
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::bar>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: baz >>[4m[38;5;1m<<diff removed token::qux>>[38;5;2m<<diff added token::quux>>[24m[39m<<diff:: blah blah>>
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
index e69de29bb2..257cc5642c 100644
|
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,0 +1,1 @@
|
|
|
|
|
+foo
|
|
|
|
|
diff --git a/file2 b/file2
|
|
|
|
|
index 257cc5642c..e69de29bb2 100644
|
|
|
|
|
--- a/file2
|
|
|
|
|
+++ b/file2
|
|
|
|
|
@@ -1,1 +1,0 @@
|
|
|
|
|
-foo
|
|
|
|
|
diff --git a/file3 b/file3
|
|
|
|
|
index 221a95a095..a543ef3892 100644
|
|
|
|
|
--- a/file3
|
|
|
|
|
+++ b/file3
|
|
|
|
|
@@ -1,2 +1,3 @@
|
|
|
|
|
foo
|
|
|
|
|
-baz qux blah blah
|
|
|
|
|
+bar
|
|
|
|
|
+baz quux blah blah
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--color=debug"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
[1m<<diff file_header::diff --git a/file1 b/file1>>[0m
|
|
|
|
|
[1m<<diff file_header::index e69de29bb2..257cc5642c 100644>>[0m
|
|
|
|
|
[1m<<diff file_header::--- a/file1>>[0m
|
|
|
|
|
[1m<<diff file_header::+++ b/file1>>[0m
|
|
|
|
|
[38;5;6m<<diff hunk_header::@@ -1,0 +1,1 @@>>[39m
|
|
|
|
|
[38;5;2m<<diff added::+>>[4m<<diff added token::foo>>[24m[39m
|
|
|
|
|
[1m<<diff file_header::diff --git a/file2 b/file2>>[0m
|
|
|
|
|
[1m<<diff file_header::index 257cc5642c..e69de29bb2 100644>>[0m
|
|
|
|
|
[1m<<diff file_header::--- a/file2>>[0m
|
|
|
|
|
[1m<<diff file_header::+++ b/file2>>[0m
|
|
|
|
|
[38;5;6m<<diff hunk_header::@@ -1,1 +1,0 @@>>[39m
|
|
|
|
|
[38;5;1m<<diff removed::->>[4m<<diff removed token::foo>>[24m[39m
|
|
|
|
|
[1m<<diff file_header::diff --git a/file3 b/file3>>[0m
|
|
|
|
|
[1m<<diff file_header::index 221a95a095..a543ef3892 100644>>[0m
|
|
|
|
|
[1m<<diff file_header::--- a/file3>>[0m
|
|
|
|
|
[1m<<diff file_header::+++ b/file3>>[0m
|
|
|
|
|
[38;5;6m<<diff hunk_header::@@ -1,2 +1,3 @@>>[39m
|
|
|
|
|
<<diff context:: foo>>
|
|
|
|
|
[38;5;1m<<diff removed::-baz >>[4m<<diff removed token::qux>>[24m<<diff removed:: blah blah>>[39m
|
|
|
|
|
[38;5;2m<<diff added::+>>[4m<<diff added token::bar>>[24m[39m
|
|
|
|
|
[38;5;2m<<diff added::+baz >>[4m<<diff added token::quux>>[24m<<diff added:: blah blah>>[39m
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
diff: add option to display complex color-words diffs without inlining
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
2024-08-14 08:47:11 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_color_words_inlining_threshold() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
let render_diff = |max_alternation: i32, args: &[&str]| {
|
|
|
|
|
let config = format!("diff.color-words.max-inline-alternation={max_alternation}");
|
|
|
|
|
test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&[&["diff", "--config-toml", &config], args].concat(),
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let file1_path = "file1-single-line";
|
|
|
|
|
let file2_path = "file2-multiple-lines-in-single-hunk";
|
|
|
|
|
let file3_path = "file3-changes-across-lines";
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join(file1_path),
|
|
|
|
|
indoc! {"
|
|
|
|
|
== adds ==
|
|
|
|
|
a b c
|
|
|
|
|
== removes ==
|
|
|
|
|
a b c d e f g
|
|
|
|
|
== adds + removes ==
|
|
|
|
|
a b c d e
|
|
|
|
|
== adds + removes + adds ==
|
|
|
|
|
a b c d e
|
|
|
|
|
== adds + removes + adds + removes ==
|
|
|
|
|
a b c d e f g
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join(file2_path),
|
|
|
|
|
indoc! {"
|
|
|
|
|
== adds; removes; adds + removes ==
|
|
|
|
|
a b c
|
|
|
|
|
a b c d e f g
|
|
|
|
|
a b c d e
|
|
|
|
|
== adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
a b c d e
|
|
|
|
|
a b c d e f g
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join(file3_path),
|
|
|
|
|
indoc! {"
|
|
|
|
|
== adds ==
|
|
|
|
|
a b c
|
|
|
|
|
== removes ==
|
|
|
|
|
a b c d
|
|
|
|
|
e f g
|
|
|
|
|
== adds + removes ==
|
|
|
|
|
a b c
|
|
|
|
|
d e
|
|
|
|
|
== adds + removes + adds ==
|
|
|
|
|
a b c
|
|
|
|
|
d e
|
|
|
|
|
== adds + removes + adds + removes ==
|
|
|
|
|
a b
|
|
|
|
|
c d e f g
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join(file1_path),
|
|
|
|
|
indoc! {"
|
|
|
|
|
== adds ==
|
|
|
|
|
a X b Y Z c
|
|
|
|
|
== removes ==
|
|
|
|
|
a c f
|
|
|
|
|
== adds + removes ==
|
|
|
|
|
a X b d
|
|
|
|
|
== adds + removes + adds ==
|
|
|
|
|
a X b d Y
|
|
|
|
|
== adds + removes + adds + removes ==
|
|
|
|
|
X a Y b d Z e
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join(file2_path),
|
|
|
|
|
indoc! {"
|
|
|
|
|
== adds; removes; adds + removes ==
|
|
|
|
|
a X b Y Z c
|
|
|
|
|
a c f
|
|
|
|
|
a X b d
|
|
|
|
|
== adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
a X b d Y
|
|
|
|
|
X a Y b d Z e
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join(file3_path),
|
|
|
|
|
indoc! {"
|
|
|
|
|
== adds ==
|
|
|
|
|
a X b
|
|
|
|
|
Y Z c
|
|
|
|
|
== removes ==
|
|
|
|
|
a c f
|
|
|
|
|
== adds + removes ==
|
|
|
|
|
a
|
|
|
|
|
X b d
|
|
|
|
|
== adds + removes + adds ==
|
|
|
|
|
a X b d
|
|
|
|
|
Y
|
|
|
|
|
== adds + removes + adds + removes ==
|
|
|
|
|
X a Y b d
|
|
|
|
|
Z e
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
2024-08-27 11:34:48 +00:00
|
|
|
|
// default
|
diff: add option to display complex color-words diffs without inlining
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
2024-08-14 08:47:11 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-08-27 11:34:48 +00:00
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 4: a b c d e f g
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 6: a X b c d e
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 8: a X b c d eY
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 : a b c d e f g
|
|
|
|
|
10: X a Y b d Z e
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: a b c d e f g
|
|
|
|
|
4 4: a X b c d e
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
7 : a b c d e f g
|
|
|
|
|
6: a X b d Y
|
|
|
|
|
7: X a Y b d Z e
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b
|
|
|
|
|
2 3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 5: a b c d
|
|
|
|
|
5 5: e f g
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 7: a
|
|
|
|
|
7 8: X b c
|
|
|
|
|
8 8: d e
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 10: a X b c
|
|
|
|
|
11 10: d e
|
|
|
|
|
11 11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 : a b
|
|
|
|
|
14 : c d e f g
|
|
|
|
|
13: X a Y b d
|
|
|
|
|
14: Z e
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// -1: inline all
|
|
|
|
|
insta::assert_snapshot!(render_diff(-1, &[]), @r###"
|
diff: add option to display complex color-words diffs without inlining
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
2024-08-14 08:47:11 +00:00
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 4: a b c d e f g
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 6: a X b c d e
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 8: a X b c d eY
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 10: X a Y b c d Z e f g
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: a b c d e f g
|
|
|
|
|
4 4: a X b c d e
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 6: a X b c d eY
|
|
|
|
|
7 7: X a Y b c d Z e f g
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b
|
|
|
|
|
2 3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 5: a b c d
|
|
|
|
|
5 5: e f g
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 7: a
|
|
|
|
|
7 8: X b c
|
|
|
|
|
8 8: d e
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 10: a X b c
|
|
|
|
|
11 10: d e
|
|
|
|
|
11 11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 13: X a Y b
|
|
|
|
|
14 13: c d
|
|
|
|
|
14 14: Z e f g
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// 0: no inlining
|
|
|
|
|
insta::assert_snapshot!(render_diff(0, &[]), @r###"
|
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 : a b c
|
|
|
|
|
2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 : a b c d e f g
|
|
|
|
|
4: a c f
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
6: a X b d
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 : a b c d e
|
|
|
|
|
8: a X b d Y
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 : a b c d e f g
|
|
|
|
|
10: X a Y b d Z e
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 : a b c
|
|
|
|
|
3 : a b c d e f g
|
|
|
|
|
4 : a b c d e
|
|
|
|
|
2: a X b Y Z c
|
|
|
|
|
3: a c f
|
|
|
|
|
4: a X b d
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
7 : a b c d e f g
|
|
|
|
|
6: a X b d Y
|
|
|
|
|
7: X a Y b d Z e
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 : a b c
|
|
|
|
|
2: a X b
|
|
|
|
|
3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 : a b c d
|
|
|
|
|
5 : e f g
|
|
|
|
|
5: a c f
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 : a b c
|
|
|
|
|
8 : d e
|
|
|
|
|
7: a
|
|
|
|
|
8: X b d
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 : a b c
|
|
|
|
|
11 : d e
|
|
|
|
|
10: a X b d
|
|
|
|
|
11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 : a b
|
|
|
|
|
14 : c d e f g
|
|
|
|
|
13: X a Y b d
|
|
|
|
|
14: Z e
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// 1: inline adds-only or removes-only lines
|
|
|
|
|
insta::assert_snapshot!(render_diff(1, &[]), @r###"
|
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 4: a b c d e f g
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
6: a X b d
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 : a b c d e
|
|
|
|
|
8: a X b d Y
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 : a b c d e f g
|
|
|
|
|
10: X a Y b d Z e
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 : a b c
|
|
|
|
|
3 : a b c d e f g
|
|
|
|
|
4 : a b c d e
|
|
|
|
|
2: a X b Y Z c
|
|
|
|
|
3: a c f
|
|
|
|
|
4: a X b d
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
7 : a b c d e f g
|
|
|
|
|
6: a X b d Y
|
|
|
|
|
7: X a Y b d Z e
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b
|
|
|
|
|
2 3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 5: a b c d
|
|
|
|
|
5 5: e f g
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 : a b c
|
|
|
|
|
8 : d e
|
|
|
|
|
7: a
|
|
|
|
|
8: X b d
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 : a b c
|
|
|
|
|
11 : d e
|
|
|
|
|
10: a X b d
|
|
|
|
|
11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 : a b
|
|
|
|
|
14 : c d e f g
|
|
|
|
|
13: X a Y b d
|
|
|
|
|
14: Z e
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// 2: inline up to adds + removes lines
|
|
|
|
|
insta::assert_snapshot!(render_diff(2, &[]), @r###"
|
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 4: a b c d e f g
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 6: a X b c d e
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 : a b c d e
|
|
|
|
|
8: a X b d Y
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 : a b c d e f g
|
|
|
|
|
10: X a Y b d Z e
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: a b c d e f g
|
|
|
|
|
4 4: a X b c d e
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
7 : a b c d e f g
|
|
|
|
|
6: a X b d Y
|
|
|
|
|
7: X a Y b d Z e
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b
|
|
|
|
|
2 3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 5: a b c d
|
|
|
|
|
5 5: e f g
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 7: a
|
|
|
|
|
7 8: X b c
|
|
|
|
|
8 8: d e
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 : a b c
|
|
|
|
|
11 : d e
|
|
|
|
|
10: a X b d
|
|
|
|
|
11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 : a b
|
|
|
|
|
14 : c d e f g
|
|
|
|
|
13: X a Y b d
|
|
|
|
|
14: Z e
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// 3: inline up to adds + removes + adds lines
|
|
|
|
|
insta::assert_snapshot!(render_diff(3, &[]), @r###"
|
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 4: a b c d e f g
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 6: a X b c d e
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 8: a X b c d eY
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 : a b c d e f g
|
|
|
|
|
10: X a Y b d Z e
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: a b c d e f g
|
|
|
|
|
4 4: a X b c d e
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 : a b c d e
|
|
|
|
|
7 : a b c d e f g
|
|
|
|
|
6: a X b d Y
|
|
|
|
|
7: X a Y b d Z e
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b
|
|
|
|
|
2 3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 5: a b c d
|
|
|
|
|
5 5: e f g
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 7: a
|
|
|
|
|
7 8: X b c
|
|
|
|
|
8 8: d e
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 10: a X b c
|
|
|
|
|
11 10: d e
|
|
|
|
|
11 11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 : a b
|
|
|
|
|
14 : c d e f g
|
|
|
|
|
13: X a Y b d
|
|
|
|
|
14: Z e
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// 4: inline up to adds + removes + adds + removes lines
|
|
|
|
|
insta::assert_snapshot!(render_diff(4, &[]), @r###"
|
|
|
|
|
Modified regular file file1-single-line:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: == removes ==
|
|
|
|
|
4 4: a b c d e f g
|
|
|
|
|
5 5: == adds + removes ==
|
|
|
|
|
6 6: a X b c d e
|
|
|
|
|
7 7: == adds + removes + adds ==
|
|
|
|
|
8 8: a X b c d eY
|
|
|
|
|
9 9: == adds + removes + adds + removes ==
|
|
|
|
|
10 10: X a Y b c d Z e f g
|
|
|
|
|
Modified regular file file2-multiple-lines-in-single-hunk:
|
|
|
|
|
1 1: == adds; removes; adds + removes ==
|
|
|
|
|
2 2: a X b Y Z c
|
|
|
|
|
3 3: a b c d e f g
|
|
|
|
|
4 4: a X b c d e
|
|
|
|
|
5 5: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
6 6: a X b c d eY
|
|
|
|
|
7 7: X a Y b c d Z e f g
|
|
|
|
|
Modified regular file file3-changes-across-lines:
|
|
|
|
|
1 1: == adds ==
|
|
|
|
|
2 2: a X b
|
|
|
|
|
2 3: Y Z c
|
|
|
|
|
3 4: == removes ==
|
|
|
|
|
4 5: a b c d
|
|
|
|
|
5 5: e f g
|
|
|
|
|
6 6: == adds + removes ==
|
|
|
|
|
7 7: a
|
|
|
|
|
7 8: X b c
|
|
|
|
|
8 8: d e
|
|
|
|
|
9 9: == adds + removes + adds ==
|
|
|
|
|
10 10: a X b c
|
|
|
|
|
11 10: d e
|
|
|
|
|
11 11: Y
|
|
|
|
|
12 12: == adds + removes + adds + removes ==
|
|
|
|
|
13 13: X a Y b
|
|
|
|
|
14 13: c d
|
|
|
|
|
14 14: Z e f g
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// context words in added/removed lines should be labeled as such
|
|
|
|
|
insta::assert_snapshot!(render_diff(2, &["--color=always"]), @r###"
|
|
|
|
|
[38;5;3mModified regular file file1-single-line:[39m
|
|
|
|
|
[38;5;1m 1[39m [38;5;2m 1[39m: == adds ==
|
|
|
|
|
[38;5;1m 2[39m [38;5;2m 2[39m: a [4m[38;5;2mX [24m[39mb [4m[38;5;2mY Z [24m[39mc
|
|
|
|
|
[38;5;1m 3[39m [38;5;2m 3[39m: == removes ==
|
|
|
|
|
[38;5;1m 4[39m [38;5;2m 4[39m: a [4m[38;5;1mb [24m[39mc [4m[38;5;1md e [24m[39mf[4m[38;5;1m g[24m[39m
|
|
|
|
|
[38;5;1m 5[39m [38;5;2m 5[39m: == adds + removes ==
|
|
|
|
|
[38;5;1m 6[39m [38;5;2m 6[39m: a [4m[38;5;2mX [24m[39mb [4m[38;5;1mc [24m[39md[4m[38;5;1m e[24m[39m
|
|
|
|
|
[38;5;1m 7[39m [38;5;2m 7[39m: == adds + removes + adds ==
|
|
|
|
|
[38;5;1m 8[39m : [38;5;1ma b [4mc [24md [4me[24m[39m
|
|
|
|
|
[38;5;2m 8[39m: [38;5;2ma [4mX [24mb d [4mY[24m[39m
|
|
|
|
|
[38;5;1m 9[39m [38;5;2m 9[39m: == adds + removes + adds + removes ==
|
|
|
|
|
[38;5;1m 10[39m : [38;5;1ma b [4mc [24md e[4m f g[24m[39m
|
|
|
|
|
[38;5;2m 10[39m: [4m[38;5;2mX [24ma [4mY [24mb d [4mZ [24me[39m
|
|
|
|
|
[38;5;3mModified regular file file2-multiple-lines-in-single-hunk:[39m
|
|
|
|
|
[38;5;1m 1[39m [38;5;2m 1[39m: == adds; removes; adds + removes ==
|
|
|
|
|
[38;5;1m 2[39m [38;5;2m 2[39m: a [4m[38;5;2mX [24m[39mb [4m[38;5;2mY Z [24m[39mc
|
|
|
|
|
[38;5;1m 3[39m [38;5;2m 3[39m: a [4m[38;5;1mb [24m[39mc [4m[38;5;1md e [24m[39mf[4m[38;5;1m g[24m[39m
|
|
|
|
|
[38;5;1m 4[39m [38;5;2m 4[39m: a [4m[38;5;2mX [24m[39mb [4m[38;5;1mc [24m[39md[4m[38;5;1m e[24m[39m
|
|
|
|
|
[38;5;1m 5[39m [38;5;2m 5[39m: == adds + removes + adds; adds + removes + adds + removes ==
|
|
|
|
|
[38;5;1m 6[39m : [38;5;1ma b [4mc [24md [4me[24m[39m
|
|
|
|
|
[38;5;1m 7[39m : [38;5;1ma b [4mc [24md e[4m f g[24m[39m
|
|
|
|
|
[38;5;2m 6[39m: [38;5;2ma [4mX [24mb d [4mY[24m[39m
|
|
|
|
|
[38;5;2m 7[39m: [4m[38;5;2mX [24ma [4mY [24mb d [4mZ [24me[39m
|
|
|
|
|
[38;5;3mModified regular file file3-changes-across-lines:[39m
|
|
|
|
|
[38;5;1m 1[39m [38;5;2m 1[39m: == adds ==
|
|
|
|
|
[38;5;1m 2[39m [38;5;2m 2[39m: a [4m[38;5;2mX [24m[39mb[4m[38;5;2m[24m[39m
|
|
|
|
|
[38;5;1m 2[39m [38;5;2m 3[39m: [4m[38;5;2mY Z[24m[39m c
|
|
|
|
|
[38;5;1m 3[39m [38;5;2m 4[39m: == removes ==
|
|
|
|
|
[38;5;1m 4[39m [38;5;2m 5[39m: a [4m[38;5;1mb [24m[39mc [4m[38;5;1md[24m[39m
|
|
|
|
|
[38;5;1m 5[39m [38;5;2m 5[39m: [4m[38;5;1me [24m[39mf[4m[38;5;1m g[24m[39m
|
|
|
|
|
[38;5;1m 6[39m [38;5;2m 6[39m: == adds + removes ==
|
|
|
|
|
[38;5;1m 7[39m [38;5;2m 7[39m: a[4m[38;5;2m[24m[39m
|
|
|
|
|
[38;5;1m 7[39m [38;5;2m 8[39m: [4m[38;5;2mX[24m[39m b [4m[38;5;1mc[24m[39m
|
|
|
|
|
[38;5;1m 8[39m [38;5;2m 8[39m: d[4m[38;5;1m e[24m[39m
|
|
|
|
|
[38;5;1m 9[39m [38;5;2m 9[39m: == adds + removes + adds ==
|
|
|
|
|
[38;5;1m 10[39m : [38;5;1ma b [4mc[24m[39m
|
|
|
|
|
[38;5;1m 11[39m : [38;5;1md[4m e[24m[39m
|
|
|
|
|
[38;5;2m 10[39m: [38;5;2ma [4mX [24mb d[4m[24m[39m
|
|
|
|
|
[38;5;2m 11[39m: [4m[38;5;2mY[24m[39m
|
|
|
|
|
[38;5;1m 12[39m [38;5;2m 12[39m: == adds + removes + adds + removes ==
|
|
|
|
|
[38;5;1m 13[39m : [38;5;1ma b[4m[24m[39m
|
|
|
|
|
[38;5;1m 14[39m : [4m[38;5;1mc[24m d e[4m f g[24m[39m
|
|
|
|
|
[38;5;2m 13[39m: [4m[38;5;2mX [24ma [4mY [24mb d[4m[24m[39m
|
|
|
|
|
[38;5;2m 14[39m: [4m[38;5;2mZ[24m e[39m
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(render_diff(2, &["--color=debug"]), @r###"
|
|
|
|
|
[38;5;3m<<diff header::Modified regular file file1-single-line:>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: == adds ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: a >>[4m[38;5;2m<<diff added token::X >>[24m[39m<<diff::b >>[4m[38;5;2m<<diff added token::Y Z >>[24m[39m<<diff::c>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 3>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: == removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 4>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 4>>[39m<<diff::: a >>[4m[38;5;1m<<diff removed token::b >>[24m[39m<<diff::c >>[4m[38;5;1m<<diff removed token::d e >>[24m[39m<<diff::f>>[4m[38;5;1m<<diff removed token:: g>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 5>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 5>>[39m<<diff::: == adds + removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 6>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 6>>[39m<<diff::: a >>[4m[38;5;2m<<diff added token::X >>[24m[39m<<diff::b >>[4m[38;5;1m<<diff removed token::c >>[24m[39m<<diff::d>>[4m[38;5;1m<<diff removed token:: e>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 7>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 7>>[39m<<diff::: == adds + removes + adds ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 8>>[39m<<diff:: : >>[38;5;1m<<diff removed::a b >>[4m<<diff removed token::c >>[24m<<diff removed::d >>[4m<<diff removed token::e>>[24m<<diff removed::>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 8>>[39m<<diff::: >>[38;5;2m<<diff added::a >>[4m<<diff added token::X >>[24m<<diff added::b d >>[4m<<diff added token::Y>>[24m<<diff added::>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 9>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 9>>[39m<<diff::: == adds + removes + adds + removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 10>>[39m<<diff:: : >>[38;5;1m<<diff removed::a b >>[4m<<diff removed token::c >>[24m<<diff removed::d e>>[4m<<diff removed token:: f g>>[24m<<diff removed::>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 10>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::X >>[24m<<diff added::a >>[4m<<diff added token::Y >>[24m<<diff added::b d >>[4m<<diff added token::Z >>[24m<<diff added::e>>[39m
|
|
|
|
|
[38;5;3m<<diff header::Modified regular file file2-multiple-lines-in-single-hunk:>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: == adds; removes; adds + removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: a >>[4m[38;5;2m<<diff added token::X >>[24m[39m<<diff::b >>[4m[38;5;2m<<diff added token::Y Z >>[24m[39m<<diff::c>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 3>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: a >>[4m[38;5;1m<<diff removed token::b >>[24m[39m<<diff::c >>[4m[38;5;1m<<diff removed token::d e >>[24m[39m<<diff::f>>[4m[38;5;1m<<diff removed token:: g>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 4>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 4>>[39m<<diff::: a >>[4m[38;5;2m<<diff added token::X >>[24m[39m<<diff::b >>[4m[38;5;1m<<diff removed token::c >>[24m[39m<<diff::d>>[4m[38;5;1m<<diff removed token:: e>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 5>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 5>>[39m<<diff::: == adds + removes + adds; adds + removes + adds + removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 6>>[39m<<diff:: : >>[38;5;1m<<diff removed::a b >>[4m<<diff removed token::c >>[24m<<diff removed::d >>[4m<<diff removed token::e>>[24m<<diff removed::>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 7>>[39m<<diff:: : >>[38;5;1m<<diff removed::a b >>[4m<<diff removed token::c >>[24m<<diff removed::d e>>[4m<<diff removed token:: f g>>[24m<<diff removed::>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 6>>[39m<<diff::: >>[38;5;2m<<diff added::a >>[4m<<diff added token::X >>[24m<<diff added::b d >>[4m<<diff added token::Y>>[24m<<diff added::>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 7>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::X >>[24m<<diff added::a >>[4m<<diff added token::Y >>[24m<<diff added::b d >>[4m<<diff added token::Z >>[24m<<diff added::e>>[39m
|
|
|
|
|
[38;5;3m<<diff header::Modified regular file file3-changes-across-lines:>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 1>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 1>>[39m<<diff::: == adds ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 2>>[39m<<diff::: a >>[4m[38;5;2m<<diff added token::X >>[24m[39m<<diff::b>>[4m[38;5;2m<<diff added token::>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 2>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 3>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::Y Z>>[24m[39m<<diff:: c>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 3>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 4>>[39m<<diff::: == removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 4>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 5>>[39m<<diff::: a >>[4m[38;5;1m<<diff removed token::b >>[24m[39m<<diff::c >>[4m[38;5;1m<<diff removed token::d>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 5>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 5>>[39m<<diff::: >>[4m[38;5;1m<<diff removed token::e >>[24m[39m<<diff::f>>[4m[38;5;1m<<diff removed token:: g>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 6>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 6>>[39m<<diff::: == adds + removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 7>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 7>>[39m<<diff::: a>>[4m[38;5;2m<<diff added token::>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 7>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 8>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::X>>[24m[39m<<diff:: b >>[4m[38;5;1m<<diff removed token::c>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 8>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 8>>[39m<<diff::: d>>[4m[38;5;1m<<diff removed token:: e>>[24m[39m<<diff::>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 9>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 9>>[39m<<diff::: == adds + removes + adds ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 10>>[39m<<diff:: : >>[38;5;1m<<diff removed::a b >>[4m<<diff removed token::c>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 11>>[39m<<diff:: : >>[38;5;1m<<diff removed::d>>[4m<<diff removed token:: e>>[24m<<diff removed::>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 10>>[39m<<diff::: >>[38;5;2m<<diff added::a >>[4m<<diff added token::X >>[24m<<diff added::b d>>[4m<<diff added token::>>[24m[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 11>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::Y>>[24m<<diff added::>>[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 12>>[39m<<diff:: >>[38;5;2m<<diff added line_number:: 12>>[39m<<diff::: == adds + removes + adds + removes ==>>
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 13>>[39m<<diff:: : >>[38;5;1m<<diff removed::a b>>[4m<<diff removed token::>>[24m[39m
|
|
|
|
|
[38;5;1m<<diff removed line_number:: 14>>[39m<<diff:: : >>[4m[38;5;1m<<diff removed token::c>>[24m<<diff removed:: d e>>[4m<<diff removed token:: f g>>[24m<<diff removed::>>[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 13>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::X >>[24m<<diff added::a >>[4m<<diff added token::Y >>[24m<<diff added::b d>>[4m<<diff added token::>>[24m[39m
|
|
|
|
|
<<diff:: >>[38;5;2m<<diff added line_number:: 14>>[39m<<diff::: >>[4m[38;5;2m<<diff added token::Z>>[24m<<diff added:: e>>[39m
|
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-31 05:36:05 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_missing_newline() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "foo\nbar").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo\nbar").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "foo").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: foo
|
2022-07-07 11:35:24 +00:00
|
|
|
|
2: bar
|
|
|
|
|
Modified regular file file2:
|
2022-03-31 05:36:05 +00:00
|
|
|
|
1 1: foo
|
|
|
|
|
2 : bar
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index 1910281566..a907ec3f43 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,1 +1,2 @@
|
|
|
|
|
-foo
|
|
|
|
|
\ No newline at end of file
|
|
|
|
|
+foo
|
|
|
|
|
+bar
|
|
|
|
|
\ No newline at end of file
|
|
|
|
|
diff --git a/file2 b/file2
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index a907ec3f43..1910281566 100644
|
2022-03-31 05:36:05 +00:00
|
|
|
|
--- a/file2
|
|
|
|
|
+++ b/file2
|
|
|
|
|
@@ -1,2 +1,1 @@
|
|
|
|
|
-foo
|
|
|
|
|
-bar
|
|
|
|
|
\ No newline at end of file
|
|
|
|
|
+foo
|
|
|
|
|
\ No newline at end of file
|
|
|
|
|
"###);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
file1 | 3 ++-
|
|
|
|
|
file2 | 3 +--
|
|
|
|
|
2 files changed, 3 insertions(+), 3 deletions(-)
|
|
|
|
|
"###);
|
2022-03-31 05:36:05 +00:00
|
|
|
|
}
|
2022-07-07 11:35:24 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_color_words_diff_missing_newline() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Empty"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nc\nd\ne\nf\ng\nh\ni").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Add no newline"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\ne\nf\ng\nh\ni").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Modify first line"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\nE\nf\ng\nh\ni").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Modify middle line"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\nE\nf\ng\nh\nI").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Modify last line"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\nE\nf\ng\nh\nI\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Append newline"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\nE\nf\ng\nh\nI").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Remove newline"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "=== Empty"]);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
2023-07-28 00:33:54 +00:00
|
|
|
|
&[
|
|
|
|
|
"log",
|
|
|
|
|
"-Tdescription",
|
|
|
|
|
"-pr::@-",
|
|
|
|
|
"--no-graph",
|
|
|
|
|
"--reversed",
|
|
|
|
|
],
|
2022-07-07 11:35:24 +00:00
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
=== Empty
|
|
|
|
|
Added regular file file1:
|
2023-08-12 15:07:59 +00:00
|
|
|
|
(empty)
|
2022-07-07 11:35:24 +00:00
|
|
|
|
=== Add no newline
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1: a
|
|
|
|
|
2: b
|
|
|
|
|
3: c
|
|
|
|
|
4: d
|
|
|
|
|
5: e
|
|
|
|
|
6: f
|
|
|
|
|
7: g
|
|
|
|
|
8: h
|
|
|
|
|
9: i
|
|
|
|
|
=== Modify first line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: aA
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
...
|
|
|
|
|
=== Modify middle line
|
|
|
|
|
Modified regular file file1:
|
2022-12-06 00:44:00 +00:00
|
|
|
|
1 1: A
|
2022-07-07 11:35:24 +00:00
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
5 5: eE
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
2022-12-06 00:44:00 +00:00
|
|
|
|
9 9: i
|
2022-07-07 11:35:24 +00:00
|
|
|
|
=== Modify last line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: iI
|
|
|
|
|
=== Append newline
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: I
|
|
|
|
|
=== Remove newline
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: I
|
|
|
|
|
=== Empty
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 : A
|
|
|
|
|
2 : b
|
|
|
|
|
3 : c
|
|
|
|
|
4 : d
|
|
|
|
|
5 : E
|
|
|
|
|
6 : f
|
|
|
|
|
7 : g
|
|
|
|
|
8 : h
|
|
|
|
|
9 : I
|
|
|
|
|
"###);
|
diff: add option to display complex color-words diffs without inlining
In this patch, I use the number of adds<->removes alternation as a threshold,
which approximates the visual complexity of diff hunks. I don't think user can
choose the threshold intuitively, but we need a config knob to try out some.
I set `max-inline-alternation = 3` locally. 0 and 1 mean "disable inlining"
and "inline adds-only/removes-only lines" respectively.
I've added "diff.<format>" config namespace assuming "ui.diff" will be
reorganized as "ui.diff-formatter" or something. #3327
Some other metrics I've tried:
```
// Per-line alternation. This also works well, but can't measure complexity of
// changes across lines.
fn count_max_diff_alternation_per_line(diff_lines: &[DiffLine]) -> usize {
diff_lines
.iter()
.map(|line| {
let sides = line.hunks.iter().map(|&(side, _)| side);
sides
.filter(|&side| side != DiffLineHunkSide::Both)
.dedup() // omit e.g. left->both->left
.count()
})
.max()
.unwrap_or(0)
}
// Per-line occupancy of changes. Large diffs don't always look complex.
fn max_diff_token_ratio_per_line(diff_lines: &[DiffLine]) -> f32 {
diff_lines
.iter()
.filter_map(|line| {
let [both_len, left_len, right_len] =
line.hunks.iter().fold([0, 0, 0], |mut acc, (side, data)| {
let index = match side {
DiffLineHunkSide::Both => 0,
DiffLineHunkSide::Left => 1,
DiffLineHunkSide::Right => 2,
};
acc[index] += data.len();
acc
});
// left/right-only change is readable
(left_len != 0 && right_len != 0).then(|| {
let diff_len = left_len + right_len;
let total_len = both_len + left_len + right_len;
(diff_len as f32) / (total_len as f32)
})
})
.reduce(f32::max)
.unwrap_or(0.0)
}
// Total occupancy of changes. Large diffs don't always look complex.
fn total_change_ratio(diff_lines: &[DiffLine]) -> f32 {
let (diff_len, total_len) = diff_lines
.iter()
.flat_map(|line| &line.hunks)
.fold((0, 0), |(diff_len, total_len), (side, data)| {
let l = data.len();
match side {
DiffLineHunkSide::Both => (diff_len, total_len + l),
DiffLineHunkSide::Left => (diff_len + l, total_len + l),
DiffLineHunkSide::Right => (diff_len + l, total_len + l),
}
});
(diff_len as f32) / (total_len as f32)
}
```
2024-08-14 08:47:11 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&[
|
|
|
|
|
"log",
|
|
|
|
|
"--config-toml=diff.color-words.max-inline-alternation=0",
|
|
|
|
|
"-Tdescription",
|
|
|
|
|
"-pr::@-",
|
|
|
|
|
"--no-graph",
|
|
|
|
|
"--reversed",
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
=== Empty
|
|
|
|
|
Added regular file file1:
|
|
|
|
|
(empty)
|
|
|
|
|
=== Add no newline
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1: a
|
|
|
|
|
2: b
|
|
|
|
|
3: c
|
|
|
|
|
4: d
|
|
|
|
|
5: e
|
|
|
|
|
6: f
|
|
|
|
|
7: g
|
|
|
|
|
8: h
|
|
|
|
|
9: i
|
|
|
|
|
=== Modify first line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 : a
|
|
|
|
|
1: A
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
...
|
|
|
|
|
=== Modify middle line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: A
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
5 : e
|
|
|
|
|
5: E
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: i
|
|
|
|
|
=== Modify last line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 : i
|
|
|
|
|
9: I
|
|
|
|
|
=== Append newline
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 : I
|
|
|
|
|
9: I
|
|
|
|
|
=== Remove newline
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 : I
|
|
|
|
|
9: I
|
|
|
|
|
=== Empty
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 : A
|
|
|
|
|
2 : b
|
|
|
|
|
3 : c
|
|
|
|
|
4 : d
|
|
|
|
|
5 : E
|
|
|
|
|
6 : f
|
|
|
|
|
7 : g
|
|
|
|
|
8 : h
|
|
|
|
|
9 : I
|
|
|
|
|
"###);
|
2022-07-07 11:35:24 +00:00
|
|
|
|
}
|
2022-12-06 00:44:00 +00:00
|
|
|
|
|
2024-09-22 05:13:06 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_ignore_whitespace() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join("file1"),
|
|
|
|
|
indoc! {"
|
|
|
|
|
foo {
|
|
|
|
|
bar;
|
|
|
|
|
}
|
|
|
|
|
baz {}
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "-mindent + whitespace insertion"]);
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join("file1"),
|
|
|
|
|
indoc! {"
|
|
|
|
|
{
|
|
|
|
|
foo {
|
|
|
|
|
bar;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
baz { }
|
|
|
|
|
"},
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["status"]);
|
|
|
|
|
|
|
|
|
|
// Git diff as reference output
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--ignore-all-space"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r#"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
index f532aa68ad..033c4a6168 100644
|
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,4 +1,6 @@
|
|
|
|
|
+{
|
|
|
|
|
foo {
|
|
|
|
|
bar;
|
|
|
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
baz { }
|
|
|
|
|
"#);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--ignore-space-change"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r#"
|
|
|
|
|
diff --git a/file1 b/file1
|
|
|
|
|
index f532aa68ad..033c4a6168 100644
|
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,4 +1,6 @@
|
|
|
|
|
-foo {
|
|
|
|
|
+{
|
|
|
|
|
+ foo {
|
|
|
|
|
bar;
|
|
|
|
|
+ }
|
|
|
|
|
}
|
|
|
|
|
-baz {}
|
|
|
|
|
+baz { }
|
|
|
|
|
"#);
|
|
|
|
|
|
|
|
|
|
// Diff-stat should respects the whitespace options
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat", "--ignore-all-space"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r#"
|
|
|
|
|
file1 | 2 ++
|
|
|
|
|
1 file changed, 2 insertions(+), 0 deletions(-)
|
|
|
|
|
"#);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat", "--ignore-space-change"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r#"
|
|
|
|
|
file1 | 6 ++++--
|
|
|
|
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
|
|
|
"#);
|
|
|
|
|
|
|
|
|
|
// Word-level changes are still highlighted
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&["diff", "--color=always", "--ignore-all-space"],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r#"
|
|
|
|
|
[38;5;3mModified regular file file1:[39m
|
|
|
|
|
[38;5;2m 1[39m: [4m[38;5;2m{[24m[39m
|
2024-09-23 06:43:22 +00:00
|
|
|
|
[38;5;1m 1[39m [38;5;2m 2[39m: [4m[38;5;2m [24m[39mfoo {
|
|
|
|
|
[38;5;1m 2[39m [38;5;2m 3[39m: [4m[38;5;2m [24m[39mbar;
|
|
|
|
|
[38;5;1m 3[39m [38;5;2m 4[39m: [4m[38;5;2m [24m[39m}
|
2024-09-22 05:13:06 +00:00
|
|
|
|
[38;5;2m 5[39m: [4m[38;5;2m}[24m[39m
|
2024-09-23 06:43:22 +00:00
|
|
|
|
[38;5;1m 4[39m [38;5;2m 6[39m: baz {[4m[38;5;2m [24m[39m}
|
2024-09-22 05:13:06 +00:00
|
|
|
|
"#);
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&["diff", "--color=always", "--ignore-space-change"],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r#"
|
|
|
|
|
[38;5;3mModified regular file file1:[39m
|
|
|
|
|
[38;5;2m 1[39m: [4m[38;5;2m{[24m[39m
|
|
|
|
|
[38;5;1m 1[39m [38;5;2m 2[39m: [4m[38;5;2m [24m[39mfoo {
|
2024-09-23 06:43:22 +00:00
|
|
|
|
[38;5;1m 2[39m [38;5;2m 3[39m: [4m[38;5;2m [24m[39mbar;
|
2024-09-22 05:13:06 +00:00
|
|
|
|
[38;5;2m 4[39m: [4m[38;5;2m }[24m[39m
|
|
|
|
|
[38;5;1m 3[39m [38;5;2m 5[39m: }
|
|
|
|
|
[38;5;1m 4[39m [38;5;2m 6[39m: baz {[4m[38;5;2m [24m[39m}
|
|
|
|
|
"#);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 00:44:00 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_skipped_context() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nc\nd\ne\nf\ng\nh\ni\nj").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "=== Left side of diffs"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@", "-m", "=== Must skip 2 lines"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\ne\nf\ng\nh\ni\nJ").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== Don't skip 1 line"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nd\ne\nf\ng\nh\nI\nj").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== No gap to skip"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nB\nc\nd\ne\nf\ng\nh\nI\nj").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== No gap to skip"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nC\nd\ne\nf\ng\nh\nI\nj").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== 1 line at start"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nc\nd\nE\nf\ng\nh\ni\nj").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== 1 line at end"]);
|
2022-12-06 00:44:00 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nc\nd\ne\nF\ng\nh\ni\nj").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&["log", "-Tdescription", "-p", "--no-graph", "--reversed"],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
=== Left side of diffs
|
|
|
|
|
Added regular file file1:
|
|
|
|
|
1: a
|
|
|
|
|
2: b
|
|
|
|
|
3: c
|
|
|
|
|
4: d
|
|
|
|
|
5: e
|
|
|
|
|
6: f
|
|
|
|
|
7: g
|
|
|
|
|
8: h
|
|
|
|
|
9: i
|
|
|
|
|
10: j
|
|
|
|
|
=== Must skip 2 lines
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: aA
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
...
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: i
|
|
|
|
|
10 10: jJ
|
|
|
|
|
=== Don't skip 1 line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: aA
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
5 5: e
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: iI
|
|
|
|
|
10 10: j
|
|
|
|
|
=== No gap to skip
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: a
|
|
|
|
|
2 2: bB
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
5 5: e
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: iI
|
|
|
|
|
10 10: j
|
|
|
|
|
=== No gap to skip
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: a
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: cC
|
|
|
|
|
4 4: d
|
|
|
|
|
5 5: e
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: iI
|
|
|
|
|
10 10: j
|
|
|
|
|
=== 1 line at start
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: a
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
5 5: eE
|
|
|
|
|
6 6: f
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
...
|
|
|
|
|
=== 1 line at end
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
3 3: c
|
|
|
|
|
4 4: d
|
|
|
|
|
5 5: e
|
|
|
|
|
6 6: fF
|
|
|
|
|
7 7: g
|
|
|
|
|
8 8: h
|
|
|
|
|
9 9: i
|
|
|
|
|
10 10: j
|
|
|
|
|
"###);
|
|
|
|
|
}
|
2023-08-02 03:12:11 +00:00
|
|
|
|
|
2024-03-02 00:57:43 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_skipped_context_nondefault() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2024-03-02 00:57:43 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nc\nd").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "=== Left side of diffs"]);
|
|
|
|
|
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@", "-m", "=== Must skip 2 lines"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nc\nD").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== Don't skip 1 line"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "A\nb\nC\nd").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== No gap to skip"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nB\nC\nd").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== 1 line at start"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nB\nc\nd").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "@-", "-m", "=== 1 line at end"]);
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "a\nb\nC\nd").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(
|
|
|
|
|
&repo_path,
|
|
|
|
|
&[
|
|
|
|
|
"log",
|
|
|
|
|
"-Tdescription",
|
|
|
|
|
"-p",
|
|
|
|
|
"--no-graph",
|
|
|
|
|
"--reversed",
|
|
|
|
|
"--context=0",
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
=== Left side of diffs
|
|
|
|
|
Added regular file file1:
|
|
|
|
|
1: a
|
|
|
|
|
2: b
|
|
|
|
|
3: c
|
|
|
|
|
4: d
|
|
|
|
|
=== Must skip 2 lines
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: aA
|
|
|
|
|
...
|
|
|
|
|
4 4: dD
|
|
|
|
|
=== Don't skip 1 line
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: aA
|
|
|
|
|
2 2: b
|
|
|
|
|
3 3: cC
|
|
|
|
|
4 4: d
|
|
|
|
|
=== No gap to skip
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: a
|
|
|
|
|
2 2: bB
|
|
|
|
|
3 3: cC
|
|
|
|
|
4 4: d
|
|
|
|
|
=== 1 line at start
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: a
|
|
|
|
|
2 2: bB
|
|
|
|
|
...
|
|
|
|
|
=== 1 line at end
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
3 3: cC
|
|
|
|
|
4 4: d
|
|
|
|
|
"###);
|
2024-06-30 11:28:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_leading_trailing_context() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
// N=5 context lines at start/end of the file
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join("file1"),
|
|
|
|
|
"1\n2\n3\n4\n5\nL\n6\n7\n8\n9\n10\n11\n",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::write(
|
|
|
|
|
repo_path.join("file1"),
|
|
|
|
|
"1\n2\n3\n4\n5\n6\nR\n7\n8\n9\n10\n11\n",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// N=5 <= num_context_lines + 1: No room to skip.
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--context=4"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
1 1: 1
|
|
|
|
|
2 2: 2
|
|
|
|
|
3 3: 3
|
|
|
|
|
4 4: 4
|
|
|
|
|
5 5: 5
|
|
|
|
|
6 : L
|
|
|
|
|
7 6: 6
|
|
|
|
|
7: R
|
|
|
|
|
8 8: 7
|
|
|
|
|
9 9: 8
|
|
|
|
|
10 10: 9
|
|
|
|
|
11 11: 10
|
|
|
|
|
12 12: 11
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// N=5 <= 2 * num_context_lines + 1: The last hunk wouldn't be split if
|
|
|
|
|
// trailing diff existed.
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--context=3"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
3 3: 3
|
|
|
|
|
4 4: 4
|
|
|
|
|
5 5: 5
|
|
|
|
|
6 : L
|
|
|
|
|
7 6: 6
|
|
|
|
|
7: R
|
|
|
|
|
8 8: 7
|
|
|
|
|
9 9: 8
|
|
|
|
|
10 10: 9
|
|
|
|
|
...
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// N=5 > 2 * num_context_lines + 1: The last hunk should be split no matter
|
|
|
|
|
// if trailing diff existed.
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--context=1"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Modified regular file file1:
|
|
|
|
|
...
|
|
|
|
|
5 5: 5
|
|
|
|
|
6 : L
|
|
|
|
|
7 6: 6
|
|
|
|
|
7: R
|
|
|
|
|
8 8: 7
|
|
|
|
|
...
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// N=5 <= num_context_lines: No room to skip.
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--context=5"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index 1bf57dee4a..69b3e1865c 100644
|
2024-06-30 11:28:32 +00:00
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -1,12 +1,12 @@
|
|
|
|
|
1
|
|
|
|
|
2
|
|
|
|
|
3
|
|
|
|
|
4
|
|
|
|
|
5
|
|
|
|
|
-L
|
|
|
|
|
6
|
|
|
|
|
+R
|
|
|
|
|
7
|
|
|
|
|
8
|
|
|
|
|
9
|
|
|
|
|
10
|
|
|
|
|
11
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// N=5 <= 2 * num_context_lines: The last hunk wouldn't be split if
|
|
|
|
|
// trailing diff existed.
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--context=3"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index 1bf57dee4a..69b3e1865c 100644
|
2024-06-30 11:28:32 +00:00
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
2024-06-30 11:54:49 +00:00
|
|
|
|
@@ -3,8 +3,8 @@
|
2024-06-30 11:28:32 +00:00
|
|
|
|
3
|
|
|
|
|
4
|
|
|
|
|
5
|
|
|
|
|
-L
|
|
|
|
|
6
|
|
|
|
|
+R
|
|
|
|
|
7
|
|
|
|
|
8
|
|
|
|
|
9
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// N=5 > 2 * num_context_lines: The last hunk should be split no matter
|
|
|
|
|
// if trailing diff existed.
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git", "--context=2"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1 b/file1
|
2024-07-14 10:26:07 +00:00
|
|
|
|
index 1bf57dee4a..69b3e1865c 100644
|
2024-06-30 11:28:32 +00:00
|
|
|
|
--- a/file1
|
|
|
|
|
+++ b/file1
|
|
|
|
|
@@ -4,6 +4,6 @@
|
|
|
|
|
4
|
|
|
|
|
5
|
|
|
|
|
-L
|
|
|
|
|
6
|
|
|
|
|
+R
|
|
|
|
|
7
|
|
|
|
|
8
|
|
|
|
|
"###);
|
2024-03-02 00:57:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-02 03:12:11 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_external_tool() {
|
|
|
|
|
let mut test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-08-02 03:12:11 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "foo\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2023-08-02 03:12:11 +00:00
|
|
|
|
std::fs::remove_file(repo_path.join("file1")).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "foo\nbar\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3"), "foo\n").unwrap();
|
|
|
|
|
|
|
|
|
|
let edit_script = test_env.set_up_fake_diff_editor();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
&edit_script,
|
|
|
|
|
"print-files-before\0print --\0print-files-after",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// diff without file patterns
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", "--tool=fake-diff-editor"]), @r###"
|
|
|
|
|
file1
|
|
|
|
|
file2
|
|
|
|
|
--
|
|
|
|
|
file2
|
|
|
|
|
file3
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// diff with file patterns
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", "--tool=fake-diff-editor", "file1"]), @r###"
|
|
|
|
|
file1
|
|
|
|
|
--
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["log", "-p", "--tool=fake-diff-editor"]), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
@ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 39d9055d
|
2023-08-02 03:12:11 +00:00
|
|
|
|
│ (no description set)
|
|
|
|
|
│ file1
|
|
|
|
|
│ file2
|
|
|
|
|
│ --
|
|
|
|
|
│ file2
|
|
|
|
|
│ file3
|
2024-07-15 22:20:10 +00:00
|
|
|
|
○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 0ad4ef22
|
2023-08-02 03:12:11 +00:00
|
|
|
|
│ (no description set)
|
|
|
|
|
│ --
|
|
|
|
|
│ file1
|
|
|
|
|
│ file2
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ zzzzzzzz root() 00000000
|
2023-08-02 03:12:11 +00:00
|
|
|
|
--
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["show", "--tool=fake-diff-editor"]), @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Commit ID: 39d9055d70873099fd924b9af218289d5663eac8
|
2023-08-02 03:12:11 +00:00
|
|
|
|
Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Author: Test User <test.user@example.com> (2001-02-03 08:05:09)
|
2024-02-12 07:26:19 +00:00
|
|
|
|
Committer: Test User <test.user@example.com> (2001-02-03 08:05:09)
|
2023-08-02 03:12:11 +00:00
|
|
|
|
|
|
|
|
|
(no description set)
|
|
|
|
|
|
|
|
|
|
file1
|
|
|
|
|
file2
|
|
|
|
|
--
|
|
|
|
|
file2
|
|
|
|
|
file3
|
|
|
|
|
"###);
|
|
|
|
|
|
2023-08-03 22:25:22 +00:00
|
|
|
|
// Enabled by default, looks up the merge-tools table
|
|
|
|
|
let config = "--config-toml=ui.diff.tool='fake-diff-editor'";
|
|
|
|
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", config]), @r###"
|
|
|
|
|
file1
|
|
|
|
|
file2
|
|
|
|
|
--
|
|
|
|
|
file2
|
|
|
|
|
file3
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Inlined command arguments
|
2024-02-02 07:55:24 +00:00
|
|
|
|
let command = escaped_fake_diff_editor_path();
|
2023-08-03 22:25:22 +00:00
|
|
|
|
let config = format!(r#"--config-toml=ui.diff.tool=["{command}", "$right", "$left"]"#);
|
|
|
|
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["diff", &config]), @r###"
|
|
|
|
|
file2
|
|
|
|
|
file3
|
|
|
|
|
--
|
|
|
|
|
file1
|
|
|
|
|
file2
|
|
|
|
|
"###);
|
|
|
|
|
|
2023-08-02 03:12:11 +00:00
|
|
|
|
// Output of external diff tool shouldn't be escaped
|
|
|
|
|
std::fs::write(&edit_script, "print \x1b[1;31mred").unwrap();
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", "--color=always", "--tool=fake-diff-editor"]),
|
|
|
|
|
@r###"
|
|
|
|
|
[1;31mred
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Non-zero exit code isn't an error
|
|
|
|
|
std::fs::write(&edit_script, "print diff\0fail").unwrap();
|
2023-08-10 23:36:37 +00:00
|
|
|
|
let (stdout, stderr) = test_env.jj_cmd_ok(&repo_path, &["show", "--tool=fake-diff-editor"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Commit ID: 39d9055d70873099fd924b9af218289d5663eac8
|
2023-08-02 03:12:11 +00:00
|
|
|
|
Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp
|
2024-06-23 22:20:33 +00:00
|
|
|
|
Author: Test User <test.user@example.com> (2001-02-03 08:05:09)
|
2024-02-12 07:26:19 +00:00
|
|
|
|
Committer: Test User <test.user@example.com> (2001-02-03 08:05:09)
|
2023-08-02 03:12:11 +00:00
|
|
|
|
|
|
|
|
|
(no description set)
|
|
|
|
|
|
|
|
|
|
diff
|
|
|
|
|
"###);
|
2024-05-14 00:33:15 +00:00
|
|
|
|
insta::assert_snapshot!(stderr.replace("exit code:", "exit status:"), @r###"
|
|
|
|
|
Warning: Tool exited with exit status: 1 (run with --debug to see the exact invocation)
|
2023-08-10 23:36:37 +00:00
|
|
|
|
"###);
|
2024-02-28 11:46:57 +00:00
|
|
|
|
|
|
|
|
|
// --tool=:builtin shouldn't be ignored
|
|
|
|
|
let stderr = test_env.jj_cmd_failure(&repo_path, &["diff", "--tool=:builtin"]);
|
|
|
|
|
insta::assert_snapshot!(strip_last_line(&stderr), @r###"
|
|
|
|
|
Error: Failed to generate diff
|
|
|
|
|
Caused by:
|
|
|
|
|
1: Error executing ':builtin' (run with --debug to see the exact invocation)
|
|
|
|
|
"###);
|
2023-08-02 03:12:11 +00:00
|
|
|
|
}
|
2023-08-13 19:30:57 +00:00
|
|
|
|
|
2024-06-27 15:53:14 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_external_file_by_file_tool() {
|
|
|
|
|
let mut test_env = TestEnvironment::default();
|
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
2024-08-06 18:04:58 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "file1\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2"), "file2\n").unwrap();
|
2024-06-27 15:53:14 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::remove_file(repo_path.join("file1")).unwrap();
|
2024-08-06 18:04:58 +00:00
|
|
|
|
std::fs::write(repo_path.join("file2"), "file2\nfile2\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3"), "file3\n").unwrap();
|
2024-08-15 15:22:34 +00:00
|
|
|
|
std::fs::write(repo_path.join("file4"), "file1\n").unwrap();
|
2024-06-27 15:53:14 +00:00
|
|
|
|
|
|
|
|
|
let edit_script = test_env.set_up_fake_diff_editor();
|
|
|
|
|
std::fs::write(
|
|
|
|
|
edit_script,
|
|
|
|
|
"print ==\0print-files-before\0print --\0print-files-after",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Enabled by default, looks up the merge-tools table
|
|
|
|
|
let config = "--config-toml=ui.diff.tool='fake-diff-editor'\nmerge-tools.fake-diff-editor.\
|
|
|
|
|
diff-invocation-mode='file-by-file'";
|
|
|
|
|
|
|
|
|
|
// diff without file patterns
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", config]), @r###"
|
|
|
|
|
==
|
|
|
|
|
file2
|
|
|
|
|
--
|
|
|
|
|
file2
|
|
|
|
|
==
|
|
|
|
|
file3
|
|
|
|
|
--
|
|
|
|
|
file3
|
2024-08-15 15:22:34 +00:00
|
|
|
|
==
|
|
|
|
|
file1
|
|
|
|
|
--
|
|
|
|
|
file4
|
2024-06-27 15:53:14 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// diff with file patterns
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", config, "file1"]), @r###"
|
|
|
|
|
==
|
|
|
|
|
file1
|
|
|
|
|
--
|
|
|
|
|
file1
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["log", "-p", config]), @r###"
|
2024-08-15 15:22:34 +00:00
|
|
|
|
@ rlvkpnrz test.user@example.com 2001-02-03 08:05:09 7b01704a
|
2024-06-27 15:53:14 +00:00
|
|
|
|
│ (no description set)
|
|
|
|
|
│ ==
|
|
|
|
|
│ file2
|
|
|
|
|
│ --
|
|
|
|
|
│ file2
|
|
|
|
|
│ ==
|
|
|
|
|
│ file3
|
|
|
|
|
│ --
|
|
|
|
|
│ file3
|
2024-08-15 15:22:34 +00:00
|
|
|
|
│ ==
|
|
|
|
|
│ file1
|
|
|
|
|
│ --
|
|
|
|
|
│ file4
|
2024-08-06 18:04:58 +00:00
|
|
|
|
○ qpvuntsm test.user@example.com 2001-02-03 08:05:08 6e485984
|
2024-06-27 15:53:14 +00:00
|
|
|
|
│ (no description set)
|
|
|
|
|
│ ==
|
|
|
|
|
│ file1
|
|
|
|
|
│ --
|
|
|
|
|
│ file1
|
|
|
|
|
│ ==
|
|
|
|
|
│ file2
|
|
|
|
|
│ --
|
|
|
|
|
│ file2
|
2024-07-15 22:20:10 +00:00
|
|
|
|
◆ zzzzzzzz root() 00000000
|
2024-06-27 15:53:14 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["show", config]), @r###"
|
2024-08-15 15:22:34 +00:00
|
|
|
|
Commit ID: 7b01704a670bc77d11ed117d362855cff1d4513b
|
2024-06-27 15:53:14 +00:00
|
|
|
|
Change ID: rlvkpnrzqnoowoytxnquwvuryrwnrmlp
|
|
|
|
|
Author: Test User <test.user@example.com> (2001-02-03 08:05:09)
|
|
|
|
|
Committer: Test User <test.user@example.com> (2001-02-03 08:05:09)
|
|
|
|
|
|
|
|
|
|
(no description set)
|
|
|
|
|
|
|
|
|
|
==
|
|
|
|
|
file2
|
|
|
|
|
--
|
|
|
|
|
file2
|
|
|
|
|
==
|
|
|
|
|
file3
|
|
|
|
|
--
|
|
|
|
|
file3
|
2024-08-15 15:22:34 +00:00
|
|
|
|
==
|
|
|
|
|
file1
|
|
|
|
|
--
|
|
|
|
|
file4
|
2024-06-27 15:53:14 +00:00
|
|
|
|
"###);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-05 06:07:24 +00:00
|
|
|
|
#[cfg(unix)]
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_external_tool_symlink() {
|
|
|
|
|
let mut test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-11-05 06:07:24 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
let external_file_path = test_env.env_root().join("external-file");
|
|
|
|
|
std::fs::write(&external_file_path, "").unwrap();
|
|
|
|
|
let external_file_permissions = external_file_path.symlink_metadata().unwrap().permissions();
|
|
|
|
|
|
|
|
|
|
std::os::unix::fs::symlink("non-existent1", repo_path.join("dead")).unwrap();
|
|
|
|
|
std::os::unix::fs::symlink(&external_file_path, repo_path.join("file")).unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::remove_file(repo_path.join("dead")).unwrap();
|
|
|
|
|
std::os::unix::fs::symlink("non-existent2", repo_path.join("dead")).unwrap();
|
|
|
|
|
std::fs::remove_file(repo_path.join("file")).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file"), "").unwrap();
|
|
|
|
|
|
|
|
|
|
let edit_script = test_env.set_up_fake_diff_editor();
|
|
|
|
|
std::fs::write(
|
2023-11-16 17:12:39 +00:00
|
|
|
|
edit_script,
|
2023-11-05 06:07:24 +00:00
|
|
|
|
"print-files-before\0print --\0print-files-after",
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
// Shouldn't try to change permission of symlinks
|
|
|
|
|
insta::assert_snapshot!(
|
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", "--tool=fake-diff-editor"]), @r###"
|
|
|
|
|
dead
|
|
|
|
|
file
|
|
|
|
|
--
|
|
|
|
|
dead
|
|
|
|
|
file
|
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// External file should be intact
|
|
|
|
|
assert_eq!(
|
|
|
|
|
external_file_path.symlink_metadata().unwrap().permissions(),
|
|
|
|
|
external_file_permissions
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-13 19:30:57 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_stat() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo\n").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
file1 | 1 +
|
|
|
|
|
1 file changed, 1 insertion(+), 0 deletions(-)
|
|
|
|
|
"###);
|
|
|
|
|
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @"0 files changed, 0 insertions(+), 0 deletions(-)");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1"), "foo\nbar\n").unwrap();
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
2023-08-13 19:30:57 +00:00
|
|
|
|
std::fs::write(repo_path.join("file1"), "bar\n").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
file1 | 1 -
|
|
|
|
|
1 file changed, 0 insertions(+), 1 deletion(-)
|
|
|
|
|
"###);
|
|
|
|
|
}
|
2023-08-30 22:48:41 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_stat_long_name_or_stat() {
|
|
|
|
|
let mut test_env = TestEnvironment::default();
|
2023-08-31 04:17:50 +00:00
|
|
|
|
test_env.add_env_var("COLUMNS", "30");
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2023-08-30 22:48:41 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
2023-08-31 00:48:18 +00:00
|
|
|
|
let get_stat = |test_env: &TestEnvironment, path_length: usize, stat_size: usize| {
|
2023-10-10 11:59:18 +00:00
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new", "root()"]);
|
2023-09-01 06:53:41 +00:00
|
|
|
|
let ascii_name = "1234567890".chars().cycle().take(path_length).join("");
|
|
|
|
|
let han_name = "一二三四五六七八九十"
|
2023-08-31 04:17:50 +00:00
|
|
|
|
.chars()
|
|
|
|
|
.cycle()
|
|
|
|
|
.take(path_length)
|
|
|
|
|
.join("");
|
2023-08-30 22:48:41 +00:00
|
|
|
|
let content = "content line\n".repeat(stat_size);
|
2023-09-01 06:53:41 +00:00
|
|
|
|
std::fs::write(repo_path.join(ascii_name), &content).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join(han_name), &content).unwrap();
|
2023-08-30 22:48:41 +00:00
|
|
|
|
test_env.jj_cmd_success(&repo_path, &["diff", "--stat"])
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-31 00:48:18 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 1, 1), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
1 | 1 +
|
2023-09-01 06:28:37 +00:00
|
|
|
|
一 | 1 +
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 2 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 00:48:18 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 1, 10), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
1 | 10 ++++++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
一 | 10 ++++++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 00:48:18 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 1, 100), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
1 | 100 +++++++++++++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
一 | 100 +++++++++++++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 00:48:18 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 10, 1), @r###"
|
2023-09-01 06:28:37 +00:00
|
|
|
|
1234567890 | 1 +
|
|
|
|
|
...五六七八九十 | 1 +
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 2 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 00:48:18 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 10, 10), @r###"
|
2023-09-01 06:28:37 +00:00
|
|
|
|
1234567890 | 10 +++++++
|
|
|
|
|
...六七八九十 | 10 +++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 00:48:18 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 10, 100), @r###"
|
2023-09-01 06:28:37 +00:00
|
|
|
|
1234567890 | 100 ++++++
|
|
|
|
|
...六七八九十 | 100 ++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 04:17:50 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 50, 1), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
...901234567890 | 1 +
|
2023-09-01 06:28:37 +00:00
|
|
|
|
...五六七八九十 | 1 +
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 2 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 04:17:50 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 50, 10), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
...01234567890 | 10 +++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
...六七八九十 | 10 +++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 04:17:50 +00:00
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 50, 100), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
...01234567890 | 100 ++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
...六七八九十 | 100 ++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-31 00:56:10 +00:00
|
|
|
|
"###);
|
|
|
|
|
|
|
|
|
|
// Lengths around where we introduce the ellipsis
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 13, 100), @r###"
|
2023-09-01 06:28:37 +00:00
|
|
|
|
1234567890123 | 100 ++++++
|
|
|
|
|
...九十一二三 | 100 ++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-31 00:56:10 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 14, 100), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
12345678901234 | 100 ++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
...十一二三四 | 100 ++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-31 00:56:10 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 15, 100), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
...56789012345 | 100 ++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
...一二三四五 | 100 ++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-31 00:56:10 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 16, 100), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
...67890123456 | 100 ++++++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
...二三四五六 | 100 ++++++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 200 insertions(+), 0 deletions(-)
|
2023-08-30 22:48:41 +00:00
|
|
|
|
"###);
|
2023-08-31 00:48:18 +00:00
|
|
|
|
|
|
|
|
|
// Very narrow terminal (doesn't have to fit, just don't crash)
|
|
|
|
|
test_env.add_env_var("COLUMNS", "10");
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 10, 10), @r###"
|
2023-08-31 00:56:10 +00:00
|
|
|
|
... | 10 ++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
... | 10 ++
|
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
2023-08-31 00:48:18 +00:00
|
|
|
|
"###);
|
|
|
|
|
test_env.add_env_var("COLUMNS", "3");
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 10, 10), @r###"
|
2023-08-31 00:56:10 +00:00
|
|
|
|
... | 10 ++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
... | 10 ++
|
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
2023-08-31 00:56:10 +00:00
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 3, 10), @r###"
|
2023-09-01 06:53:41 +00:00
|
|
|
|
123 | 10 ++
|
2023-09-01 06:28:37 +00:00
|
|
|
|
... | 10 ++
|
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
|
|
|
|
"###);
|
|
|
|
|
insta::assert_snapshot!(get_stat(&test_env, 1, 10), @r###"
|
|
|
|
|
1 | 10 ++
|
|
|
|
|
一 | 10 ++
|
2023-09-01 06:53:41 +00:00
|
|
|
|
2 files changed, 20 insertions(+), 0 deletions(-)
|
2023-08-31 00:48:18 +00:00
|
|
|
|
"###);
|
2023-08-30 22:48:41 +00:00
|
|
|
|
}
|
2024-02-02 06:26:24 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_diff_binary() {
|
|
|
|
|
let test_env = TestEnvironment::default();
|
2024-05-17 19:49:25 +00:00
|
|
|
|
test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]);
|
2024-02-02 06:26:24 +00:00
|
|
|
|
let repo_path = test_env.env_root().join("repo");
|
|
|
|
|
|
|
|
|
|
std::fs::write(repo_path.join("file1.png"), b"\x89PNG\r\n\x1a\nabcdefg\0").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2.png"), b"\x89PNG\r\n\x1a\n0123456\0").unwrap();
|
|
|
|
|
test_env.jj_cmd_ok(&repo_path, &["new"]);
|
|
|
|
|
std::fs::remove_file(repo_path.join("file1.png")).unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file2.png"), "foo\nbar\n").unwrap();
|
|
|
|
|
std::fs::write(repo_path.join("file3.png"), b"\x89PNG\r\n\x1a\nxyz\0").unwrap();
|
|
|
|
|
// try a file that's valid UTF-8 but contains control characters
|
|
|
|
|
std::fs::write(repo_path.join("file4.png"), b"\0\0\0").unwrap();
|
|
|
|
|
|
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
Removed regular file file1.png:
|
|
|
|
|
(binary)
|
|
|
|
|
Modified regular file file2.png:
|
|
|
|
|
(binary)
|
|
|
|
|
Added regular file file3.png:
|
|
|
|
|
(binary)
|
|
|
|
|
Added regular file file4.png:
|
|
|
|
|
(binary)
|
|
|
|
|
"###);
|
|
|
|
|
|
2024-07-14 10:49:57 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--git"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
diff --git a/file1.png b/file1.png
|
|
|
|
|
deleted file mode 100644
|
|
|
|
|
index 2b65b23c22..0000000000
|
|
|
|
|
Binary files a/file1.png and /dev/null differ
|
|
|
|
|
diff --git a/file2.png b/file2.png
|
|
|
|
|
index 7f036ce788..3bd1f0e297 100644
|
|
|
|
|
Binary files a/file2.png and b/file2.png differ
|
|
|
|
|
diff --git a/file3.png b/file3.png
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000000..deacfbc286
|
|
|
|
|
Binary files /dev/null and b/file3.png differ
|
|
|
|
|
diff --git a/file4.png b/file4.png
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000000..4227ca4e87
|
|
|
|
|
Binary files /dev/null and b/file4.png differ
|
|
|
|
|
"###);
|
|
|
|
|
|
2024-02-02 06:26:24 +00:00
|
|
|
|
let stdout = test_env.jj_cmd_success(&repo_path, &["diff", "--stat"]);
|
|
|
|
|
insta::assert_snapshot!(stdout, @r###"
|
|
|
|
|
file1.png | 3 ---
|
|
|
|
|
file2.png | 5 ++---
|
|
|
|
|
file3.png | 3 +++
|
|
|
|
|
file4.png | 1 +
|
|
|
|
|
4 files changed, 6 insertions(+), 6 deletions(-)
|
|
|
|
|
"###);
|
|
|
|
|
}
|