branch: externals/vc-jj
commit 3e69d919bd4a483eb4bfcf9fe8a4dc9d7037e90b
Author: Wojciech Siewierski <wojci...@siewierski.eu>
Commit: Wojciech Siewierski <wojci...@siewierski.eu>

    Initial commit
---
 vc-jj.el | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 178 insertions(+)

diff --git a/vc-jj.el b/vc-jj.el
new file mode 100644
index 0000000000..92d940bb74
--- /dev/null
+++ b/vc-jj.el
@@ -0,0 +1,178 @@
+;;; vc-jj.el --- A vc.el backend for Jujutsu VCS  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024  Wojciech Siewierski
+
+;; Author: Wojciech Siewierski
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; A backend for vc.el to handle Jujutsu repositories.
+
+;;; Code:
+
+(autoload 'vc-setup-buffer "vc-dispatcher")
+(autoload 'vc-switches "vc")
+
+(add-to-list 'vc-handled-backends 'JJ)
+
+(defun vc-jj-revision-granularity () 'repository)
+(defun vc-jj-checkout-model (_files) 'implicit)
+(defun vc-jj-update-on-retrieve-tag () nil)
+
+
+(defun vc-jj--file-tracked (file)
+  (with-temp-buffer
+    (and (= 0 (call-process "jj" nil t nil "file" "list" "--" file))
+         (not (= (point-min) (point-max))))))
+
+(defun vc-jj--file-modified (file)
+  (with-temp-buffer
+    (and (= 0 (call-process "jj" nil t nil "diff" "--name-only" "--" file))
+         (not (= (point-min) (point-max))))))
+
+
+;;;###autoload (defun vc-jj-registered (file)
+;;;###autoload   "Return non-nil if FILE is registered with jj."
+;;;###autoload   (if (vc-find-root file ".jj")       ; Short cut.
+;;;###autoload       (progn
+;;;###autoload         (load "vc-jj" nil t)
+;;;###autoload         (vc-jj-registered file))))
+
+(defun vc-jj-registered (file)
+  (when-let ((root (vc-jj-root file)))
+    (let ((relative (file-relative-name file root))
+          (default-directory root))
+      (vc-jj--file-tracked relative))))
+
+(defun vc-jj-state (file)
+  (when-let ((root (vc-jj-root file)))
+    (let ((relative (file-relative-name file root))
+          (default-directory root))
+      (cond
+       ((vc-jj--file-modified relative)
+        'edited)
+       ((vc-jj--file-tracked relative)
+        'up-to-date)))))
+
+(defun vc-jj-dir-status-files (dir _files update-function)
+  ;; TODO: should be async!
+  (let ((files (apply #'process-lines "jj" "file" "list" "--" dir))
+        (modified (apply #'process-lines "jj" "diff" "--name-only" "--" dir)))
+    (mapcar (lambda (file)
+              (let ((vc-state (if (member file modified)
+                                  'edited
+                                'up-to-date)))
+                (list file vc-state))))))
+
+(defun vc-jj-working-revision (file)
+  (when-let ((root (vc-jj-root file)))
+    (let ((relative (file-relative-name file root))
+          (default-directory root))
+      (let ((rev (if (vc-jj--file-modified relative)
+                     "@"
+                   "@-")))
+        (car (process-lines "jj" "log" "--no-graph"
+                            "-r" rev
+                            "-T" "self.change_id().short() ++ \"\\n\""))))))
+
+(defun vc-jj-create-repo ()
+  (if current-prefix-arg
+      (call-process "jj" nil nil nil "git" "init" "--colocate")
+    (call-process "jj" nil nil nil "git" "init")))
+
+(defun vc-jj-register (_files &optional _comment)
+  ;; No action needed.
+  )
+
+(defun vc-jj-checkin (files comment &optional _rev)
+  (let ((args (append (vc-switches 'jj 'checkin) (list "--") files)))
+    (apply #'call-process "jj" nil nil nil "commit" "-m" comment "--" args)))
+
+(defun vc-jj-find-revision (file rev buffer)
+  (call-process "jj" nil buffer nil "file" "show" "-r" rev "--" file))
+
+(defun vc-jj-checkout (file &optional rev)
+  (let ((args (if rev
+                  (list "--from" rev "--" file)
+                (list "--" file))))
+    (call-process "jj" nil nil nil "restore" args)))
+
+(defun vc-jj-revert (file &optional _contents-done)
+  (call-process "jj" nil nil nil "restore" "--" file))
+
+(defun vc-jj-print-log (files buffer &optional _shortlog start-revision limit)
+  (vc-setup-buffer buffer)
+  (let ((inhibit-read-only t)
+        (args (append
+               (when limit
+                 (list "-n" (number-to-string limit)))
+               (when start-revision
+                 (list "-r" (concat ".." start-revision)))
+               (list "--")
+               files)))
+    (apply #'call-process "jj" nil buffer nil "log" args))
+  (goto-char (point-min)))
+
+(defun vc-jj-show-log-entry (revision)
+  (goto-char (point-min))
+  (when (search-forward-regexp
+         (concat "^[^|]\\s-+\\(" (regexp-quote revision) "\\)\\s-+")
+         nil t)
+    (goto-char (match-beginning 1))))
+
+;; (defun vc-jj-log-outgoing (buffer remote-location)
+;;   ;; TODO
+;;   )
+;; (defun vc-jj-log-incoming (buffer remote-location)
+;;   ;; TODO
+;;   )
+
+(defun vc-jj-root (_file)
+  (with-temp-buffer
+    (when (= 0 (call-process "jj" nil (list t nil) nil "root"))
+      (buffer-substring (point-min) (1- (point-max))))))
+
+(defalias 'vc-jj-responsible-p #'vc-jj-root)
+
+
+(defconst vc-jj-diff-switches '("--git"))
+
+(defun vc-jj-diff (files &optional rev1 rev2 buffer async)
+  (setq buffer (or buffer "*vc-diff*"))
+  (cond
+   ((and (null rev1)
+         (null rev2))
+    (setq rev1 "@-"))
+   ((null rev1)
+    (setq rev1 "root()")))
+  (setq rev2 (or rev2 "@"))
+  (let ((inhibit-read-only t)
+        (args (append (vc-switches 'jj 'diff) (list "--") files)))
+    (apply #'call-process "jj" nil buffer nil "diff" "--from" rev1 "--to" rev2 
args)))
+
+(defun vc-jj-revision-completion-table (files)
+  (let ((revisions
+         (apply #'process-lines
+                "jj" "log" "--no-graph"
+                "-T" "self.change_id() ++ \"\\n\"" "--" files)))
+    (lambda (string pred action)
+      (if (eq action 'metadata)
+          `(metadata . ((display-sort-function . ,#'identity)))
+        (complete-with-action action revisions string pred)))))
+
+
+(provide 'vc-jj)
+;;; vc-jj.el ends here

Reply via email to