diff options
| author | Tino Calancha | 2020-05-31 12:31:27 +0200 |
|---|---|---|
| committer | Tino Calancha | 2020-05-31 12:31:27 +0200 |
| commit | abe7c22da96694ced1bc80ec7eb9eb8a662a568b (patch) | |
| tree | fe3b5f03fd32b3ab65738a27e0721052cc250940 | |
| parent | 780f674a82a90c4e3e32583059b498bfa57e4a06 (diff) | |
| download | emacs-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/NEWS | 3 | ||||
| -rw-r--r-- | lisp/replace.el | 72 | ||||
| -rw-r--r-- | test/lisp/replace-tests.el | 42 |
3 files changed, 116 insertions, 1 deletions
| @@ -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." | |||
| 757 | Maximum length of the history list is determined by the value | 757 | Maximum length of the history list is determined by the value |
| 758 | of `history-length', which see.") | 758 | of `history-length', which see.") |
| 759 | 759 | ||
| 760 | (defvar occur-highlight-regexp t | ||
| 761 | "Regexp matching part of visited source lines to highlight temporarily. | ||
| 762 | Highlight 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 | |||
| 552 | Eval BODY with `next-error-highlight' and `next-error-highlight-no-select' | ||
| 553 | bound 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 |