Blame


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