commit | author | age
|
5cb5f7
|
1 |
;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*- |
C |
2 |
|
|
3 |
;; Copyright (C) 2010-2018 The Magit Project Contributors |
|
4 |
;; |
|
5 |
;; You should have received a copy of the AUTHORS.md file which |
|
6 |
;; lists all contributors. If not, see http://magit.vc/authors. |
|
7 |
|
|
8 |
;; Author: Jonas Bernoulli <jonas@bernoul.li> |
|
9 |
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li> |
|
10 |
|
|
11 |
;; Magit is free software; you can redistribute it and/or modify it |
|
12 |
;; under the terms of the GNU General Public License as published by |
|
13 |
;; the Free Software Foundation; either version 3, or (at your option) |
|
14 |
;; any later version. |
|
15 |
;; |
|
16 |
;; Magit is distributed in the hope that it will be useful, but WITHOUT |
|
17 |
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|
18 |
;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
|
19 |
;; License for more details. |
|
20 |
;; |
|
21 |
;; You should have received a copy of the GNU General Public License |
|
22 |
;; along with Magit. If not, see http://www.gnu.org/licenses. |
|
23 |
|
|
24 |
;;; Commentary: |
|
25 |
|
|
26 |
;; This library implements the abstract major-mode `magit-mode' from |
|
27 |
;; which almost all other Magit major-modes derive. The code in here |
|
28 |
;; is mostly concerned with creating and refreshing Magit buffers. |
|
29 |
|
|
30 |
;;; Code: |
|
31 |
|
|
32 |
(require 'cl-lib) |
|
33 |
(require 'dash) |
|
34 |
|
|
35 |
(eval-when-compile |
|
36 |
(require 'subr-x)) |
|
37 |
|
|
38 |
(require 'magit-section) |
|
39 |
(require 'magit-git) |
|
40 |
|
|
41 |
;; For `magit-display-buffer-fullcolumn-most-v1' from `git-commit' |
|
42 |
(defvar git-commit-mode) |
|
43 |
;; For `magit-xref-insert-buttons' from `magit' |
|
44 |
(defvar magit-diff-show-xref-buttons) |
|
45 |
(defvar magit-revision-show-xref-buttons) |
|
46 |
;; For `magit-refresh' |
|
47 |
(defvar magit-post-commit-hook-commands) |
|
48 |
(defvar magit-post-stage-hook-commands) |
|
49 |
(defvar magit-post-unstage-hook-commands) |
|
50 |
;; For `magit-refresh' and `magit-refresh-all' |
|
51 |
(declare-function magit-auto-revert-buffers "magit-autorevert" ()) |
|
52 |
;; For `magit-refresh-buffer' |
|
53 |
(declare-function magit-process-unset-mode-line-error-status "magit-process" ()) |
|
54 |
;; For `magit-mode-setup-internal' |
|
55 |
(declare-function magit-status-goto-initial-section "magit-status" ()) |
|
56 |
|
|
57 |
(require 'format-spec) |
|
58 |
(require 'help-mode) |
|
59 |
|
|
60 |
;;; Options |
|
61 |
|
|
62 |
(defcustom magit-mode-hook |
|
63 |
'(magit-load-config-extensions |
|
64 |
magit-xref-setup) |
|
65 |
"Hook run when entering a mode derived from Magit mode." |
|
66 |
:group 'magit-modes |
|
67 |
:type 'hook |
|
68 |
:options '(magit-load-config-extensions |
|
69 |
magit-xref-setup |
|
70 |
bug-reference-mode)) |
|
71 |
|
|
72 |
(defcustom magit-mode-setup-hook |
|
73 |
'(magit-maybe-save-repository-buffers |
|
74 |
magit-set-buffer-margin) |
|
75 |
"Hook run by `magit-mode-setup'. |
|
76 |
|
|
77 |
This is run right after displaying the buffer and right before |
|
78 |
generating or updating its content. `magit-mode-hook' and other, |
|
79 |
more specific, `magit-mode-*-hook's on the other hand are run |
|
80 |
right before displaying the buffer. Usually one of these hooks |
|
81 |
should be used instead of this one." |
|
82 |
:package-version '(magit . "2.3.0") |
|
83 |
:group 'magit-modes |
|
84 |
:type 'hook |
|
85 |
:options '(magit-maybe-save-repository-buffers |
|
86 |
magit-set-buffer-margin)) |
|
87 |
|
|
88 |
(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers) |
|
89 |
"Hook run before refreshing in `magit-refresh'. |
|
90 |
|
|
91 |
This hook, or `magit-post-refresh-hook', should be used |
|
92 |
for functions that are not tied to a particular buffer. |
|
93 |
|
|
94 |
To run a function with a particular buffer current, use |
|
95 |
`magit-refresh-buffer-hook' and use `derived-mode-p' |
|
96 |
inside your function." |
|
97 |
:package-version '(magit . "2.4.0") |
|
98 |
:group 'magit-refresh |
|
99 |
:type 'hook |
|
100 |
:options '(magit-maybe-save-repository-buffers)) |
|
101 |
|
|
102 |
(defcustom magit-post-refresh-hook nil |
|
103 |
"Hook run after refreshing in `magit-refresh'. |
|
104 |
|
|
105 |
This hook, or `magit-pre-refresh-hook', should be used |
|
106 |
for functions that are not tied to a particular buffer. |
|
107 |
|
|
108 |
To run a function with a particular buffer current, use |
|
109 |
`magit-refresh-buffer-hook' and use `derived-mode-p' |
|
110 |
inside your function." |
|
111 |
:package-version '(magit . "2.4.0") |
|
112 |
:group 'magit-refresh |
|
113 |
:type 'hook) |
|
114 |
|
|
115 |
(defcustom magit-display-buffer-function 'magit-display-buffer-traditional |
|
116 |
"The function used display a Magit buffer. |
|
117 |
|
|
118 |
All Magit buffers (buffers whose major-modes derive from |
|
119 |
`magit-mode') are displayed using `magit-display-buffer', |
|
120 |
which in turn uses the function specified here." |
|
121 |
:package-version '(magit . "2.3.0") |
|
122 |
:group 'magit-buffers |
|
123 |
:type '(radio (function-item magit-display-buffer-traditional) |
|
124 |
(function-item magit-display-buffer-same-window-except-diff-v1) |
|
125 |
(function-item magit-display-buffer-fullframe-status-v1) |
|
126 |
(function-item magit-display-buffer-fullframe-status-topleft-v1) |
|
127 |
(function-item magit-display-buffer-fullcolumn-most-v1) |
|
128 |
(function-item display-buffer) |
|
129 |
(function :tag "Function"))) |
|
130 |
|
|
131 |
(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration) |
|
132 |
"Hook run by `magit-display-buffer' before displaying the buffer." |
|
133 |
:package-version '(magit . "2.3.0") |
|
134 |
:group 'magit-buffers |
|
135 |
:type 'hook |
|
136 |
:get 'magit-hook-custom-get |
|
137 |
:options '(magit-save-window-configuration)) |
|
138 |
|
|
139 |
(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated) |
|
140 |
"Hook run by `magit-display-buffer' after displaying the buffer." |
|
141 |
:package-version '(magit . "2.3.0") |
|
142 |
:group 'magit-buffers |
|
143 |
:type 'hook |
|
144 |
:get 'magit-hook-custom-get |
|
145 |
:options '(magit-maybe-set-dedicated)) |
|
146 |
|
|
147 |
(defcustom magit-generate-buffer-name-function |
|
148 |
'magit-generate-buffer-name-default-function |
|
149 |
"The function used to generate the name for a Magit buffer." |
|
150 |
:package-version '(magit . "2.3.0") |
|
151 |
:group 'magit-buffers |
|
152 |
:type '(radio (function-item magit-generate-buffer-name-default-function) |
|
153 |
(function :tag "Function"))) |
|
154 |
|
|
155 |
(defcustom magit-buffer-name-format "%x%M%v: %t%x" |
|
156 |
"The format string used to name Magit buffers. |
|
157 |
|
|
158 |
The following %-sequences are supported: |
|
159 |
|
|
160 |
`%m' The name of the major-mode, but with the `-mode' suffix |
|
161 |
removed. |
|
162 |
|
|
163 |
`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'. |
|
164 |
|
|
165 |
`%v' The value the buffer is locked to, in parentheses, or an |
|
166 |
empty string if the buffer is not locked to a value. |
|
167 |
|
|
168 |
`%V' Like \"%v\", but the string is prefixed with a space, unless |
|
169 |
it is an empty string. |
|
170 |
|
|
171 |
`%t' The top-level directory of the working tree of the |
|
172 |
repository, or if `magit-uniquify-buffer-names' is non-nil |
|
173 |
an abbreviation of that. |
|
174 |
|
|
175 |
`%x' If `magit-uniquify-buffer-names' is nil \"*\", otherwise the |
|
176 |
empty string. Due to limitations of the `uniquify' package, |
|
177 |
buffer names must end with the path. |
|
178 |
|
|
179 |
`%T' Obsolete, use \"%t%x\" instead. Like \"%t\", but append an |
|
180 |
asterisk if and only if `magit-uniquify-buffer-names' is nil. |
|
181 |
|
|
182 |
The value should always contain \"%m\" or \"%M\", \"%v\" or |
|
183 |
\"%V\", and \"%t\" (or the obsolete \"%T\"). |
|
184 |
|
|
185 |
If `magit-uniquify-buffer-names' is non-nil, then the value must |
|
186 |
end with \"%t\" or \"%t%x\" (or the obsolete \"%T\"). See issue |
|
187 |
#2841. |
|
188 |
|
|
189 |
This is used by `magit-generate-buffer-name-default-function'. |
|
190 |
If another `magit-generate-buffer-name-function' is used, then |
|
191 |
it may not respect this option, or on the contrary it may |
|
192 |
support additional %-sequences." |
|
193 |
:package-version '(magit . "2.12.0") |
|
194 |
:group 'magit-buffers |
|
195 |
:type 'string) |
|
196 |
|
|
197 |
(defcustom magit-uniquify-buffer-names t |
|
198 |
"Whether to uniquify the names of Magit buffers." |
|
199 |
:package-version '(magit . "2.3.0") |
|
200 |
:group 'magit-buffers |
|
201 |
:type 'boolean) |
|
202 |
|
|
203 |
(defcustom magit-bury-buffer-function 'magit-restore-window-configuration |
|
204 |
"The function used to bury or kill the current Magit buffer." |
|
205 |
:package-version '(magit . "2.3.0") |
|
206 |
:group 'magit-buffers |
|
207 |
:type '(radio (function-item quit-window) |
|
208 |
(function-item magit-mode-quit-window) |
|
209 |
(function-item magit-restore-window-configuration) |
|
210 |
(function :tag "Function"))) |
|
211 |
|
|
212 |
(defcustom magit-use-sticky-arguments t |
|
213 |
"How to reuse arguments from existing diff and log buffers. |
|
214 |
|
|
215 |
nil Always use the default value of the variable |
|
216 |
`magit-log-arguments' for log commands. Likewise, |
|
217 |
always use the default value of the variable |
|
218 |
`magit-diff-arguments' for diff command calls. |
|
219 |
|
|
220 |
current If the mode of the current buffer is derived from |
|
221 |
`magit-log-mode' or `magit-diff-mode', reuse the |
|
222 |
arguments from that buffer instead of those given by |
|
223 |
the variable `magit-log-arguments' or |
|
224 |
`magit-diff-arguments', respectively. |
|
225 |
|
|
226 |
t Like `current', but if the mode of the current buffer |
|
227 |
is not derived from `magit-log-mode' or |
|
228 |
`magit-diff-mode', use the arguments from the current |
|
229 |
repository's active (i.e. non-locked) `magit-log-mode' |
|
230 |
or `magit-diff-mode' buffer, respectively, if it |
|
231 |
exists. |
|
232 |
|
|
233 |
Note that commands that generate a |
|
234 |
`magit-revision-mode' or `magit-stash-mode' buffer will |
|
235 |
also collect their diff arguments from the active |
|
236 |
`magit-diff-mode' buffer. |
|
237 |
|
|
238 |
In general, there is a separation between the \"sticky\" |
|
239 |
arguments for log and diff buffers, but there is one special |
|
240 |
case: if the current buffer is a log buffer, |
|
241 |
`magit-show-commit' (considered a diff command) uses the file |
|
242 |
filter from the log buffer." |
|
243 |
:package-version '(magit . "2.11.0") |
|
244 |
:group 'magit-buffers |
|
245 |
:type '(choice (const :tag "disabled" nil) |
|
246 |
(const :tag "sticky for current" current) |
|
247 |
(const :tag "sticky" t))) |
|
248 |
|
|
249 |
(defcustom magit-region-highlight-hook |
|
250 |
'(magit-section-update-region magit-diff-update-hunk-region) |
|
251 |
"Functions used to highlight the region. |
|
252 |
|
|
253 |
Each function is run with the current section as only argument |
|
254 |
until one of them returns non-nil. If all functions return nil, |
|
255 |
then fall back to regular region highlighting." |
|
256 |
:package-version '(magit . "2.1.0") |
|
257 |
:group 'magit-refresh |
|
258 |
:type 'hook |
|
259 |
:options '(magit-section-update-region magit-diff-update-hunk-region)) |
|
260 |
|
|
261 |
(defcustom magit-create-buffer-hook nil |
|
262 |
"Normal hook run after creating a new `magit-mode' buffer." |
|
263 |
:package-version '(magit . "2.90.0") |
|
264 |
:group 'magit-refresh |
|
265 |
:type 'hook) |
|
266 |
|
|
267 |
(defcustom magit-refresh-buffer-hook nil |
|
268 |
"Normal hook for `magit-refresh-buffer' to run after refreshing." |
|
269 |
:package-version '(magit . "2.1.0") |
|
270 |
:group 'magit-refresh |
|
271 |
:type 'hook) |
|
272 |
|
|
273 |
(defcustom magit-refresh-status-buffer t |
|
274 |
"Whether the status buffer is refreshed after running git. |
|
275 |
|
|
276 |
When this is non-nil, then the status buffer is automatically |
|
277 |
refreshed after running git for side-effects, in addition to the |
|
278 |
current Magit buffer, which is always refreshed automatically. |
|
279 |
|
|
280 |
Only set this to nil after exhausting all other options to |
|
281 |
improve performance." |
|
282 |
:package-version '(magit . "2.4.0") |
|
283 |
:group 'magit-refresh |
|
284 |
:group 'magit-status |
|
285 |
:type 'boolean) |
|
286 |
|
|
287 |
(defcustom magit-refresh-verbose nil |
|
288 |
"Whether to revert Magit buffers verbosely." |
|
289 |
:package-version '(magit . "2.1.0") |
|
290 |
:group 'magit-refresh |
|
291 |
:type 'boolean) |
|
292 |
|
|
293 |
(defcustom magit-save-repository-buffers t |
|
294 |
"Whether to save file-visiting buffers when appropriate. |
|
295 |
|
|
296 |
If non-nil, then all modified file-visiting buffers belonging |
|
297 |
to the current repository may be saved before running Magit |
|
298 |
commands and before creating or refreshing Magit buffers. |
|
299 |
If `dontask', then this is done without user intervention, for |
|
300 |
any other non-nil value the user has to confirm each save. |
|
301 |
|
|
302 |
The default is t to avoid surprises, but `dontask' is the |
|
303 |
recommended value." |
|
304 |
:group 'magit-essentials |
|
305 |
:group 'magit-buffers |
|
306 |
:type '(choice (const :tag "Never" nil) |
|
307 |
(const :tag "Ask" t) |
|
308 |
(const :tag "Save without asking" dontask))) |
|
309 |
|
|
310 |
(defcustom magit-keep-region-overlay nil |
|
311 |
"Whether to keep the region overlay when there is a valid selection. |
|
312 |
|
|
313 |
By default Magit removes the regular region overlay if, and only |
|
314 |
if, that region constitutes a valid selection as understood by |
|
315 |
Magit commands. Otherwise it does not remove that overlay, and |
|
316 |
the region looks like it would in other buffers. |
|
317 |
|
|
318 |
There are two types of such valid selections: hunk-internal |
|
319 |
regions and regions that select two or more sibling sections. |
|
320 |
In such cases Magit removes the region overlay and instead |
|
321 |
highlights a slightly larger range. All text (for hunk-internal |
|
322 |
regions) or the headings of all sections (for sibling selections) |
|
323 |
that are inside that range (not just inside the region) are acted |
|
324 |
on by commands such as the staging command. This buffer range |
|
325 |
begins at the beginning of the line on which the region begins |
|
326 |
and ends at the end of the line on which the region ends. |
|
327 |
|
|
328 |
Because Magit acts on this larger range and not the region, it is |
|
329 |
actually quite important to visualize that larger range. If we |
|
330 |
don't do that, then one might think that these commands act on |
|
331 |
the region instead. If you want to *also* visualize the region, |
|
332 |
then set this option to t. But please note that when the region |
|
333 |
does *not* constitute a valid selection, then the region is |
|
334 |
*always* visualized as usual, and that it is usually under such |
|
335 |
circumstances that you want to use a non-magit command to act on |
|
336 |
the region. |
|
337 |
|
|
338 |
Besides keeping the region overlay, setting this option to t also |
|
339 |
causes all face properties, except for `:foreground', to be |
|
340 |
ignored for the faces used to highlight headings of selected |
|
341 |
sections. This avoids the worst conflicts that result from |
|
342 |
displaying the region and the selection overlays at the same |
|
343 |
time. We are not interested in dealing with other conflicts. |
|
344 |
In fact we *already* provide a way to avoid all of these |
|
345 |
conflicts: *not* changing the value of this option. |
|
346 |
|
|
347 |
It should be clear by now that we consider it a mistake to set |
|
348 |
this to display the region when the Magit selection is also |
|
349 |
visualized, but since it has been requested a few times and |
|
350 |
because it doesn't cost much to offer this option we do so. |
|
351 |
However that might change. If the existence of this option |
|
352 |
starts complicating other things, then it will be removed." |
|
353 |
:package-version '(magit . "2.3.0") |
|
354 |
:group 'magit-miscellaneous |
|
355 |
:type 'boolean) |
|
356 |
|
|
357 |
;;; Magit Mode |
|
358 |
|
|
359 |
(defvar magit-mode-map |
|
360 |
(let ((map (make-keymap))) |
|
361 |
(suppress-keymap map t) |
|
362 |
(cond ((featurep 'jkl) |
|
363 |
(define-key map [return] 'magit-visit-thing) |
|
364 |
(define-key map [C-return] 'magit-dired-jump) |
|
365 |
(define-key map [tab] 'magit-section-toggle) |
|
366 |
(define-key map [C-tab] 'magit-section-cycle) |
|
367 |
(define-key map [M-tab] 'magit-section-cycle-diffs) |
|
368 |
(define-key map [S-tab] 'magit-section-cycle-global) |
|
369 |
(define-key map (kbd "M-o") 'magit-section-up) |
|
370 |
(define-key map (kbd "i") 'magit-section-backward) |
|
371 |
(define-key map (kbd "k") 'magit-section-forward) |
|
372 |
(define-key map (kbd "M-i") 'magit-section-backward-sibling) |
|
373 |
(define-key map (kbd "M-k") 'magit-section-forward-sibling) |
|
374 |
(define-key map (kbd "p") 'magit-push-popup) |
|
375 |
(define-key map (kbd ",") 'magit-delete-thing) |
|
376 |
(define-key map (kbd ";") 'magit-file-untrack) |
|
377 |
(define-key map (kbd "C-c C-i") 'magit-gitignore-popup)) |
|
378 |
(t |
|
379 |
(define-key map [C-return] 'magit-visit-thing) |
|
380 |
(define-key map (kbd "C-m") 'magit-visit-thing) |
|
381 |
(define-key map (kbd "C-M-i") 'magit-dired-jump) |
|
382 |
(define-key map (kbd "C-i") 'magit-section-toggle) |
|
383 |
(define-key map [C-tab] 'magit-section-cycle) |
|
384 |
(define-key map [M-tab] 'magit-section-cycle-diffs) |
|
385 |
;; [backtab] is the most portable binding for Shift+Tab. |
|
386 |
(define-key map [backtab] 'magit-section-cycle-global) |
|
387 |
(define-key map (kbd "^") 'magit-section-up) |
|
388 |
(define-key map (kbd "p") 'magit-section-backward) |
|
389 |
(define-key map (kbd "n") 'magit-section-forward) |
|
390 |
(define-key map (kbd "M-p") 'magit-section-backward-sibling) |
|
391 |
(define-key map (kbd "M-n") 'magit-section-forward-sibling) |
|
392 |
(define-key map (kbd "P") 'magit-push-popup) |
|
393 |
(define-key map (kbd "k") 'magit-delete-thing) |
|
394 |
(define-key map (kbd "K") 'magit-file-untrack) |
|
395 |
(define-key map (kbd "i") 'magit-gitignore-popup) |
|
396 |
(define-key map (kbd "I") 'magit-gitignore-popup))) |
|
397 |
(define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up) |
|
398 |
(define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down) |
|
399 |
(define-key map "+" 'magit-diff-more-context) |
|
400 |
(define-key map "-" 'magit-diff-less-context) |
|
401 |
(define-key map "0" 'magit-diff-default-context) |
|
402 |
(define-key map "1" 'magit-section-show-level-1) |
|
403 |
(define-key map "2" 'magit-section-show-level-2) |
|
404 |
(define-key map "3" 'magit-section-show-level-3) |
|
405 |
(define-key map "4" 'magit-section-show-level-4) |
|
406 |
(define-key map (kbd "M-1") 'magit-section-show-level-1-all) |
|
407 |
(define-key map (kbd "M-2") 'magit-section-show-level-2-all) |
|
408 |
(define-key map (kbd "M-3") 'magit-section-show-level-3-all) |
|
409 |
(define-key map (kbd "M-4") 'magit-section-show-level-4-all) |
|
410 |
(define-key map "$" 'magit-process-buffer) |
|
411 |
(define-key map "%" 'magit-worktree-popup) |
|
412 |
(define-key map "a" 'magit-cherry-apply) |
|
413 |
(define-key map "A" 'magit-cherry-pick-popup) |
|
414 |
(define-key map "b" 'magit-branch-popup) |
|
415 |
(define-key map "B" 'magit-bisect-popup) |
|
416 |
(define-key map "c" 'magit-commit-popup) |
|
417 |
(define-key map "d" 'magit-diff-popup) |
|
418 |
(define-key map "D" 'magit-diff-refresh-popup) |
|
419 |
(define-key map "e" 'magit-ediff-dwim) |
|
420 |
(define-key map "E" 'magit-ediff-popup) |
|
421 |
(define-key map "f" 'magit-fetch-popup) |
|
422 |
(define-key map "F" 'magit-pull-popup) |
|
423 |
(define-key map "g" 'magit-refresh) |
|
424 |
(define-key map "G" 'magit-refresh-all) |
|
425 |
(define-key map "h" 'magit-dispatch-popup) |
|
426 |
(define-key map "?" 'magit-dispatch-popup) |
|
427 |
(define-key map "l" 'magit-log-popup) |
|
428 |
(define-key map "L" 'magit-log-refresh-popup) |
|
429 |
(define-key map "m" 'magit-merge-popup) |
|
430 |
(define-key map "M" 'magit-remote-popup) |
|
431 |
(define-key map "o" 'magit-submodule-popup) |
|
432 |
(define-key map "O" 'magit-subtree-popup) |
|
433 |
(define-key map "q" 'magit-mode-bury-buffer) |
|
434 |
(define-key map "r" 'magit-rebase-popup) |
|
435 |
(define-key map "R" 'magit-file-rename) |
|
436 |
(define-key map "t" 'magit-tag-popup) |
|
437 |
(define-key map "T" 'magit-notes-popup) |
|
438 |
(define-key map "s" 'magit-stage-file) |
|
439 |
(define-key map "S" 'magit-stage-modified) |
|
440 |
(define-key map "u" 'magit-unstage-file) |
|
441 |
(define-key map "U" 'magit-unstage-all) |
|
442 |
(define-key map "v" 'magit-revert-no-commit) |
|
443 |
(define-key map "V" 'magit-revert-popup) |
|
444 |
(define-key map "w" 'magit-am-popup) |
|
445 |
(define-key map "W" 'magit-patch-popup) |
|
446 |
(define-key map "x" 'magit-reset-quickly) |
|
447 |
(define-key map "X" 'magit-reset-popup) |
|
448 |
(define-key map "y" 'magit-show-refs-popup) |
|
449 |
(define-key map "Y" 'magit-cherry) |
|
450 |
(define-key map "z" 'magit-stash-popup) |
|
451 |
(define-key map "Z" 'magit-stash-popup) |
|
452 |
(define-key map ":" 'magit-git-command) |
|
453 |
(define-key map "!" 'magit-run-popup) |
|
454 |
(define-key map (kbd "C-c C-c") 'magit-dispatch-popup) |
|
455 |
(define-key map (kbd "C-c C-e") 'magit-edit-thing) |
|
456 |
(define-key map (kbd "C-c C-w") 'magit-browse-thing) |
|
457 |
(define-key map (kbd "C-x a") 'magit-add-change-log-entry) |
|
458 |
(define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window) |
|
459 |
(define-key map (kbd "C-w") 'magit-copy-section-value) |
|
460 |
(define-key map (kbd "M-w") 'magit-copy-buffer-revision) |
|
461 |
(define-key map [remap previous-line] 'magit-previous-line) |
|
462 |
(define-key map [remap next-line] 'magit-next-line) |
|
463 |
(define-key map [remap evil-previous-line] 'evil-previous-visual-line) |
|
464 |
(define-key map [remap evil-next-line] 'evil-next-visual-line) |
|
465 |
map) |
|
466 |
"Parent keymap for all keymaps of modes derived from `magit-mode'.") |
|
467 |
|
|
468 |
(defun magit-delete-thing () |
|
469 |
"This is a placeholder command. |
|
470 |
Where applicable, section-specific keymaps bind another command |
|
471 |
which deletes the thing at point." |
|
472 |
(interactive) |
|
473 |
(user-error "There is no thing at point that could be deleted")) |
|
474 |
|
|
475 |
(defun magit-visit-thing () |
|
476 |
"This is a placeholder command. |
|
477 |
Where applicable, section-specific keymaps bind another command |
|
478 |
which visits the thing at point." |
|
479 |
(interactive) |
|
480 |
(if (eq magit-current-popup 'magit-dispatch-popup) |
|
481 |
(progn (setq magit-current-popup nil) |
|
482 |
(call-interactively (key-binding (this-command-keys)))) |
|
483 |
(user-error "There is no thing at point that could be visited"))) |
|
484 |
|
|
485 |
(defun magit-edit-thing () |
|
486 |
"This is a placeholder command. |
|
487 |
Where applicable, section-specific keymaps bind another command |
|
488 |
which lets you edit the thing at point, likely in another buffer." |
|
489 |
(interactive) |
|
490 |
(if (eq magit-current-popup 'magit-dispatch-popup) |
|
491 |
(progn (setq magit-current-popup nil) |
|
492 |
(call-interactively (key-binding (this-command-keys)))) |
|
493 |
(user-error "There is no thing at point that could be edited"))) |
|
494 |
|
|
495 |
(defun magit-browse-thing () |
|
496 |
"This is a placeholder command. |
|
497 |
Where applicable, section-specific keymaps bind another command |
|
498 |
which visits the thing at point using `browse-url'." |
|
499 |
(interactive) |
|
500 |
(user-error "There is no thing at point that could be browsed")) |
|
501 |
|
|
502 |
(easy-menu-define magit-mode-menu magit-mode-map |
|
503 |
"Magit menu" |
|
504 |
'("Magit" |
|
505 |
["Refresh" magit-refresh t] |
|
506 |
["Refresh all" magit-refresh-all t] |
|
507 |
"---" |
|
508 |
["Stage" magit-stage t] |
|
509 |
["Stage modified" magit-stage-modified t] |
|
510 |
["Unstage" magit-unstage t] |
|
511 |
["Reset index" magit-reset-index t] |
|
512 |
["Commit" magit-commit-popup t] |
|
513 |
["Add log entry" magit-commit-add-log t] |
|
514 |
["Tag" magit-tag-create t] |
|
515 |
"---" |
|
516 |
["Diff working tree" magit-diff-working-tree t] |
|
517 |
["Diff" magit-diff t] |
|
518 |
("Log" |
|
519 |
["Log" magit-log-other t] |
|
520 |
["Reflog" magit-reflog-other t] |
|
521 |
["Extended..." magit-log-popup t]) |
|
522 |
"---" |
|
523 |
["Cherry pick" magit-cherry-pick t] |
|
524 |
["Revert commit" magit-revert-popup t] |
|
525 |
"---" |
|
526 |
["Ignore globally" magit-gitignore-globally t] |
|
527 |
["Ignore locally" magit-gitignore-locally t] |
|
528 |
["Discard" magit-discard t] |
|
529 |
["Reset head and index" magit-reset-mixed t] |
|
530 |
["Stash" magit-stash-both t] |
|
531 |
["Snapshot" magit-snapshot-both t] |
|
532 |
"---" |
|
533 |
["Branch..." magit-checkout t] |
|
534 |
["Merge" magit-merge t] |
|
535 |
["Ediff resolve" magit-ediff-resolve t] |
|
536 |
["Rebase..." magit-rebase-popup t] |
|
537 |
"---" |
|
538 |
["Push" magit-push t] |
|
539 |
["Pull" magit-pull-branch t] |
|
540 |
["Remote update" magit-fetch-all t] |
|
541 |
("Submodule" |
|
542 |
["Submodule update" magit-submodule-update t] |
|
543 |
["Submodule update and init" magit-submodule-setup t] |
|
544 |
["Submodule init" magit-submodule-init t] |
|
545 |
["Submodule sync" magit-submodule-sync t]) |
|
546 |
"---" |
|
547 |
("Extensions") |
|
548 |
"---" |
|
549 |
["Display Git output" magit-process-buffer t] |
|
550 |
["Quit Magit" magit-mode-bury-buffer t])) |
|
551 |
|
|
552 |
(defun magit-load-config-extensions () |
|
553 |
"Load Magit extensions that are defined at the Git config layer." |
|
554 |
(dolist (ext (magit-get-all "magit.extension")) |
|
555 |
(let ((sym (intern (format "magit-%s-mode" ext)))) |
|
556 |
(when (fboundp sym) |
|
557 |
(funcall sym 1))))) |
|
558 |
|
|
559 |
(define-derived-mode magit-mode special-mode "Magit" |
|
560 |
"Parent major mode from which Magit major modes inherit. |
|
561 |
|
|
562 |
Magit is documented in info node `(magit)'." |
|
563 |
:group 'magit-modes |
|
564 |
(buffer-disable-undo) |
|
565 |
(setq truncate-lines t) |
|
566 |
(setq buffer-read-only t) |
|
567 |
(setq-local line-move-visual t) ; see #1771 |
|
568 |
(setq show-trailing-whitespace nil) |
|
569 |
(setq list-buffers-directory (abbreviate-file-name default-directory)) |
|
570 |
(hack-dir-local-variables-non-file-buffer) |
|
571 |
(make-local-variable 'text-property-default-nonsticky) |
|
572 |
(push (cons 'keymap t) text-property-default-nonsticky) |
|
573 |
(add-hook 'post-command-hook #'magit-section-update-highlight t t) |
|
574 |
(add-hook 'deactivate-mark-hook #'magit-section-update-highlight t t) |
|
575 |
(setq-local redisplay-highlight-region-function 'magit-highlight-region) |
|
576 |
(setq-local redisplay-unhighlight-region-function 'magit-unhighlight-region) |
|
577 |
(setq mode-line-process (magit-repository-local-get 'mode-line-process)) |
|
578 |
(when (bound-and-true-p global-linum-mode) |
|
579 |
(linum-mode -1)) |
|
580 |
(when (and (fboundp 'nlinum-mode) |
|
581 |
(bound-and-true-p global-nlinum-mode)) |
|
582 |
(nlinum-mode -1)) |
|
583 |
(when (and (fboundp 'display-line-numbers-mode) |
|
584 |
(bound-and-true-p global-display-line-numbers-mode)) |
|
585 |
(display-line-numbers-mode -1)) |
|
586 |
(add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache)) |
|
587 |
|
|
588 |
(defvar-local magit-region-overlays nil) |
|
589 |
|
|
590 |
(defun magit-delete-region-overlays () |
|
591 |
(mapc #'delete-overlay magit-region-overlays) |
|
592 |
(setq magit-region-overlays nil)) |
|
593 |
|
|
594 |
(defun magit-highlight-region (start end window rol) |
|
595 |
(magit-delete-region-overlays) |
|
596 |
(if (and (run-hook-with-args-until-success 'magit-region-highlight-hook |
|
597 |
(magit-current-section)) |
|
598 |
(not magit-keep-region-overlay) |
|
599 |
(not (= (line-number-at-pos start) |
|
600 |
(line-number-at-pos end))) |
|
601 |
;; (not (eq (car-safe last-command-event) 'mouse-movement)) |
|
602 |
) |
|
603 |
(funcall (default-value 'redisplay-unhighlight-region-function) rol) |
|
604 |
(funcall (default-value 'redisplay-highlight-region-function) |
|
605 |
start end window rol))) |
|
606 |
|
|
607 |
(defun magit-unhighlight-region (rol) |
|
608 |
(setq magit-section-highlighted-section nil) |
|
609 |
(magit-delete-region-overlays) |
|
610 |
(funcall (default-value 'redisplay-unhighlight-region-function) rol)) |
|
611 |
|
|
612 |
(defvar-local magit-refresh-args nil |
|
613 |
"The arguments used to refresh the current buffer.") |
|
614 |
(put 'magit-refresh-args 'permanent-local t) |
|
615 |
|
|
616 |
(defvar-local magit-previous-section nil) |
|
617 |
(put 'magit-previous-section 'permanent-local t) |
|
618 |
|
|
619 |
(defun magit-mode-setup (mode &rest args) |
|
620 |
"Setup up a MODE buffer using ARGS to generate its content." |
|
621 |
(magit-mode-setup-internal mode args)) |
|
622 |
|
|
623 |
(defun magit-mode-setup-internal (mode args &optional locked) |
|
624 |
"Setup up a MODE buffer using ARGS to generate its content. |
|
625 |
When optional LOCKED is non-nil, then create a buffer that is |
|
626 |
locked to its value, which is derived from MODE and ARGS." |
|
627 |
(let* ((value (and locked (magit-buffer-lock-value mode args))) |
|
628 |
(buffer (magit-mode-get-buffer mode nil nil value)) |
|
629 |
(section (and buffer (magit-current-section))) |
|
630 |
(created (not buffer))) |
|
631 |
(unless buffer |
|
632 |
(setq buffer (magit-with-toplevel |
|
633 |
(magit-generate-new-buffer mode value)))) |
|
634 |
(with-current-buffer buffer |
|
635 |
(setq magit-previous-section section) |
|
636 |
(setq magit-refresh-args args) |
|
637 |
(funcall mode) |
|
638 |
(when created |
|
639 |
(magit-status-goto-initial-section) |
|
640 |
(run-hooks 'magit-create-buffer-hook))) |
|
641 |
(magit-display-buffer buffer) |
|
642 |
(with-current-buffer buffer |
|
643 |
(run-hooks 'magit-mode-setup-hook) |
|
644 |
(magit-refresh-buffer)))) |
|
645 |
|
|
646 |
(defvar magit-display-buffer-noselect nil |
|
647 |
"If non-nil, then `magit-display-buffer' doesn't call `select-window'.") |
|
648 |
|
|
649 |
(defun magit-display-buffer (buffer) |
|
650 |
"Display BUFFER in some window and maybe select it. |
|
651 |
|
|
652 |
Display the buffer using `magit-display-buffer-function' and |
|
653 |
then, unless `magit-display-buffer-noselect' is non-nil, select |
|
654 |
the window which was used to display the buffer. |
|
655 |
|
|
656 |
Also run the hooks `magit-pre-display-buffer-hook' |
|
657 |
and `magit-post-display-buffer-hook'." |
|
658 |
(with-current-buffer buffer |
|
659 |
(run-hooks 'magit-pre-display-buffer-hook)) |
|
660 |
(let ((window (funcall magit-display-buffer-function buffer))) |
|
661 |
(unless magit-display-buffer-noselect |
|
662 |
(let* ((old-frame (selected-frame)) |
|
663 |
(new-frame (window-frame window))) |
|
664 |
(select-window window) |
|
665 |
(unless (eq old-frame new-frame) |
|
666 |
(select-frame-set-input-focus new-frame))))) |
|
667 |
(with-current-buffer buffer |
|
668 |
(run-hooks 'magit-post-display-buffer-hook))) |
|
669 |
|
|
670 |
(defun magit-display-buffer-traditional (buffer) |
|
671 |
"Display BUFFER the way this has traditionally been done." |
|
672 |
(display-buffer |
|
673 |
buffer (if (and (derived-mode-p 'magit-mode) |
|
674 |
(not (memq (with-current-buffer buffer major-mode) |
|
675 |
'(magit-process-mode |
|
676 |
magit-revision-mode |
|
677 |
magit-diff-mode |
|
678 |
magit-stash-mode |
|
679 |
magit-status-mode)))) |
|
680 |
'(display-buffer-same-window) |
|
681 |
nil))) ; display in another window |
|
682 |
|
|
683 |
(defun magit-display-buffer-same-window-except-diff-v1 (buffer) |
|
684 |
"Display BUFFER in the selected window except for some modes. |
|
685 |
If a buffer's `major-mode' derives from `magit-diff-mode' or |
|
686 |
`magit-process-mode', display it in another window. Display all |
|
687 |
other buffers in the selected window." |
|
688 |
(display-buffer |
|
689 |
buffer (if (with-current-buffer buffer |
|
690 |
(derived-mode-p 'magit-diff-mode 'magit-process-mode)) |
|
691 |
nil ; display in another window |
|
692 |
'(display-buffer-same-window)))) |
|
693 |
|
|
694 |
(defun magit--display-buffer-fullframe (buffer alist) |
|
695 |
(when-let ((window (or (display-buffer-reuse-window buffer alist) |
|
696 |
(display-buffer-same-window buffer alist) |
|
697 |
(display-buffer-pop-up-window buffer alist) |
|
698 |
(display-buffer-use-some-window buffer alist)))) |
|
699 |
(delete-other-windows window) |
|
700 |
window)) |
|
701 |
|
|
702 |
(defun magit-display-buffer-fullframe-status-v1 (buffer) |
|
703 |
"Display BUFFER, filling entire frame if BUFFER is a status buffer. |
|
704 |
Otherwise, behave like `magit-display-buffer-traditional'." |
|
705 |
(if (eq (with-current-buffer buffer major-mode) |
|
706 |
'magit-status-mode) |
|
707 |
(display-buffer buffer '(magit--display-buffer-fullframe)) |
|
708 |
(magit-display-buffer-traditional buffer))) |
|
709 |
|
|
710 |
(defun magit--display-buffer-topleft (buffer alist) |
|
711 |
(or (display-buffer-reuse-window buffer alist) |
|
712 |
(when-let ((window2 (display-buffer-pop-up-window buffer alist))) |
|
713 |
(let ((window1 (get-buffer-window)) |
|
714 |
(buffer1 (current-buffer)) |
|
715 |
(buffer2 (window-buffer window2)) |
|
716 |
(w2-quit-restore (window-parameter window2 'quit-restore))) |
|
717 |
(set-window-buffer window1 buffer2) |
|
718 |
(set-window-buffer window2 buffer1) |
|
719 |
(select-window window2) |
|
720 |
;; Swap some window state that `magit-mode-quit-window' and |
|
721 |
;; `quit-restore-window' inspect. |
|
722 |
(set-window-prev-buffers window2 (cdr (window-prev-buffers window1))) |
|
723 |
(set-window-prev-buffers window1 nil) |
|
724 |
(set-window-parameter window2 'magit-dedicated |
|
725 |
(window-parameter window1 'magit-dedicated)) |
|
726 |
(set-window-parameter window1 'magit-dedicated t) |
|
727 |
(set-window-parameter window1 'quit-restore |
|
728 |
(list 'window 'window |
|
729 |
(nth 2 w2-quit-restore) |
|
730 |
(nth 3 w2-quit-restore))) |
|
731 |
(set-window-parameter window2 'quit-restore nil) |
|
732 |
window1)))) |
|
733 |
|
|
734 |
(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer) |
|
735 |
"Display BUFFER, filling entire frame if BUFFER is a status buffer. |
|
736 |
When BUFFER derives from `magit-diff-mode' or |
|
737 |
`magit-process-mode', try to display BUFFER to the top or left of |
|
738 |
the current buffer rather than to the bottom or right, as |
|
739 |
`magit-display-buffer-fullframe-status-v1' would. Whether the |
|
740 |
split is made vertically or horizontally is determined by |
|
741 |
`split-window-preferred-function'." |
|
742 |
(display-buffer |
|
743 |
buffer |
|
744 |
(cond ((eq (with-current-buffer buffer major-mode) |
|
745 |
'magit-status-mode) |
|
746 |
'(magit--display-buffer-fullframe)) |
|
747 |
((with-current-buffer buffer |
|
748 |
(derived-mode-p 'magit-diff-mode 'magit-process-mode)) |
|
749 |
'(magit--display-buffer-topleft)) |
|
750 |
(t |
|
751 |
'(display-buffer-same-window))))) |
|
752 |
|
|
753 |
(defun magit--display-buffer-fullcolumn (buffer alist) |
|
754 |
(when-let ((window (or (display-buffer-reuse-window buffer alist) |
|
755 |
(display-buffer-same-window buffer alist) |
|
756 |
(display-buffer-below-selected buffer alist)))) |
|
757 |
(delete-other-windows-vertically window) |
|
758 |
window)) |
|
759 |
|
|
760 |
(defun magit-display-buffer-fullcolumn-most-v1 (buffer) |
|
761 |
"Display BUFFER using the full column except in some cases. |
|
762 |
For most cases where BUFFER's `major-mode' derives from |
|
763 |
`magit-mode', display it in the selected window and grow that |
|
764 |
window to the full height of the frame, deleting other windows in |
|
765 |
that column as necessary. However, display BUFFER in another |
|
766 |
window if 1) BUFFER's mode derives from `magit-process-mode', or |
|
767 |
2) BUFFER's mode derives from `magit-diff-mode', provided that |
|
768 |
the mode of the current buffer derives from `magit-log-mode' or |
|
769 |
`magit-cherry-mode'." |
|
770 |
(display-buffer |
|
771 |
buffer |
|
772 |
(cond ((and (or git-commit-mode |
|
773 |
(derived-mode-p 'magit-log-mode 'magit-cherry-mode)) |
|
774 |
(with-current-buffer buffer |
|
775 |
(derived-mode-p 'magit-diff-mode))) |
|
776 |
nil) |
|
777 |
((with-current-buffer buffer |
|
778 |
(derived-mode-p 'magit-process-mode)) |
|
779 |
nil) |
|
780 |
(t |
|
781 |
'(magit--display-buffer-fullcolumn))))) |
|
782 |
|
|
783 |
(defun magit-maybe-set-dedicated () |
|
784 |
"Mark the selected window as dedicated if appropriate. |
|
785 |
|
|
786 |
If a new window was created to display the buffer, then remember |
|
787 |
that fact. That information is used by `magit-mode-quit-window', |
|
788 |
to determine whether the window should be deleted when its last |
|
789 |
Magit buffer is buried." |
|
790 |
(let ((window (get-buffer-window (current-buffer)))) |
|
791 |
(when (and (window-live-p window) |
|
792 |
(not (window-prev-buffers window))) |
|
793 |
(set-window-parameter window 'magit-dedicated t)))) |
|
794 |
|
|
795 |
(defvar-local magit--default-directory nil |
|
796 |
"Value of `default-directory' when buffer is generated. |
|
797 |
This exists to prevent a let-bound `default-directory' from |
|
798 |
tricking `magit-mode-get-buffer' or `magit-mode-get-buffers' into |
|
799 |
thinking a buffer belongs to a repo that it doesn't.") |
|
800 |
(put 'magit--default-directory 'permanent-local t) |
|
801 |
|
|
802 |
(defun magit-mode-get-buffers () |
|
803 |
(let ((topdir (magit-toplevel))) |
|
804 |
(--filter (with-current-buffer it |
|
805 |
(and (derived-mode-p 'magit-mode) |
|
806 |
(equal magit--default-directory topdir))) |
|
807 |
(buffer-list)))) |
|
808 |
|
|
809 |
(defvar-local magit-buffer-locked-p nil) |
|
810 |
(put 'magit-buffer-locked-p 'permanent-local t) |
|
811 |
|
|
812 |
(defun magit-mode-get-buffer (mode &optional create frame value) |
|
813 |
(when create |
|
814 |
(error "`magit-mode-get-buffer's CREATE argument is obsolete")) |
|
815 |
(if-let ((topdir (magit-toplevel))) |
|
816 |
(--first (with-current-buffer it |
|
817 |
(and (eq major-mode mode) |
|
818 |
(equal magit--default-directory topdir) |
|
819 |
(if value |
|
820 |
(and magit-buffer-locked-p |
|
821 |
(equal (magit-buffer-lock-value) value)) |
|
822 |
(not magit-buffer-locked-p)))) |
|
823 |
(if frame |
|
824 |
(mapcar #'window-buffer |
|
825 |
(window-list (unless (eq frame t) frame))) |
|
826 |
(buffer-list))) |
|
827 |
(magit--not-inside-repository-error))) |
|
828 |
|
|
829 |
(defun magit-generate-new-buffer (mode &optional value) |
|
830 |
(let* ((name (funcall magit-generate-buffer-name-function mode value)) |
|
831 |
(buffer (generate-new-buffer name))) |
|
832 |
(with-current-buffer buffer |
|
833 |
(setq magit--default-directory default-directory) |
|
834 |
(setq magit-buffer-locked-p (and value t)) |
|
835 |
(magit-restore-section-visibility-cache mode)) |
|
836 |
(when magit-uniquify-buffer-names |
|
837 |
(add-to-list 'uniquify-list-buffers-directory-modes mode) |
|
838 |
(with-current-buffer buffer |
|
839 |
(setq list-buffers-directory (abbreviate-file-name default-directory))) |
|
840 |
(let ((uniquify-buffer-name-style |
|
841 |
(if (memq uniquify-buffer-name-style '(nil forward)) |
|
842 |
'post-forward-angle-brackets |
|
843 |
uniquify-buffer-name-style))) |
|
844 |
(uniquify-rationalize-file-buffer-names |
|
845 |
name (file-name-directory (directory-file-name default-directory)) |
|
846 |
buffer))) |
|
847 |
buffer)) |
|
848 |
|
|
849 |
(defun magit-generate-buffer-name-default-function (mode &optional value) |
|
850 |
"Generate buffer name for a MODE buffer in the current repository. |
|
851 |
The returned name is based on `magit-buffer-name-format' and |
|
852 |
takes `magit-uniquify-buffer-names' and VALUE, if non-nil, into |
|
853 |
account." |
|
854 |
(let ((m (substring (symbol-name mode) 0 -5)) |
|
855 |
(v (and value (format "%s" (if (listp value) value (list value))))) |
|
856 |
(n (if magit-uniquify-buffer-names |
|
857 |
(file-name-nondirectory |
|
858 |
(directory-file-name default-directory)) |
|
859 |
(abbreviate-file-name default-directory)))) |
|
860 |
(format-spec |
|
861 |
magit-buffer-name-format |
|
862 |
`((?m . ,m) |
|
863 |
(?M . ,(if (eq mode 'magit-status-mode) "magit" m)) |
|
864 |
(?v . ,(or v "")) |
|
865 |
(?V . ,(if v (concat " " v) "")) |
|
866 |
(?t . ,n) |
|
867 |
(?x . ,(if magit-uniquify-buffer-names "" "*")) |
|
868 |
(?T . ,(if magit-uniquify-buffer-names n (concat n "*"))))))) |
|
869 |
|
|
870 |
(defun magit-toggle-buffer-lock () |
|
871 |
"Lock the current buffer to its value or unlock it. |
|
872 |
|
|
873 |
Locking a buffer to its value prevents it from being reused to |
|
874 |
display another value. The name of a locked buffer contains its |
|
875 |
value, which allows telling it apart from other locked buffers |
|
876 |
and the unlocked buffer. |
|
877 |
|
|
878 |
Not all Magit buffers can be locked to their values, for example |
|
879 |
it wouldn't make sense to lock a status buffer. |
|
880 |
|
|
881 |
There can only be a single unlocked buffer using a certain |
|
882 |
major-mode per repository. So when a buffer is being unlocked |
|
883 |
and another unlocked buffer already exists for that mode and |
|
884 |
repository, then the former buffer is instead deleted and the |
|
885 |
latter is displayed in its place." |
|
886 |
(interactive) |
|
887 |
(if magit-buffer-locked-p |
|
888 |
(if-let ((unlocked (magit-mode-get-buffer major-mode))) |
|
889 |
(let ((locked (current-buffer))) |
|
890 |
(switch-to-buffer unlocked nil t) |
|
891 |
(kill-buffer locked)) |
|
892 |
(setq magit-buffer-locked-p nil) |
|
893 |
(rename-buffer (funcall magit-generate-buffer-name-function |
|
894 |
major-mode))) |
|
895 |
(if-let ((value (magit-buffer-lock-value))) |
|
896 |
(if-let ((locked (magit-mode-get-buffer major-mode nil nil value))) |
|
897 |
(let ((unlocked (current-buffer))) |
|
898 |
(switch-to-buffer locked nil t) |
|
899 |
(kill-buffer unlocked)) |
|
900 |
(setq magit-buffer-locked-p t) |
|
901 |
(rename-buffer (funcall magit-generate-buffer-name-function |
|
902 |
major-mode value))) |
|
903 |
(user-error "Buffer has no value it could be locked to")))) |
|
904 |
|
|
905 |
(defvar magit-buffer-lock-functions '((forge-topic-mode . car)) |
|
906 |
"Provide buffer-locking support for third-party modes. |
|
907 |
An alist of symbols to functions. |
|
908 |
|
|
909 |
The symbol must be the major-mode the locked buffer will have. |
|
910 |
|
|
911 |
The function must take a single argument, a list of refresh |
|
912 |
arguments (the value of `magit-refresh-args') and return a |
|
913 |
value that identifies the buffer (i.e., its 'lock value'). |
|
914 |
If the third-party mode is invoked as |
|
915 |
|
|
916 |
(magit-mode-setup-internal #\\='my-mode \\='(1 2 3) t) |
|
917 |
|
|
918 |
the function will be invoked as |
|
919 |
|
|
920 |
(funcall lock-func \\='(1 2 3)) |
|
921 |
|
|
922 |
if the cons (my-mode . lock-func) is in this list. |
|
923 |
|
|
924 |
This variable is intended for third-party extensions; |
|
925 |
`magit-buffer-lock-value' implements all built-in behavior. |
|
926 |
|
|
927 |
See also `magit-toggle-buffer-lock'.") |
|
928 |
|
|
929 |
(cl-defun magit-buffer-lock-value |
|
930 |
(&optional (mode major-mode) |
|
931 |
(args magit-refresh-args)) |
|
932 |
"Find an appropriate buffer lock value for MODE under ARGS. |
|
933 |
See also `magit-buffer-lock-functions'." |
|
934 |
(cl-case mode |
|
935 |
(magit-cherry-mode |
|
936 |
(pcase-let ((`(,upstream ,head) args)) |
|
937 |
(concat head ".." upstream))) |
|
938 |
(magit-diff-mode |
|
939 |
(pcase-let ((`(,rev-or-range ,const ,_args ,files) args)) |
|
940 |
(nconc (cons (or rev-or-range |
|
941 |
(if (member "--cached" const) |
|
942 |
(progn (setq const (delete "--cached" const)) |
|
943 |
'staged) |
|
944 |
'unstaged)) |
|
945 |
const) |
|
946 |
(and files (cons "--" files))))) |
|
947 |
(magit-log-mode |
|
948 |
(pcase-let ((`(,revs ,_args ,files) args)) |
|
949 |
(if (and revs files) |
|
950 |
(append revs (cons "--" files)) |
|
951 |
(append revs files)))) |
|
952 |
(magit-refs-mode |
|
953 |
(pcase-let ((`(,ref ,args) args)) |
|
954 |
(cons (or ref "HEAD") args))) |
|
955 |
(magit-revision-mode |
|
956 |
(pcase-let ((`(,rev ,_const ,_args ,files) args)) |
|
957 |
(if files (cons rev files) (list rev)))) |
|
958 |
((magit-reflog-mode ; (ref ~args) |
|
959 |
magit-stash-mode ; (stash _const _args _files) |
|
960 |
magit-stashes-mode) ; (ref) |
|
961 |
(car args)) |
|
962 |
(t |
|
963 |
(--when-let (cdr (assq mode magit-buffer-lock-functions)) |
|
964 |
(funcall it args))))) |
|
965 |
|
|
966 |
(defun magit-mode-bury-buffer (&optional kill-buffer) |
|
967 |
"Bury the current buffer. |
|
968 |
With a prefix argument, kill the buffer instead. |
|
969 |
This is done using `magit-bury-buffer-function'." |
|
970 |
(interactive "P") |
|
971 |
(funcall magit-bury-buffer-function kill-buffer)) |
|
972 |
|
|
973 |
(defun magit-mode-quit-window (kill-buffer) |
|
974 |
"Quit the selected window and bury its buffer. |
|
975 |
|
|
976 |
This behaves similar to `quit-window', but when the window |
|
977 |
was originally created to display a Magit buffer and the |
|
978 |
current buffer is the last remaining Magit buffer that was |
|
979 |
ever displayed in the selected window, then delete that |
|
980 |
window." |
|
981 |
(if (or (one-window-p) |
|
982 |
(--first (let ((buffer (car it))) |
|
983 |
(and (not (eq buffer (current-buffer))) |
|
984 |
(buffer-live-p buffer) |
|
985 |
(or (not (window-parameter nil 'magit-dedicated)) |
|
986 |
(with-current-buffer buffer |
|
987 |
(derived-mode-p 'magit-mode |
|
988 |
'magit-process-mode))))) |
|
989 |
(window-prev-buffers))) |
|
990 |
(quit-window kill-buffer) |
|
991 |
(let ((window (selected-window))) |
|
992 |
(quit-window kill-buffer) |
|
993 |
(when (window-live-p window) |
|
994 |
(delete-window window))))) |
|
995 |
|
|
996 |
;;; Refresh Magit Buffers |
|
997 |
|
|
998 |
(defvar inhibit-magit-refresh nil) |
|
999 |
|
|
1000 |
(defun magit-refresh () |
|
1001 |
"Refresh some buffers belonging to the current repository. |
|
1002 |
|
|
1003 |
Refresh the current buffer if its major mode derives from |
|
1004 |
`magit-mode', and refresh the corresponding status buffer. |
|
1005 |
|
|
1006 |
Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." |
|
1007 |
(interactive) |
|
1008 |
(unless inhibit-magit-refresh |
|
1009 |
(unwind-protect |
|
1010 |
(let ((start (current-time)) |
|
1011 |
(magit--refresh-cache (or magit--refresh-cache |
|
1012 |
(list (cons 0 0))))) |
|
1013 |
(when magit-refresh-verbose |
|
1014 |
(message "Refreshing magit...")) |
|
1015 |
(magit-run-hook-with-benchmark 'magit-pre-refresh-hook) |
|
1016 |
(when (derived-mode-p 'magit-mode) |
|
1017 |
(magit-refresh-buffer)) |
|
1018 |
(--when-let (and magit-refresh-status-buffer |
|
1019 |
(not (derived-mode-p 'magit-status-mode)) |
|
1020 |
(magit-mode-get-buffer 'magit-status-mode)) |
|
1021 |
(with-current-buffer it |
|
1022 |
(magit-refresh-buffer))) |
|
1023 |
(magit-auto-revert-buffers) |
|
1024 |
(cond |
|
1025 |
((and (not this-command) |
|
1026 |
(memq last-command magit-post-commit-hook-commands)) |
|
1027 |
(magit-run-hook-with-benchmark 'magit-post-commit-hook)) |
|
1028 |
((memq this-command magit-post-stage-hook-commands) |
|
1029 |
(magit-run-hook-with-benchmark 'magit-post-stage-hook)) |
|
1030 |
((memq this-command magit-post-unstage-hook-commands) |
|
1031 |
(magit-run-hook-with-benchmark 'magit-post-unstage-hook))) |
|
1032 |
(magit-run-hook-with-benchmark 'magit-post-refresh-hook) |
|
1033 |
(when magit-refresh-verbose |
|
1034 |
(message "Refreshing magit...done (%.3fs, cached %s/%s)" |
|
1035 |
(float-time (time-subtract (current-time) start)) |
|
1036 |
(caar magit--refresh-cache) |
|
1037 |
(+ (caar magit--refresh-cache) |
|
1038 |
(cdar magit--refresh-cache))))) |
|
1039 |
(run-hooks 'magit-unwind-refresh-hook)))) |
|
1040 |
|
|
1041 |
(defun magit-refresh-all () |
|
1042 |
"Refresh all buffers belonging to the current repository. |
|
1043 |
|
|
1044 |
Refresh all Magit buffers belonging to the current repository, |
|
1045 |
and revert buffers that visit files located inside the current |
|
1046 |
repository. |
|
1047 |
|
|
1048 |
Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." |
|
1049 |
(interactive) |
|
1050 |
(magit-run-hook-with-benchmark 'magit-pre-refresh-hook) |
|
1051 |
(dolist (buffer (magit-mode-get-buffers)) |
|
1052 |
(with-current-buffer buffer (magit-refresh-buffer))) |
|
1053 |
(magit-auto-revert-buffers) |
|
1054 |
(magit-run-hook-with-benchmark 'magit-post-refresh-hook)) |
|
1055 |
|
|
1056 |
(defvar-local magit-refresh-start-time nil) |
|
1057 |
|
|
1058 |
(defun magit-refresh-buffer () |
|
1059 |
"Refresh the current Magit buffer." |
|
1060 |
(setq magit-refresh-start-time (current-time)) |
|
1061 |
(let ((refresh (intern (format "%s-refresh-buffer" |
|
1062 |
(substring (symbol-name major-mode) 0 -5)))) |
|
1063 |
(magit--refresh-cache (or magit--refresh-cache (list (cons 0 0))))) |
|
1064 |
(when (functionp refresh) |
|
1065 |
(when magit-refresh-verbose |
|
1066 |
(message "Refreshing buffer `%s'..." (buffer-name))) |
|
1067 |
(let* ((buffer (current-buffer)) |
|
1068 |
(windows |
|
1069 |
(--mapcat (with-selected-window it |
|
1070 |
(with-current-buffer buffer |
|
1071 |
(when-let ((section (magit-current-section))) |
|
1072 |
(list |
|
1073 |
(nconc (list it section) |
|
1074 |
(magit-refresh-get-relative-position)))))) |
|
1075 |
(or (get-buffer-window-list buffer nil t) |
|
1076 |
(list (selected-window)))))) |
|
1077 |
(deactivate-mark) |
|
1078 |
(setq magit-section-highlight-overlays nil) |
|
1079 |
(setq magit-section-highlighted-section nil) |
|
1080 |
(setq magit-section-highlighted-sections nil) |
|
1081 |
(setq magit-section-unhighlight-sections nil) |
|
1082 |
(magit-process-unset-mode-line-error-status) |
|
1083 |
(let ((inhibit-read-only t)) |
|
1084 |
(erase-buffer) |
|
1085 |
(save-excursion |
|
1086 |
(apply refresh magit-refresh-args))) |
|
1087 |
(dolist (window windows) |
|
1088 |
(with-selected-window (car window) |
|
1089 |
(with-current-buffer buffer |
|
1090 |
(apply #'magit-section-goto-successor (cdr window))))) |
|
1091 |
(run-hooks 'magit-refresh-buffer-hook) |
|
1092 |
(magit-section-update-highlight) |
|
1093 |
(set-buffer-modified-p nil)) |
|
1094 |
(when magit-refresh-verbose |
|
1095 |
(message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name) |
|
1096 |
(float-time (time-subtract (current-time) |
|
1097 |
magit-refresh-start-time))))))) |
|
1098 |
|
|
1099 |
(defun magit-refresh-get-relative-position () |
|
1100 |
(when-let ((section (magit-current-section))) |
|
1101 |
(let ((start (oref section start))) |
|
1102 |
(list (count-lines start (point)) |
|
1103 |
(- (point) (line-beginning-position)) |
|
1104 |
(and (magit-hunk-section-p section) |
|
1105 |
(region-active-p) |
|
1106 |
(progn (goto-char (line-beginning-position)) |
|
1107 |
(when (looking-at "^[-+]") (forward-line)) |
|
1108 |
(while (looking-at "^[ @]") (forward-line)) |
|
1109 |
(let ((beg (point))) |
|
1110 |
(cond ((looking-at "^[-+]") |
|
1111 |
(forward-line) |
|
1112 |
(while (looking-at "^[-+]") (forward-line)) |
|
1113 |
(while (looking-at "^ ") (forward-line)) |
|
1114 |
(forward-line -1) |
|
1115 |
(regexp-quote (buffer-substring-no-properties |
|
1116 |
beg (line-end-position)))) |
|
1117 |
(t t))))))))) |
|
1118 |
|
|
1119 |
;;; Save File-Visiting Buffers |
|
1120 |
|
|
1121 |
(defvar disable-magit-save-buffers nil) |
|
1122 |
|
|
1123 |
(defun magit-pre-command-hook () |
|
1124 |
(setq disable-magit-save-buffers nil)) |
|
1125 |
(add-hook 'pre-command-hook #'magit-pre-command-hook) |
|
1126 |
|
|
1127 |
(defvar magit-after-save-refresh-buffers nil) |
|
1128 |
|
|
1129 |
(defun magit-after-save-refresh-buffers () |
|
1130 |
(dolist (buffer magit-after-save-refresh-buffers) |
|
1131 |
(when (buffer-live-p buffer) |
|
1132 |
(with-current-buffer buffer |
|
1133 |
(magit-refresh-buffer)))) |
|
1134 |
(setq magit-after-save-refresh-buffers nil) |
|
1135 |
(remove-hook 'post-command-hook 'magit-after-save-refresh-buffers)) |
|
1136 |
|
|
1137 |
(defun magit-after-save-refresh-status () |
|
1138 |
"Refresh the status buffer of the current repository. |
|
1139 |
|
|
1140 |
This function is intended to be added to `after-save-hook'. |
|
1141 |
|
|
1142 |
If the status buffer does not exist or the file being visited in |
|
1143 |
the current buffer isn't inside the working tree of a repository, |
|
1144 |
then do nothing. |
|
1145 |
|
|
1146 |
Note that refreshing a Magit buffer is done by re-creating its |
|
1147 |
contents from scratch, which can be slow in large repositories. |
|
1148 |
If you are not satisfied with Magit's performance, then you |
|
1149 |
should obviously not add this function to that hook." |
|
1150 |
(when (and (not disable-magit-save-buffers) |
|
1151 |
(magit-inside-worktree-p t)) |
|
1152 |
(--when-let (ignore-errors (magit-mode-get-buffer 'magit-status-mode)) |
|
1153 |
(add-to-list 'magit-after-save-refresh-buffers it) |
|
1154 |
(add-hook 'post-command-hook 'magit-after-save-refresh-buffers)))) |
|
1155 |
|
|
1156 |
(defun magit-maybe-save-repository-buffers () |
|
1157 |
"Maybe save file-visiting buffers belonging to the current repository. |
|
1158 |
Do so if `magit-save-repository-buffers' is non-nil. You should |
|
1159 |
not remove this from any hooks, instead set that variable to nil |
|
1160 |
if you so desire." |
|
1161 |
(when (and magit-save-repository-buffers |
|
1162 |
(not disable-magit-save-buffers)) |
|
1163 |
(setq disable-magit-save-buffers t) |
|
1164 |
(let ((msg (current-message))) |
|
1165 |
(magit-save-repository-buffers |
|
1166 |
(eq magit-save-repository-buffers 'dontask)) |
|
1167 |
(when (and msg |
|
1168 |
(current-message) |
|
1169 |
(not (equal msg (current-message)))) |
|
1170 |
(message "%s" msg))))) |
|
1171 |
|
|
1172 |
(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers) |
|
1173 |
(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers) |
|
1174 |
(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers) |
|
1175 |
|
|
1176 |
(defvar-local magit-inhibit-refresh-save nil) |
|
1177 |
|
|
1178 |
(defun magit-save-repository-buffers (&optional arg) |
|
1179 |
"Save file-visiting buffers belonging to the current repository. |
|
1180 |
After any buffer where `buffer-save-without-query' is non-nil |
|
1181 |
is saved without asking, the user is asked about each modified |
|
1182 |
buffer which visits a file in the current repository. Optional |
|
1183 |
argument (the prefix) non-nil means save all with no questions." |
|
1184 |
(interactive "P") |
|
1185 |
(when-let ((topdir (magit-rev-parse-safe "--show-toplevel"))) |
|
1186 |
(let ((remote (file-remote-p topdir)) |
|
1187 |
(save-some-buffers-action-alist |
|
1188 |
`((?Y (lambda (buffer) |
|
1189 |
(with-current-buffer buffer |
|
1190 |
(setq buffer-save-without-query t) |
|
1191 |
(save-buffer))) |
|
1192 |
"to save the current buffer and remember choice") |
|
1193 |
(?N (lambda (buffer) |
|
1194 |
(with-current-buffer buffer |
|
1195 |
(setq magit-inhibit-refresh-save t))) |
|
1196 |
"to skip the current buffer and remember choice") |
|
1197 |
,@save-some-buffers-action-alist))) |
|
1198 |
(save-some-buffers |
|
1199 |
arg (lambda () |
|
1200 |
(and (not magit-inhibit-refresh-save) |
|
1201 |
buffer-file-name |
|
1202 |
(file-exists-p (file-name-directory buffer-file-name)) |
|
1203 |
;; Avoid needlessly connecting to unrelated remotes. |
|
1204 |
(equal (file-remote-p buffer-file-name) |
|
1205 |
remote) |
|
1206 |
(string-prefix-p topdir (file-truename buffer-file-name)) |
|
1207 |
(equal (magit-rev-parse-safe "--show-toplevel") |
|
1208 |
topdir))))))) |
|
1209 |
|
|
1210 |
;;; Restore Window Configuration |
|
1211 |
|
|
1212 |
(defvar magit-inhibit-save-previous-winconf nil) |
|
1213 |
|
|
1214 |
(defvar-local magit-previous-window-configuration nil) |
|
1215 |
(put 'magit-previous-window-configuration 'permanent-local t) |
|
1216 |
|
|
1217 |
(defun magit-save-window-configuration () |
|
1218 |
"Save the current window configuration. |
|
1219 |
|
|
1220 |
Later, when the buffer is buried, it may be restored by |
|
1221 |
`magit-restore-window-configuration'." |
|
1222 |
(if magit-inhibit-save-previous-winconf |
|
1223 |
(when (eq magit-inhibit-save-previous-winconf 'unset) |
|
1224 |
(setq magit-previous-window-configuration nil)) |
|
1225 |
(unless (get-buffer-window (current-buffer) (selected-frame)) |
|
1226 |
(setq magit-previous-window-configuration |
|
1227 |
(current-window-configuration))))) |
|
1228 |
|
|
1229 |
(defun magit-restore-window-configuration (&optional kill-buffer) |
|
1230 |
"Bury or kill the current buffer and restore previous window configuration." |
|
1231 |
(let ((winconf magit-previous-window-configuration) |
|
1232 |
(buffer (current-buffer)) |
|
1233 |
(frame (selected-frame))) |
|
1234 |
(quit-window kill-buffer (selected-window)) |
|
1235 |
(when (and winconf (equal frame (window-configuration-frame winconf))) |
|
1236 |
(set-window-configuration winconf) |
|
1237 |
(when (buffer-live-p buffer) |
|
1238 |
(with-current-buffer buffer |
|
1239 |
(setq magit-previous-window-configuration nil)))))) |
|
1240 |
|
|
1241 |
;;; Buffer History |
|
1242 |
|
|
1243 |
(defun magit-go-backward () |
|
1244 |
"Move backward in current buffer's history." |
|
1245 |
(interactive) |
|
1246 |
(if help-xref-stack |
|
1247 |
(help-xref-go-back (current-buffer)) |
|
1248 |
(user-error "No previous entry in buffer's history"))) |
|
1249 |
|
|
1250 |
(defun magit-go-forward () |
|
1251 |
"Move forward in current buffer's history." |
|
1252 |
(interactive) |
|
1253 |
(if help-xref-forward-stack |
|
1254 |
(help-xref-go-forward (current-buffer)) |
|
1255 |
(user-error "No next entry in buffer's history"))) |
|
1256 |
|
|
1257 |
(defun magit-insert-xref-buttons (&optional _) |
|
1258 |
"Insert xref buttons." |
|
1259 |
(when (or help-xref-stack help-xref-forward-stack) |
|
1260 |
(when help-xref-stack |
|
1261 |
(magit-xref-insert-button help-back-label 'magit-xref-backward)) |
|
1262 |
(when help-xref-forward-stack |
|
1263 |
(when help-xref-stack |
|
1264 |
(insert " ")) |
|
1265 |
(magit-xref-insert-button help-forward-label 'magit-xref-forward)))) |
|
1266 |
|
|
1267 |
(defun magit-xref-insert-button (label type) |
|
1268 |
(magit-insert-section (button label) |
|
1269 |
(insert-text-button label 'type type |
|
1270 |
'help-args (list (current-buffer))))) |
|
1271 |
|
|
1272 |
(define-button-type 'magit-xref-backward |
|
1273 |
:supertype 'help-back |
|
1274 |
'mouse-face 'magit-section-highlight |
|
1275 |
'help-echo (purecopy "mouse-2, RET: go back to previous history entry")) |
|
1276 |
|
|
1277 |
(define-button-type 'magit-xref-forward |
|
1278 |
:supertype 'help-forward |
|
1279 |
'mouse-face 'magit-section-highlight |
|
1280 |
'help-echo (purecopy "mouse-2, RET: go back to next history entry")) |
|
1281 |
|
|
1282 |
(defun magit-xref-setup () |
|
1283 |
"Insert backward/forward buttons if the major-mode supports it. |
|
1284 |
Currently `magit-log-mode', `magit-reflog-mode', |
|
1285 |
`magit-diff-mode', and `magit-revision-mode' support it" |
|
1286 |
(when (memq major-mode '(magit-log-mode |
|
1287 |
magit-reflog-mode |
|
1288 |
magit-diff-mode |
|
1289 |
magit-revision-mode)) |
|
1290 |
(when help-xref-stack-item |
|
1291 |
(push (cons (point) help-xref-stack-item) help-xref-stack) |
|
1292 |
(setq help-xref-forward-stack nil)) |
|
1293 |
(when (called-interactively-p 'interactive) |
|
1294 |
(--when-let (nthcdr 10 help-xref-stack) |
|
1295 |
(setcdr it nil))) |
|
1296 |
(setq help-xref-stack-item |
|
1297 |
`(magit-xref-restore ,default-directory ,@magit-refresh-args)))) |
|
1298 |
|
|
1299 |
(defun magit-xref-restore (&rest args) |
|
1300 |
(magit-xref-setup) |
|
1301 |
(setq default-directory (car args)) |
|
1302 |
(setq magit-refresh-args (cdr args)) |
|
1303 |
(magit-refresh-buffer)) |
|
1304 |
|
|
1305 |
;;; Repository-Local Cache |
|
1306 |
|
|
1307 |
(defvar magit-repository-local-cache nil |
|
1308 |
"Alist mapping `magit-toplevel' paths to alists of key/value pairs.") |
|
1309 |
|
|
1310 |
(defun magit-repository-local-repository () |
|
1311 |
"Return the key for the current repository." |
|
1312 |
(or (bound-and-true-p magit--default-directory) |
|
1313 |
(magit-toplevel))) |
|
1314 |
|
|
1315 |
(defun magit-repository-local-set (key value &optional repository) |
|
1316 |
"Set the repository-local VALUE for KEY. |
|
1317 |
|
|
1318 |
Unless specified, REPOSITORY is the current buffer's repository. |
|
1319 |
|
|
1320 |
If REPOSITORY is nil (meaning there is no current repository), |
|
1321 |
then the value is not cached, and we return nil." |
|
1322 |
(let* ((repokey (or repository (magit-repository-local-repository))) |
|
1323 |
(cache (assoc repokey magit-repository-local-cache))) |
|
1324 |
;; Don't cache values for a nil REPOSITORY, as the 'set' and 'get' |
|
1325 |
;; calls for some KEY may happen in unrelated contexts. |
|
1326 |
(when repokey |
|
1327 |
(if cache |
|
1328 |
(let ((keyvalue (assoc key (cdr cache)))) |
|
1329 |
(if keyvalue |
|
1330 |
;; Update pre-existing value for key. |
|
1331 |
(setcdr keyvalue value) |
|
1332 |
;; No such key in repository-local cache. |
|
1333 |
(push (cons key value) (cdr cache)))) |
|
1334 |
;; No cache for this repository. |
|
1335 |
(push (cons repokey (list (cons key value))) |
|
1336 |
magit-repository-local-cache))))) |
|
1337 |
|
|
1338 |
(defun magit-repository-local-exists-p (key &optional repository) |
|
1339 |
"Non-nil when a repository-local value exists for KEY. |
|
1340 |
|
|
1341 |
Returns a (KEY . value) cons cell. |
|
1342 |
|
|
1343 |
The KEY is matched using `equal'. |
|
1344 |
|
|
1345 |
Unless specified, REPOSITORY is the current buffer's repository." |
|
1346 |
(let* ((repokey (or repository (magit-repository-local-repository))) |
|
1347 |
(cache (assoc repokey magit-repository-local-cache))) |
|
1348 |
(and cache |
|
1349 |
(assoc key (cdr cache))))) |
|
1350 |
|
|
1351 |
(defun magit-repository-local-get (key &optional default repository) |
|
1352 |
"Return the repository-local value for KEY. |
|
1353 |
|
|
1354 |
Return DEFAULT if no value for KEY exists. |
|
1355 |
|
|
1356 |
The KEY is matched using `equal'. |
|
1357 |
|
|
1358 |
Unless specified, REPOSITORY is the current buffer's repository." |
|
1359 |
(let ((keyvalue (magit-repository-local-exists-p key repository))) |
|
1360 |
(if keyvalue |
|
1361 |
(cdr keyvalue) |
|
1362 |
default))) |
|
1363 |
|
|
1364 |
(defun magit-repository-local-delete (key &optional repository) |
|
1365 |
"Delete the repository-local value for KEY. |
|
1366 |
|
|
1367 |
Unless specified, REPOSITORY is the current buffer's repository." |
|
1368 |
(let* ((repokey (or repository (magit-repository-local-repository))) |
|
1369 |
(cache (assoc repokey magit-repository-local-cache))) |
|
1370 |
(when cache |
|
1371 |
;; There is no `assoc-delete-all'. |
|
1372 |
(setf (cdr cache) |
|
1373 |
(cl-delete key (cdr cache) :key #'car :test #'equal))))) |
|
1374 |
|
|
1375 |
(defun magit-zap-caches () |
|
1376 |
"Zap caches for the current repository. |
|
1377 |
Remove the repository's entry from `magit-repository-local-cache' |
|
1378 |
and set `magit-section-visibility-cache' to nil in all of the |
|
1379 |
repository's Magit buffers." |
|
1380 |
(interactive) |
|
1381 |
(magit-with-toplevel |
|
1382 |
(setq magit-repository-local-cache |
|
1383 |
(cl-delete default-directory |
|
1384 |
magit-repository-local-cache |
|
1385 |
:key #'car :test #'equal))) |
|
1386 |
(dolist (buffer (magit-mode-get-buffers)) |
|
1387 |
(with-current-buffer buffer |
|
1388 |
(setq magit-section-visibility-cache nil)))) |
|
1389 |
|
|
1390 |
;;; Utilities |
|
1391 |
|
|
1392 |
(defun magit-run-hook-with-benchmark (hook) |
|
1393 |
(when hook |
|
1394 |
(if magit-refresh-verbose |
|
1395 |
(let ((start (current-time))) |
|
1396 |
(message "Running %s..." hook) |
|
1397 |
(run-hooks hook) |
|
1398 |
(message "Running %s...done (%.3fs)" hook |
|
1399 |
(float-time (time-subtract (current-time) start)))) |
|
1400 |
(run-hooks hook)))) |
|
1401 |
|
|
1402 |
;;; _ |
|
1403 |
(provide 'magit-mode) |
|
1404 |
;;; magit-mode.el ends here |