Skip to content

Commit 1aa079b

Browse files
committed
templates: Expose copy/move path formatting in template language
1 parent a1c9c3d commit 1aa079b

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ should not be broken.
101101
* Added `join()` template function. This is different from `separate()` in that
102102
it adds a separator between all arguments, even if empty.
103103

104+
* `TreeDiffEntry` type now has a `formatted_path()` method that formats
105+
renames/copies appropriately.
106+
104107
### Fixed bugs
105108

106109
* `jj fix` now prints a warning if a tool failed to run on a file.

cli/src/commit_templater.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2399,6 +2399,21 @@ fn builtin_tree_diff_entry_methods<'repo>() -> CommitTemplateBuildMethodFnMap<'r
23992399
Ok(out_property.into_dyn_wrapped())
24002400
},
24012401
);
2402+
map.insert(
2403+
"formatted_path",
2404+
|language, _diagnostics, _build_ctx, self_property, function| {
2405+
function.expect_no_arguments()?;
2406+
let path_converter = language.path_converter;
2407+
let out_property = self_property.map(move |entry| {
2408+
if entry.path.copy_operation().is_some() {
2409+
path_converter.format_copied_path(entry.path.source(), entry.path.target())
2410+
} else {
2411+
path_converter.format_file_path(entry.path.target())
2412+
}
2413+
});
2414+
Ok(out_property.into_dyn_wrapped())
2415+
},
2416+
);
24022417
// TODO: add status_code() or status_char()?
24032418
map.insert(
24042419
"source",

cli/tests/test_commit_template.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,58 @@ fn test_log_diff_predefined_formats() {
14401440
");
14411441
}
14421442

1443+
#[test]
1444+
fn test_log_diff_formatted_path() {
1445+
let test_env = TestEnvironment::default();
1446+
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
1447+
let work_dir = test_env.work_dir("repo");
1448+
1449+
// Create a structure with nested directories.
1450+
work_dir.create_dir("src");
1451+
work_dir.create_dir("src/old");
1452+
work_dir.create_dir("src/new");
1453+
work_dir.write_file("src/old/file.rs", "content");
1454+
work_dir.write_file("src/common.rs", "content");
1455+
work_dir.write_file("top.txt", "content");
1456+
work_dir.run_jj(["commit", "-m", "initial"]).success();
1457+
1458+
// Rename within nested directory (common prefix/suffix).
1459+
work_dir
1460+
.run_jj(["file", "track", "src/new/file.rs"])
1461+
.success();
1462+
work_dir.write_file("src/new/file.rs", "content");
1463+
std::fs::remove_file(work_dir.root().join("src/old/file.rs")).unwrap();
1464+
work_dir.run_jj(["commit", "-m", "rename nested"]).success();
1465+
1466+
// Rename at top level.
1467+
work_dir.run_jj(["file", "track", "renamed.txt"]).success();
1468+
work_dir.write_file("renamed.txt", "content");
1469+
std::fs::remove_file(work_dir.root().join("top.txt")).unwrap();
1470+
work_dir.run_jj(["commit", "-m", "rename top"]).success();
1471+
1472+
// Test formatted_path() shows compact format for renames.
1473+
let template = indoc! {r#"
1474+
concat(
1475+
description.first_line() ++ ":\n",
1476+
diff.files().map(|e|
1477+
e.formatted_path() ++ " [" ++ e.status() ++ "]\n"
1478+
).join(""),
1479+
)
1480+
"#};
1481+
let output = work_dir.run_jj(["log", "--no-graph", "-r", "::@- & ~root()", "-T", template]);
1482+
insta::assert_snapshot!(output, @r"
1483+
rename top:
1484+
{top.txt => renamed.txt} [renamed]
1485+
rename nested:
1486+
src/{old => new}/file.rs [renamed]
1487+
initial:
1488+
src/common.rs [added]
1489+
src/old/file.rs [added]
1490+
top.txt [added]
1491+
[EOF]
1492+
");
1493+
}
1494+
14431495
#[test]
14441496
fn test_file_list_entries() {
14451497
let test_env = TestEnvironment::default();

docs/templates.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,9 @@ This type cannot be printed. The following methods are defined.
603603
points to the target (or right) entry.
604604
* `.status() -> String`: One of `"modified"`, `"added"`, `"removed"`,
605605
`"copied"`, or `"renamed"`.
606+
* `.formatted_path() -> String`: Formatted path with common prefix/suffix extraction
607+
for renames and copies. For example, `src/{old => new}/file.rs` instead of showing
608+
full paths. For non-copy/rename operations, equivalent to `.path()`.
606609
* `.source() -> TreeEntry`: The source (or left) entry.
607610
* `.target() -> TreeEntry`: The target (or right) entry.
608611

0 commit comments

Comments
 (0)