mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 9d27fc972e84736015ab3b1c331888a8fe3d1276
commit | author | age
5cb5f7 1 ;;; magit-autorevert.el --- revert buffers when files in repository change  -*- 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 ;;; Code:
25
26 (require 'cl-lib)
27 (require 'dash)
28
29 (require 'magit-git)
30
31 (require 'autorevert)
32
33 ;;; Options
34
35 (defgroup magit-auto-revert nil
36   "Revert buffers when files in repository change."
37   :link '(custom-group-link auto-revert)
38   :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
39   :group 'auto-revert
40   :group 'magit-essentials
41   :group 'magit-modes)
42
43 (defcustom auto-revert-buffer-list-filter nil
44   "Filter that determines which buffers `auto-revert-buffers' reverts.
45
46 This option is provided by `magit', which also redefines
47 `auto-revert-buffers' to respect it.  Magit users who do not turn
48 on the local mode `auto-revert-mode' themselves, are best served
49 by setting the value to `magit-auto-revert-repository-buffers-p'.
50
51 However the default is nil, to not disturb users who do use the
52 local mode directly.  If you experience delays when running Magit
53 commands, then you should consider using one of the predicates
54 provided by Magit - especially if you also use Tramp.
55
56 Users who do turn on `auto-revert-mode' in buffers in which Magit
57 doesn't do that for them, should likely not use any filter.
58 Users who turn on `global-auto-revert-mode', do not have to worry
59 about this option, because it is disregarded if the global mode
60 is enabled."
61   :package-version '(magit . "2.4.2")
62   :group 'auto-revert
63   :group 'magit-auto-revert
64   :group 'magit-related
65   :type '(radio (const :tag "no filter" nil)
66                 (function-item magit-auto-revert-buffer-p)
67                 (function-item magit-auto-revert-repository-buffer-p)
68                 function))
69
70 (defcustom magit-auto-revert-tracked-only t
71   "Whether `magit-auto-revert-mode' only reverts tracked files."
72   :package-version '(magit . "2.4.0")
73   :group 'magit-auto-revert
74   :type 'boolean
75   :set (lambda (var val)
76          (set var val)
77          (when (and (bound-and-true-p magit-auto-revert-mode)
78                     (featurep 'magit-autorevert))
79            (magit-auto-revert-mode -1)
80            (magit-auto-revert-mode))))
81
82 (defcustom magit-auto-revert-immediately t
83   "Whether Magit reverts buffers immediately.
84
85 If this is non-nil and either `global-auto-revert-mode' or
86 `magit-auto-revert-mode' is enabled, then Magit immediately
87 reverts buffers by explicitly calling `auto-revert-buffers'
88 after running git for side-effects.
89
90 If `auto-revert-use-notify' is non-nil (and file notifications
91 are actually supported), then `magit-auto-revert-immediately'
92 does not have to be non-nil, because the reverts happen
93 immediately anyway.
94
95 If `magit-auto-revert-immediately' and `auto-revert-use-notify'
96 are both nil, then reverts happen after `auto-revert-interval'
97 seconds of user inactivity.  That is not desirable."
98   :package-version '(magit . "2.4.0")
99   :group 'magit-auto-revert
100   :type 'boolean)
101
102 ;;; Mode
103
104 (defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
105   (if file
106       (--when-let (find-buffer-visiting file)
107         (with-current-buffer it
108           (magit-turn-on-auto-revert-mode-if-desired)))
109     (when (and buffer-file-name
110                (file-readable-p buffer-file-name)
111                (magit-toplevel)
112                (or (not magit-auto-revert-tracked-only)
113                    (magit-file-tracked-p buffer-file-name))
114                (not auto-revert-mode)         ; see #3014
115                (not global-auto-revert-mode)) ; see #3460
116       (auto-revert-mode 1))))
117
118 ;;;###autoload
119 (define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
120   magit-turn-on-auto-revert-mode-if-desired
121   :package-version '(magit . "2.4.0")
122   :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
123   :group 'magit-auto-revert
124   :group 'magit-essentials
125   ;; - When `global-auto-revert-mode' is enabled, then this mode is
126   ;;   redundant.
127   ;; - In all other cases enable the mode because if buffers are not
128   ;;   automatically reverted that would make many very common tasks
129   ;;   much more cumbersome.
130   ;; - When `magit-revert-buffers' is nil, then the user has opted out
131   ;;   of the automatic reverts while a very old implementation was
132   ;;   still in use.  We continued to respect that setting for another
133   ;;   two and a half years, but no longer do so now.
134   :init-value (and (not global-auto-revert-mode)
135                    (not noninteractive)))
136 ;; - Unfortunately `:init-value t' only sets the value of the mode
137 ;;   variable but does not cause the mode function to be called.
138 ;; - I don't think it works like this on purpose, but since one usually
139 ;;   should not enable global modes by default, it is understandable.
140 ;; - If the user has set the variable `magit-auto-revert-mode' to nil
141 ;;   after loading magit (instead of doing so before loading magit or
142 ;;   by using the function), then we should still respect that setting.
143 ;; - If the user has set the obsolete variable `magit-revert-buffers'
144 ;;   to nil before or after loading magit, then we should still respect
145 ;;   that setting.
146 ;; - If the user sets one of these variables after loading magit and
147 ;;   after `after-init-hook' has run, then that won't have an effect
148 ;;   and there is nothing we can do about it.
149 (defun magit-auto-revert-mode--init-kludge ()
150   "This is an internal kludge to be used on `after-init-hook'.
151 Do not use this function elsewhere, and don't remove it from
152 the `after-init-hook'.  For more information see the comments
153 and code surrounding the definition of this function."
154   (if magit-auto-revert-mode
155       (let ((start (current-time)))
156         (magit-message "Turning on magit-auto-revert-mode...")
157         (magit-auto-revert-mode 1)
158         (magit-message
159          "Turning on magit-auto-revert-mode...done%s"
160          (let ((elapsed (float-time (time-subtract (current-time) start))))
161            (if (> elapsed 0.2)
162                (format " (%.3fs, %s buffers checked)" elapsed
163                        (length (buffer-list)))
164              ""))))
165     (magit-auto-revert-mode -1)))
166 (if after-init-time
167     ;; Since `after-init-hook' has already been
168     ;; run, turn the mode on or off right now.
169     (magit-auto-revert-mode--init-kludge)
170   ;; By the time the init file has been fully loaded the
171   ;; values of the relevant variables might have changed.
172   (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t))
173
174 (put 'magit-auto-revert-mode 'function-documentation
175      "Toggle Magit Auto Revert mode.
176 With a prefix argument ARG, enable Magit Auto Revert mode if ARG
177 is positive, and disable it otherwise.  If called from Lisp,
178 enable the mode if ARG is omitted or nil.
179
180 Magit Auto Revert mode is a global minor mode that reverts
181 buffers associated with a file that is located inside a Git
182 repository when the file changes on disk.  Use `auto-revert-mode'
183 to revert a particular buffer.  Or use `global-auto-revert-mode'
184 to revert all file-visiting buffers, not just those that visit
185 a file located inside a Git repository.
186
187 This global mode works by turning on the buffer-local mode
188 `auto-revert-mode' at the time a buffer is first created.  The
189 local mode is turned on if the visited file is being tracked in
190 a Git repository at the time when the buffer is created.
191
192 If `magit-auto-revert-tracked-only' is non-nil (the default),
193 then only tracked files are reverted.  But if you stage a
194 previously untracked file using `magit-stage', then this mode
195 notices that.
196
197 Unlike `global-auto-revert-mode', this mode never reverts any
198 buffers that are not visiting files.
199
200 The behavior of this mode can be customized using the options
201 in the `autorevert' and `magit-autorevert' groups.
202
203 This function calls the hook `magit-auto-revert-mode-hook'.")
204
205 (defun magit-auto-revert-buffers ()
206   (when (and magit-auto-revert-immediately
207              (or global-auto-revert-mode
208                  (and magit-auto-revert-mode auto-revert-buffer-list)))
209     (let ((auto-revert-buffer-list-filter
210            (or auto-revert-buffer-list-filter
211                'magit-auto-revert-repository-buffer-p)))
212       (auto-revert-buffers))))
213
214 (defvar magit-auto-revert-toplevel nil)
215
216 (when (< emacs-major-version 25)
217   (defvar auto-revert-buffers-counter 1
218     "Incremented each time `auto-revert-buffers' is called"))
219
220 (defun magit-auto-revert-buffer-p (buffer)
221   "Return t if BUFFER visits a file inside the current repository.
222 The current repository is the one in which `default-directory' is
223 located.  If there is no current repository, then return t for
224 any BUFFER."
225   (magit-auto-revert-repository-buffer-p buffer t))
226
227 (defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
228   "Return t if BUFFER visits a file inside the current repository.
229 The current repository is the one in which `default-directory' is
230 located.  If there is no current repository, then return FALLBACK
231 \(which defaults to nil) for any BUFFER."
232   ;; Call `magit-toplevel' just once per cycle.
233   (unless (and magit-auto-revert-toplevel
234                (= (cdr magit-auto-revert-toplevel)
235                   auto-revert-buffers-counter))
236     (setq magit-auto-revert-toplevel
237           (cons (or (magit-toplevel) 'no-repo)
238                 auto-revert-buffers-counter)))
239   (let ((top (car magit-auto-revert-toplevel)))
240     (if (eq top 'no-repo)
241         fallback
242       (let ((dir (with-current-buffer buffer default-directory)))
243         (and (equal (file-remote-p dir)
244                     (file-remote-p top))
245              ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
246              (file-in-directory-p dir top))))))
247
248 (defun auto-revert-buffers--buffer-list-filter ()
249   (when (< emacs-major-version 25)
250     (cl-incf auto-revert-buffers-counter))
251   (when auto-revert-buffer-list-filter
252     (setq auto-revert-buffer-list
253           (--filter auto-revert-buffer-list-filter
254                     auto-revert-buffer-list))))
255
256 (advice-add 'auto-revert-buffers :before
257             'auto-revert-buffers--buffer-list-filter)
258
259 ;;; _
260 (provide 'magit-autorevert)
261 ;;; magit-autorevert.el ends here