Add new xref-query-replace command
* lisp/progmodes/xref.el (xref--match-buffer-bounds): New function, extracted from xref-pulse-momentarily. (xref-query-replace): New command. (xref--query-replace-1): New helper function. (xref--xref-buffer-mode-map): Add `r' binding.
This commit is contained in:
parent
4051fb202e
commit
b6ac30ab43
1 changed files with 72 additions and 6 deletions
|
@ -342,18 +342,22 @@ elements is negated."
|
|||
(pcase-let ((`(,beg . ,end)
|
||||
(save-excursion
|
||||
(or
|
||||
(let ((bounds (xref-match-bounds xref--current-item)))
|
||||
(when bounds
|
||||
(cons (progn (move-to-column (car bounds))
|
||||
(point))
|
||||
(progn (move-to-column (cdr bounds))
|
||||
(point)))))
|
||||
(xref--match-buffer-bounds xref--current-item)
|
||||
(back-to-indentation)
|
||||
(if (eolp)
|
||||
(cons (line-beginning-position) (1+ (point)))
|
||||
(cons (point) (line-end-position)))))))
|
||||
(pulse-momentary-highlight-region beg end 'next-error)))
|
||||
|
||||
(defun xref--match-buffer-bounds (item)
|
||||
(save-excursion
|
||||
(let ((bounds (xref-match-bounds item)))
|
||||
(when bounds
|
||||
(cons (progn (move-to-column (car bounds))
|
||||
(point))
|
||||
(progn (move-to-column (cdr bounds))
|
||||
(point)))))))
|
||||
|
||||
;; etags.el needs this
|
||||
(defun xref-clear-marker-stack ()
|
||||
"Discard all markers from the marker stack."
|
||||
|
@ -483,11 +487,72 @@ Used for temporary buffers.")
|
|||
(xref-quit)
|
||||
(xref--pop-to-location xref window)))
|
||||
|
||||
(defun xref-query-replace (from to)
|
||||
"Perform interactive replacement in all current matches."
|
||||
(interactive
|
||||
(list (read-regexp "Query replace regexp in matches" ".*")
|
||||
(read-regexp "Replace with: ")))
|
||||
(let (pairs item)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
;; TODO: Check that none of the matches are out of date;
|
||||
;; offer to re-scan otherwise. Note that saving the last
|
||||
;; modification tick won't work, as long as not all of the
|
||||
;; buffers are kept open.
|
||||
(while (setq item (xref--search-property 'xref-item))
|
||||
(when (xref-match-bounds item)
|
||||
(save-excursion
|
||||
(xref--goto-location (xref-item-location item))
|
||||
(let ((bounds (xref--match-buffer-bounds item))
|
||||
(beg (make-marker))
|
||||
(end (make-marker)))
|
||||
(move-marker beg (car bounds))
|
||||
(move-marker end (cdr bounds))
|
||||
(push (cons beg end) pairs)))))
|
||||
(setq pairs (nreverse pairs)))
|
||||
(unless pairs (user-error "No suitable matches here"))
|
||||
(xref--query-replace-1 from to pairs))
|
||||
(dolist (pair pairs)
|
||||
(move-marker (car pair) nil)
|
||||
(move-marker (cdr pair) nil)))))
|
||||
|
||||
(defun xref--query-replace-1 (from to pairs)
|
||||
(let* ((query-replace-lazy-highlight nil)
|
||||
current-pair current-buf
|
||||
;; Counteract the "do the next match now" hack in
|
||||
;; `perform-replace'. And still, it'll report that those
|
||||
;; matches were "filtered out" at the end.
|
||||
(isearch-filter-predicate
|
||||
(lambda (beg end)
|
||||
(and current-pair
|
||||
(eq (current-buffer) current-buf)
|
||||
(>= beg (car current-pair))
|
||||
(<= end (cdr current-pair)))))
|
||||
(replace-re-search-function
|
||||
(lambda (from &optional _bound noerror)
|
||||
(let (found)
|
||||
(while (and (not found) pairs)
|
||||
(setq current-pair (pop pairs)
|
||||
current-buf (marker-buffer (car current-pair)))
|
||||
(pop-to-buffer current-buf)
|
||||
(goto-char (car current-pair))
|
||||
(when (re-search-forward from (cdr current-pair) noerror)
|
||||
(setq found t)))
|
||||
found))))
|
||||
;; FIXME: Despite this being a multi-buffer replacement, `N'
|
||||
;; doesn't work, because we're not using
|
||||
;; `multi-query-replace-map', and it would expect the below
|
||||
;; function to be called once per buffer.
|
||||
(perform-replace from to t t nil)))
|
||||
|
||||
(defvar xref--xref-buffer-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map [remap quit-window] #'xref-quit)
|
||||
(define-key map (kbd "n") #'xref-next-line)
|
||||
(define-key map (kbd "p") #'xref-prev-line)
|
||||
(define-key map (kbd "r") #'xref-query-replace)
|
||||
(define-key map (kbd "RET") #'xref-goto-xref)
|
||||
(define-key map (kbd "C-o") #'xref-show-location-at-point)
|
||||
;; suggested by Johan Claesson "to further reduce finger movement":
|
||||
|
@ -900,6 +965,7 @@ IGNORES is a list of glob patterns."
|
|||
(goto-char (point-min))
|
||||
(forward-line (1- line))
|
||||
(syntax-propertize (line-end-position))
|
||||
;; TODO: Handle multiple matches per line.
|
||||
(when (re-search-forward regexp (line-end-position) t)
|
||||
(goto-char (match-beginning 0))
|
||||
(let ((loc (xref-make-file-location file line
|
||||
|
|
Loading…
Add table
Reference in a new issue