aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTino Calancha2020-05-31 12:31:27 +0200
committerTino Calancha2020-05-31 12:31:27 +0200
commitabe7c22da96694ced1bc80ec7eb9eb8a662a568b (patch)
treefe3b5f03fd32b3ab65738a27e0721052cc250940
parent780f674a82a90c4e3e32583059b498bfa57e4a06 (diff)
downloademacs-abe7c22da96694ced1bc80ec7eb9eb8a662a568b.tar.gz
emacs-abe7c22da96694ced1bc80ec7eb9eb8a662a568b.zip
occur: Add bindings for next-error-no-select
Make the navigation in the occur buffer closer to the navigation in the compilation buffer. Add bindings to navigate the occur matches (Bug#39121). Honor `next-error-highlight' and `next-error-highlight-no-select' when navigating the occurrences. * lisp/replace.el (occur-highlight-regexp, occur-highlight-overlay): New variables. (occur-1): Set `occur-highlight-regexp' to the searched regexp. (occur-goto-locus-delete-o, occur--highlight-occurrence): New defuns. (occur-mode-display-occurrence, occur-mode-goto-occurrence): Use `occur--highlight-occurrence'. (occur-mode-map): Bind n to `next-error-no-select' and p to `previous-error-no-select' * etc/NEWS (Changes in Specialized Modes and Packages in Emacs 28.1): Announce this change. * test/lisp/replace-tests.el (replace-tests-with-highlighted-occurrence): Add helper macro. (occur-highlight-occurrence): Add test.
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/replace.el72
-rw-r--r--test/lisp/replace-tests.el42
3 files changed, 116 insertions, 1 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 64cf0abbdb4..3086ffaf91b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -109,6 +109,9 @@ setting the variable 'auto-save-visited-mode' buffer-locally to nil.
109 109
110* Changes in Specialized Modes and Packages in Emacs 28.1 110* Changes in Specialized Modes and Packages in Emacs 28.1
111 111
112** New bindings in occur-mode, 'next-error-no-select' bound to 'n' and
113'previous-error-no-select' bound to 'p'.
114
112** EIEIO: 'oset' and 'oset-default' are declared obsolete. 115** EIEIO: 'oset' and 'oset-default' are declared obsolete.
113 116
114** New minor mode 'cl-font-lock-built-in-mode' for `lisp-mode'. 117** New minor mode 'cl-font-lock-built-in-mode' for `lisp-mode'.
diff --git a/lisp/replace.el b/lisp/replace.el
index f3a71f87fec..69092c16f96 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -757,6 +757,13 @@ which will run faster and will not set the mark or print anything."
757Maximum length of the history list is determined by the value 757Maximum length of the history list is determined by the value
758of `history-length', which see.") 758of `history-length', which see.")
759 759
760(defvar occur-highlight-regexp t
761 "Regexp matching part of visited source lines to highlight temporarily.
762Highlight entire line if t; don't highlight source lines if nil.")
763
764(defvar occur-highlight-overlay nil
765 "Overlay used to temporarily highlight occur matches.")
766
760(defvar occur-collect-regexp-history '("\\1") 767(defvar occur-collect-regexp-history '("\\1")
761 "History of regexp for occur's collect operation") 768 "History of regexp for occur's collect operation")
762 769
@@ -1113,6 +1120,8 @@ a previously found match."
1113 (define-key map "\C-m" 'occur-mode-goto-occurrence) 1120 (define-key map "\C-m" 'occur-mode-goto-occurrence)
1114 (define-key map "o" 'occur-mode-goto-occurrence-other-window) 1121 (define-key map "o" 'occur-mode-goto-occurrence-other-window)
1115 (define-key map "\C-o" 'occur-mode-display-occurrence) 1122 (define-key map "\C-o" 'occur-mode-display-occurrence)
1123 (define-key map "n" 'next-error-no-select)
1124 (define-key map "p" 'previous-error-no-select)
1116 (define-key map "\M-n" 'occur-next) 1125 (define-key map "\M-n" 'occur-next)
1117 (define-key map "\M-p" 'occur-prev) 1126 (define-key map "\M-p" 'occur-prev)
1118 (define-key map "r" 'occur-rename-buffer) 1127 (define-key map "r" 'occur-rename-buffer)
@@ -1261,9 +1270,12 @@ If not invoked by a mouse click, go to occurrence on the current line."
1261 (with-current-buffer (window-buffer (posn-window (event-end event))) 1270 (with-current-buffer (window-buffer (posn-window (event-end event)))
1262 (save-excursion 1271 (save-excursion
1263 (goto-char (posn-point (event-end event))) 1272 (goto-char (posn-point (event-end event)))
1264 (occur-mode-find-occurrence)))))) 1273 (occur-mode-find-occurrence)))))
1274 (regexp occur-highlight-regexp))
1265 (pop-to-buffer (marker-buffer pos)) 1275 (pop-to-buffer (marker-buffer pos))
1266 (goto-char pos) 1276 (goto-char pos)
1277 (let ((end-mk (save-excursion (re-search-forward regexp nil t))))
1278 (occur--highlight-occurrence pos end-mk))
1267 (when buffer (next-error-found buffer (current-buffer))) 1279 (when buffer (next-error-found buffer (current-buffer)))
1268 (run-hooks 'occur-mode-find-occurrence-hook))) 1280 (run-hooks 'occur-mode-find-occurrence-hook)))
1269 1281
@@ -1277,17 +1289,74 @@ If not invoked by a mouse click, go to occurrence on the current line."
1277 (next-error-found buffer (current-buffer)) 1289 (next-error-found buffer (current-buffer))
1278 (run-hooks 'occur-mode-find-occurrence-hook))) 1290 (run-hooks 'occur-mode-find-occurrence-hook)))
1279 1291
1292;; Stolen from compile.el
1293(defun occur-goto-locus-delete-o ()
1294 (delete-overlay occur-highlight-overlay)
1295 ;; Get rid of timer and hook that would try to do this again.
1296 (if (timerp next-error-highlight-timer)
1297 (cancel-timer next-error-highlight-timer))
1298 (remove-hook 'pre-command-hook
1299 #'occur-goto-locus-delete-o))
1300
1301;; Highlight the current visited occurrence.
1302;; Adapted from `compilation-goto-locus'.
1303(defun occur--highlight-occurrence (mk end-mk)
1304 (let ((highlight-regexp occur-highlight-regexp))
1305 (if (timerp next-error-highlight-timer)
1306 (cancel-timer next-error-highlight-timer))
1307 (unless occur-highlight-overlay
1308 (setq occur-highlight-overlay
1309 (make-overlay (point-min) (point-min)))
1310 (overlay-put occur-highlight-overlay 'face 'next-error))
1311 (with-current-buffer (marker-buffer mk)
1312 (save-excursion
1313 (if end-mk (goto-char end-mk) (end-of-line))
1314 (let ((end (point)))
1315 (if mk (goto-char mk) (beginning-of-line))
1316 (if (and (stringp highlight-regexp)
1317 (re-search-forward highlight-regexp end t))
1318 (progn
1319 (goto-char (match-beginning 0))
1320 (move-overlay occur-highlight-overlay
1321 (match-beginning 0) (match-end 0)
1322 (current-buffer)))
1323 (move-overlay occur-highlight-overlay
1324 (point) end (current-buffer)))
1325 (if (or (eq next-error-highlight t)
1326 (numberp next-error-highlight))
1327 ;; We want highlighting: delete overlay on next input.
1328 (add-hook 'pre-command-hook
1329 #'occur-goto-locus-delete-o)
1330 ;; We don't want highlighting: delete overlay now.
1331 (delete-overlay occur-highlight-overlay))
1332 ;; We want highlighting for a limited time:
1333 ;; set up a timer to delete it.
1334 (when (numberp next-error-highlight)
1335 (setq next-error-highlight-timer
1336 (run-at-time next-error-highlight nil
1337 'occur-goto-locus-delete-o))))))
1338 (when (eq next-error-highlight 'fringe-arrow)
1339 ;; We want a fringe arrow (instead of highlighting).
1340 (setq next-error-overlay-arrow-position
1341 (copy-marker (line-beginning-position))))))
1342
1280(defun occur-mode-display-occurrence () 1343(defun occur-mode-display-occurrence ()
1281 "Display in another window the occurrence the current line describes." 1344 "Display in another window the occurrence the current line describes."
1282 (interactive) 1345 (interactive)
1283 (let ((buffer (current-buffer)) 1346 (let ((buffer (current-buffer))
1284 (pos (occur-mode-find-occurrence)) 1347 (pos (occur-mode-find-occurrence))
1348 (regexp occur-highlight-regexp)
1349 (next-error-highlight next-error-highlight-no-select)
1350 (display-buffer-overriding-action
1351 '(nil (inhibit-same-window . t)))
1285 window) 1352 window)
1286 (setq window (display-buffer (marker-buffer pos) t)) 1353 (setq window (display-buffer (marker-buffer pos) t))
1287 ;; This is the way to set point in the proper window. 1354 ;; This is the way to set point in the proper window.
1288 (save-selected-window 1355 (save-selected-window
1289 (select-window window) 1356 (select-window window)
1290 (goto-char pos) 1357 (goto-char pos)
1358 (let ((end-mk (save-excursion (re-search-forward regexp nil t))))
1359 (occur--highlight-occurrence pos end-mk))
1291 (next-error-found buffer (current-buffer)) 1360 (next-error-found buffer (current-buffer))
1292 (run-hooks 'occur-mode-find-occurrence-hook)))) 1361 (run-hooks 'occur-mode-find-occurrence-hook))))
1293 1362
@@ -1612,6 +1681,7 @@ See also `multi-occur'."
1612 (buffer-undo-list t) 1681 (buffer-undo-list t)
1613 (occur--final-pos nil)) 1682 (occur--final-pos nil))
1614 (erase-buffer) 1683 (erase-buffer)
1684 (set (make-local-variable 'occur-highlight-regexp) regexp)
1615 (let ((count 1685 (let ((count
1616 (if (stringp nlines) 1686 (if (stringp nlines)
1617 ;; Treat nlines as a regexp to collect. 1687 ;; Treat nlines as a regexp to collect.
diff --git a/test/lisp/replace-tests.el b/test/lisp/replace-tests.el
index f5cff92d546..aed14c33572 100644
--- a/test/lisp/replace-tests.el
+++ b/test/lisp/replace-tests.el
@@ -546,4 +546,46 @@ Return the last evalled form in BODY."
546 ?q 546 ?q
547 (string= expected (buffer-string)))))) 547 (string= expected (buffer-string))))))
548 548
549(defmacro replace-tests-with-highlighted-occurrence (highlight-locus &rest body)
550 "Helper macro to test the highlight of matches when navigating occur buffer.
551
552Eval BODY with `next-error-highlight' and `next-error-highlight-no-select'
553bound to HIGHLIGHT-LOCUS."
554 (declare (indent 1) (debug (form body)))
555 `(let ((regexp "foo")
556 (next-error-highlight ,highlight-locus)
557 (next-error-highlight-no-select ,highlight-locus)
558 (buffer (generate-new-buffer "test"))
559 (inhibit-message t))
560 (unwind-protect
561 ;; Local bind to disable the deletion of `occur-highlight-overlay'
562 (cl-letf (((symbol-function 'occur-goto-locus-delete-o) (lambda ())))
563 (with-current-buffer buffer (dotimes (_ 3) (insert regexp ?\n)))
564 (pop-to-buffer buffer)
565 (occur regexp)
566 (pop-to-buffer "*Occur*")
567 (occur-next)
568 ,@body)
569 (kill-buffer buffer)
570 (kill-buffer "*Occur*"))))
571
572(ert-deftest occur-highlight-occurrence ()
573 "Test for https://debbugs.gnu.org/39121 ."
574 (let ((alist '((nil . nil) (0.5 . t) (t . t) (fringe-arrow . nil)))
575 (check-overlays
576 (lambda (has-ov)
577 (eq has-ov (not (null (overlays-in (point-min) (point-max))))))))
578 (pcase-dolist (`(,highlight-locus . ,has-overlay) alist)
579 ;; Visiting occurrences
580 (replace-tests-with-highlighted-occurrence highlight-locus
581 (occur-mode-goto-occurrence)
582 (should (funcall check-overlays has-overlay)))
583 ;; Displaying occurrences
584 (replace-tests-with-highlighted-occurrence highlight-locus
585 (occur-mode-display-occurrence)
586 (with-current-buffer (marker-buffer
587 (get-text-property (point) 'occur-target))
588 (should (funcall check-overlays has-overlay)))))))
589
590
549;;; replace-tests.el ends here 591;;; replace-tests.el ends here