aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTassilo Horn2020-06-11 17:02:02 +0200
committerTassilo Horn2020-06-17 18:53:13 +0200
commit6dd702a7b62a26f9aeefd045cc99ff6ed0882ec9 (patch)
treef6f22691503a0023647c6aac162de838920e8ab6
parent9682aa2f2493c89af1894ad2d52543d57f4958a5 (diff)
downloademacs-feature/bug-reference-setup.tar.gz
emacs-feature/bug-reference-setup.zip
bug-reference-setupfeature/bug-reference-setup
-rw-r--r--lisp/progmodes/bug-reference.el197
-rw-r--r--lisp/vc/vc.el10
2 files changed, 204 insertions, 3 deletions
diff --git a/lisp/progmodes/bug-reference.el b/lisp/progmodes/bug-reference.el
index 02af263ec34..20558de6b02 100644
--- a/lisp/progmodes/bug-reference.el
+++ b/lisp/progmodes/bug-reference.el
@@ -139,12 +139,208 @@ The second subexpression should match the bug reference (usually a number)."
139 (when url 139 (when url
140 (browse-url url)))))) 140 (browse-url url))))))
141 141
142(defun bug-reference--maybe-setup-from-vc (url url-rx bug-rx bug-url-fmt)
143 (when (string-match url-rx url)
144 (setq-local bug-reference-bug-regexp bug-rx)
145 (setq-local bug-reference-url-format
146 (let (groups)
147 (dotimes (i (/ (length (match-data)) 2))
148 (push (match-string i url) groups))
149 (funcall bug-url-fmt (nreverse groups))))))
150
151(defvar bug-reference-setup-from-vc-alist
152 `(;; GNU projects on savannah. FIXME: Only a fraction of
153 ;; them uses debbugs.
154 ("git\\.\\(?:sv\\|savannah\\)\\.gnu\\.org:"
155 "\\<\\([Bb]ug ?#?\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)\\>"
156 ,(lambda (_) "https://debbugs.gnu.org/%s"))
157 ;; GitHub projects. Here #17 may refer to either an issue
158 ;; or a pull request but visiting the issue/17 web page
159 ;; will automatically redirect to the pull/17 page if 17 is
160 ;; a PR. Explicit user/project#17 links to possibly
161 ;; different projects are also supported.
162 ("[/@]github.com[/:]\\([.A-Za-z0-9_/-]+\\)\\.git"
163 "\\([.A-Za-z0-9_/-]+\\)?\\(?:#\\)\\([0-9]+\\)\\>"
164 ,(lambda (groups)
165 (let ((ns-project (nth 1 groups)))
166 (lambda ()
167 (concat "https://github.com/"
168 (or
169 ;; Explicit user/proj#18 link.
170 (match-string 1)
171 ns-project)
172 "/issues/"
173 (match-string 2))))))
174 ;; GitLab projects. Here #18 is an issue and !17 is a merge
175 ;; request. Explicit namespace/project#18 references to possibly
176 ;; different projects are also supported.
177 ("[/@]gitlab.com[/:]\\([.A-Za-z0-9_/-]+\\)\\.git"
178 "\\(?1:[.A-Za-z0-9_/-]+\\)?\\(?3:[#!]\\)\\(?2:[0-9]+\\)\\>"
179 ,(lambda (groups)
180 (let ((ns-project (nth 1 groups)))
181 (lambda ()
182 (concat "https://gitlab.com/"
183 (or (match-string 1)
184 ns-project)
185 "/-/"
186 (if (string= (match-string 3) "#")
187 "issues/"
188 "merge_requests/")
189 (match-string 2)))))))
190 "An alist for setting up `bug-reference-mode' based on VC URL.
191
192Each element has the form (URL-REGEXP BUG-REGEXP URL-FORMAT-FN).
193
194URL-REGEXP is matched against the version control URL of the
195current buffer's file. If it matches, BUG-REGEXP is set as
196`bug-reference-bug-regexp'. URL-FORMAT-FN is a function of one
197argument that receives a list of the groups 0 to N of matching
198URL-REGEXP against the VCS URL and return the value to be set as
199`bug-reference-url-format'.")
200
201(defun bug-reference-try-setup-from-vc ()
202 "Try setting up `bug-reference-mode' based on VCS information.
203Tests each configuration from `bug-reference-setup-from-vc-alist'
204and sets it if applicable."
205 (when buffer-file-name
206 (let* ((backend (vc-responsible-backend buffer-file-name t))
207 (url
208 (or (ignore-errors
209 (vc-call-backend backend 'repository-url "upstream"))
210 (ignore-errors
211 (vc-call-backend backend 'repository-url)))))
212 (when url
213 (catch 'found
214 (dolist (config bug-reference-setup-from-vc-alist)
215 (when (apply #'bug-reference--maybe-setup-from-vc
216 url config)
217 (throw 'found t))))))))
218
219(defvar bug-reference-setup-from-mail-alist
220 `((,(regexp-opt '("emacs" "auctex" "gnus") 'words)
221 ,(regexp-opt '("@debbugs.gnu.org" "-devel@gnu.org"
222 ;; List-Id of Gnus devel mailing list.
223 "ding.gnus.org"))
224 "\\([Bb]ug ?#?\\)\\([0-9]+\\(?:#[0-9]+\\)?\\)"
225 "https://debbugs.gnu.org/%s"))
226 ;; TODO: Adapt docstring!
227 "An alist for setting up `bug-reference-mode' based in mail modes.
228
229This takes action if `bug-reference-mode' is enabled in group and
230message buffers of Emacs mail clients. Currently, only Gnus is
231supported.
232
233Each element has the form
234
235 (GROUP-REGEXP HEADER-REGEXP BUG-REGEXP URL-FORMAT)
236
237GROUP-REGEXP is a regexp matched against the current mail folder
238name or newsgroup. HEADER-REGEXP is a regexp matched against the
239From, To, Cc, and List-ID header values of the current mail or
240newsgroup message. If any of those matches, BUG-REGEXP is set as
241`bug-reference-bug-regexp' and URL-FORMAT is set as
242`bug-reference-url-format'.
243
244Note: In Gnus, if a summary buffer has been set up based on
245GROUP-REGEXP, all article buffers opened from there will get the
246same `bug-reference-url-format' and `bug-reference-url-format'.")
247
248(defvar gnus-newsgroup-name)
249
250(defun bug-reference--maybe-setup-from-mail (group headers)
251 (catch 'setup-done
252 (dolist (config bug-reference-setup-from-mail-alist)
253 (when (or
254 (and group
255 (car config)
256 (string-match-p (car config) group))
257 (and headers
258 (nth 1 config)
259 (catch 'matching-header
260 (dolist (h headers)
261 (when (and h (string-match-p (nth 1 config) h))
262 (throw 'matching-header t))))))
263 (setq-local bug-reference-bug-regexp (nth 2 config))
264 (setq-local bug-reference-url-format (nth 3 config))
265 (throw 'setup-done t)))))
266
267(defun bug-reference-try-setup-from-gnus ()
268 "Try setting up `bug-reference-mode' based on Gnus group or article.
269Tests each configuration from `bug-reference-setup-from-mail-alist'
270and sets it if applicable."
271 (when (and (derived-mode-p 'gnus-summary-mode)
272 (bound-and-true-p gnus-newsgroup-name))
273 ;; Gnus reuses its article buffer so we have to check whenever the
274 ;; article changes.
275 (add-hook 'gnus-article-prepare-hook
276 #'bug-reference--try-setup-gnus-article)
277 (bug-reference--maybe-setup-from-mail gnus-newsgroup-name nil)))
278
279(defvar gnus-article-buffer)
280(defvar gnus-summary-buffer)
281(declare-function mail-header-extract "mailheader")
282(declare-function mail-header "mailheader")
283
284(defun bug-reference--try-setup-gnus-article ()
285 (with-demoted-errors
286 "Error in bug-reference--try-setup-gnus-article: %S"
287 (when (and bug-reference-mode ;; Only if enabled in article buffers.
288 (derived-mode-p
289 'gnus-article-mode
290 ;; Apparently, gnus-article-prepare-hook is run in the
291 ;; summary buffer...
292 'gnus-summary-mode)
293 gnus-article-buffer
294 (buffer-live-p (get-buffer gnus-article-buffer)))
295 (with-current-buffer gnus-article-buffer
296 (catch 'setup-done
297 ;; Copy over the values from the summary buffer.
298 (when (and gnus-summary-buffer
299 (buffer-live-p gnus-summary-buffer))
300 (setq-local bug-reference-bug-regexp
301 (with-current-buffer gnus-summary-buffer
302 bug-reference-bug-regexp))
303 (setq-local bug-reference-url-format
304 (with-current-buffer gnus-summary-buffer
305 bug-reference-url-format))
306 (when (and bug-reference-bug-regexp
307 bug-reference-url-format)
308 (throw 'setup-done t)))
309 ;; If the summary had no values, try setting according to
310 ;; the values of the From, To, and Cc headers.
311 (let ((headers (save-excursion
312 (goto-char (point-min))
313 (mail-header-extract)))
314 header-values)
315 (dolist (h '(list-id to from cc))
316 (let ((val (mail-header h headers)))
317 (when val
318 (push val header-values))))
319 (bug-reference--maybe-setup-from-mail
320 nil header-values)))))))
321
322(defun bug-reference--after-hook ()
323 (when (or bug-reference-mode
324 bug-reference-prog-mode)
325 ;; Automatic setup only if the variables aren't already set, e.g.,
326 ;; by a local variables section in the file.
327 (unless (and bug-reference-bug-regexp
328 bug-reference-url-format)
329 (with-demoted-errors
330 "Error during bug-reference auto-setup: %S"
331 (catch 'setup
332 (dolist (f (list #'bug-reference-try-setup-from-vc
333 #'bug-reference-try-setup-from-gnus))
334 (when (funcall f)
335 (throw 'setup t))))))))
336
142;;;###autoload 337;;;###autoload
143(define-minor-mode bug-reference-mode 338(define-minor-mode bug-reference-mode
144 "Toggle hyperlinking bug references in the buffer (Bug Reference mode)." 339 "Toggle hyperlinking bug references in the buffer (Bug Reference mode)."
145 nil 340 nil
146 "" 341 ""
147 nil 342 nil
343 :after-hook (bug-reference--after-hook)
148 (if bug-reference-mode 344 (if bug-reference-mode
149 (jit-lock-register #'bug-reference-fontify) 345 (jit-lock-register #'bug-reference-fontify)
150 (jit-lock-unregister #'bug-reference-fontify) 346 (jit-lock-unregister #'bug-reference-fontify)
@@ -158,6 +354,7 @@ The second subexpression should match the bug reference (usually a number)."
158 nil 354 nil
159 "" 355 ""
160 nil 356 nil
357 :after-hook (bug-reference--after-hook)
161 (if bug-reference-prog-mode 358 (if bug-reference-prog-mode
162 (jit-lock-register #'bug-reference-fontify) 359 (jit-lock-register #'bug-reference-fontify)
163 (jit-lock-unregister #'bug-reference-fontify) 360 (jit-lock-unregister #'bug-reference-fontify)
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index ce947d21f95..9b12d449785 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -964,7 +964,7 @@ use."
964 (throw 'found bk)))) 964 (throw 'found bk))))
965 965
966;;;###autoload 966;;;###autoload
967(defun vc-responsible-backend (file) 967(defun vc-responsible-backend (file &optional no-error)
968 "Return the name of a backend system that is responsible for FILE. 968 "Return the name of a backend system that is responsible for FILE.
969 969
970If FILE is already registered, return the 970If FILE is already registered, return the
@@ -974,7 +974,10 @@ responsible for FILE is returned.
974 974
975Note that if FILE is a symbolic link, it will not be resolved -- 975Note that if FILE is a symbolic link, it will not be resolved --
976the responsible backend system for the symbolic link itself will 976the responsible backend system for the symbolic link itself will
977be reported." 977be reported.
978
979If NO-ERROR is nil, signal an error that no VC backend is
980responsible for the given file."
978 (or (and (not (file-directory-p file)) (vc-backend file)) 981 (or (and (not (file-directory-p file)) (vc-backend file))
979 (catch 'found 982 (catch 'found
980 ;; First try: find a responsible backend. If this is for registration, 983 ;; First try: find a responsible backend. If this is for registration,
@@ -982,7 +985,8 @@ be reported."
982 (dolist (backend vc-handled-backends) 985 (dolist (backend vc-handled-backends)
983 (and (vc-call-backend backend 'responsible-p file) 986 (and (vc-call-backend backend 'responsible-p file)
984 (throw 'found backend)))) 987 (throw 'found backend))))
985 (error "No VC backend is responsible for %s" file))) 988 (unless no-error
989 (error "No VC backend is responsible for %s" file))))
986 990
987(defun vc-expand-dirs (file-or-dir-list backend) 991(defun vc-expand-dirs (file-or-dir-list backend)
988 "Expands directories in a file list specification. 992 "Expands directories in a file list specification.