GNU bug report logs - #36967
27.0.50; Duplicate lines in xref output

Previous Next

Package: emacs;

Reported by: Juri Linkov <juri <at> linkov.net>

Date: Wed, 7 Aug 2019 22:04:01 UTC

Severity: normal

Merged with 43715

Found in versions 27.0.50, 28.0.50

Fixed in version 28.1

Done: Dmitry Gutov <dgutov <at> yandex.ru>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 36967 in the body.
You can then email your comments to 36967 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Wed, 07 Aug 2019 22:04:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Juri Linkov <juri <at> linkov.net>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Wed, 07 Aug 2019 22:04:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: bug-gnu-emacs <at> gnu.org
Subject: 27.0.50; Duplicate lines in xref output
Date: Thu, 08 Aug 2019 00:52:13 +0300
I tried to use project-find-regexp more often than rgrep,
but unfortunately xref still has a fundamental flaw:

0. emacs -Q
1. M-x project-find-regexp RET regexp RET
2. The output buffer *xref* contains duplicate lines
   when regexp is found on the same line several times,
   each duplicate output line has separate highlighting
   for every regexp occurrence.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Wed, 07 Aug 2019 22:14:01 GMT) Full text and rfc822 format available.

Message #8 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dgutov <at> yandex.ru>
To: Juri Linkov <juri <at> linkov.net>, 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Thu, 8 Aug 2019 01:13:07 +0300
On 08.08.2019 0:52, Juri Linkov wrote:
> I tried to use project-find-regexp more often than rgrep,
> but unfortunately xref still has a fundamental flaw:
> 
> 0. emacs -Q
> 1. M-x project-find-regexp RET regexp RET
> 2. The output buffer *xref* contains duplicate lines
>     when regexp is found on the same line several times,
>     each duplicate output line has separate highlighting
>     for every regexp occurrence.

I don't know how "fundamental" it is, but indeed, it's somewhat of a 
drawback. Suggestions for improving it (API change and/or implementation 
change) are welcome.




Forcibly Merged 36967 43715. Request was from Juri Linkov <juri <at> linkov.net> to control <at> debbugs.gnu.org. (Wed, 30 Sep 2020 19:29:02 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Wed, 02 Dec 2020 21:36:02 GMT) Full text and rfc822 format available.

Message #13 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: Dmitry Gutov <dgutov <at> yandex.ru>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Wed, 02 Dec 2020 23:30:18 +0200
[Message part 1 (text/plain, inline)]
>> I tried to use project-find-regexp more often than rgrep,
>> but unfortunately xref still has a fundamental flaw:
>> 0. emacs -Q
>> 1. M-x project-find-regexp RET regexp RET
>> 2. The output buffer *xref* contains duplicate lines
>>     when regexp is found on the same line several times,
>>     each duplicate output line has separate highlighting
>>     for every regexp occurrence.
>
> I don't know how "fundamental" it is, but indeed, it's somewhat of
> a drawback. Suggestions for improving it (API change and/or implementation
> change) are welcome.

Here is the patch that makes the broken project-find-regexp usable:

[xref-usable.patch (text/x-diff, inline)]
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 3b19debb79..1f5e45f20d 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -1461,11 +1461,10 @@ xref--collect-matches
                                  syntax-needed)))))
 
 (defun xref--collect-matches-1 (regexp file line line-beg line-end syntax-needed)
-  (let (matches)
+  (let ((summary (buffer-substring line-beg line-end))
+        matches)
     (when syntax-needed
       (syntax-propertize line-end))
-    ;; FIXME: This results in several lines with the same
-    ;; summary. Solve with composite pattern?
     (while (and
             ;; REGEXP might match an empty string.  Or line.
             (or (null matches)
@@ -1473,12 +1472,12 @@ xref--collect-matches-1
             (re-search-forward regexp line-end t))
       (let* ((beg-column (- (match-beginning 0) line-beg))
              (end-column (- (match-end 0) line-beg))
-             (loc (xref-make-file-location file line beg-column))
-             (summary (buffer-substring line-beg line-end)))
+             (loc (xref-make-file-location file line beg-column)))
         (add-face-text-property beg-column end-column 'xref-match
                                 t summary)
-        (push (xref-make-match summary loc (- end-column beg-column))
-              matches)))
+        (unless matches
+          (push (xref-make-match summary loc (- end-column beg-column))
+                matches))))
     (nreverse matches)))
 
 (defun xref--find-file-buffer (file)

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Thu, 03 Dec 2020 01:36:01 GMT) Full text and rfc822 format available.

Message #16 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dgutov <at> yandex.ru>
To: Juri Linkov <juri <at> linkov.net>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Thu, 3 Dec 2020 03:35:19 +0200
On 02.12.2020 23:30, Juri Linkov wrote:
>>> I tried to use project-find-regexp more often than rgrep,
>>> but unfortunately xref still has a fundamental flaw:
>>> 0. emacs -Q
>>> 1. M-x project-find-regexp RET regexp RET
>>> 2. The output buffer *xref* contains duplicate lines
>>>      when regexp is found on the same line several times,
>>>      each duplicate output line has separate highlighting
>>>      for every regexp occurrence.
>>
>> I don't know how "fundamental" it is, but indeed, it's somewhat of
>> a drawback. Suggestions for improving it (API change and/or implementation
>> change) are welcome.
> 
> Here is the patch that makes the broken

Pretty harsh there.

> project-find-regexp usable:

Okay, impressions:

When the line has two matches, the new code only collects the first 
match. So 'matches' is always an list with one element (or nil).

Upside: repetitions are not shown anymore, but the match highlighting is 
still applied.

Downside: xref-query-replace-in-results won't work in those cases 
anymore; it will only replace one match. Because the list only contains 
one location, and not all of them. And that command is pretty nice to have.

Here's an alternative proposal:

Combine the lines inside the rendering code instead.

So each xref will have a separate location, but then xref--insert-xrefs 
will see that xref-location-line value repeats across some consecutive 
locations, and will combine them into single line with some text 
property magic (basically, copying the summary from one of them, and 
then applying 'xref-item and 'face properties appropriately). This 
retains the xref item semantics (as opposed to, say, associating an xref 
item with multiple locations). And _hopefully_ the replace-related code 
won't need any changes.

As a bonus, 'n' and 'p' should then automatically change behavior to 
jump between locations when they are on the same line.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Thu, 03 Dec 2020 21:40:03 GMT) Full text and rfc822 format available.

Message #19 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: Dmitry Gutov <dgutov <at> yandex.ru>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Thu, 03 Dec 2020 23:30:05 +0200
>> Here is the patch that makes the broken
>
> Pretty harsh there.

But true: I can't use it in the current form, and was waiting
when someone will fix it.

>> project-find-regexp usable:
>
> Downside: xref-query-replace-in-results won't work in those cases anymore;
> it will only replace one match. Because the list only contains one
> location, and not all of them. And that command is pretty nice to have.

Sorry, I missed this use case because I still know too little about details
of xref.el.

> Here's an alternative proposal:
>
> Combine the lines inside the rendering code instead.
>
> So each xref will have a separate location, but then xref--insert-xrefs
> will see that xref-location-line value repeats across some consecutive
> locations, and will combine them into single line with some text property
> magic (basically, copying the summary from one of them, and then applying
> 'xref-item and 'face properties appropriately). This retains the xref item
> semantics (as opposed to, say, associating an xref item with multiple
> locations). And _hopefully_ the replace-related code won't need
> any changes.

I tried to improve xref--insert-xrefs to group matches by lines
by using the most convenient function seq-group-by.  But then
noticed that xref.el doesn't rely on seq.el.  Even xref--alistify
that groups matches by files could be replaced by seq-group-by.
Is it a requirement to avoid using seq functions in xref.el?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Thu, 03 Dec 2020 23:45:01 GMT) Full text and rfc822 format available.

Message #22 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dgutov <at> yandex.ru>
To: Juri Linkov <juri <at> linkov.net>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Fri, 4 Dec 2020 01:44:47 +0200
On 03.12.2020 23:30, Juri Linkov wrote:
>>> Here is the patch that makes the broken
>>
>> Pretty harsh there.
> 
> But true: I can't use it in the current form, and was waiting
> when someone will fix it.

It's great to see you get this ball rolling.

>> Here's an alternative proposal:
>>
>> Combine the lines inside the rendering code instead.
>>
>> So each xref will have a separate location, but then xref--insert-xrefs
>> will see that xref-location-line value repeats across some consecutive
>> locations, and will combine them into single line with some text property
>> magic (basically, copying the summary from one of them, and then applying
>> 'xref-item and 'face properties appropriately). This retains the xref item
>> semantics (as opposed to, say, associating an xref item with multiple
>> locations). And _hopefully_ the replace-related code won't need
>> any changes.
> 
> I tried to improve xref--insert-xrefs to group matches by lines
> by using the most convenient function seq-group-by.  But then
> noticed that xref.el doesn't rely on seq.el.  Even xref--alistify
> that groups matches by files could be replaced by seq-group-by.
> Is it a requirement to avoid using seq functions in xref.el?

Not really, no. project.el pulls in seq already, why not have xref do it 
too.

I'm _slightly_ worried about extra garbage if we do seq-group-by twice 
(with an extra list for every line, even those that don't need it), but 
that's what benchmarking is for (can do that later).




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Sun, 06 Dec 2020 21:17:02 GMT) Full text and rfc822 format available.

Message #25 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: Dmitry Gutov <dgutov <at> yandex.ru>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Sun, 06 Dec 2020 22:31:02 +0200
[Message part 1 (text/plain, inline)]
> I'm _slightly_ worried about extra garbage if we do seq-group-by twice
> (with an extra list for every line, even those that don't need it), but
> that's what benchmarking is for (can do that later).

I'm worried about extra garbage too, so this patch doesn't cause extra lists.

[multiline-xref-insert-xrefs.patch (text/x-diff, inline)]
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 9f5fc57142..260623180e 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -832,17 +832,28 @@ xref--insert-xrefs
                                (length (and line (format "%d" line)))))
            for line-format = (and max-line-width
                                   (format "%%%dd: " max-line-width))
+           with prev-line-key = nil
            do
            (xref--insert-propertized '(face xref-file-header xref-group t)
                                      group "\n")
            (cl-loop for (xref . more2) on xrefs do
                     (with-slots (summary location) xref
                       (let* ((line (xref-location-line location))
+                             (line-key (list (xref-location-group location) line))
                              (prefix
                               (if line
                                   (propertize (format line-format line)
                                               'face 'xref-line-number)
                                 "  ")))
+                        (when (equal prev-line-key line-key)
+                          (let ((column (xref-file-location-column location)))
+                            (delete-region
+                             (save-excursion
+                               (forward-line -1)
+                               (move-to-column (+ (length prefix) column))
+                               (point))
+                             (point))
+                            (setq summary (substring summary column) prefix "")))
                         (xref--insert-propertized
                          (list 'xref-item xref
                                'mouse-face 'highlight
@@ -850,7 +861,8 @@ xref--insert-xrefs
                                'help-echo
                                (concat "mouse-2: display in another window, "
                                        "RET or mouse-1: follow reference"))
-                         prefix summary)))
+                         prefix summary)
+                        (setq prev-line-key line-key)))
                     (insert "\n"))))
 
 (defun xref--analyze (xrefs)
[Message part 3 (text/plain, inline)]
However, there is a problem: when xref--insert-xrefs is called by
'M-.' that uses etags, then it signals an error:

  cl-no-applicable-method xref-file-location-column

And I don't know how to fix etags to add columns.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Wed, 09 Dec 2020 03:55:01 GMT) Full text and rfc822 format available.

Message #28 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dgutov <at> yandex.ru>
To: Juri Linkov <juri <at> linkov.net>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Wed, 9 Dec 2020 05:53:55 +0200
On 06.12.2020 22:31, Juri Linkov wrote:
>> I'm _slightly_ worried about extra garbage if we do seq-group-by twice
>> (with an extra list for every line, even those that don't need it), but
>> that's what benchmarking is for (can do that later).
> 
> I'm worried about extra garbage too, so this patch doesn't cause extra lists.

Thanks! Seems to work well. Especially with this addition:

diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 9f5fc57142..9ad956d496 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -595,7 +595,8 @@ xref-prev-line

 (defun xref--item-at-point ()
   (save-excursion
-    (back-to-indentation)
+    (when (eolp)
+      (forward-char -1))
     (get-text-property (point) 'xref-item)))

 (defun xref-goto-xref (&optional quit)

> However, there is a problem: when xref--insert-xrefs is called by
> 'M-.' that uses etags, then it signals an error:

Does it happen when two symbols do indeed get defined on the same line? 
Sounds like a rare situation.

>    cl-no-applicable-method xref-file-location-column
> 
> And I don't know how to fix etags to add columns.

Using xref-file-location-column there kind of breaks the abstraction. I 
was thinking more along the lines of text-prop search for the column 
inside the summary string:

(setq column
      (with-temp-buffer
        (insert summary)
        (goto-char (point-min))
        (let ((match
               (text-property-search-forward
                'face 'xref-match
                (lambda (target value)
                  (or (eq target value)
                      (and (listp value)
                           (member target value)))))))
          (and match
               (1- (prop-match-beginning match))))))

That's quite a bit longer, though. And it still will work only with some 
kinds of xrefs: I'm not sure I know how to add columns to etags either. 
Not to mention third-party xref backends.

The rest won't get deduplication, but that's probably all right.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#36967; Package emacs. (Wed, 09 Dec 2020 13:58:01 GMT) Full text and rfc822 format available.

Message #31 received at 36967 <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dgutov <at> yandex.ru>
To: Juri Linkov <juri <at> linkov.net>
Cc: 36967 <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Wed, 9 Dec 2020 15:57:09 +0200
On 09.12.2020 05:53, Dmitry Gutov wrote:
> Using xref-file-location-column there kind of breaks the abstraction. I 
> was thinking more along the lines of text-prop search for the column 
> inside the summary string:

Although we'll probably make it an optional method, just like 
xref-location-line is already.

Then we won't have to do all that gymnastics with the temp buffer.




Reply sent to Dmitry Gutov <dgutov <at> yandex.ru>:
You have taken responsibility. (Mon, 21 Dec 2020 01:43:01 GMT) Full text and rfc822 format available.

Notification sent to Juri Linkov <juri <at> linkov.net>:
bug acknowledged by developer. (Mon, 21 Dec 2020 01:43:01 GMT) Full text and rfc822 format available.

Message #36 received at 36967-done <at> debbugs.gnu.org (full text, mbox):

From: Dmitry Gutov <dgutov <at> yandex.ru>
To: Juri Linkov <juri <at> linkov.net>
Cc: Pankaj Jangid <pankaj <at> codeisgreat.org>, 36967-done <at> debbugs.gnu.org
Subject: Re: bug#36967: 27.0.50; Duplicate lines in xref output
Date: Mon, 21 Dec 2020 03:42:41 +0200
Version: 28.1

On 09.12.2020 15:57, Dmitry Gutov wrote:
> On 09.12.2020 05:53, Dmitry Gutov wrote:
>> Using xref-file-location-column there kind of breaks the abstraction. 
>> I was thinking more along the lines of text-prop search for the column 
>> inside the summary string:
> 
> Although we'll probably make it an optional method, just like 
> xref-location-line is already.

And now done.

I've pushed the slightly tweaked Juri's patch and the change described 
above.

With that, the bug should be fixed now. Please let me know if something 
is still amiss.

Thanks all!




Reply sent to Dmitry Gutov <dgutov <at> yandex.ru>:
You have taken responsibility. (Mon, 21 Dec 2020 01:43:02 GMT) Full text and rfc822 format available.

Notification sent to Pankaj Jangid <pankaj <at> codeisgreat.org>:
bug acknowledged by developer. (Mon, 21 Dec 2020 01:43:02 GMT) Full text and rfc822 format available.

bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Mon, 18 Jan 2021 12:24:04 GMT) Full text and rfc822 format available.

This bug report was last modified 3 years and 97 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.