Blame


1 406d7b4d 2020-12-26 op ;;; vc-got.el --- Game of Tree backend for VC -*- lexical-binding: t; -*-
2 af5ef7cd 2020-11-29 op
3 406d7b4d 2020-12-26 op ;; Copyright (C) 2020 Omar Polo
4 af5ef7cd 2020-11-29 op
5 76d978fa 2021-01-05 op ;; Author: Omar Polo <op@omarpolo.com>
6 d3ca33b4 2021-08-16 op ;; URL: https://git.omarpolo.com/vc-got/
7 406d7b4d 2020-12-26 op ;; Keywords: vc
8 d3ca33b4 2021-08-16 op ;; Version: 0
9 d3ca33b4 2021-08-16 op ;; Package-Requires: ((emacs "27.1"))
10 af5ef7cd 2020-11-29 op
11 406d7b4d 2020-12-26 op ;; This program is free software; you can redistribute it and/or modify
12 406d7b4d 2020-12-26 op ;; it under the terms of the GNU General Public License as published by
13 406d7b4d 2020-12-26 op ;; the Free Software Foundation, either version 3 of the License, or
14 406d7b4d 2020-12-26 op ;; (at your option) any later version.
15 af5ef7cd 2020-11-29 op
16 406d7b4d 2020-12-26 op ;; This program is distributed in the hope that it will be useful,
17 406d7b4d 2020-12-26 op ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 406d7b4d 2020-12-26 op ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 406d7b4d 2020-12-26 op ;; GNU General Public License for more details.
20 af5ef7cd 2020-11-29 op
21 406d7b4d 2020-12-26 op ;; You should have received a copy of the GNU General Public License
22 406d7b4d 2020-12-26 op ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
23 406d7b4d 2020-12-26 op
24 7726b6c9 2021-08-10 op ;;; Commentary:
25 af5ef7cd 2020-11-29 op
26 af5ef7cd 2020-11-29 op ;; Backend implementation status
27 af5ef7cd 2020-11-29 op ;;
28 af5ef7cd 2020-11-29 op ;; Function marked with `*' are required, those with `-' are optional.
29 af5ef7cd 2020-11-29 op ;;
30 af5ef7cd 2020-11-29 op ;; FUNCTION NAME STATUS
31 af5ef7cd 2020-11-29 op ;;
32 af5ef7cd 2020-11-29 op ;; BACKEND PROPERTIES:
33 af5ef7cd 2020-11-29 op ;; * revision-granularity DONE
34 af5ef7cd 2020-11-29 op ;; - update-on-retrieve-tag XXX: what should this do?
35 af5ef7cd 2020-11-29 op ;;
36 af5ef7cd 2020-11-29 op ;; STATE-QUERYING FUNCTIONS:
37 af5ef7cd 2020-11-29 op ;; * registered DONE
38 af5ef7cd 2020-11-29 op ;; * state DONE
39 af5ef7cd 2020-11-29 op ;; - dir-status-files DONE
40 a8466f02 2020-12-07 op ;; - dir-extra-headers DONE
41 2d83de2e 2021-01-05 op ;; - dir-printer DONE
42 af5ef7cd 2020-11-29 op ;; - status-fileinfo-extra NOT IMPLEMENTED
43 af5ef7cd 2020-11-29 op ;; * working-revision DONE
44 af5ef7cd 2020-11-29 op ;; * checkout-model DONE
45 694534b4 2020-12-05 op ;; - mode-line-string DONE
46 23a0b465 2020-11-30 op ;;
47 23a0b465 2020-11-30 op ;; STATE-CHANGING FUNCTIONS:
48 23a0b465 2020-11-30 op ;; * create-repo NOT IMPLEMENTED
49 eb85ad27 2020-12-05 op ;; I don't think got init does what this function is supposed to
50 eb85ad27 2020-12-05 op ;; do.
51 23a0b465 2020-11-30 op ;; * register DONE
52 23a0b465 2020-11-30 op ;; - responsible-p DONE
53 3cdb0759 2020-01-03 47739920+ ;; - receive-file NOT NEEDED, default `register' works fine
54 241a3b12 2021-08-11 op ;; - unregister DONE
55 23a0b465 2020-11-30 op ;; * checkin DONE
56 23a0b465 2020-11-30 op ;; * find-revision DONE
57 eb85ad27 2020-12-05 op ;; * checkout NOT IMPLEMENTED
58 eb85ad27 2020-12-05 op ;; I'm not sure how to properly implement this. Does filling
59 eb85ad27 2020-12-05 op ;; FILE with the find-revision do the trick? Or use got update?
60 eb85ad27 2020-12-05 op ;; * revert DONE
61 eb85ad27 2020-12-05 op ;; - merge-file NOT IMPLEMENTED
62 eb85ad27 2020-12-05 op ;; - merge-branch DONE
63 eb85ad27 2020-12-05 op ;; - merge-news NOT IMPLEMENTED
64 eb85ad27 2020-12-05 op ;; - pull DONE
65 686eac9a 2020-12-07 op ;; - push DONE
66 686eac9a 2020-12-07 op ;; uses git
67 3cdb0759 2020-01-03 47739920+ ;; - steal-lock NOT NEEDED, `got' is not using locks
68 eb85ad27 2020-12-05 op ;; - modify-change-comment NOT IMPLEMENTED
69 eb85ad27 2020-12-05 op ;; can be implemented via histedit, if I understood correctly
70 eb85ad27 2020-12-05 op ;; what it is supposed to do.
71 eb85ad27 2020-12-05 op ;; - mark-resolved NOT IMPLEMENTED
72 eb85ad27 2020-12-05 op ;; - find-admin-dir NOT IMPLEMENTED
73 eb85ad27 2020-12-05 op ;;
74 eb85ad27 2020-12-05 op ;; HISTORY FUNCTIONS
75 eb85ad27 2020-12-05 op ;; * print-log DONE
76 9ad1eb5d 2020-12-07 op ;; * log-outgoing DONE
77 6eda2f1f 2020-12-26 op ;; * log-incoming DONE
78 eb85ad27 2020-12-05 op ;; - log-search DONE
79 0a3316a6 2021-02-22 op ;; - log-view-mode DONE
80 6eda2f1f 2020-12-26 op ;; - show-log-entry NOT IMPLEMENTED
81 6eda2f1f 2020-12-26 op ;; - comment-history NOT IMPLEMENTED
82 6eda2f1f 2020-12-26 op ;; - update-changelog NOT IMPLEMENTED
83 7c257a7b 2020-12-31 noreply ;; * diff DONE
84 5fb2f474 2021-08-10 op ;; - revision-completion-table DONE
85 3f25d9ff 2020-01-02 noreply ;; - annotate-command DONE
86 3f25d9ff 2020-01-02 noreply ;; - annotate-time DONE
87 424f5152 2021-08-10 op ;; - annotate-current-time NOT NEEDED
88 424f5152 2021-08-10 op ;; the default time handling is enough.
89 3f25d9ff 2020-01-02 noreply ;; - annotate-extract-revision-at-line DONE
90 7c257a7b 2020-12-31 noreply ;; - region-history NOT IMPLEMENTED
91 7c257a7b 2020-12-31 noreply ;; - region-history-mode NOT IMPLEMENTED
92 7c257a7b 2020-12-31 noreply ;; - mergebase NOT IMPLEMENTED
93 7c257a7b 2020-12-31 noreply ;;
94 7c257a7b 2020-12-31 noreply ;; TAG SYSTEM
95 6ab1c7b4 2021-08-11 op ;; - create-tag DONE
96 09d59379 2021-08-11 op ;; - retrieve-tag DONE
97 7c257a7b 2020-12-31 noreply ;;
98 7c257a7b 2020-12-31 noreply ;; MISCELLANEOUS NOT IMPLEMENTED
99 3cdb0759 2020-01-03 47739920+ ;; - make-version-backups-p NOT NEEDED, `got' works fine locally
100 7c257a7b 2020-12-31 noreply ;; - root DONE
101 49945a03 2021-08-11 op ;; - ignore NOT NEEDED, the default action is good
102 49945a03 2021-08-11 op ;; - ignore-completion-table NOT NEEDED, the default action is good
103 2552a6c7 2021-08-11 op ;; - find-ignore-file DONE
104 3f25d9ff 2020-01-02 noreply ;; - previous-revision DONE
105 3f25d9ff 2020-01-02 noreply ;; - next-revision DONE
106 7c257a7b 2020-12-31 noreply ;; - log-edit-mode NOT IMPLEMENTED
107 3cdb0759 2020-01-03 47739920+ ;; - check-headers NOT NEEDED, `got' does not use headers
108 a96df0e8 2020-01-03 noreply ;; - delete-file DONE
109 3cdb0759 2020-01-03 47739920+ ;; - rename-file NOT NEEDED, `delete' + `register' is enough
110 c151c257 2021-08-03 op ;; - find-file-hook DONE
111 3cdb0759 2020-01-03 47739920+ ;; - extra-menu NOT IMPLEMENTED, add `import', `integrate', `stage'?
112 3cdb0759 2020-01-03 47739920+ ;; - extra-dir-menu NOT IMPLEMENTED, same as above
113 7bb16f79 2020-01-03 op ;; - conflicted-files DONE
114 8b635a9f 2020-01-03 op ;; - repository-url DONE
115 af5ef7cd 2020-11-29 op
116 eb85ad27 2020-12-05 op ;; TODO: vc-git has most function that starts with:
117 eb85ad27 2020-12-05 op ;;
118 eb85ad27 2020-12-05 op ;; (let* ((root (vc-git-root default-directory))
119 eb85ad27 2020-12-05 op ;; (buffer (format "*vc-git : %s*" (expand-file-name root)))
120 eb85ad27 2020-12-05 op ;; ...)
121 eb85ad27 2020-12-05 op ;; ...)
122 eb85ad27 2020-12-05 op ;;
123 eb85ad27 2020-12-05 op ;; we should 1) investigate if also other backends do something like
124 eb85ad27 2020-12-05 op ;; this (or if there is a better way) and 2) try to do the same.
125 eb85ad27 2020-12-05 op
126 af5ef7cd 2020-11-29 op ;;; Code:
127 af5ef7cd 2020-11-29 op
128 af5ef7cd 2020-11-29 op (eval-when-compile
129 af5ef7cd 2020-11-29 op (require 'subr-x))
130 af5ef7cd 2020-11-29 op
131 af5ef7cd 2020-11-29 op (require 'cl-lib)
132 af5ef7cd 2020-11-29 op (require 'seq)
133 23a0b465 2020-11-30 op (require 'vc)
134 3f25d9ff 2020-01-02 noreply (require 'vc-annotate)
135 6b6c8a78 2021-01-04 op
136 2d83de2e 2021-01-05 op ;; FIXME: avoid loading this? We only need it for
137 2d83de2e 2021-01-05 op ;; vc-dir-filename-mouse-map in our custom printer.
138 2d83de2e 2021-01-05 op (require 'vc-dir)
139 ba123905 2020-12-08 op
140 e79563bd 2020-12-31 noreply (defgroup vc-got nil
141 e79563bd 2020-12-31 noreply "VC GoT backend."
142 e79563bd 2020-12-31 noreply :group 'vc)
143 af5ef7cd 2020-11-29 op
144 e79563bd 2020-12-31 noreply (defcustom vc-got-program "got"
145 e79563bd 2020-12-31 noreply "Name of the Got executable (excluding any arguments)."
146 6eea6cfb 2021-01-05 op :type 'string)
147 e79563bd 2020-12-31 noreply
148 12ca62f2 2020-12-26 op (defcustom vc-got-diff-switches t
149 12ca62f2 2020-12-26 op "String or list of strings specifying switches for Got diff under VC.
150 12ca62f2 2020-12-26 op If nil, use the value of `vc-diff-switches'. If t, use no switches."
151 12ca62f2 2020-12-26 op :type '(choice (const :tag "Unspecified" nil)
152 12ca62f2 2020-12-26 op (const :tag "None" t)
153 12ca62f2 2020-12-26 op (string :tag "Argument String")
154 6eea6cfb 2021-01-05 op (repeat :tag "Argument List" :value ("") string)))
155 12ca62f2 2020-12-26 op
156 af5ef7cd 2020-11-29 op ;; helpers
157 f09d6359 2020-12-31 noreply (defun vc-got--program-version ()
158 76d978fa 2021-01-05 op "Return string representing the got version."
159 f09d6359 2020-12-31 noreply (let (process-file-side-effects)
160 f09d6359 2020-12-31 noreply (with-temp-buffer
161 f09d6359 2020-12-31 noreply (vc-got--call "-V")
162 f09d6359 2020-12-31 noreply (substring (buffer-string) 4 -1))))
163 af5ef7cd 2020-11-29 op
164 af5ef7cd 2020-11-29 op (defun vc-got-root (file)
165 af5ef7cd 2020-11-29 op "Return the work tree root for FILE, or nil."
166 6a973a79 2021-08-11 op (vc-find-root file ".got"))
167 af5ef7cd 2020-11-29 op
168 af5ef7cd 2020-11-29 op (defmacro vc-got-with-worktree (file &rest body)
169 af5ef7cd 2020-11-29 op "Evaluate BODY in the work tree directory of FILE."
170 af5ef7cd 2020-11-29 op (declare (indent defun))
171 af5ef7cd 2020-11-29 op `(when-let (default-directory (vc-got-root ,file))
172 af5ef7cd 2020-11-29 op ,@body))
173 686eac9a 2020-12-07 op
174 686eac9a 2020-12-07 op (defun vc-got--repo-root ()
175 686eac9a 2020-12-07 op "Return the path to the repository root.
176 686eac9a 2020-12-07 op Assume `default-directory' is inside a got worktree."
177 686eac9a 2020-12-07 op (vc-got-with-worktree default-directory
178 686eac9a 2020-12-07 op (with-temp-buffer
179 686eac9a 2020-12-07 op (insert-file-contents ".got/repository")
180 76d978fa 2021-01-05 op (string-trim (buffer-string) "" "\n"))))
181 af5ef7cd 2020-11-29 op
182 af5ef7cd 2020-11-29 op (defun vc-got--call (&rest args)
183 76d978fa 2021-01-05 op "Call `vc-got-program' with ARGS.
184 76d978fa 2021-01-05 op The output will be placed in the current buffer."
185 fab791a2 2020-01-03 op (apply #'process-file vc-got-program nil (current-buffer) nil
186 fab791a2 2020-01-03 op (cl-remove-if #'null (flatten-list args))))
187 af5ef7cd 2020-11-29 op
188 23a0b465 2020-11-30 op (defun vc-got--add (files)
189 23a0b465 2020-11-30 op "Add FILES to got, passing `vc-register-switches' to the command invocation."
190 23a0b465 2020-11-30 op (with-temp-buffer
191 c3185bf7 2021-08-11 op (vc-got--call "add" vc-register-switches "--" files)))
192 23a0b465 2020-11-30 op
193 0a66694e 2020-01-02 op (defun vc-got--log (&optional path limit start-commit stop-commit
194 0a66694e 2020-01-02 op search-pattern reverse)
195 76d978fa 2021-01-05 op "Execute the log command in the worktree of PATH in the current buffer.
196 23a0b465 2020-11-30 op LIMIT limits the maximum number of commit returned.
197 23a0b465 2020-11-30 op
198 518ede14 2020-12-05 op START-COMMIT: start traversing history at the specified commit.
199 9ad1eb5d 2020-12-07 op STOP-COMMIT: stop traversing history at the specified commit.
200 518ede14 2020-12-05 op SEARCH-PATTERN: limit to log messages matched by the regexp given.
201 0a66694e 2020-01-02 op REVERSE: display the log messages in reverse order.
202 518ede14 2020-12-05 op
203 23a0b465 2020-11-30 op Return nil if the command failed or if PATH isn't included in any
204 23a0b465 2020-11-30 op worktree."
205 0a66694e 2020-01-02 op (let (process-file-side-effects)
206 0a66694e 2020-01-02 op (vc-got-with-worktree (or path default-directory)
207 0a3316a6 2021-02-22 op (when (zerop
208 0a3316a6 2021-02-22 op (save-excursion
209 0a3316a6 2021-02-22 op (vc-got--call "log"
210 0a3316a6 2021-02-22 op (when limit (list "-l" (format "%s" limit)))
211 0a3316a6 2021-02-22 op (when start-commit (list "-c" start-commit))
212 0a3316a6 2021-02-22 op (when stop-commit (list "-x" stop-commit))
213 0a3316a6 2021-02-22 op (when search-pattern (list "-s" search-pattern))
214 0a3316a6 2021-02-22 op (when reverse '("-R"))
215 c3185bf7 2021-08-11 op "--"
216 0a3316a6 2021-02-22 op path)))
217 0a3316a6 2021-02-22 op (save-excursion
218 0a3316a6 2021-02-22 op (delete-matching-lines "^-----------------------------------------------$")
219 0a3316a6 2021-02-22 op t)))))
220 af5ef7cd 2020-11-29 op
221 887e0699 2021-02-22 op (defun vc-got--status (status-codes dir-or-file &optional files)
222 668dc8eb 2021-01-04 op "Return a list of lists '(FILE STATUS STAGE-STATUS).
223 af5ef7cd 2020-11-29 op DIR-OR-FILE can be either a directory or a file. If FILES is
224 af5ef7cd 2020-11-29 op given, return the status of those files, otherwise the status of
225 668dc8eb 2021-01-04 op DIR-OR-FILE. STATUS-CODES is either nil, or a string that's
226 668dc8eb 2021-01-04 op passed as the -s flag to got status to limit the types of status
227 668dc8eb 2021-01-04 op to report (e.g. \"CD\" to report only conflicts and deleted
228 668dc8eb 2021-01-04 op files)."
229 2d039a22 2021-02-21 op (with-temp-buffer
230 2d039a22 2021-02-21 op (let* ((default-directory (expand-file-name
231 2d039a22 2021-02-21 op (if (file-directory-p dir-or-file)
232 2d039a22 2021-02-21 op dir-or-file
233 2d039a22 2021-02-21 op (file-name-directory dir-or-file))))
234 2d039a22 2021-02-21 op (root (vc-got-root default-directory))
235 2d039a22 2021-02-21 op (process-file-side-effects))
236 2d039a22 2021-02-21 op (when (zerop (vc-got--call "status"
237 2d039a22 2021-02-21 op (when status-codes (list "-s" status-codes))
238 c3185bf7 2021-08-11 op "--"
239 2d039a22 2021-02-21 op (or files dir-or-file)))
240 2d039a22 2021-02-21 op (goto-char (point-min))
241 2d039a22 2021-02-21 op (cl-loop until (eobp)
242 2d039a22 2021-02-21 op ;; the format of each line is
243 2d039a22 2021-02-21 op ;; <status-char> <stage-char> <spc> <filename> \n
244 2d039a22 2021-02-21 op collect (let* ((file-status (prog1 (vc-got--parse-status-char
245 2d039a22 2021-02-21 op (char-after))
246 2d039a22 2021-02-21 op (forward-char)))
247 2d039a22 2021-02-21 op (stage-status (prog1 (vc-got--parse-stage-char
248 2d039a22 2021-02-21 op (char-after))
249 2d039a22 2021-02-21 op (forward-char)))
250 2d039a22 2021-02-21 op (filename (progn
251 2d039a22 2021-02-21 op (forward-char)
252 2d039a22 2021-02-21 op (buffer-substring (point)
253 2d039a22 2021-02-21 op (line-end-position)))))
254 2d039a22 2021-02-21 op (list (file-relative-name (expand-file-name filename root)
255 2d039a22 2021-02-21 op default-directory)
256 2d039a22 2021-02-21 op (or file-status (and stage-status 'staged))
257 2d039a22 2021-02-21 op stage-status))
258 2d039a22 2021-02-21 op do (forward-line))))))
259 af5ef7cd 2020-11-29 op
260 668dc8eb 2021-01-04 op (defun vc-got--parse-status-char (c)
261 668dc8eb 2021-01-04 op "Parse status char C into a symbol accepted by `vc-state'."
262 668dc8eb 2021-01-04 op (cl-case c
263 668dc8eb 2021-01-04 op (?M 'edited)
264 668dc8eb 2021-01-04 op (?A 'added)
265 668dc8eb 2021-01-04 op (?D 'removed)
266 668dc8eb 2021-01-04 op (?C 'conflict)
267 668dc8eb 2021-01-04 op (?! 'missing)
268 76d978fa 2021-01-05 op (?~ 'edited) ; XXX: what does it means for a file to be ``obstructed''?
269 668dc8eb 2021-01-04 op (?? 'unregistered)
270 76d978fa 2021-01-05 op (?m 'edited) ; modified file modes
271 668dc8eb 2021-01-04 op (?N nil)))
272 af5ef7cd 2020-11-29 op
273 668dc8eb 2021-01-04 op (defun vc-got--parse-stage-char (c)
274 668dc8eb 2021-01-04 op "Parse the stage status char C into a symbol."
275 668dc8eb 2021-01-04 op (cl-case c
276 2d83de2e 2021-01-05 op (?M 'edit)
277 2d83de2e 2021-01-05 op (?A 'add)
278 2d83de2e 2021-01-05 op (?D 'remove)))
279 af5ef7cd 2020-11-29 op
280 23a0b465 2020-11-30 op (defun vc-got--tree-parse ()
281 23a0b465 2020-11-30 op "Parse into an alist the output of got tree -i in the current buffer."
282 23a0b465 2020-11-30 op (goto-char (point-min))
283 23a0b465 2020-11-30 op (cl-loop
284 23a0b465 2020-11-30 op until (= (point) (point-max))
285 23a0b465 2020-11-30 op collect (let* ((obj-start (point))
286 23a0b465 2020-11-30 op (_ (forward-word))
287 23a0b465 2020-11-30 op (obj (buffer-substring obj-start (point)))
288 76d978fa 2021-01-05 op (_ (forward-char)) ; skip the space
289 23a0b465 2020-11-30 op (filename-start (point))
290 23a0b465 2020-11-30 op (_ (move-end-of-line nil))
291 23a0b465 2020-11-30 op (filename (buffer-substring filename-start (point))))
292 23a0b465 2020-11-30 op ;; goto the start of the next line
293 23a0b465 2020-11-30 op (forward-line)
294 23a0b465 2020-11-30 op (move-beginning-of-line nil)
295 23a0b465 2020-11-30 op `(,filename . ,obj))))
296 23a0b465 2020-11-30 op
297 23a0b465 2020-11-30 op (defun vc-got--tree (commit path)
298 67332bad 2021-01-05 op "Return an alist representing the got tree command output.
299 76d978fa 2021-01-05 op The outputted tree will be localised in the given PATH at the
300 67332bad 2021-01-05 op given COMMIT."
301 23a0b465 2020-11-30 op (vc-got-with-worktree path
302 76d978fa 2021-01-05 op (let (process-file-side-effects)
303 76d978fa 2021-01-05 op (with-temp-buffer
304 c3185bf7 2021-08-11 op (when (zerop (vc-got--call "tree" "-c" commit "-i" "--" path))
305 76d978fa 2021-01-05 op (vc-got--tree-parse))))))
306 23a0b465 2020-11-30 op
307 23a0b465 2020-11-30 op (defun vc-got--cat (commit obj-id)
308 23a0b465 2020-11-30 op "Execute got cat -c COMMIT OBJ-ID in the current buffer."
309 76d978fa 2021-01-05 op (let (process-file-side-effects)
310 76d978fa 2021-01-05 op (zerop (vc-got--call "cat" "-c" commit obj-id))))
311 eb85ad27 2020-12-05 op
312 eb85ad27 2020-12-05 op (defun vc-got--revert (&rest files)
313 76d978fa 2021-01-05 op "Execute got revert FILES."
314 eb85ad27 2020-12-05 op (vc-got-with-worktree (car files)
315 eb85ad27 2020-12-05 op (with-temp-buffer
316 c3185bf7 2021-08-11 op (zerop (vc-got--call "revert" "--" files)))))
317 eb85ad27 2020-12-05 op
318 eb85ad27 2020-12-05 op (defun vc-got--list-branches ()
319 eb85ad27 2020-12-05 op "Return an alist of (branch . commit)."
320 76d978fa 2021-01-05 op (let (process-file-side-effects)
321 76d978fa 2021-01-05 op (with-temp-buffer
322 76d978fa 2021-01-05 op (when (zerop (vc-got--call "branch" "-l"))
323 76d978fa 2021-01-05 op (goto-char (point-min))
324 76d978fa 2021-01-05 op (cl-loop
325 76d978fa 2021-01-05 op until (= (point) (point-max))
326 76d978fa 2021-01-05 op ;; parse the `* $branchname: $commit', from the end
327 76d978fa 2021-01-05 op ;; XXX: use a regex?
328 76d978fa 2021-01-05 op collect (let* ((_ (move-end-of-line nil))
329 76d978fa 2021-01-05 op (end-commit (point))
330 76d978fa 2021-01-05 op (_ (backward-word))
331 76d978fa 2021-01-05 op (start-commit (point))
332 76d978fa 2021-01-05 op (_ (backward-char 2))
333 76d978fa 2021-01-05 op (end-branchname (point))
334 76d978fa 2021-01-05 op (_ (move-beginning-of-line nil))
335 76d978fa 2021-01-05 op (_ (forward-char 2))
336 76d978fa 2021-01-05 op (start-branchname (point))
337 76d978fa 2021-01-05 op (branchname (buffer-substring start-branchname end-branchname))
338 76d978fa 2021-01-05 op (commit (buffer-substring start-commit end-commit)))
339 76d978fa 2021-01-05 op (forward-line)
340 76d978fa 2021-01-05 op (move-beginning-of-line nil)
341 76d978fa 2021-01-05 op `(,branchname . ,commit)))))))
342 eb85ad27 2020-12-05 op
343 694534b4 2020-12-05 op (defun vc-got--current-branch ()
344 694534b4 2020-12-05 op "Return the current branch."
345 76d978fa 2021-01-05 op (let (process-file-side-effects)
346 76d978fa 2021-01-05 op (with-temp-buffer
347 76d978fa 2021-01-05 op (when (zerop (vc-got--call "branch"))
348 76d978fa 2021-01-05 op (string-trim (buffer-string) "" "\n")))))
349 eb85ad27 2020-12-05 op
350 eb85ad27 2020-12-05 op (defun vc-got--integrate (branch)
351 eb85ad27 2020-12-05 op "Integrate BRANCH into the current one."
352 eb85ad27 2020-12-05 op (with-temp-buffer
353 76d978fa 2021-01-05 op (zerop (vc-got--call "integrate" branch))))
354 db89d6fd 2021-08-16 op
355 db89d6fd 2021-08-16 op (defun vc-got--update (branch &optional paths)
356 db89d6fd 2021-08-16 op "Update to a different commit or BRANCH.
357 db89d6fd 2021-08-16 op Optionally restrict the update operation to files at or within
358 db89d6fd 2021-08-16 op the specified PATHS."
359 db89d6fd 2021-08-16 op (with-temp-buffer
360 db89d6fd 2021-08-16 op (unless (zerop (vc-got--call "update" "-b" branch "--" paths))
361 db89d6fd 2021-08-16 op (error "[vc-got] can't update to branch %s: %s"
362 db89d6fd 2021-08-16 op branch
363 db89d6fd 2021-08-16 op (buffer-string)))))
364 23a0b465 2020-11-30 op
365 eb85ad27 2020-12-05 op (defun vc-got--diff (&rest args)
366 eb85ad27 2020-12-05 op "Call got diff with ARGS. The result will be stored in the current buffer."
367 76d978fa 2021-01-05 op (let (process-file-side-effects)
368 76d978fa 2021-01-05 op (zerop (vc-got--call "diff"
369 76d978fa 2021-01-05 op (vc-switches 'got 'diff)
370 c3185bf7 2021-08-11 op "--"
371 76d978fa 2021-01-05 op (mapcar #'file-relative-name args)))))
372 6b6c8a78 2021-01-04 op
373 6b6c8a78 2021-01-04 op (defun vc-got--unstage (file-or-directory)
374 6b6c8a78 2021-01-04 op "Unstage all the staged hunks at or within FILE-OR-DIRECTORY.
375 6b6c8a78 2021-01-04 op If it's nil, unstage every staged changes across the entire work
376 6b6c8a78 2021-01-04 op tree."
377 c3185bf7 2021-08-11 op (zerop (vc-got--call "unstage" "--" file-or-directory)))
378 a96df0e8 2020-01-03 noreply
379 a96df0e8 2020-01-03 noreply (defun vc-got--remove (file &optional force keep-local)
380 76d978fa 2021-01-05 op "Use got to remove FILE.
381 76d978fa 2021-01-05 op If FORCE is non-nil perform the operation even if a file contains
382 76d978fa 2021-01-05 op local modification. If KEEP-LOCAL is non-nil keep the affected
383 76d978fa 2021-01-05 op files on disk."
384 a96df0e8 2020-01-03 noreply (vc-got-with-worktree (or file default-directory)
385 a96df0e8 2020-01-03 noreply (with-temp-buffer
386 76d978fa 2021-01-05 op (zerop (vc-got--call "remove"
387 76d978fa 2021-01-05 op (when force "-f")
388 76d978fa 2021-01-05 op (when keep-local "-k")
389 c3185bf7 2021-08-11 op "--"
390 76d978fa 2021-01-05 op file)))))
391 eb85ad27 2020-12-05 op
392 5fb2f474 2021-08-10 op (defun vc-got--ref ()
393 5fb2f474 2021-08-10 op "Return a list of all references."
394 5fb2f474 2021-08-10 op (let (process-file-side-effects
395 5fb2f474 2021-08-10 op (re "^refs/\\(heads\\|remotes\\|tags\\)/\\(.*\\):")
396 5fb2f474 2021-08-10 op ;; hardcoding HEAD because it's always present and the regexp
397 5fb2f474 2021-08-10 op ;; won't match it.
398 5fb2f474 2021-08-10 op (table (list "HEAD")))
399 5fb2f474 2021-08-10 op (vc-got-with-worktree default-directory
400 5fb2f474 2021-08-10 op (with-temp-buffer
401 5fb2f474 2021-08-10 op (when (zerop (vc-got--call "ref" "-l"))
402 5fb2f474 2021-08-10 op (goto-char (point-min))
403 5fb2f474 2021-08-10 op (while (re-search-forward re nil t)
404 5fb2f474 2021-08-10 op (push (match-string 2) table))
405 5fb2f474 2021-08-10 op table)))))
406 8014bde1 2021-08-10 op
407 8014bde1 2021-08-10 op (defun vc-got--branch (name)
408 8014bde1 2021-08-10 op "Try to create and switch to the branch called NAME."
409 8014bde1 2021-08-10 op (let (process-file-side-effects)
410 8014bde1 2021-08-10 op (vc-got-with-worktree default-directory
411 8014bde1 2021-08-10 op (with-temp-buffer
412 c3185bf7 2021-08-11 op (if (zerop (vc-got--call "branch" "--" name))
413 8014bde1 2021-08-10 op t
414 8014bde1 2021-08-10 op (error "[vc-got] can't create branch %s: %s" name
415 8014bde1 2021-08-10 op (buffer-string)))))))
416 5fb2f474 2021-08-10 op
417 af5ef7cd 2020-11-29 op
418 af5ef7cd 2020-11-29 op ;; Backend properties
419 af5ef7cd 2020-11-29 op
420 af5ef7cd 2020-11-29 op (defun vc-got-revision-granularity ()
421 af5ef7cd 2020-11-29 op "Got has REPOSITORY granularity."
422 af5ef7cd 2020-11-29 op 'repository)
423 af5ef7cd 2020-11-29 op
424 af5ef7cd 2020-11-29 op ;; XXX: what this should do? The description is not entirely clear
425 af5ef7cd 2020-11-29 op (defun vc-got-update-on-retrieve-tag ()
426 af5ef7cd 2020-11-29 op nil)
427 af5ef7cd 2020-11-29 op
428 af5ef7cd 2020-11-29 op
429 af5ef7cd 2020-11-29 op ;; State-querying functions
430 af5ef7cd 2020-11-29 op
431 af5ef7cd 2020-11-29 op ;;;###autoload (defun vc-got-registered (file)
432 af5ef7cd 2020-11-29 op ;;;###autoload "Return non-nil if FILE is registered with got."
433 af5ef7cd 2020-11-29 op ;;;###autoload (when (vc-find-root file ".got")
434 af5ef7cd 2020-11-29 op ;;;###autoload (load "vc-got" nil t)
435 af5ef7cd 2020-11-29 op ;;;###autoload (vc-got-registered file)))
436 af5ef7cd 2020-11-29 op
437 af5ef7cd 2020-11-29 op (defun vc-got-registered (file)
438 af5ef7cd 2020-11-29 op "Return non-nil if FILE is registered with got."
439 af5ef7cd 2020-11-29 op (if (file-directory-p file)
440 76d978fa 2021-01-05 op nil ; got doesn't track directories
441 4093d2f9 2020-12-04 op (when (vc-find-root file ".got")
442 668dc8eb 2021-01-04 op (let ((s (vc-got-state file)))
443 668dc8eb 2021-01-04 op (not (or (eq s 'unregistered)
444 668dc8eb 2021-01-04 op (null s)))))))
445 af5ef7cd 2020-11-29 op
446 af5ef7cd 2020-11-29 op (defun vc-got-state (file)
447 af5ef7cd 2020-11-29 op "Return the current version control state of FILE. See `vc-state'."
448 af5ef7cd 2020-11-29 op (unless (file-directory-p file)
449 76d978fa 2021-01-05 op (let (process-file-side-effects)
450 76d978fa 2021-01-05 op ;; Manually calling got status and checking the result inline to
451 76d978fa 2021-01-05 op ;; avoid building the data structure in vc-got--status.
452 76d978fa 2021-01-05 op (with-temp-buffer
453 c3185bf7 2021-08-11 op (when (zerop (vc-got--call "status" "--" file))
454 76d978fa 2021-01-05 op (goto-char (point-min))
455 76d978fa 2021-01-05 op (if (eobp)
456 76d978fa 2021-01-05 op 'up-to-date
457 76d978fa 2021-01-05 op (vc-got--parse-status-char (char-after))))))))
458 dcb5b83a 2021-01-08 op
459 dcb5b83a 2021-01-08 op (defun vc-got--dir-filter-files (files)
460 dcb5b83a 2021-01-08 op "Remove ., .. and .got from FILES."
461 dcb5b83a 2021-01-08 op (cl-loop for file in files
462 dcb5b83a 2021-01-08 op unless (or (string= file "..")
463 dcb5b83a 2021-01-08 op (string= file ".")
464 dcb5b83a 2021-01-08 op (string= file ".got"))
465 dcb5b83a 2021-01-08 op collect file))
466 af5ef7cd 2020-11-29 op
467 af5ef7cd 2020-11-29 op (defun vc-got-dir-status-files (dir files update-function)
468 5b4a6b90 2021-01-04 op "Build the status for FILES in DIR.
469 76d978fa 2021-01-05 op The builded result is given to the callback UPDATE-FUNCTION. If
470 5b4a6b90 2021-01-04 op FILES is nil, consider all the files in DIR."
471 dcb5b83a 2021-01-08 op (let* ((fs (vc-got--dir-filter-files (or files (directory-files dir))))
472 d346ca63 2021-01-08 op ;; XXX: we call with files, wich will probably be nil on the
473 d346ca63 2021-01-08 op ;; first run, so we catch deleted, missing and edited files
474 d346ca63 2021-01-08 op ;; in subdirectories.
475 d346ca63 2021-01-08 op (res (vc-got--status nil dir files))
476 d346ca63 2021-01-08 op double-check)
477 82289421 2020-01-02 op (cl-loop for file in fs
478 76d978fa 2021-01-05 op do (when (and (not (cdr (assoc file res #'string=)))
479 76d978fa 2021-01-05 op (not (file-directory-p file))
480 76d978fa 2021-01-05 op ;; if file doesn't exists, it's a
481 76d978fa 2021-01-05 op ;; untracked file that was removed.
482 76d978fa 2021-01-05 op (file-exists-p file))
483 d346ca63 2021-01-08 op ;; if we don't know the status of a file here, it's
484 d346ca63 2021-01-08 op ;; either up-to-date or ignored. Save it for a
485 d346ca63 2021-01-08 op ;; double check
486 d346ca63 2021-01-08 op (push file double-check)))
487 cb973832 2021-01-08 op (cl-loop with statuses = (vc-got--status nil dir double-check)
488 cb973832 2021-01-08 op for file in double-check
489 cb973832 2021-01-08 op unless (eq 'unregistered (cadr (assoc file statuses #'string=)))
490 d346ca63 2021-01-08 op do (push (list file 'up-to-date nil) res))
491 d346ca63 2021-01-08 op (funcall update-function res nil)))
492 af5ef7cd 2020-11-29 op
493 c27df03e 2020-01-03 op (defun vc-got-dir-extra-headers (dir)
494 c27df03e 2020-01-03 op "Return a string for the `vc-dir' buffer heading for directory DIR."
495 76d978fa 2021-01-05 op (let ((remote (vc-got-repository-url dir)))
496 76d978fa 2021-01-05 op (concat (propertize "Repository : " 'face 'font-lock-type-face)
497 76d978fa 2021-01-05 op (vc-got--repo-root) "\n"
498 76d978fa 2021-01-05 op (when remote
499 76d978fa 2021-01-05 op (concat
500 76d978fa 2021-01-05 op (propertize "Remote URL : " 'face 'font-lock-type-face)
501 76d978fa 2021-01-05 op (vc-got-repository-url dir) "\n"))
502 76d978fa 2021-01-05 op (propertize "Branch : " 'face 'font-lock-type-face)
503 76d978fa 2021-01-05 op (vc-got--current-branch))))
504 2d83de2e 2021-01-05 op
505 2d83de2e 2021-01-05 op (defun vc-got-dir-printer (info)
506 2d83de2e 2021-01-05 op "Pretty-printer for the vc-dir-fileinfo structure INFO."
507 2d83de2e 2021-01-05 op (let* ((isdir (vc-dir-fileinfo->directory info))
508 76d978fa 2021-01-05 op (state (if isdir "" (vc-dir-fileinfo->state info)))
509 76d978fa 2021-01-05 op (stage-state (vc-dir-fileinfo->extra info))
510 76d978fa 2021-01-05 op (filename (vc-dir-fileinfo->name info)))
511 2d83de2e 2021-01-05 op (insert
512 2d83de2e 2021-01-05 op (propertize
513 2d83de2e 2021-01-05 op (format "%c" (if (vc-dir-fileinfo->marked info) ?* ? ))
514 2d83de2e 2021-01-05 op 'face 'font-lock-type-face)
515 9e019413 2021-01-05 op " "
516 9e019413 2021-01-05 op (propertize
517 9e019413 2021-01-05 op (if stage-state
518 76d978fa 2021-01-05 op (format "staged:%-6s" stage-state)
519 76d978fa 2021-01-05 op (format "%-13s" ""))
520 9e019413 2021-01-05 op 'face (cond ((memq stage-state '(add edit)) 'font-lock-constant-face)
521 76d978fa 2021-01-05 op ((eq stage-state 'remove) 'font-lock-warning-face)
522 76d978fa 2021-01-05 op (t 'font-lock-variable-name-face)))
523 9e019413 2021-01-05 op " "
524 2d83de2e 2021-01-05 op (propertize
525 2d83de2e 2021-01-05 op (format "%-14s" state)
526 2d83de2e 2021-01-05 op 'face (cond ((eq state 'up-to-date) 'font-lock-builtin-face)
527 76d978fa 2021-01-05 op ((memq state '(missing conflict)) 'font-lock-warning-face)
528 76d978fa 2021-01-05 op ((eq state 'edited) 'font-lock-constant-face)
529 76d978fa 2021-01-05 op (t 'font-lock-variable-name-face))
530 2d83de2e 2021-01-05 op 'mouse-face 'highlight)
531 2d83de2e 2021-01-05 op " "
532 2d83de2e 2021-01-05 op (propertize
533 2d83de2e 2021-01-05 op (format "%s" filename)
534 2d83de2e 2021-01-05 op 'face
535 2d83de2e 2021-01-05 op (if isdir 'font-lock-comment-delimiter-face 'font-lock-function-name-face)
536 2d83de2e 2021-01-05 op 'help-echo
537 2d83de2e 2021-01-05 op (if isdir
538 76d978fa 2021-01-05 op "Directory\nVC operations can be applied to it\nmouse-3: Pop-up menu"
539 76d978fa 2021-01-05 op "File\nmouse-3: Pop-up menu")
540 2d83de2e 2021-01-05 op 'mouse-face 'highlight
541 2d83de2e 2021-01-05 op 'keymap vc-dir-filename-mouse-map))))
542 a8466f02 2020-12-07 op
543 af5ef7cd 2020-11-29 op (defun vc-got-working-revision (file)
544 c0c9a339 2020-12-04 op "Return the id of the last commit that touched the FILE or \"0\" for a new (but added) file."
545 af5ef7cd 2020-11-29 op (or
546 af5ef7cd 2020-11-29 op (with-temp-buffer
547 518ede14 2020-12-05 op (when (vc-got--log file 1)
548 af5ef7cd 2020-11-29 op (let (start)
549 af5ef7cd 2020-11-29 op (goto-char (point-min))
550 76d978fa 2021-01-05 op (forward-word) ; skip "commit"
551 76d978fa 2021-01-05 op (forward-char) ; skip the space
552 76d978fa 2021-01-05 op (setq start (point)) ; store start of the SHA
553 76d978fa 2021-01-05 op (forward-word) ; goto SHA end
554 af5ef7cd 2020-11-29 op (buffer-substring start (point)))))
555 af5ef7cd 2020-11-29 op ;; special case: if this file is added but has no previous commits
556 af5ef7cd 2020-11-29 op ;; touching it, got log will fail (as expected), but we have to
557 af5ef7cd 2020-11-29 op ;; return "0".
558 af5ef7cd 2020-11-29 op (when (eq (vc-got-state file) 'added)
559 af5ef7cd 2020-11-29 op "0")))
560 af5ef7cd 2020-11-29 op
561 af5ef7cd 2020-11-29 op (defun vc-got-checkout-model (_files)
562 5b4a6b90 2021-01-04 op "Got uses an implicit checkout model for every file."
563 af5ef7cd 2020-11-29 op 'implicit)
564 af5ef7cd 2020-11-29 op
565 694534b4 2020-12-05 op (defun vc-got-mode-line-string (file)
566 694534b4 2020-12-05 op "Return the VC mode line string for FILE."
567 694534b4 2020-12-05 op (vc-got-with-worktree file
568 694534b4 2020-12-05 op (let ((def (vc-default-mode-line-string 'Got file)))
569 694534b4 2020-12-05 op (concat (substring def 0 4) (vc-got--current-branch)))))
570 694534b4 2020-12-05 op
571 23a0b465 2020-11-30 op
572 23a0b465 2020-11-30 op ;; state-changing functions
573 23a0b465 2020-11-30 op
574 23a0b465 2020-11-30 op (defun vc-got-create-repo (_backend)
575 7726b6c9 2021-08-10 op "Create an empty repository in the current directory."
576 7726b6c9 2021-08-10 op (error "[vc-got] create-repo not implemented"))
577 23a0b465 2020-11-30 op
578 23a0b465 2020-11-30 op (defun vc-got-register (files &optional _comment)
579 23a0b465 2020-11-30 op "Register FILES, passing `vc-register-switches' to the backend command."
580 23a0b465 2020-11-30 op (vc-got--add files))
581 23a0b465 2020-11-30 op
582 9e805da8 2020-11-30 op (defalias 'vc-got-responsible-p #'vc-got-root)
583 241a3b12 2021-08-11 op
584 241a3b12 2021-08-11 op (defun vc-got-unregister (file)
585 241a3b12 2021-08-11 op "Unregister FILE."
586 9114bbc3 2021-08-11 op (vc-got--remove file t t))
587 23a0b465 2020-11-30 op
588 23a0b465 2020-11-30 op (defun vc-got-checkin (files comment &optional _rev)
589 23a0b465 2020-11-30 op "Commit FILES with COMMENT as commit message."
590 23a0b465 2020-11-30 op (with-temp-buffer
591 ad36649b 2021-02-25 op (unless (zerop (vc-got--call "commit" "-m"
592 e7747ce0 2021-08-11 op (log-edit-extract-headers nil comment)
593 c3185bf7 2021-08-11 op "--"
594 ad36649b 2021-02-25 op files))
595 26362bf0 2021-08-11 op (error "[vc-got] can't commit: %s" (buffer-string)))))
596 23a0b465 2020-11-30 op
597 23a0b465 2020-11-30 op (defun vc-got-find-revision (file rev buffer)
598 c0c9a339 2020-12-04 op "Fill BUFFER with the content of FILE in the given revision REV."
599 23a0b465 2020-11-30 op (when-let (obj-id (assoc file (vc-got--tree rev file) #'string=))
600 23a0b465 2020-11-30 op (with-current-buffer buffer
601 23a0b465 2020-11-30 op (vc-got-with-worktree file
602 23a0b465 2020-11-30 op (vc-got--cat rev obj-id)))))
603 55091167 2020-12-05 op
604 eb85ad27 2020-12-05 op (defun vc-got-checkout (_file &optional _rev)
605 76d978fa 2021-01-05 op "Checkout revision REV of FILE.
606 76d978fa 2021-01-05 op If REV is t, checkout from the head."
607 7726b6c9 2021-08-10 op (error "[vc-got] checkout not implemented"))
608 eb85ad27 2020-12-05 op
609 eb85ad27 2020-12-05 op (defun vc-got-revert (file &optional _content-done)
610 eb85ad27 2020-12-05 op "Revert FILE back to working revision."
611 eb85ad27 2020-12-05 op (vc-got--revert file))
612 eb85ad27 2020-12-05 op
613 eb85ad27 2020-12-05 op (defun vc-got-merge-branch ()
614 eb85ad27 2020-12-05 op "Prompt for a branch and integrate it into the current one."
615 eb85ad27 2020-12-05 op ;; XXX: be smart and try to "got rebase" if "got integrate" fails?
616 eb85ad27 2020-12-05 op (let* ((branches (cl-loop for (branch . commit) in (vc-got--list-branches)
617 eb85ad27 2020-12-05 op collect branch))
618 eb85ad27 2020-12-05 op (branch (completing-read "Merge from branch: " branches)))
619 eb85ad27 2020-12-05 op (when branch
620 eb85ad27 2020-12-05 op (vc-got--integrate branch))))
621 686eac9a 2020-12-07 op
622 dec54a74 2021-02-21 op (defun vc-got--push-pull (cmd op prompt)
623 dec54a74 2021-02-21 op "Execute CMD OP, or prompt the user if PROMPT is non-nil."
624 dec54a74 2021-02-21 op (let ((buffer (format "*vc-got : %s*" (expand-file-name default-directory))))
625 686eac9a 2020-12-07 op (when-let (cmd (if prompt
626 686eac9a 2020-12-07 op (split-string
627 686eac9a 2020-12-07 op (read-shell-command (format "%s %s command: " cmd op)
628 1870c8bd 2021-03-27 op (format "%s %s " cmd op))
629 686eac9a 2020-12-07 op " " t)
630 686eac9a 2020-12-07 op (list cmd op)))
631 dec54a74 2021-02-21 op (apply #'vc-do-async-command buffer default-directory cmd)
632 dec54a74 2021-02-21 op ;; this comes from vc-git.el. We're using git to push, so in
633 dec54a74 2021-02-21 op ;; part it makes sense, but we should revisit for full Got
634 dec54a74 2021-02-21 op ;; support.
635 dec54a74 2021-02-21 op (with-current-buffer buffer
636 dec54a74 2021-02-21 op (vc-compilation-mode 'git)
637 dec54a74 2021-02-21 op (let ((comp-cmd (mapconcat #'identity cmd " ")))
638 dec54a74 2021-02-21 op (setq-local compile-command comp-cmd
639 dec54a74 2021-02-21 op compilation-directory default-directory
640 dec54a74 2021-02-21 op compilation-arguments (list comp-cmd
641 dec54a74 2021-02-21 op nil
642 dec54a74 2021-02-21 op (lambda (_ign) buffer)
643 dec54a74 2021-02-21 op nil))))
644 dec54a74 2021-02-21 op (vc-set-async-update buffer))))
645 eb85ad27 2020-12-05 op
646 67e0b4d2 2021-08-03 op ;; TODO: this can be expanded. See whan omyksh does:
647 67e0b4d2 2021-08-03 op ;; function got-sync {
648 67e0b4d2 2021-08-03 op ;; local _remote _info _branch
649 67e0b4d2 2021-08-03 op ;; _remote=$1
650 67e0b4d2 2021-08-03 op ;; _info="$(got info)"
651 67e0b4d2 2021-08-03 op ;; _branch="$(echo "$_info" | awk '/branch reference:/ {l = split($NF, a, "/"); print a[l]}')"
652 67e0b4d2 2021-08-03 op ;; [ -z $_remote ] && _remote="origin"
653 67e0b4d2 2021-08-03 op ;; [ -z $_branch ] && _branch="main"
654 67e0b4d2 2021-08-03 op ;; got fetch "$_remote" && got update -b "$_remote/$_branch" && \
655 67e0b4d2 2021-08-03 op ;; got rebase $_branch
656 67e0b4d2 2021-08-03 op ;; }
657 eb85ad27 2020-12-05 op (defun vc-got-pull (prompt)
658 eb85ad27 2020-12-05 op "Execute got pull, prompting the user for the full command if PROMPT is not nil."
659 dec54a74 2021-02-21 op (let ((default-directory (vc-got-root default-directory)))
660 dec54a74 2021-02-21 op (vc-got--push-pull vc-got-program "fetch" prompt)))
661 686eac9a 2020-12-07 op
662 686eac9a 2020-12-07 op (defun vc-got-push (prompt)
663 686eac9a 2020-12-07 op "Run git push (not got!) in the repository dir.
664 686eac9a 2020-12-07 op If PROMPT is non-nil, prompt for the git command to run."
665 dec54a74 2021-02-21 op (let ((default-directory (vc-got--repo-root)))
666 dec54a74 2021-02-21 op (vc-got--push-pull "git" "push" prompt)))
667 eb85ad27 2020-12-05 op
668 424f5152 2021-08-10 op
669 424f5152 2021-08-10 op ;; History functions
670 424f5152 2021-08-10 op
671 eb85ad27 2020-12-05 op (defun vc-got-print-log (files buffer &optional _shortlog start-revision limit)
672 eb85ad27 2020-12-05 op "Insert the revision log for FILES into BUFFER.
673 76d978fa 2021-01-05 op LIMIT limits the number of commits, optionally starting at
674 76d978fa 2021-01-05 op START-REVISION."
675 eb85ad27 2020-12-05 op (with-current-buffer buffer
676 eb85ad27 2020-12-05 op ;; the *vc-diff* may be read only
677 4571b1fd 2020-12-05 op (let ((inhibit-read-only t))
678 eb85ad27 2020-12-05 op (cl-loop for file in files
679 4571b1fd 2020-12-05 op do (vc-got--log (file-relative-name file) limit start-revision)))))
680 eb85ad27 2020-12-05 op
681 9ad1eb5d 2020-12-07 op ;; XXX: this includes also the latest commit in REMOTE-LOCATION.
682 9ad1eb5d 2020-12-07 op (defun vc-got-log-outgoing (buffer remote-location)
683 9ad1eb5d 2020-12-07 op "Fill BUFFER with the diff between the local worktree branch and REMOTE-LOCATION."
684 9ad1eb5d 2020-12-07 op (vc-setup-buffer buffer)
685 9ad1eb5d 2020-12-07 op (let ((rl (if (or (not remote-location) (string-empty-p remote-location))
686 9ad1eb5d 2020-12-07 op (concat "origin/" (vc-got--current-branch))
687 9ad1eb5d 2020-12-07 op remote-location))
688 9ad1eb5d 2020-12-07 op (inhibit-read-only t))
689 9ad1eb5d 2020-12-07 op (with-current-buffer buffer
690 9ad1eb5d 2020-12-07 op (vc-got--log nil nil nil rl))))
691 6eda2f1f 2020-12-26 op
692 6eda2f1f 2020-12-26 op (defun vc-got-incoming (buffer remote-location)
693 6eda2f1f 2020-12-26 op "Fill BUFFER with the diff between the REMOTE-LOCATION and the local worktree branch."
694 6eda2f1f 2020-12-26 op (let ((rl (if (or (not remote-location) (string-empty-p remote-location))
695 6eda2f1f 2020-12-26 op (concat "origin/" (vc-got--current-branch))
696 6eda2f1f 2020-12-26 op remote-location))
697 6eda2f1f 2020-12-26 op (inhibit-read-only t))
698 6eda2f1f 2020-12-26 op (with-current-buffer buffer
699 6eda2f1f 2020-12-26 op (vc-got--log nil nil (vc-got--current-branch) rl))))
700 9ad1eb5d 2020-12-07 op
701 eb85ad27 2020-12-05 op (defun vc-got-log-search (buffer pattern)
702 eb85ad27 2020-12-05 op "Search commits for PATTERN and write the results found in BUFFER."
703 eb85ad27 2020-12-05 op (with-current-buffer buffer
704 eb85ad27 2020-12-05 op (let ((inhibit-read-only t))
705 9ad1eb5d 2020-12-07 op (vc-got--log nil nil nil nil pattern))))
706 eb85ad27 2020-12-05 op
707 0a3316a6 2021-02-22 op (define-derived-mode vc-got-log-view-mode log-view-mode "Got-Log-View"
708 0a3316a6 2021-02-22 op "Got-specific log-view mode.
709 0a3316a6 2021-02-22 op Heavily inspired by `vc-git-log-view-mode'."
710 0a3316a6 2021-02-22 op (require 'add-log)
711 0a3316a6 2021-02-22 op (setq-local
712 0a3316a6 2021-02-22 op log-view-file-re regexp-unmatchable
713 0a3316a6 2021-02-22 op log-view-per-file-logs nil
714 0a3316a6 2021-02-22 op log-view-message-re "^commit +\\([0-9a-z]+\\)"
715 0a3316a6 2021-02-22 op
716 0a3316a6 2021-02-22 op log-view-font-lock-keywords
717 0a3316a6 2021-02-22 op (append
718 0a3316a6 2021-02-22 op `((,log-view-message-re (1 'change-log-acknowledgment)))
719 0a3316a6 2021-02-22 op ;; Handle the case:
720 0a3316a6 2021-02-22 op ;; user: foo@bar
721 0a3316a6 2021-02-22 op '(("^from: \\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)"
722 0a3316a6 2021-02-22 op (1 'change-log-email))
723 0a3316a6 2021-02-22 op ;; Handle the case:
724 0a3316a6 2021-02-22 op ;; user: FirstName LastName <foo@bar>
725 0a3316a6 2021-02-22 op ("^from: \\([^<(]+?\\)[ \t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]"
726 0a3316a6 2021-02-22 op (1 'change-log-name)
727 0a3316a6 2021-02-22 op (2 'change-log-email))
728 0a3316a6 2021-02-22 op ("^date: \\(.+\\)" (1 'change-log-date))))))
729 0a3316a6 2021-02-22 op
730 eb85ad27 2020-12-05 op ;; TODO: async
731 f18d3e11 2020-12-05 op ;; TODO: return 0 or 1
732 eb85ad27 2020-12-05 op (defun vc-got-diff (files &optional rev1 rev2 buffer _async)
733 eb85ad27 2020-12-05 op "Insert into BUFFER (or *vc-diff*) the diff for FILES from REV1 to REV2."
734 f457868b 2020-12-07 op (let* ((buffer (get-buffer-create (or buffer "*vc-diff*")))
735 eb85ad27 2020-12-05 op (inhibit-read-only t))
736 eb85ad27 2020-12-05 op (with-current-buffer buffer
737 8ec0bb76 2021-08-11 op (vc-got-with-worktree (or (car files)
738 8ec0bb76 2021-08-11 op default-directory)
739 e9a5df05 2021-08-10 op (if (and (null rev1)
740 e9a5df05 2021-08-10 op (null rev2))
741 e9a5df05 2021-08-10 op (dolist (file files)
742 e9a5df05 2021-08-10 op (vc-got--diff file))
743 e9a5df05 2021-08-10 op ;; TODO: if rev1 is nil, diff from the current version until
744 e9a5df05 2021-08-10 op ;; rev2.
745 83559c7c 2021-08-11 op ;;
746 e9a5df05 2021-08-10 op ;; TODO: if rev2 is nil as well, diff against an empty tree
747 e9a5df05 2021-08-10 op ;; (i.e. get the patch from `got log -p rev1')
748 83559c7c 2021-08-11 op ;;
749 83559c7c 2021-08-11 op ;; TODO: it would be nice to optionally include FILES here,
750 83559c7c 2021-08-11 op ;; it would make the `=' key on the *Annotate* buffer do the
751 83559c7c 2021-08-11 op ;; right thing, but AFAICS got doesn't provide something
752 83559c7c 2021-08-11 op ;; like this. Probably only hacking something with ``log
753 83559c7c 2021-08-11 op ;; -p'' and filtering?
754 e9a5df05 2021-08-10 op (vc-got--diff rev1 rev2))))))
755 5fb2f474 2021-08-10 op
756 5fb2f474 2021-08-10 op (defun vc-got-revision-completion-table (_files)
757 5fb2f474 2021-08-10 op "Return a completion table for existing revisions.
758 5fb2f474 2021-08-10 op Ignores FILES because GoT doesn't have the concept of ``file
759 5fb2f474 2021-08-10 op revisions''; instead, like with git, you have tags and branches."
760 5fb2f474 2021-08-10 op (letrec ((table (lazy-completion-table
761 5fb2f474 2021-08-10 op table (lambda () (vc-got--ref)))))
762 5fb2f474 2021-08-10 op table))
763 3f25d9ff 2020-01-02 noreply
764 3f25d9ff 2020-01-02 noreply (defun vc-got-annotate-command (file buf &optional rev)
765 67332bad 2021-01-05 op "Show annotated contents of FILE in buffer BUF. If given, use revision REV."
766 3f25d9ff 2020-01-02 noreply (let (process-file-side-effects)
767 3f25d9ff 2020-01-02 noreply (with-current-buffer buf
768 3f25d9ff 2020-01-02 noreply ;; FIXME: vc-ensure-vc-buffer won't recognise this buffer as managed
769 3f25d9ff 2020-01-02 noreply ;; by got unless vc-parent-buffer points to a buffer managed by got.
770 3f25d9ff 2020-01-02 noreply ;; investigate why this is needed.
771 3f25d9ff 2020-01-02 noreply (set (make-local-variable 'vc-parent-buffer) (find-file-noselect file))
772 76d978fa 2021-01-05 op (vc-got--call "blame"
773 76d978fa 2021-01-05 op (when rev (list "-c" rev))
774 c3185bf7 2021-08-11 op "--"
775 76d978fa 2021-01-05 op file))))
776 3f25d9ff 2020-01-02 noreply
777 3f25d9ff 2020-01-02 noreply (defconst vc-got--annotate-re
778 3f25d9ff 2020-01-02 noreply (concat "^[0-9]\\{1,\\}) " ; line number followed by )
779 3f25d9ff 2020-01-02 noreply "\\([a-z0-9]+\\) " ; SHA-1 of commit
780 3f25d9ff 2020-01-02 noreply "\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}\\) " ; year-mm-dd
781 3f25d9ff 2020-01-02 noreply "\\([^ ]\\)+ ") ; author
782 3f25d9ff 2020-01-02 noreply "Regexp to match annotation output lines.
783 3f25d9ff 2020-01-02 noreply
784 3f25d9ff 2020-01-02 noreply Provides capture groups for:
785 3f25d9ff 2020-01-02 noreply 1. revision id
786 3f25d9ff 2020-01-02 noreply 2. date of commit
787 3f25d9ff 2020-01-02 noreply 3. author of commit")
788 3f25d9ff 2020-01-02 noreply
789 3f25d9ff 2020-01-02 noreply (defconst vc-got--commit-re "^commit \\([a-z0-9]+\\)"
790 3f25d9ff 2020-01-02 noreply "Regexp to match commit lines.
791 3f25d9ff 2020-01-02 noreply
792 3f25d9ff 2020-01-02 noreply Provides capture group for the commit revision id.")
793 3f25d9ff 2020-01-02 noreply
794 3f25d9ff 2020-01-02 noreply (defun vc-got-annotate-time ()
795 3f25d9ff 2020-01-02 noreply "Return the time of the next line of annotation at or after point.
796 3f25d9ff 2020-01-02 noreply Value is returned as floating point fractional number of days."
797 3f25d9ff 2020-01-02 noreply (save-excursion
798 3f25d9ff 2020-01-02 noreply (beginning-of-line)
799 3f25d9ff 2020-01-02 noreply (when (looking-at vc-got--annotate-re)
800 3f25d9ff 2020-01-02 noreply (let ((str (match-string-no-properties 2)))
801 3f25d9ff 2020-01-02 noreply (vc-annotate-convert-time
802 3f25d9ff 2020-01-02 noreply (encode-time 0 0 0
803 3f25d9ff 2020-01-02 noreply (string-to-number (substring str 8 10))
804 3f25d9ff 2020-01-02 noreply (string-to-number (substring str 5 7))
805 3f25d9ff 2020-01-02 noreply (string-to-number (substring str 0 4))))))))
806 eb85ad27 2020-12-05 op
807 3f25d9ff 2020-01-02 noreply (defun vc-got-annotate-extract-revision-at-line ()
808 67332bad 2021-01-05 op "Return revision corresponding to the current line or nil."
809 3f25d9ff 2020-01-02 noreply (save-excursion
810 3f25d9ff 2020-01-02 noreply (beginning-of-line)
811 3f25d9ff 2020-01-02 noreply (when (looking-at vc-got--annotate-re)
812 3f25d9ff 2020-01-02 noreply (match-string-no-properties 1))))
813 3f25d9ff 2020-01-02 noreply
814 424f5152 2021-08-10 op
815 8014bde1 2021-08-10 op ;; Tag system
816 6ab1c7b4 2021-08-11 op
817 6ab1c7b4 2021-08-11 op (defun vc-got--tag-callback (tag)
818 6ab1c7b4 2021-08-11 op "`log-edit' callback for `vc-got-create-tag'.
819 6ab1c7b4 2021-08-11 op Creates the TAG using the content of the current buffer."
820 6ab1c7b4 2021-08-11 op (interactive)
821 6ab1c7b4 2021-08-11 op (let ((msg (buffer-substring-no-properties (point-min)
822 6ab1c7b4 2021-08-11 op (point-max))))
823 6ab1c7b4 2021-08-11 op (with-temp-buffer
824 c3185bf7 2021-08-11 op (unless (zerop (vc-got--call "tag" "-m" msg "--" tag))
825 6ab1c7b4 2021-08-11 op (error "[vc-got] can't create tag %s: %s" tag (buffer-string))))))
826 8014bde1 2021-08-10 op
827 8014bde1 2021-08-10 op (defun vc-got-create-tag (_dir name branchp)
828 8014bde1 2021-08-10 op "Attach the tag NAME to the state of the worktree.
829 6ab1c7b4 2021-08-11 op DIR is ignored (tags are global, not per-file). If BRANCHP is
830 6ab1c7b4 2021-08-11 op true, NAME should create a new branch otherwise it will pop-up a
831 6ab1c7b4 2021-08-11 op `log-edit' buffer to provide the tag message."
832 8014bde1 2021-08-10 op ;; TODO: vc reccomends to ensure that all the file are in a clean
833 8014bde1 2021-08-10 op ;; state, but is it useful?
834 8014bde1 2021-08-10 op (if branchp
835 8014bde1 2021-08-10 op (vc-got--branch name)
836 6ab1c7b4 2021-08-11 op (let ((buf (get-buffer-create "*vc-got tag*")))
837 6ab1c7b4 2021-08-11 op (with-current-buffer buf
838 6ab1c7b4 2021-08-11 op (erase-buffer)
839 6ab1c7b4 2021-08-11 op (switch-to-buffer buf)
840 6ab1c7b4 2021-08-11 op (log-edit (lambda ()
841 6ab1c7b4 2021-08-11 op (interactive)
842 6ab1c7b4 2021-08-11 op (unwind-protect
843 6ab1c7b4 2021-08-11 op (vc-got--tag-callback name)
844 6ab1c7b4 2021-08-11 op (kill-buffer buf))))))))
845 8014bde1 2021-08-10 op
846 09d59379 2021-08-11 op (defun vc-got-retrieve-tag (dir name _update)
847 09d59379 2021-08-11 op "Switch to the tag NAME for files at or below DIR."
848 09d59379 2021-08-11 op (let ((default-directory dir))
849 db89d6fd 2021-08-16 op (vc-got--update name dir)))
850 09d59379 2021-08-11 op
851 8014bde1 2021-08-10 op
852 424f5152 2021-08-10 op ;; Miscellaneous
853 424f5152 2021-08-10 op
854 2552a6c7 2021-08-11 op (defun vc-got-find-ignore-file (file)
855 2552a6c7 2021-08-11 op "Return the gitignore file that controls FILE."
856 2552a6c7 2021-08-11 op (expand-file-name ".gitignore"
857 2552a6c7 2021-08-11 op (vc-got-root file)))
858 2552a6c7 2021-08-11 op
859 3f25d9ff 2020-01-02 noreply (defun vc-got-previous-revision (file rev)
860 3f25d9ff 2020-01-02 noreply "Return the revision number that precedes REV for FILE, or nil if no such revision exists."
861 3f25d9ff 2020-01-02 noreply (with-temp-buffer
862 3f25d9ff 2020-01-02 noreply (vc-got--log file 2 rev nil nil t)
863 3f25d9ff 2020-01-02 noreply (goto-char (point-min))
864 3f25d9ff 2020-01-02 noreply (keep-lines "^commit")
865 3f25d9ff 2020-01-02 noreply (when (looking-at vc-got--commit-re)
866 3f25d9ff 2020-01-02 noreply (match-string-no-properties 1))))
867 3f25d9ff 2020-01-02 noreply
868 3f25d9ff 2020-01-02 noreply (defun vc-got-next-revision (file rev)
869 67332bad 2021-01-05 op "Return the revision number that follows REV for FILE, or nil if no such revision exists."
870 3f25d9ff 2020-01-02 noreply (with-temp-buffer
871 3f25d9ff 2020-01-02 noreply (vc-got--log file nil nil rev)
872 3f25d9ff 2020-01-02 noreply (keep-lines "^commit" (point-min) (point-max))
873 3f25d9ff 2020-01-02 noreply (goto-char (point-max))
874 76d978fa 2021-01-05 op (forward-line -1) ; return from empty line to last actual commit
875 3f25d9ff 2020-01-02 noreply (unless (= (point) (point-min))
876 3f25d9ff 2020-01-02 noreply (forward-line -1)
877 3f25d9ff 2020-01-02 noreply (when (looking-at vc-got--commit-re)
878 3f25d9ff 2020-01-02 noreply (match-string-no-properties 1)))))
879 3f25d9ff 2020-01-02 noreply
880 a96df0e8 2020-01-03 noreply (defun vc-got-delete-file (file)
881 a96df0e8 2020-01-03 noreply "Delete FILE locally and mark it deleted in work tree."
882 a96df0e8 2020-01-03 noreply (vc-got--remove file t))
883 a96df0e8 2020-01-03 noreply
884 c151c257 2021-08-03 op (defun vc-got-find-file-hook ()
885 c151c257 2021-08-03 op "Activate `smerge-mode' if there is a conflict."
886 c151c257 2021-08-03 op ;; just like vc-git-find-file-hook
887 c151c257 2021-08-03 op (when (and buffer-file-name
888 c151c257 2021-08-03 op (eq (vc-state buffer-file-name 'Got) 'conflict)
889 c151c257 2021-08-03 op (save-excursion
890 c151c257 2021-08-03 op (goto-char (point-min))
891 c151c257 2021-08-03 op (re-search-forward "^<<<<<<< " nil 'noerror)))
892 c151c257 2021-08-03 op (smerge-start-session)
893 c151c257 2021-08-03 op (vc-message-unresolved-conflicts buffer-file-name)))
894 c151c257 2021-08-03 op
895 7bb16f79 2020-01-03 op (defun vc-got-conflicted-files (dir)
896 7bb16f79 2020-01-03 op "Return the list of files with conflicts in directory DIR."
897 7bb16f79 2020-01-03 op (let* ((root (vc-got-root dir))
898 7bb16f79 2020-01-03 op (default-directory root)
899 7bb16f79 2020-01-03 op (process-file-side-effects))
900 7bb16f79 2020-01-03 op (cl-loop with conflicts = nil
901 668dc8eb 2021-01-04 op for (file status _) in (vc-got--status "C" ".")
902 7bb16f79 2020-01-03 op do (when (and (eq status 'conflict)
903 7bb16f79 2020-01-03 op (file-in-directory-p file dir))
904 7bb16f79 2020-01-03 op (push file conflicts))
905 7bb16f79 2020-01-03 op finally return conflicts)))
906 7bb16f79 2020-01-03 op
907 8b635a9f 2020-01-03 op (defun vc-got-repository-url (_file &optional remote-name)
908 8b635a9f 2020-01-03 op "Return URL for REMOTE-NAME, or for \"origin\" if nil."
909 8b635a9f 2020-01-03 op (let* ((default-directory (vc-got--repo-root))
910 8b635a9f 2020-01-03 op (remote-name (or remote-name "origin"))
911 8b635a9f 2020-01-03 op (heading (concat "[remote \"" remote-name "\"]"))
912 76d978fa 2021-01-05 op (conf (cond ((file-exists-p ".git/config") ".git/config")
913 76d978fa 2021-01-05 op ((file-exists-p ".git") nil)
914 76d978fa 2021-01-05 op ((file-exists-p "config") "config")))
915 8b635a9f 2020-01-03 op found)
916 6f42ede4 2021-01-05 op (when conf
917 6f42ede4 2021-01-05 op (with-temp-buffer
918 f8a9db56 2020-01-03 op (insert-file-contents conf)
919 f8a9db56 2020-01-03 op (goto-char (point-min))
920 f8a9db56 2020-01-03 op (when (search-forward heading nil t)
921 f8a9db56 2020-01-03 op (forward-line)
922 f8a9db56 2020-01-03 op (while (and (not found)
923 76d978fa 2021-01-05 op (looking-at ".*=") ; too broad?
924 7a5ead65 2020-01-03 op (not (= (point) (point-max))))
925 f8a9db56 2020-01-03 op (when (looking-at ".*url = \\(.*\\)")
926 7a5ead65 2020-01-03 op (setq found (match-string-no-properties 1)))
927 7a5ead65 2020-01-03 op (forward-line))
928 f8a9db56 2020-01-03 op found)))))
929 8b635a9f 2020-01-03 op
930 2d83de2e 2021-01-05 op
931 2d83de2e 2021-01-05 op ;; hacks
932 2d83de2e 2021-01-05 op (defun vc-got-fix-dir-move-to-goal-column (fn)
933 2d83de2e 2021-01-05 op "Move the cursor on the file column.
934 76d978fa 2021-01-05 op Adviced around `vc-dir-move-to-goal-column' (FN) because it hardcodes column 25."
935 2d83de2e 2021-01-05 op (if (not (vc-find-root default-directory ".got"))
936 2d83de2e 2021-01-05 op (funcall fn)
937 2d83de2e 2021-01-05 op (beginning-of-line)
938 2d83de2e 2021-01-05 op (unless (eolp)
939 9e019413 2021-01-05 op (forward-char 31))))
940 2d83de2e 2021-01-05 op (advice-add 'vc-dir-move-to-goal-column :around #'vc-got-fix-dir-move-to-goal-column)
941 2d83de2e 2021-01-05 op
942 af5ef7cd 2020-11-29 op (provide 'vc-got)
943 af5ef7cd 2020-11-29 op ;;; vc-got.el ends here