xref: Keep track of temporary buffers

Fixes: debbugs:19466

xref: Keep track of temporary buffers.
* lisp/progmodes/xref.el (xref--temporary-buffers, xref--selected)
(xref--inhibit-mark-selected): New variables.
(xref--mark-selected): New function.
(xref--show-location): Maybe add the buffer to
`xref--temporary-buffers', add `xref--mark-selected' to
`buffer-list-update-hook' there.
(xref--window): Add docstring.
(xref-quit): Rename from `xref--quit'.  Update both references.
Add KILL argument.  When it's non-nil, kill the temporary buffers
that haven't been selected by the user.
(xref--show-xref-buffer): Change the second argument to alist,
extract the values for `xref--window' and
`xref--temporary-buffers' from it.  Add `xref--mark-selected' to
`buffer-list-update-hook' to each buffer in the list.
(xref--show-xrefs): Move the logic of calling `xref-find-function'
here.  Save the difference between buffer lists before and after
it's called as "temporary buffers", and `pass it to
`xref-show-xrefs-function'.
(xref--find-definitions, xref-find-references)
(xref-find-apropos): Update accordingly.
This commit is contained in:
Dmitry Gutov 2015-01-21 08:43:39 +02:00
parent 9a895795e8
commit 956b13c527
2 changed files with 99 additions and 34 deletions

View file

@ -1,3 +1,27 @@
2015-01-21 Dmitry Gutov <dgutov@yandex.ru>
xref: Keep track of temporary buffers (bug#19466).
* progmodes/xref.el (xref--temporary-buffers, xref--selected)
(xref--inhibit-mark-selected): New variables.
(xref--mark-selected): New function.
(xref--show-location): Maybe add the buffer to
`xref--temporary-buffers', add `xref--mark-selected' to
`buffer-list-update-hook' there.
(xref--window): Add docstring.
(xref-quit): Rename from `xref--quit'. Update both references.
Add KILL argument. When it's non-nil, kill the temporary buffers
that haven't been selected by the user.
(xref--show-xref-buffer): Change the second argument to alist,
extract the values for `xref--window' and
`xref--temporary-buffers' from it. Add `xref--mark-selected' to
`buffer-list-update-hook' to each buffer in the list.
(xref--show-xrefs): Move the logic of calling `xref-find-function'
here. Save the difference between buffer lists before and after
it's called as "temporary buffers", and `pass it to
`xref-show-xrefs-function'.
(xref--find-definitions, xref-find-references)
(xref-find-apropos): Update accordingly.
2015-01-20 Artur Malabarba <bruce.connor.am@gmail.com>
* emacs-lisp/package.el (package-dir-info): Fix `while' logic.

View file

@ -339,6 +339,20 @@ WINDOW controls how the buffer is displayed:
(defvar-local xref--display-history nil
"List of pairs (BUFFER . WINDOW), for temporarily displayed buffers.")
(defvar-local xref--temporary-buffers nil
"List of buffers created by xref code.")
(defvar-local xref--selected nil
"t if the current buffer has ever been selected.
Used for temporary buffers.")
(defvar xref--inhibit-mark-selected nil)
(defun xref--mark-selected ()
(unless xref--inhibit-mark-selected
(setq xref--selected t))
(remove-hook 'buffer-list-update-hook #'xref--mark-selected t))
(defun xref--save-to-history (buf win)
(let ((restore (window-parameter win 'quit-restore)))
;; Save the new entry if the window displayed another buffer
@ -359,8 +373,16 @@ WINDOW controls how the buffer is displayed:
(defun xref--show-location (location)
(condition-case err
(let ((xref-buf (current-buffer)))
(let ((xref-buf (current-buffer))
(bl (buffer-list))
(xref--inhibit-mark-selected t))
(xref--goto-location location)
(let ((buf (current-buffer)))
(unless (memq buf bl)
;; Newly created.
(add-hook 'buffer-list-update-hook #'xref--mark-selected nil t)
(with-current-buffer xref-buf
(push buf xref--temporary-buffers))))
(xref--display-position (point) t 1 xref-buf))
(user-error (message (error-message-string err)))))
@ -386,7 +408,8 @@ WINDOW controls how the buffer is displayed:
(defun xref--location-at-point ()
(get-text-property (point) 'xref-location))
(defvar-local xref--window nil)
(defvar-local xref--window nil
"ACTION argument to call `display-buffer' with.")
(defun xref-goto-xref ()
"Jump to the xref on the current line and bury the xref buffer."
@ -395,7 +418,7 @@ WINDOW controls how the buffer is displayed:
(let ((loc (or (xref--location-at-point)
(user-error "No reference at point")))
(window xref--window))
(xref--quit)
(xref-quit)
(xref--pop-to-location loc window)))
(define-derived-mode xref--xref-buffer-mode fundamental-mode "XREF"
@ -403,7 +426,7 @@ WINDOW controls how the buffer is displayed:
(setq buffer-read-only t))
(let ((map xref--xref-buffer-mode-map))
(define-key map (kbd "q") #'xref--quit)
(define-key map (kbd "q") #'xref-quit)
(define-key map (kbd "n") #'xref-next-line)
(define-key map (kbd "p") #'xref-prev-line)
(define-key map (kbd "RET") #'xref-goto-xref)
@ -413,17 +436,31 @@ WINDOW controls how the buffer is displayed:
(define-key map (kbd ".") #'xref-next-line)
(define-key map (kbd ",") #'xref-prev-line))
(defun xref--quit ()
"Quit all windows in `xref--display-history', then quit current window."
(interactive)
(defun xref-quit (&optional kill)
"Perform cleanup, then quit the current window.
The cleanup consists of burying all temporarily displayed
buffers, and if KILL is non-nil, of killing all buffers that were
created in the process of showing xrefs.
Exceptions are made for buffers switched to by the user in the
meantime, and other window configuration changes. These are
preserved."
(interactive "P")a
(let ((window (selected-window))
(history xref--display-history))
(setq xref--display-history nil)
(when kill
(let ((xref--inhibit-mark-selected t)
kill-buffer-query-functions)
(dolist (buf xref--temporary-buffers)
(unless (buffer-local-value 'xref--selected buf)
(kill-buffer buf)))
(setq xref--temporary-buffers nil)))
(pcase-dolist (`(,buf . ,win) history)
(when (and (window-live-p win)
(eq buf (window-buffer win)))
(quit-window nil win)))
(quit-window nil window)))
(quit-window kill window)))
(defconst xref-buffer-name "*xref*"
"The name of the buffer to show xrefs.")
@ -471,7 +508,7 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
(xref-location-group (xref--xref-location x)))
#'equal))
(defun xref--show-xref-buffer (xrefs window)
(defun xref--show-xref-buffer (xrefs alist)
(let ((xref-alist (xref--analyze xrefs)))
(with-current-buffer (get-buffer-create xref-buffer-name)
(let ((inhibit-read-only t))
@ -480,7 +517,11 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
(xref--xref-buffer-mode)
(pop-to-buffer (current-buffer))
(goto-char (point-min))
(setq xref--window window)
(setq xref--window (assoc-default 'window alist))
(setq xref--temporary-buffers (assoc-default 'temporary-buffers alist))
(dolist (buf xref--temporary-buffers)
(with-current-buffer buf
(add-hook 'buffer-list-update-hook #'xref--mark-selected nil t)))
(current-buffer)))))
@ -493,16 +534,21 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
(defvar xref-show-xrefs-function 'xref--show-xref-buffer
"Function to display a list of xrefs.")
(defun xref--show-xrefs (id kind xrefs window)
(cond
((null xrefs)
(user-error "No known %s for: %s" kind id))
((not (cdr xrefs))
(xref-push-marker-stack)
(xref--pop-to-location (xref--xref-location (car xrefs)) window))
(t
(xref-push-marker-stack)
(funcall xref-show-xrefs-function xrefs window))))
(defun xref--show-xrefs (input kind arg window)
(let* ((bl (buffer-list))
(xrefs (funcall xref-find-function kind arg))
(tb (cl-set-difference (buffer-list) bl)))
(cond
((null xrefs)
(user-error "No known %s for: %s" (symbol-name kind) input))
((not (cdr xrefs))
(xref-push-marker-stack)
(xref--pop-to-location (xref--xref-location (car xrefs)) window))
(t
(xref-push-marker-stack)
(funcall xref-show-xrefs-function xrefs
`((window . ,window)
(temporary-buffers . ,tb)))))))
(defun xref--read-identifier (prompt)
"Return the identifier at point or read it from the minibuffer."
@ -517,9 +563,7 @@ Return an alist of the form ((FILENAME . (XREF ...)) ...)."
;;; Commands
(defun xref--find-definitions (id window)
(xref--show-xrefs id "definitions"
(funcall xref-find-function 'definitions id)
window))
(xref--show-xrefs id 'definitions id window))
;;;###autoload
(defun xref-find-definitions (identifier)
@ -546,9 +590,7 @@ prompt for it."
"Find references to the identifier at point.
With prefix argument, prompt for the identifier."
(interactive (list (xref--read-identifier "Find references of: ")))
(xref--show-xrefs identifier "references"
(funcall xref-find-function 'references identifier)
nil))
(xref--show-xrefs identifier 'references identifier nil))
;;;###autoload
(defun xref-find-apropos (pattern)
@ -557,14 +599,13 @@ The argument has the same meaning as in `apropos'."
(interactive (list (read-from-minibuffer
"Search for pattern (word list or regexp): ")))
(require 'apropos)
(xref--show-xrefs pattern "apropos"
(funcall xref-find-function 'apropos
(apropos-parse-pattern
(if (string-equal (regexp-quote pattern) pattern)
;; Split into words
(or (split-string pattern "[ \t]+" t)
(user-error "No word list given"))
pattern)))
(xref--show-xrefs pattern 'apropos
(apropos-parse-pattern
(if (string-equal (regexp-quote pattern) pattern)
;; Split into words
(or (split-string pattern "[ \t]+" t)
(user-error "No word list given"))
pattern))
nil))