mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-26 22:10:52 +00:00
jj resolve --list
: make output colorful
The description is usually in yellow, which looks nice and neutral. If the conflict has more than 2 sides or has special files, that's marked in red.
This commit is contained in:
parent
89de9aeae1
commit
fc9795e902
3 changed files with 67 additions and 17 deletions
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::collections::{BTreeSet, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -2448,12 +2448,16 @@ fn print_conflicted_paths(
|
||||||
let sides = n_adds.max(conflict.removes.len() + 1);
|
let sides = n_adds.max(conflict.removes.len() + 1);
|
||||||
let deletions = sides - n_adds;
|
let deletions = sides - n_adds;
|
||||||
|
|
||||||
let mut seen_objects = BTreeSet::new(); // Sort for consistency and easier testing
|
let mut seen_objects = BTreeMap::new(); // Sort for consistency and easier testing
|
||||||
if deletions > 0 {
|
if deletions > 0 {
|
||||||
seen_objects.insert(format!(
|
seen_objects.insert(
|
||||||
"{deletions} deletion{}",
|
format!(
|
||||||
if deletions > 1 { "s" } else { "" }
|
// Starting with a number sorts this first
|
||||||
));
|
"{deletions} deletion{}",
|
||||||
|
if deletions > 1 { "s" } else { "" }
|
||||||
|
),
|
||||||
|
"normal", // Deletions don't interfere with `jj resolve` or diff display
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// TODO: We might decide it's OK for `jj resolve` to ignore special files in the
|
// TODO: We might decide it's OK for `jj resolve` to ignore special files in the
|
||||||
// `removes` of a conflict (see e.g. https://github.com/martinvonz/jj/pull/978). In
|
// `removes` of a conflict (see e.g. https://github.com/martinvonz/jj/pull/978). In
|
||||||
|
@ -2473,21 +2477,48 @@ fn print_conflicted_paths(
|
||||||
TreeValue::Conflict(_) => "another conflict (you found a bug!)",
|
TreeValue::Conflict(_) => "another conflict (you found a bug!)",
|
||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
"difficult",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let seen_objects = seen_objects.into_iter().collect_vec();
|
|
||||||
let msg_tail = match &seen_objects[..] {
|
|
||||||
[] => "".to_string(),
|
|
||||||
[only] => format!(" including {only}"),
|
|
||||||
[first @ .., last] => format!(" including {} and {}", first.join(", "), last),
|
|
||||||
};
|
|
||||||
let msg = format!("{sides}-sided conflict{msg_tail}");
|
|
||||||
|
|
||||||
writeln!(
|
write!(
|
||||||
formatter,
|
formatter,
|
||||||
"{}\t{msg}",
|
"{}\t",
|
||||||
&workspace_command.format_file_path(repo_path)
|
&workspace_command.format_file_path(repo_path)
|
||||||
)?;
|
)?;
|
||||||
|
formatter.with_label("conflict_description", |formatter| {
|
||||||
|
let print_pair = |formatter: &mut dyn Formatter, (text, label): &(String, &str)| {
|
||||||
|
formatter.with_label(label, |fmt| fmt.write_str(text))
|
||||||
|
};
|
||||||
|
print_pair(
|
||||||
|
formatter,
|
||||||
|
&(
|
||||||
|
format!("{sides}-sided"),
|
||||||
|
if sides > 2 { "difficult" } else { "normal" },
|
||||||
|
),
|
||||||
|
)?;
|
||||||
|
formatter.write_str(" conflict")?;
|
||||||
|
|
||||||
|
if !seen_objects.is_empty() {
|
||||||
|
formatter.write_str(" including ")?;
|
||||||
|
let seen_objects = seen_objects.into_iter().collect_vec();
|
||||||
|
match &seen_objects[..] {
|
||||||
|
[] => unreachable!(),
|
||||||
|
[only] => print_pair(formatter, only)?,
|
||||||
|
[first, middle @ .., last] => {
|
||||||
|
print_pair(formatter, first)?;
|
||||||
|
for pair in middle {
|
||||||
|
formatter.write_str(", ")?;
|
||||||
|
print_pair(formatter, pair)?;
|
||||||
|
}
|
||||||
|
formatter.write_str(" and ")?;
|
||||||
|
print_pair(formatter, last)?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
writeln!(formatter)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
"warning" = "yellow"
|
"warning" = "yellow"
|
||||||
"hint" = "blue"
|
"hint" = "blue"
|
||||||
|
|
||||||
|
"conflict_description" = "yellow"
|
||||||
|
"conflict_description difficult" = "red"
|
||||||
|
|
||||||
"commit_id" = "blue"
|
"commit_id" = "blue"
|
||||||
"change_id" = "magenta"
|
"change_id" = "magenta"
|
||||||
"author" = "yellow"
|
"author" = "yellow"
|
||||||
|
|
|
@ -375,6 +375,11 @@ fn test_too_many_parents() {
|
||||||
create_commit(&test_env, &repo_path, "conflict", &["a", "b", "c"], &[]);
|
create_commit(&test_env, &repo_path, "conflict", &["a", "b", "c"], &[]);
|
||||||
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]),
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list"]),
|
||||||
@"file 3-sided conflict");
|
@"file 3-sided conflict");
|
||||||
|
// Test warning color
|
||||||
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list", "--color=always"]),
|
||||||
|
@r###"
|
||||||
|
file [33m[31m3-sided[33m conflict[0m
|
||||||
|
"###);
|
||||||
|
|
||||||
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
||||||
insta::assert_snapshot!(error, @r###"
|
insta::assert_snapshot!(error, @r###"
|
||||||
|
@ -502,6 +507,11 @@ fn test_description_with_dir_and_deletion() {
|
||||||
@r###"
|
@r###"
|
||||||
file 3-sided conflict including 1 deletion and a directory
|
file 3-sided conflict including 1 deletion and a directory
|
||||||
"###);
|
"###);
|
||||||
|
// Test warning color. The deletion is fine, so it's not highlighted
|
||||||
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list", "--color=always"]),
|
||||||
|
@r###"
|
||||||
|
file [33m[31m3-sided[33m conflict including 1 deletion and [31ma directory[33m[0m
|
||||||
|
"###);
|
||||||
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
let error = test_env.jj_cmd_failure(&repo_path, &["resolve"]);
|
||||||
insta::assert_snapshot!(error, @r###"
|
insta::assert_snapshot!(error, @r###"
|
||||||
Error: Failed to use external tool to resolve: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file":
|
Error: Failed to use external tool to resolve: Only conflicts that involve normal files (not symlinks, not executable, etc.) are supported. Conflict summary for "file":
|
||||||
|
@ -579,6 +589,12 @@ fn test_multiple_conflicts() {
|
||||||
file1 2-sided conflict
|
file1 2-sided conflict
|
||||||
file2 2-sided conflict
|
file2 2-sided conflict
|
||||||
"###);
|
"###);
|
||||||
|
// Test colors
|
||||||
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["resolve", "--list", "--color=always"]),
|
||||||
|
@r###"
|
||||||
|
file1 [33m2-sided conflict[0m
|
||||||
|
file2 [33m2-sided conflict[0m
|
||||||
|
"###);
|
||||||
|
|
||||||
let editor_script = test_env.set_up_fake_editor();
|
let editor_script = test_env.set_up_fake_editor();
|
||||||
|
|
||||||
|
@ -586,7 +602,7 @@ fn test_multiple_conflicts() {
|
||||||
std::fs::write(&editor_script, "expect\n\0write\nresolution file2\n").unwrap();
|
std::fs::write(&editor_script, "expect\n\0write\nresolution file2\n").unwrap();
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
test_env.jj_cmd_success(&repo_path, &["resolve", "file2"]), @r###"
|
test_env.jj_cmd_success(&repo_path, &["resolve", "file2"]), @r###"
|
||||||
Working copy now at: 06cafc2b5489 conflict
|
Working copy now at: 5b4465fc6c31 conflict
|
||||||
Added 0 files, modified 1 files, removed 0 files
|
Added 0 files, modified 1 files, removed 0 files
|
||||||
After this operation, some files at this revision still have conflicts:
|
After this operation, some files at this revision still have conflicts:
|
||||||
file1 2-sided conflict
|
file1 2-sided conflict
|
||||||
|
@ -610,7 +626,7 @@ fn test_multiple_conflicts() {
|
||||||
std::fs::write(&editor_script, "expect\n\0write\nresolution file2\n").unwrap();
|
std::fs::write(&editor_script, "expect\n\0write\nresolution file2\n").unwrap();
|
||||||
insta::assert_snapshot!(
|
insta::assert_snapshot!(
|
||||||
test_env.jj_cmd_success(&repo_path, &["resolve", "--quiet", "file2"]), @r###"
|
test_env.jj_cmd_success(&repo_path, &["resolve", "--quiet", "file2"]), @r###"
|
||||||
Working copy now at: 02326c070aa4 conflict
|
Working copy now at: afb1b8512e98 conflict
|
||||||
Added 0 files, modified 1 files, removed 0 files
|
Added 0 files, modified 1 files, removed 0 files
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue