1 ;; vc-got-stage.el --- Stage changes in vc-got diff buffers -*- lexical-binding: t; -*-
6 (defgroup vc-got-stage nil
7 "Stage hunks in vc-got diff buffers"
9 :prefix "vc-got-stage-")
11 (defface vc-got-stage-staged-face
12 '((t (:foreground "red" :background "yellow")))
13 "Face used to highlight the staged mark on changes."
16 (defvar vc-got-stage-fileset nil
17 "The files diffed in the last call to `vc-got-diff'.")
19 (defvar vc-got-stage-overlay-priority 0
20 "Specify overlay priority.
21 Higher values means higher priority. DON'T use negative numbers.")
23 (defvar vc-got-stage--overlays nil
24 "The list of overlays.")
26 (defvar vc-got-stage-prefix-map
27 (let ((map (make-sparse-keymap)))
28 (define-key map (kbd "A") #'vc-got-stage-apply)
29 (define-key map (kbd "b") #'vc-got-stage-beginning-of-change)
30 (define-key map (kbd "e") #'vc-got-stage-end-of-change)
31 (define-key map (kbd "n") #'vc-got-stage-next-change)
32 (define-key map (kbd "p") #'vc-got-stage-prev-change)
33 (define-key map (kbd "t") #'vc-got-stage-toggle-mark)
35 "Keymap for function `vc-got-stage-mode'.")
38 (define-minor-mode vc-got-stage-mode
39 "Stage hunks in vc-got diff buffers.
41 \\{vc-got-stage-mode-map}"
43 :keymap (let ((map (make-sparse-keymap)))
44 (define-key map (kbd "C-c g") vc-got-stage-prefix-map)
47 ;;;###autoload (defun vc-got-stage-activate ()
48 ;;;###autoload "Activate vg-got-stage-mode if the current buffer is a vc-got diff."
49 ;;;###autoload (when-let (root (vc-find-root default-directory ".got"))
50 ;;;###autoload (vc-got-stage-mode +1)))
52 (defun vc-got-stage-activate ()
53 "Activate vg-got-stage-mode if the current buffer is a vc-got diff."
54 (message "VC got stage activate? %s" (vc-find-root default-directory ".got"))
55 (when-let (root (vc-find-root default-directory ".got"))
56 (vc-got-stage-mode +1)))
58 ;;;###autoload (add-hook 'diff-mode-hook #'vc-got-stage-activate)
59 (add-hook 'diff-mode-hook #'vc-got-stage-activate)
61 (defun vc-got-stage--in-change ()
62 "T if the point is in a line that's part of a change."
65 (when-let (ch (char-after))
69 (defun vc-got-stage--change-marked-p ()
70 "T if the current change is marked."
73 for overlay in vc-got-stage--overlays
74 if (and (overlay-start overlay)
75 (= p (overlay-start overlay)))
77 finally (return nil))))
79 (defun vc-got-stage--compute-y-or-n (buf)
80 "Fill BUF with ``y'' or ``n'' lines for staging purpose."
82 (goto-char (point-min))
84 (while (not (= p (progn (vc-got-stage-next-change)
87 (if (vc-got-stage--change-marked-p)
88 (with-current-buffer buf
90 (with-current-buffer buf
93 (defun vc-got-stage--apply-impl (script tmp-file)
94 "Apply the stages using SCRIPT as script (TMP-FILE is the path)."
96 (let* ((default-directory (vc-find-root default-directory ".got"))
97 (stage-buf (get-buffer-create "*vc-got-stage*")))
98 (unless (zerop (apply #'process-file "got" nil stage-buf nil "unstage"
99 (mapcar #'file-relative-name vc-got-stage-fileset)))
100 (pop-to-buffer stage-buf)
101 (error "Got unstage failed"))
102 (vc-got-stage--compute-y-or-n script)
103 (with-current-buffer script
105 (unless (zerop (apply #'process-file "got" nil stage-buf nil "stage" "-p"
106 "-F" tmp-file (mapcar #'file-relative-name
107 vc-got-stage-fileset)))
108 (pop-to-buffer stage-buf)
109 (error "Got stage failed"))))
111 (defun vc-got-stage-apply ()
113 This will first reset the stages of all the involved files, then
114 stage the marked changes."
116 (let* ((tmp-file (make-temp-file "vc-got-stage-script"))
117 (script (find-file-noselect tmp-file)))
119 (vc-got-stage--apply-impl script tmp-file)
121 (delete-file tmp-file))))
123 (defun vc-got-stage-beginning-of-change ()
124 "Goto the beginning of the current change."
128 (while (vc-got-stage--in-change)
132 (defun vc-got-stage-end-of-change ()
133 "Goto the end of the current change."
137 (while (vc-got-stage--in-change)
141 (defun vc-got-stage--prevnext-change (n)
142 "Goto next/previous change by N."
143 (let ((start (point)))
145 (while (and (not (= (point) (if (= n -1)
148 (vc-got-stage--in-change))
150 (while (let ((face (get-text-property (point) 'face)))
151 (and (not (= (point) (if (= n -1)
154 (or (eq face 'diff-hunk-header)
155 (eq face 'diff-header)
156 (eq face 'diff-context))))
159 (vc-got-stage-beginning-of-change))
160 (unless (vc-got-stage--in-change)
162 (message "No prev/next change"))))
164 (defun vc-got-stage-prev-change ()
165 "Goto previous change."
167 (vc-got-stage--prevnext-change -1))
169 (defun vc-got-stage-next-change ()
172 (vc-got-stage--prevnext-change +1))
174 (defun vc-got-stage--delete-overlay-at (point)
175 "Delete overlays at POINT.
176 Return t if something was deleted."
178 (cl-delete-if (lambda (overlay)
179 (let ((start (overlay-start overlay)))
180 ;; silently drop dangling overlays
184 (delete-overlay overlay)
186 vc-got-stage--overlays)
189 (defun vc-got-stage-toggle-mark ()
190 "Toggle the staged status on the change at point."
192 (when (vc-got-stage--in-change)
194 (vc-got-stage-beginning-of-change)
195 (unless (vc-got-stage--delete-overlay-at (point))
196 (let ((overlay (make-overlay (point) (point))))
200 'display '(left-fringe right-triangle)
201 'face 'vc-got-stage-staged-face))
202 (push overlay vc-got-stage--overlays))))))
204 (provide 'vc-got-stage)
205 ;;; vc-got-stage.el ends here