commit b6ac30ab435596f1be6023ad22471bf570a11c4a (HEAD, refs/remotes/origin/master) Author: Dmitry Gutov Date: Tue Jul 21 03:25:24 2015 +0300 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. diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 1613692..5f681b0 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -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 commit 4051fb202ee92edce95a3d0a9763d0d130f82770 Author: Dmitry Gutov Date: Tue Jul 21 00:44:41 2015 +0300 ; Fix a typo diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el index 0847fda..1613692 100644 --- a/lisp/progmodes/xref.el +++ b/lisp/progmodes/xref.el @@ -508,7 +508,7 @@ Used for temporary buffers.") (n (abs n)) (xref nil)) (dotimes (_ n) - (setq (xref--search-property 'xref-item backward))) + (setq xref (xref--search-property 'xref-item backward))) (cond (xref (xref--pop-to-location xref)) (t commit 136dd7bc02576a10ea77b33afd3cb9179c064e3d Author: Paul Eggert Date: Mon Jul 20 09:47:39 2015 -0700 Simplify icalendar decoding of Z dates * lisp/calendar/icalendar.el (icalendar--decode-isodatetime): Simplify calculation of time strings with trailing "Z". diff --git a/lisp/calendar/icalendar.el b/lisp/calendar/icalendar.el index da5d85e..3e2a2f8 100644 --- a/lisp/calendar/icalendar.el +++ b/lisp/calendar/icalendar.el @@ -618,13 +618,7 @@ FIXME: multiple comma-separated values should be allowed!" (when (and (> (length isodatetimestring) 15) ;; UTC specifier present (char-equal ?Z (aref isodatetimestring 15))) - ;; if not UTC add current-time-zone offset - ;; current-time-zone should be called with actual UTC time - ;; (daylight saving at that time may differ to current one) - (setq second (+ (car (current-time-zone - (encode-time second minute hour day month year - 0))) - second))) + (setq zone t)) ;; shift if necessary (if day-shift (let ((mdy (calendar-gregorian-from-absolute