fordon_greeman / voidfiles

Branch: 2079ec5
Switch branches/tags
main
theidioticdev add emacs 2079ec5 23h ago
286 lines · 11 KB Raw Blame History
1 ;;; magit-transient.el --- Support for transients -*- lexical-binding:t -*-
2
3 ;; Copyright (C) 2008-2026 The Magit Project Contributors
4
5 ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
6 ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev>
7
8 ;; SPDX-License-Identifier: GPL-3.0-or-later
9
10 ;; Magit is free software: you can redistribute it and/or modify it
11 ;; under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
14 ;;
15 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
16 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
18 ;; License for more details.
19 ;;
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with Magit. If not, see <https://www.gnu.org/licenses/>.
22
23 ;;; Commentary:
24
25 ;; This library implements Magit-specific prefix and suffix classes,
26 ;; and their methods.
27
28 ;;; Code:
29
30 (require 'magit-git)
31 (require 'magit-mode)
32 (require 'magit-process)
33
34 (require 'transient)
35
36 ;;; Classes
37
38 (defclass magit--git-variable (transient-variable)
39 ((scope :initarg :scope)
40 (global :initarg :global :initform nil)
41 (default :initarg :default :initform nil)
42 (location :initform nil)
43 (accessible-format :initform "%i%k %d is %v")))
44
45 (defclass magit--git-variable:choices (magit--git-variable)
46 ((choices :initarg :choices)
47 (fallback :initarg :fallback :initform nil)))
48
49 (defclass magit--git-variable:boolean (magit--git-variable:choices)
50 ((choices :initarg :choices :initform '("true" "false"))))
51
52 (defclass magit--git-variable:urls (magit--git-variable)
53 ((seturl-arg :initarg :seturl-arg :initform nil)))
54
55 ;;; Methods
56 ;;;; Init
57
58 (cl-defmethod transient-init-scope ((obj magit--git-variable))
59 (oset obj scope
60 (cond (transient--prefix
61 (oref transient--prefix scope))
62 ((slot-boundp obj 'scope)
63 (funcall (oref obj scope) obj)))))
64
65 (cl-defmethod transient-init-value ((obj magit--git-variable))
66 (oset obj variable (format (oref obj variable) (oref obj scope)))
67 (cond-let
68 ((oref obj global)
69 (oset obj location 'global)
70 (oset obj value (magit--git-variable-get obj "--global")))
71 ([_(magit-get-boolean "extensions.worktreeConfig")]
72 [val (magit--git-variable-get obj "--worktree")]
73 (oset obj location 'worktree)
74 (oset obj value val))
75 (t
76 (oset obj location 'local)
77 (oset obj value (magit--git-variable-get obj "--local")))))
78
79 (defun magit--git-variable-get (obj arg)
80 (let ((var (oref obj variable)))
81 (cond
82 ((cl-typep obj 'magit--git-variable:boolean)
83 (with-temp-buffer
84 (and (zerop (magit-process-git t "config" "--bool" arg var))
85 (buffer-substring (point-min) (1- (point-max))))))
86 ((oref obj multi-value)
87 (magit-get-all arg var))
88 ((magit-get arg var)))))
89
90 ;;;; Read
91
92 (cl-defmethod transient-infix-read :around ((obj magit--git-variable:urls))
93 (transient--with-emergency-exit
94 (transient--with-suspended-override
95 (mapcar (lambda (url)
96 (if (string-prefix-p "~" url)
97 (expand-file-name url)
98 url))
99 (cl-call-next-method obj)))))
100
101 (cl-defmethod transient-infix-read :around ((obj magit--git-variable))
102 (pcase (list (and (= (prefix-numeric-value current-prefix-arg) 16)
103 (magit-get-boolean "extensions.worktreeConfig"))
104 (oref obj location))
105 ('(t local)
106 (oset obj location 'worktree)
107 (oref obj value))
108 ('(t worktree)
109 (oset obj location 'local)
110 (magit-set nil "--worktree" (oref obj variable))
111 (magit--git-variable-get obj "--local"))
112 (_ (cl-call-next-method obj))))
113
114 (cl-defmethod transient-infix-read ((obj magit--git-variable:choices))
115 (let ((choices (oref obj choices)))
116 (when (functionp choices)
117 (setq choices (funcall choices)))
118 (cond-let
119 ((or transient-prefer-reading-value current-prefix-arg)
120 (pcase-let*
121 ((`(,unset . ,choices)
122 (magit--git-variable-list-choices obj))
123 (unset (or unset "(unset)"))
124 (choice (magit-completing-read
125 (format "Set `%s' to" (oref obj variable))
126 (nconc (mapcar #'magit--delete-text-properties choices)
127 (list (propertize unset 'face
128 'transient-inactive-value)))
129 nil t)))
130 (if (equal choice unset) nil choice)))
131 ([value (oref obj value)]
132 (cadr (member value choices)))
133 ((car choices)))))
134
135 ;;;; Readers
136
137 (defun magit-transient-read-person (prompt initial-input history)
138 (magit-completing-read
139 prompt (magit-list-people) nil nil initial-input history))
140
141 (defun magit-transient-read-persons (prompt initial-input history)
142 (magit-completing-read-multiple
143 prompt (magit-list-people) nil nil initial-input history))
144
145 (defun magit-list-people ()
146 (mapcar (##save-excursion
147 (and (string-match "\\`[\s\t]+[0-9]+\t" %)
148 (list (substring % (match-end 0)))))
149 (magit-git-lines "shortlog" "-n" "-s" "-e" "HEAD")))
150
151 (defun magit-transient-read-revision (prompt initial-input history)
152 (magit-completing-read prompt (cons "HEAD" (magit-list-refnames))
153 nil 'any initial-input history
154 (or (magit-branch-or-commit-at-point)
155 (magit-get-current-branch))))
156
157 ;;;; Set
158
159 (cl-defmethod transient-infix-set ((obj magit--git-variable) value)
160 (let ((variable (oref obj variable))
161 (arg (format "--%s" (oref obj location))))
162 (oset obj value value)
163 (if (oref obj multi-value)
164 (magit-set-all value arg variable)
165 (magit-set value arg variable))
166 (magit-refresh)
167 (unless (or value transient--prefix)
168 (message "Unset %s" variable))))
169
170 (cl-defmethod transient-infix-set ((obj magit--git-variable:urls) values)
171 (let ((previous (oref obj value))
172 (seturl (oref obj seturl-arg))
173 (remote (oref transient--prefix scope)))
174 (oset obj value values)
175 (dolist (v (cl-set-difference values previous :test #'equal))
176 (magit-call-git "remote" "set-url" seturl "--add" remote v))
177 (dolist (v (cl-set-difference previous values :test #'equal))
178 (magit-call-git "remote" "set-url" seturl "--delete" remote
179 (concat "^" (regexp-quote v) "$")))
180 (magit-refresh)))
181
182 ;;;; Draw
183
184 (cl-defmethod transient-format-description ((obj magit--git-variable))
185 (concat (and (eq (oref obj location) 'worktree)
186 "worktree's ")
187 (or (oref obj description)
188 (oref obj variable))))
189
190 (cl-defmethod transient-format-value ((obj magit--git-variable))
191 (cond-let*
192 ([value (oref obj value)]
193 (if (oref obj multi-value)
194 (if (cdr value)
195 (mapconcat (##concat "\n "
196 (propertize % 'face 'transient-value))
197 value "")
198 (propertize (car value) 'face 'transient-value))
199 (propertize (car (split-string value "\n"))
200 'face 'transient-value)))
201 ([default (oref obj default)]
202 [default (if (functionp default) (funcall default) default)]
203 (if transient-prefer-reading-value
204 (format "unset, using default, which is %s"
205 (propertize default 'face 'transient-value))
206 (concat (propertize "default:" 'face 'transient-inactive-value)
207 (propertize default 'face 'transient-value))))
208 ((propertize "unset" 'face 'transient-inactive-value))))
209
210 (cl-defmethod transient-format-value ((obj magit--git-variable:choices))
211 (if transient-prefer-reading-value
212 (cl-call-next-method)
213 (pcase-let ((`(,fallback . ,choices) (magit--git-variable-list-choices obj)))
214 (concat
215 (propertize "[" 'face 'transient-inactive-value)
216 (string-join choices (propertize "|" 'face 'transient-inactive-value))
217 (and fallback (propertize "|" 'face 'transient-inactive-value))
218 fallback
219 (propertize "]" 'face 'transient-inactive-value)))))
220
221 (defun magit--git-variable-list-choices (obj)
222 (with-slots (choices value location) obj
223 (when (functionp choices)
224 (setq choices (funcall choices)))
225 (cons
226 (cond-let*
227 ([_(eq location 'worktree)]
228 [local (magit--git-variable-get obj "--local")]
229 (propertize (concat "local:" local)
230 'face (cond (value
231 'transient-inactive-value)
232 ((member local choices)
233 'transient-value)
234 ('font-lock-warning-face))))
235 ([_(not (eq location 'global))]
236 [global (magit--git-variable-get obj "--global")]
237 (propertize (concat "global:" global)
238 'face (cond (value
239 'transient-inactive-value)
240 ((member global choices)
241 'transient-value)
242 ('font-lock-warning-face))))
243 ([fallback* (oref obj fallback)]
244 [fallback (magit-get fallback*)]
245 (propertize (concat fallback* ":" fallback)
246 'face (if value
247 'transient-inactive-value
248 'transient-value)))
249 ([default* (oref obj default)]
250 [default (if (functionp default*) (funcall default* obj) default*)]
251 (propertize (if (functionp default*)
252 (concat "dwim:" default)
253 (concat "default:" default))
254 'face (if value
255 'transient-inactive-value
256 'transient-value))))
257 (mapcar (lambda (choice)
258 (propertize choice
259 'face (if (equal choice value)
260 (if (member choice choices)
261 'transient-value
262 'font-lock-warning-face)
263 'transient-inactive-value)))
264 (if (and value (not (member value choices)))
265 (cons value choices)
266 choices)))))
267
268 ;;; _
269 (provide 'magit-transient)
270 ;; Local Variables:
271 ;; read-symbol-shorthands: (
272 ;; ("and$" . "cond-let--and$")
273 ;; ("thread$" . "cond-let--thread$")
274 ;; ("when$" . "cond-let--when$")
275 ;; ("and-let*" . "cond-let--and-let*")
276 ;; ("and-let" . "cond-let--and-let")
277 ;; ("if-let*" . "cond-let--if-let*")
278 ;; ("if-let" . "cond-let--if-let")
279 ;; ("when-let*" . "cond-let--when-let*")
280 ;; ("when-let" . "cond-let--when-let")
281 ;; ("while-let*" . "cond-let--while-let*")
282 ;; ("while-let" . "cond-let--while-let")
283 ;; ("match-string" . "match-string")
284 ;; ("match-str" . "match-string-no-properties"))
285 ;; End:
286 ;;; magit-transient.el ends here