summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristoffer Balintona <krisbalintona@gmail.com>2026-04-27 16:50:36 -0500
committerKristoffer Balintona <krisbalintona@gmail.com>2026-04-27 17:03:33 -0500
commit03ab3ba867905fa2cf565209ac70e6df8e70c967 (patch)
tree6a75c526a93adfe98892d3efc4e0ee1de575e0b1
parent1407704c50b27f99f4a44a6622e96e79850deca8 (diff)
fix: Address edge case in file rename tracking in vc-dir buffersexternals/vc-jj
Also add a new test case for it.
-rw-r--r--vc-jj-tests.el23
-rw-r--r--vc-jj.el28
2 files changed, 39 insertions, 12 deletions
diff --git a/vc-jj-tests.el b/vc-jj-tests.el
index 1155ecf..389635b 100644
--- a/vc-jj-tests.el
+++ b/vc-jj-tests.el
@@ -291,7 +291,7 @@ When a file is renamed, its old file path should have a VC state of
When a directory is renamed, the files contained within it are reported
along the same lines."
- ;; Rename file
+ ;; Rename root-level file
(vc-jj-test--with-repo repo
;; 2026-04-26: It seems like Jujutsu's rename detection requires
;; file content to identify a single-file rename: without content,
@@ -311,7 +311,26 @@ along the same lines."
("after rename.txt" added ( :rename-state added
:rename-other-filename "before rename.txt"))))))
- ;; Rename subdirectory
+ ;; Rename file in subdirectory
+ (vc-jj-test--with-repo repo
+ (make-directory "subdir")
+ (write-region "foo bar" nil "subdir/before rename.txt")
+ (shell-command "jj new")
+ (shell-command "mv 'subdir/before rename.txt' 'subdir/after rename.txt'")
+
+ (should (eq (vc-jj-state "subdir/before rename.txt") 'removed))
+ (should (eq (vc-jj-state "subdir/after rename.txt") 'added))
+ (should (seq-set-equal-p
+ (vc-jj-dir-status-files repo nil
+ #'vc-jj-test--dir-status-files-update-function)
+ '(("subdir/before rename.txt" removed
+ ( :rename-state removed
+ :rename-other-filename "subdir/after rename.txt"))
+ ("subdir/after rename.txt" added
+ ( :rename-state added
+ :rename-other-filename "subdir/before rename.txt"))))))
+
+ ;; Rename entire subdirectory
(vc-jj-test--with-repo repo
(make-directory "dir before rename/subdir" t)
;; 2026-04-26: It seems that, unlike single-file renames,
diff --git a/vc-jj.el b/vc-jj.el
index 65f5397..71a0e80 100644
--- a/vc-jj.el
+++ b/vc-jj.el
@@ -465,19 +465,27 @@ path prepended with a two-character type string indicating the before
and after types of the file."
(let ((table (make-hash-table :test #'equal)))
(mapc (lambda (line)
- (if (string-match (rx "{" (group (1+ anychar)) " => " (group (1+ anychar)) "}"
- (opt "/" (group (1+ anychar))))
+ (if (string-match (rx (group-n 1 (* anychar))
+ "{"
+ (group-n 2 (1+ (not (any "}"))))
+ " => "
+ (group-n 3 (1+ (not (any "}"))))
+ "}"
+ (group-n 4 (* anychar)))
line)
;; For renamed files, create separate entries for the
- ;; before-rename and after-rename files
- (let ((before (match-string 1 line))
- (after (match-string 2 line))
- (subdir-file (match-string 3 line)))
- (when subdir-file ; When a directory was renamed
- (setq before (file-name-concat before subdir-file)
- after (file-name-concat after subdir-file)))
+ ;; before-rename and after-rename files. The rename
+ ;; block {before => after} may appear mid-path, so we
+ ;; reconstruct full paths using the surrounding
+ ;; context.
+ (let* ((prefix (substring (match-string 1 line) 3))
+ (before-part (match-string 2 line))
+ (after-part (match-string 3 line))
+ (suffix (match-string 4 line))
+ (before (concat prefix before-part suffix))
+ (after (concat prefix after-part suffix)))
(puthash before "F-" table) ; Removed state
- (puthash after "-F" table) ; Added state
+ (puthash after "-F" table) ; Added state
(when extra-table
;; Populate EXTRA-TABLE with rename information
(puthash before (list :rename-state 'removed :rename-other-filename after)