Subject: 28.0.50; [PATCH] New xref commands xref-prev-group and xref-next-group

From: Daniel Martín <[email-masked]>
Date: Mon, 07 Dec 2020 00:31:44 +0100

In an *xref* buffer one can navigate quickly through the results with
'p' and 'n'.  However, when there is a lot of results grouped in a bunch
of files, in some cases it's more interesting to skip results and go to
the first item of the previous or next group (typically, it will be the
first result that is in a different file).  The attached patch adds two
commands for that, and binds them to 'P' and 'N', respectively.

Do you think this is a generally useful feature?  Do you think the
keybindings I chose are appropriate?  If so, feel free to install the
attached patch.  It already includes a NEWS entry and the corresponding
updates to the Emacs manual.  Thanks.

>From 7217cf0aee1a27ee0adc9576f510a6696a8b6759 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Mart=C3=ADn?= <[email-masked]>
Date: Sun, 6 Dec 2020 23:59:51 +0100
Subject: [PATCH] Add commands xref-next-group and xref-prev-group

* lisp/progmodes/xref.el (xref-next-group): New command that navigates
to the first item of the next xref group (typically a file).
(xref-prev-group): New command that navigates
to the first item of the next xref group (typically a file).
(xref--xref-buffer-mode-map): Bound the new commands to 'N' and 'P',
respectively.
* doc/emacs/maintaining.texi (Xref Commands): Document the new
commands in the Emacs manual.
* etc/NEWS: Announce them.
---
 doc/emacs/maintaining.texi | 10 ++++++++++
 etc/NEWS                   |  5 +++++
 lisp/progmodes/xref.el     | 21 +++++++++++++++++++++
 3 files changed, 36 insertions(+)

diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 1f10b68b8a..4bc8fdb593 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -2199,12 +2199,22 @@ Xref Commands
 Move to the next reference and display it in the other window
 (@code{xref-next-line}).
 
+@item N
+@findex xref-next-group
+Move to the first reference of the next reference group and display it in the other window
+(@code{xref-next-group}).
+
 @item p
 @itemx ,
 @findex xref-prev-line
 Move to the previous reference and display it in the other window
 (@code{xref-prev-line}).
 
+@item P
+@findex xref-prev-group
+Move to the first reference of the previous reference group and display it in the other window
+(@code{xref-prev-group}).
+
 @item C-o
 @findex xref-show-location-at-point
 Display the reference on the current line in the other window
diff --git a/etc/NEWS b/etc/NEWS
index 525ed8b36e..83bde4b377 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1192,6 +1192,11 @@ So far Grep and ripgrep are supported.  ripgrep seems to offer better
 performance in certain cases, in particular for case-insensitive
 searches.
 
+---
+*** New commands xref-prev-group and xref-next-group.
+These commands are bound respectively to 'P' and 'N', and navigate to
+the first item of the previous or next group in the "*xref*" buffer.
+
 ** json.el
 
 ---
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 9f5fc57142..28c6a0b5b0 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -593,6 +593,25 @@ xref-prev-line
   (xref--search-property 'xref-item t)
   (xref-show-location-at-point))
 
+(defun xref-next-group ()
+  "Move to the first item of the next xref group and display its source in the appropriate window."
+  (interactive)
+  (xref--search-property 'xref-group)
+  (xref--search-property 'xref-item)
+  (xref-show-location-at-point))
+
+(defun xref-prev-group ()
+  "Move to the first item of the previous xref group and display its source in the appropriate window."
+  (interactive)
+  ;; Search for the xref group of the current item, provided that the
+  ;; point is not already in an xref group.
+  (unless (plist-member (text-properties-at (point)) 'xref-group)
+    (xref--search-property 'xref-group t))
+  ;; Search for the previous xref group.
+  (xref--search-property 'xref-group t)
+  (xref--search-property 'xref-item)
+  (xref-show-location-at-point))
+
 (defun xref--item-at-point ()
   (save-excursion
     (back-to-indentation)
@@ -738,6 +757,8 @@ xref--xref-buffer-mode-map
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "n") #'xref-next-line)
     (define-key map (kbd "p") #'xref-prev-line)
+    (define-key map (kbd "N") #'xref-next-group)
+    (define-key map (kbd "P") #'xref-prev-group)
     (define-key map (kbd "r") #'xref-query-replace-in-results)
     (define-key map (kbd "RET") #'xref-goto-xref)
     (define-key map (kbd "TAB")  #'xref-quit-and-goto-xref)
-- 
2.28.0