bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

classic Classic list List threaded Threaded
64 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
I've been trying to understand why when the current file-vising buffer
has next-error-function set localy, sometimes `next-error' uses it, and
sometimes it uses next-error-function from next-error-last-buffer.

Looking at the current `next-error-find-buffer', the logic is this:

- If a buffer visible in the current frame has next-error-function set,
  *and* if there's only one such buffer, use it.

- If next-error-last-buffer has it set, use that.

Othewise, if both of the above fail,

- If the current buffer has next-error-function set, use it.

That's nonsense. Why should the question of whether the current buffer's
next-error-function is used be decided by whether there are any other
visible buffers with that variable set.

Apparently, this peculiarity has been there for 10.5 years now,
introduced in 03e75c7e0 by Juri Linkov. But there's no bug reference, nor
a link to a discussion.

I'm guessing it was an attempt to solve a problem of
next-error-last-buffer never being used if the current buffer has
next-error-function. But I think the solution is worse than the problem.
It least the previous behavior was consistent.

In GNU Emacs 25.0.50.1 (x86_64-unknown-linux-gnu, GTK+ Version 3.12.2)
 of 2015-05-02 on axl
Windowing system distributor `The X.Org Foundation', version 11.0.11601901
System Description: Ubuntu 14.10



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Stefan Monnier
> Apparently, this peculiarity has been there for 10.5 years now,
> introduced in 03e75c7e0 by Juri Linkov. But there's no bug reference, nor
> a link to a discussion.

IIRC this had something to do with hitting C-x ` to jump through the
various elements of a *compile* or *grep* buffer, where some of those
C-x ` may end up jumping to a buffer that itself has
next-error-function set.


        Stefan



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 05/03/2015 08:49 AM, Stefan Monnier wrote:

> IIRC this had something to do with hitting C-x ` to jump through the
> various elements of a *compile* or *grep* buffer, where some of those
> C-x ` may end up jumping to a buffer that itself has
> next-error-function set.

That's what I guessed, then. It doesn't solve the problem completely
anyway. If the *grep* buffer is buried or displayed in a different frame
(which is arguably is the best case for using C-x `), C-x ` might open a
buffer with next-error-function set, and it will overtake, if it's the
only one such in the currently visible frame. There's no easy way to get
back to Grep's next-error-function either.

Why don't we prioritize, in next-error-find-buffer,
next-error-last-buffer over everything else (change the order to 2 3 1 4
5 6)?

And then add some way to change next-error-last-buffer programmatically
(choosing between the current buffer, if it has next-error-function set,
and all other buffers with next-error-function set and buffer-file-name
nil; defaulting to the current one).

M-0 C-x ` (like suggested by Vitaly) might be OK, to change the used
buffer and move to the next error in one step (and similarly in
previous-error). But that hijacks the meaning of 0 argument.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Ted Zlatanov
On Sun, 3 May 2015 15:56:11 +0300 Dmitry Gutov <[hidden email]> wrote:

DG> Why don't we prioritize, in next-error-find-buffer,
DG> next-error-last-buffer over everything else (change the order to 2 3 1
DG> 4 5 6)?

For reference, here are the steps:

   ;; 1. If one window on the selected frame displays such buffer, return it.
   ;; 2. If next-error-last-buffer is an acceptable buffer, use that.
   ;; 3. If the current buffer is acceptable, choose it.
   ;; 4. Look for any acceptable buffer.
   ;; 5. Use the current buffer as a last resort if it qualifies,
   ;; 6. Give up.

How about a `next-error-priority' which can be numerically:

* local (each position refers to the file itself) = 0 (occur)
* finder (each position refers to other files) = 100 (compile, grep)
* or can be set by the mode to something else

Then (1) can become "if one window on the selected frame has the highest
priority, return it."

Ted



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 05/05/2015 01:03 AM, Ted Zlatanov wrote:

> Then (1) can become "if one window on the selected frame has the highest
> priority, return it."

How will this help the user to control which error function to use next?

And why the windows on the selected frame? If *compile* is buried, does
it become useless? I'd say the opposite.

Or suppose I have 4 windows open in the frame, and each one's buffer has
a next-error-function that refers only to positions in the current file?
And there's a *compile* buffer buried somewhere. How do I actually use
the current buffer's next-error-function, aside from C-x 1?



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Ted Zlatanov
On Tue, 5 May 2015 01:22:39 +0300 Dmitry Gutov <[hidden email]> wrote:

DG> On 05/05/2015 01:03 AM, Ted Zlatanov wrote:
>> Then (1) can become "if one window on the selected frame has the highest
>> priority, return it."

DG> How will this help the user to control which error function to use next?

It doesn't help the user.  It helps mode writers give their modes the
appropriate priority so the user doesn't have to know.

DG> And why the windows on the selected frame? If *compile* is buried,
DG> does it become useless? I'd say the opposite.

Perhaps?  I am giving a suggestion, not a full implementation.  The
essential thing is that we rank buffers, not just pick "the last one" or
the "one visible with 5 hieroglyphs" or whatever other DWIMmery we
currently use.

DG> Or suppose I have 4 windows open in the frame, and each one's buffer
DG> has a next-error-function that refers only to positions in the current
DG> file? And there's a *compile* buffer buried somewhere. How do I
DG> actually use the current buffer's next-error-function, aside from C-x
DG> 1?

Some history: I actually, long ago when `next-error' turned into a
navigation facility, we[1] had the idea of "meta next-error" which would
navigate one level higher than local. That would have made this whole
discussion, including rankings by priority, moot by simply saying "to
navigate between files (compile, grep) you use `meta-next-error' or
whatever it's called. to navigate inside file locations, use
`next-error'."

I was supposed to write a patch after the release but... the dog ate my
TODO list.

Perhaps you are interested in adapting that code instead of hacking on
the current scheme?  Or should I retry implementing it?  9 years late is
not too bad, right? :)

If there's a time to implement this, I'd say it's now, before the 25.1
release, because it will break how many people expect `next-error' to
work.  But OTOH I think it will improve the UI.

Thanks
Ted

[1] Lars, me, and others: https://lists.gnu.org/archive/html/emacs-devel/2006-04/msg00488.html



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 05/05/2015 01:33 AM, Ted Zlatanov wrote:

> Some history: I actually, long ago when `next-error' turned into a
> navigation facility, we[1] had the idea of "meta next-error" which would
> navigate one level higher than local. That would have made this whole
> discussion, including rankings by priority, moot by simply saying "to
> navigate between files (compile, grep) you use `meta-next-error' or
> whatever it's called. to navigate inside file locations, use
> `next-error'."

Thanks for the link.

That would've been an improvement, but it wouldn't solve a related
problem: when *grep* buffer was created after a *compile* one, how to
get back to using *compile*'s list of errors.

> Perhaps you are interested in adapting that code instead of hacking on
> the current scheme?  Or should I retry implementing it?  9 years late is
> not too bad, right? :)

9 years is just right, but I'm not sure how much of that implementation
we would reuse. It's also not obvious me how to move to the next file,
if you only have a next-error-function.

M-g M-f/b could switch between next-error-last-buffer values, though.
Especially if they're organized in a ring, like Helmut suggested. That
will require an update to any Compilation-like mode.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Ted Zlatanov
On Tue, 5 May 2015 18:05:29 +0300 Dmitry Gutov <[hidden email]> wrote:

DG> On 05/05/2015 01:33 AM, Ted Zlatanov wrote:
>> Some history: I actually, long ago when `next-error' turned into a
>> navigation facility, we[1] had the idea of "meta next-error" which would
>> navigate one level higher than local. That would have made this whole
>> discussion, including rankings by priority, moot by simply saying "to
>> navigate between files (compile, grep) you use `meta-next-error' or
>> whatever it's called. to navigate inside file locations, use
>> `next-error'."

DG> Thanks for the link.

DG> That would've been an improvement, but it wouldn't solve a related
DG> problem: when *grep* buffer was created after a *compile* one, how to
DG> get back to using *compile*'s list of errors.

I think we have to accept the visible or last used one in that case.

>> Perhaps you are interested in adapting that code instead of hacking on
>> the current scheme?  Or should I retry implementing it?  9 years late is
>> not too bad, right? :)

DG> 9 years is just right, but I'm not sure how much of that
DG> implementation we would reuse. It's also not obvious me how to move to
DG> the next file, if you only have a next-error-function.

I'm happy to make suggestions but please take this in a direction that
makes sense to you.

Ted



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Juri Linkov-2
In reply to this post by Dmitry Gutov
> - If a buffer visible in the current frame has next-error-function set,
>   *and* if there's only one such buffer, use it.
>
> - If next-error-last-buffer has it set, use that.
>
> Othewise, if both of the above fail,
>
> - If the current buffer has next-error-function set, use it.
>
> Apparently, this peculiarity has been there for 10.5 years now,
> introduced in 03e75c7e0 by Juri Linkov. But there's no bug reference, nor
> a link to a discussion.

Sorry, I missed this bug report and regret that it caused you to revert
xref's next-error-function integration.

The link to the discussion is here:
http://lists.gnu.org/archive/html/emacs-devel/2004-05/msg00614.html
where you can see the case that we need to support.

Now that we have window-local variables, it's possible to support
this case in a proper way.  Instead of checking if a buffer visible
in the current frame, we should check the window-local value of
next-error-last-buffer.  Thus invoking next-error in the window
with the source buffer will continue navigation using the right value
of next-error-last-buffer that navigated to its previous occurrence.

Thus, the steps will be the following:

1. If window-local next-error-last-buffer is an acceptable buffer, use that.
2. If next-error-last-buffer is an acceptable buffer, use that.
3. If the current buffer is acceptable, choose it.
4. Look for any acceptable buffer.
5. Use the current buffer as a last resort if it qualifies, even despite AVOID-CURRENT.
6. Give up.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
Hi Juri,

Thank you for the reply.

But having had time to consider this issue, I think there are benefits
to how it currently works. For instance, if I want to switch from a
Compilation's buffer next-error-function to the current file buffer's
one, I just need to bury Compilation (doing the reverse might be harder,
however). If we change this logic, we should make sure not to make
anything worse.

On 01/25/2016 12:10 AM, Juri Linkov wrote:

> The link to the discussion is here:
> http://lists.gnu.org/archive/html/emacs-devel/2004-05/msg00614.html
> where you can see the case that we need to support.

In this scenario, it seems like you could have benefited from
next-error-last-buffer value being frame-local instead (maybe
implemented as a frame parameter?).

> Now that we have window-local variables, it's possible to support
> this case in a proper way.  Instead of checking if a buffer visible
> in the current frame, we should check the window-local value of
> next-error-last-buffer.  Thus invoking next-error in the window
> with the source buffer will continue navigation using the right value
> of next-error-last-buffer that navigated to its previous occurrence.

How do linting minor modes (like Flycheck or Flymake) fit into this?

Suppose I called M-x compile (or, better yet, M-x grep), navigated to
some file buffer from it and then see that it has some linter errors
highlighed by Flycheck. So I want to use the current buffer's
next-error-function now, and jump between linter warnings using
next/previous-error. How do I do that? IIU your plan correctly, the
current window-local next-error-last-buffer value will continue pointing
at the Grep buffer, even if I bury it.

Basically, I want to have two at least somewhat guessable sequences of
actions that would let the user choose which buffer to use for its
next-error-function.

As discussed in this issue, the best way to do that seems to require:

- Some indicator that a given buffer's next-error-function points to
other buffer (then, if you're in a different buffer, that other buffer
is still relevant). Like a buffer-local variable called, for example,
next-error-function-nonlocal.

- A command (or several) to switch between the plausible candidates for
next-error-last-buffer. Maybe just have a single command that uses
read-buffer with a predicate checking the aforementioned variable and an
extra option that means "just use the current buffer".

- Ignore next-error-last-buffer's visibility. Or make it frame-local, to
account for your scenario as well (but that would bring extra
complexity: some people use use frames like almost separate
applications, and other can use frames instead of windows, and display
them side-by-side).

WDYT?



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Juri Linkov-2
>> The link to the discussion is here:
>> http://lists.gnu.org/archive/html/emacs-devel/2004-05/msg00614.html
>> where you can see the case that we need to support.
>
> In this scenario, it seems like you could have benefited from
> next-error-last-buffer value being frame-local instead (maybe implemented
> as a frame parameter?).

A frame might contain more pairs of navigational/target windows,
e.g. a window with *grep* output, and a file buffer visited from *grep*;
a window with *Occur*, and another place in the same file buffer
but visited from *Occur*, etc.

So frame-local is not of help here, whereas window-local is,
provided a navigational window (like *grep*/*compilation*)
always displays target buffers in another dedicated window.

As I see this is not what xref currently does: navigating in it
jumps between many different windows that is very inconvenient,
but this can be easily fixed to work the sane way as *grep*
or *compilation* already works.

>> Now that we have window-local variables, it's possible to support
>> this case in a proper way.  Instead of checking if a buffer visible
>> in the current frame, we should check the window-local value of
>> next-error-last-buffer.  Thus invoking next-error in the window
>> with the source buffer will continue navigation using the right value
>> of next-error-last-buffer that navigated to its previous occurrence.
>
> How do linting minor modes (like Flycheck or Flymake) fit into this?

Does Flycheck or Flymake display a navigation window with a list of results?
If not, then this is a new case that we need to support as well.

> Suppose I called M-x compile (or, better yet, M-x grep), navigated to some
> file buffer from it and then see that it has some linter errors highlighed
> by Flycheck. So I want to use the current buffer's next-error-function now,
> and jump between linter warnings using next/previous-error. How do I do
> that? IIU your plan correctly, the current window-local
> next-error-last-buffer value will continue pointing at the Grep buffer,
> even if I bury it.

What if you have two navigations in the same buffer, and both are
without a navigation window that you can't bury?

> Basically, I want to have two at least somewhat guessable sequences of
> actions that would let the user choose which buffer to use for its
> next-error-function.
>
> As discussed in this issue, the best way to do that seems to require:
>
> - Some indicator that a given buffer's next-error-function points to other
> buffer (then, if you're in a different buffer, that other buffer is still
> relevant). Like a buffer-local variable called, for example,
> next-error-function-nonlocal.

Do you mean to bind a navigation buffer with navigated target buffers/windows?

> - A command (or several) to switch between the plausible candidates for
> next-error-last-buffer. Maybe just have a single command that uses
> read-buffer with a predicate checking the aforementioned variable and an
> extra option that means "just use the current buffer".

This would be too complicated to use.

> - Ignore next-error-last-buffer's visibility. Or make it frame-local, to
> account for your scenario as well (but that would bring extra complexity:
> some people use use frames like almost separate applications, and other can
> use frames instead of windows, and display them side-by-side).

Buffers are displayed in windows, so better to bind them to windows.

> WDYT?

I remember the original idea was to always continue the same navigation
that displayed a given target buffer/window, so switching to another
navigation in the same window could be achieved by explicitly navigating
to another result from another navigation, e.g. when current navigation
was from *compilation* then switching to *grep* buffer and typing M-n
for the next grep hit in the same file buffer.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 01/26/2016 12:55 AM, Juri Linkov wrote:

> A frame might contain more pairs of navigational/target windows,
> e.g. a window with *grep* output, and a file buffer visited from *grep*;
> a window with *Occur*, and another place in the same file buffer
> but visited from *Occur*, etc.

Yes, but it wasn't your scenario there. In that scenario, you switched
to a different frame, which had only a *compilation* buffer visible, and
were surprised to see a next-error-function used from a non-visible
buffer you last accessed in a different frame.

> So frame-local is not of help here, whereas window-local is,
> provided a navigational window (like *grep*/*compilation*)
> always displays target buffers in another dedicated window.

How does it really help? You've navigated from *grep*, to that buffer A,
then did that from *compilation*, and then you can't continue jumping to
next *grep* occurrences from that buffer.

frame-local could be sufficient if we were sure that different
navigation windows show error locations in distinctly different sets of
windows, IMHO.

We can fix xref, but not every next-error-function uses the same window,
and that's not codified in this variable's docstring.
change-log-next-error doesn't.

> As I see this is not what xref currently does: navigating in it
> jumps between many different windows that is very inconvenient,
> but this can be easily fixed to work the sane way as *grep*
> or *compilation* already works.

Yes, this can use an improvement.

>> How do linting minor modes (like Flycheck or Flymake) fit into this?
>
> Does Flycheck or Flymake display a navigation window with a list of results?

Flycheck has such a buffer, but it's not displayed by default. And in
any case, it sets next-error-function locally in file buffers, but not
in its "list of errors" buffer.

Hmm. Apparently, Flymake doesn't set next-error-function, so we can
disregard it.

js2-mode is another example: it's a major mode that sets
next-error-function in its buffers. You can ask it for the "list of
errors" buffer as well, but it's usually not shown.

> If not, then this is a new case that we need to support as well.

Apparently so.

>> Suppose I called M-x compile (or, better yet, M-x grep), navigated to some
>> file buffer from it and then see that it has some linter errors highlighed
>> by Flycheck. So I want to use the current buffer's next-error-function now,
>> and jump between linter warnings using next/previous-error. How do I do
>> that? IIU your plan correctly, the current window-local
>> next-error-last-buffer value will continue pointing at the Grep buffer,
>> even if I bury it.
>
> What if you have two navigations in the same buffer, and both are
> without a navigation window that you can't bury?

I don't follow. The above was an attempt to point out an hole in your
plan. I'm not sure you can refute that with a "what if" counter-example.

>> - Some indicator that a given buffer's next-error-function points to other
>> buffer (then, if you're in a different buffer, that other buffer is still
>> relevant). Like a buffer-local variable called, for example,
>> next-error-function-nonlocal.
>
> Do you mean to bind a navigation buffer with navigated target buffers/windows?

I mean to ask compilation-mode (as well as other similar modes) to
(setq-local next-error-function-nonlocal t), in addition to setting
next-error-function and next-error-last-buffer.

>> - A command (or several) to switch between the plausible candidates for
>> next-error-last-buffer. Maybe just have a single command that uses
>> read-buffer with a predicate checking the aforementioned variable and an
>> extra option that means "just use the current buffer".
>
> This would be too complicated to use.

Why complicated? It would just be a way to choose the source of errors
to follow. You'd also be able to do that by clicking on an error, or
pressing RET, in the "nonlocal" navigation buffers.

The main point, however, which you might not agree with, is to make
next-error-last-buffer global.

>> - Ignore next-error-last-buffer's visibility. Or make it frame-local, to
>> account for your scenario as well (but that would bring extra complexity:
>> some people use use frames like almost separate applications, and other can
>> use frames instead of windows, and display them side-by-side).
>
> Buffers are displayed in windows, so better to bind them to windows.

Making next-error-last-buffer window-local feels clunkier to me: there
would be no indication that a given window is following *Compilation*,
for example. And up until now, next-error worked more or less in a
global fashion.

> I remember the original idea was to always continue the same navigation
> that displayed a given target buffer/window, so switching to another
> navigation in the same window could be achieved by explicitly navigating
> to another result from another navigation, e.g. when current navigation
> was from *compilation* then switching to *grep* buffer and typing M-n
> for the next grep hit in the same file buffer.

How will you "switch" to the next-error-function set locally by Flycheck
in the current file-visiting buffer?

How will you switch between Grep and Compilation if they display a
location in the same buffer (and window)? Won't the desired navigation
buffer have to be visible? So you'd have to select some window, switch
to that buffer in it, and then click or press RET on some error?

Using a command to switch between next-error-last-buffer candidates
seems much quicker.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Juri Linkov-2
> How does it really help? You've navigated from *grep*, to that buffer A,
> then did that from *compilation*, and then you can't continue jumping to
> next *grep* occurrences from that buffer.

I suppose that navigation from every navigational window displays its targets
in own dedicated window that will be associated with its “parent” window.
So e.g. after navigating from *grep* to window A, and from *compilation*
to window B, next-error invoked from windows A or B will continue
the right navigation.

> We can fix xref, but not every next-error-function uses the same window,
> and that's not codified in this variable's docstring. change-log-next-error
> doesn't.

If some next-error-function doesn't use the same window, still there is
no problem because its displayed window will continue the last navigation
visited in that window.

>>> Suppose I called M-x compile (or, better yet, M-x grep), navigated to some
>>> file buffer from it and then see that it has some linter errors highlighed
>>> by Flycheck. So I want to use the current buffer's next-error-function now,
>>> and jump between linter warnings using next/previous-error. How do I do
>>> that? IIU your plan correctly, the current window-local
>>> next-error-last-buffer value will continue pointing at the Grep buffer,
>>> even if I bury it.
>>
>> What if you have two navigations in the same buffer, and both are
>> without a navigation window that you can't bury?
>
> I don't follow. The above was an attempt to point out an hole in your
> plan. I'm not sure you can refute that with a "what if" counter-example.

This adds another problematic case to consider, but we could avoid it
by always requiring creation of a navigation buffer, possibly hidden
when necessary.  (As for your point about a hole, I already addressed it
below - that requires unburing a navigation buffer that you want switch to).

>>> - Some indicator that a given buffer's next-error-function points to other
>>> buffer (then, if you're in a different buffer, that other buffer is still
>>> relevant). Like a buffer-local variable called, for example,
>>> next-error-function-nonlocal.
>>
>> Do you mean to bind a navigation buffer with navigated target buffers/windows?
>
> I mean to ask compilation-mode (as well as other similar modes) to
> (setq-local next-error-function-nonlocal t), in addition to setting
> next-error-function and next-error-last-buffer.

How this could help to point to other buffer?

>>> - A command (or several) to switch between the plausible candidates for
>>> next-error-last-buffer. Maybe just have a single command that uses
>>> read-buffer with a predicate checking the aforementioned variable and an
>>> extra option that means "just use the current buffer".
>>
>> This would be too complicated to use.
>
> Why complicated? It would just be a way to choose the source of errors to
> follow. You'd also be able to do that by clicking on an error, or pressing
> RET, in the "nonlocal" navigation buffers.

I think it would be more WYSIWYG first to switch to the navigation buffer,
and then to click on an error, or press RET.

> The main point, however, which you might not agree with, is to make
> next-error-last-buffer global.

I prefer this precedence:
1. window-local next-error-last-buffer
2. buffer-local next-error-last-buffer
3. global next-error-last-buffer

>>> - Ignore next-error-last-buffer's visibility. Or make it frame-local, to
>>> account for your scenario as well (but that would bring extra complexity:
>>> some people use use frames like almost separate applications, and other can
>>> use frames instead of windows, and display them side-by-side).
>>
>> Buffers are displayed in windows, so better to bind them to windows.
>
> Making next-error-last-buffer window-local feels clunkier to me: there
> would be no indication that a given window is following *Compilation*, for
> example. And up until now, next-error worked more or less in
> a global fashion.

Are you hinting that currently there is such indication in the form of
navigation buffer's window displayed in the same frame (rule#1 in
next-error-find-buffer)?

I proposed window-local next-error-last-buffer only because you had
some problems with this rule using in xref.

>> I remember the original idea was to always continue the same navigation
>> that displayed a given target buffer/window, so switching to another
>> navigation in the same window could be achieved by explicitly navigating
>> to another result from another navigation, e.g. when current navigation
>> was from *compilation* then switching to *grep* buffer and typing M-n
>> for the next grep hit in the same file buffer.
>
> How will you "switch" to the next-error-function set locally by Flycheck in
> the current file-visiting buffer?

By restarting Flycheck?

> How will you switch between Grep and Compilation if they display a location
> in the same buffer (and window)? Won't the desired navigation buffer have
> to be visible? So you'd have to select some window, switch to that buffer
> in it, and then click or press RET on some error?

Yes.

> Using a command to switch between next-error-last-buffer candidates seems
> much quicker.

In case of Flycheck, there will be no next-error-last-buffer, no?



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 01/27/2016 03:57 AM, Juri Linkov wrote:

> I suppose that navigation from every navigational window displays its targets
> in own dedicated window that will be associated with its “parent” window.

That's a considerable change. Associated how? The window itself won't
have any indication with which navigation buffer it's associated with,
will it?

And what if you do have the same buffer references in different
navigation windows? Will they have to show it in both associated
windows? That seems wasteful.

> So e.g. after navigating from *grep* to window A, and from *compilation*
> to window B, next-error invoked from windows A or B will continue
> the right navigation.

Suppose you've did that, then turned left to look out of the window for
half a minute, then looked back at Emacs. How are you going to predict
what M-x next-error will do?

Now, in addition to remembering which navigational command you ran last,
you have to remember the window associations.

>> We can fix xref, but not every next-error-function uses the same window,
>> and that's not codified in this variable's docstring. change-log-next-error
>> doesn't.
>
> If some next-error-function doesn't use the same window, still there is
> no problem because its displayed window will continue the last navigation
> visited in that window.

And soon, all windows in the frame will refer to the ChangeLog buffer as
its next-error-last-buffer, right?

`next-error' always continuing the last navigation does not require
window-local values. We can just have next-error-last-buffer to be global.

And if you're still thinking of the two-frame scenario, here's a little
modification:

- Run M-x grep in one frame, with several windows, jump to an error
there, in window A.
- Switch to another frame, run M-x compile there.
- Switch back to the first frame. But select some other window than A.
Call M-x next-error, and see it use the location from the *compilation*
buffer, even though *grep* is visible right there.

That scenario looks just as counter-intuitive to me as the original one.
Your proposal would only fix the original one.

> This adds another problematic case to consider, but we could avoid it
> by always requiring creation of a navigation buffer, possibly hidden
> when necessary.  (As for your point about a hole, I already addressed it
> below - that requires unburing a navigation buffer that you want switch to).

One navigational buffer per file buffer? That's too much.

>> I mean to ask compilation-mode (as well as other similar modes) to
>> (setq-local next-error-function-nonlocal t), in addition to setting
>> next-error-function and next-error-last-buffer.
>
> How this could help to point to other buffer?

It will only tag it to be available for completion in the new
pick-next-error-last-buffer command.

Or we can put those buffers in a ring, which was also suggested here
previously. That would also tag them, and allow switching between them
in a historical fashion.

>> Why complicated? It would just be a way to choose the source of errors to
>> follow. You'd also be able to do that by clicking on an error, or pressing
>> RET, in the "nonlocal" navigation buffers.
>
> I think it would be more WYSIWYG first to switch to the navigation buffer,
> and then to click on an error, or press RET.

That can also be a way to change the global next-error-last-buffer
value. And whether it's window-local or not, neither scenario solves the
Flycheck problem.

>> The main point, however, which you might not agree with, is to make
>> next-error-last-buffer global.
>
> I prefer this precedence:
> 1. window-local next-error-last-buffer
> 2. buffer-local next-error-last-buffer
> 3. global next-error-last-buffer

My preference is: 3, 2. Except we never set next-error-last-buffer
locally, so we should interpret the global nil value to mean "the
current buffer".

>> Making next-error-last-buffer window-local feels clunkier to me: there
>> would be no indication that a given window is following *Compilation*, for
>> example. And up until now, next-error worked more or less in
>> a global fashion.
>
> Are you hinting that currently there is such indication in the form of
> navigation buffer's window displayed in the same frame (rule#1 in
> next-error-find-buffer)?

That an one option - we can indeed keep some logic reliant on whether
next-error-last-buffer is visible in the current frame (but drop the
"not more than one" limitation, because it leads to non-intuitive behavior).

Then the change to the API could be smaller, but the use case of using
next-error with non-visible navigational buffers will be more broken
than currently.

But my first choice is to not rely on buffer visibility at all, and
simply follow the current global next-error-last-buffer value, as well
as provide an easy way to switch to a different one.

> I proposed window-local next-error-last-buffer only because you had
> some problems with this rule using in xref.

Yes, I did. But IIUC, Eli had more of a problem with the

(if (eq (length window-buffers) 1)

part of that rule. The commit that disabled next-error integration in
xref has a link to that discussion in its message.

>> How will you "switch" to the next-error-function set locally by Flycheck in
>> the current file-visiting buffer?
>
> By restarting Flycheck?

Restarting how? It's a minor mode that triggers linting checks when the
buffer is saved, or you've typed something and wait a bit, or the file
buffer has just been opened. The exact set of conditions is customizable.

And it doesn't set next-error-last-buffer at all.

But suppose it did. Imagine: you M-x compile, jump to an error, that
opens the file in a new buffer, Flycheck kicks in, runs its linting
check, and sets next-error-function and next-error-last-buffer in that
buffer. If you call next-error now, you'll be jumping to the next
linting error, not *compilation* error.

>> How will you switch between Grep and Compilation if they display a location
>> in the same buffer (and window)? Won't the desired navigation buffer have
>> to be visible? So you'd have to select some window, switch to that buffer
>> in it, and then click or press RET on some error?
>
> Yes.

Lots of clicking.

>> Using a command to switch between next-error-last-buffer candidates seems
>> much quicker.
>
> In case of Flycheck, there will be no next-error-last-buffer, no?

We should interpret nil as "use the current buffer".



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Juri Linkov-2
>> So e.g. after navigating from *grep* to window A, and from *compilation*
>> to window B, next-error invoked from windows A or B will continue
>> the right navigation.
>
> Suppose you've did that, then turned left to look out of the window for
> half a minute, then looked back at Emacs. How are you going to predict what
> M-x next-error will do?

You can see an arrow indication in the left fringe of the navigational window
that points to the location of the current file displayed in an adjacent window.

> But my first choice is to not rely on buffer visibility at all, and simply
> follow the current global next-error-last-buffer value, as well as provide
> an easy way to switch to a different one.

I just posted an IDE-like layout to emacs-devel, and it demonstrates that the
current rule#1 in next-error-find-buffer is the right thing to do in this
scenario: after switching from e.g. *grep* to *xref* in the bottom window,
next-error will continue navigation from the visible navigation buffer.
So no changes are required in this case.

>> I proposed window-local next-error-last-buffer only because you had
>> some problems with this rule using in xref.
>
> Yes, I did. But IIUC, Eli had more of a problem with the
>
> (if (eq (length window-buffers) 1)
>
> part of that rule. The commit that disabled next-error integration in xref
> has a link to that discussion in its message.

The rule (if (eq (length window-buffers) 1) itself is not a problem.

The problem is in the cases that this rule doesn't support, i.e.
(< (length window-buffers) 1) and (> (length window-buffers) 1)
We need to find a way to handle these cases as well.

>>> How will you switch between Grep and Compilation if they display a location
>>> in the same buffer (and window)? Won't the desired navigation buffer have
>>> to be visible? So you'd have to select some window, switch to that buffer
>>> in it, and then click or press RET on some error?
>>
>> Yes.
>
> Lots of clicking.

No clicking at all, I don't use the mouse :)



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 01/28/2016 01:57 AM, Juri Linkov wrote:

> You can see an arrow indication in the left fringe of the navigational window
> that points to the location of the current file displayed in an adjacent window.

That's only true of compilation-mode and its derivatives. It's not a
part of next-error-function contract (again, change-log-next-error does
nothing of the sort; diff-next-error doesn't either).

Maybe it's a good idea, but I'm not sure how to enforce something like
that, to be able to rely on it. And a small arrow in one window is not a
great indicator anyway.

> I just posted an IDE-like layout to emacs-devel, and it demonstrates that the
> current rule#1 in next-error-find-buffer is the right thing to do in this
> scenario: after switching from e.g. *grep* to *xref* in the bottom window,
> next-error will continue navigation from the visible navigation buffer.
> So no changes are required in this case.

What case? We're not going to introduce IDE-like layout as the
mandatory, or the default, behavior.

The rule#1, as written, also poorly interacts with Flycheck-like use
cases. Are you going to comment on that part discussion?

Because if you're going to disregard it, we might as well stop talking
right now: any acceptable proposal, as far as I'm concerned, handles
that case.

> The problem is in the cases that this rule doesn't support, i.e.
> (< (length window-buffers) 1) and (> (length window-buffers) 1)
> We need to find a way to handle these cases as well.

Yes: remove that check, for example.

We can also realize that the rule #1 is an attempt to do the following:
if next-error-last-buffer is no longer visible, try to pick a
navigational buffer among the currently visible ones.

However, the rule tries to limit the number of visible navigational
buffer to one, and aborts otherwise. I think that's because it doesn't
know any better way to distinguish between navigational buffers and
plain file-visiting buffers that have next-error-function set locally
(navigational buffers can also be file-visiting, as in the cases of
change-log-mode and diff-mode). The new variable that I proposed would help.

> No clicking at all, I don't use the mouse :)

Lots of pressing the buttons, then. Which is what I meant.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Juri Linkov-2
> Maybe it's a good idea, but I'm not sure how to enforce something like
> that, to be able to rely on it. And a small arrow in one window is not
> a great indicator anyway.

A good indication could be provided by a new global minor mode
‘global-next-error-minor-mode’ showing in the mode line
the currently active navigation, and allowing switching
to another navigation.

> The rule#1, as written, also poorly interacts with Flycheck-like use
> cases. Are you going to comment on that part discussion?

Flycheck provides its own keybinding ‘C-c ! n’ for ‘flycheck-next-error’,
so really there is no problem.

A real problem is when a navigational buffer does exist, but it's hidden.
IIUC, due to this problem you reverted next-error integration in xref, right?

> We can also realize that the rule #1 is an attempt to do the following: if
> next-error-last-buffer is no longer visible, try to pick a navigational
> buffer among the currently visible ones.

You mean next-error-last-buffer is no longer visible _on the selected frame_?

> However, the rule tries to limit the number of visible navigational buffer
> to one, and aborts otherwise. I think that's because it doesn't know any
> better way to distinguish between navigational buffers and plain
> file-visiting buffers that have next-error-function set locally
> (navigational buffers can also be file-visiting, as in the cases of
> change-log-mode and diff-mode). The new variable that I proposed
> would help.

Yes, this is because it's hard to find a better way, and I'm not sure
how next-error-function-nonlocal could help, because sometimes a navigation
might visit another non-file navigational buffer, e.g. multi-occur
visiting a *compilation* buffer.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 01/29/2016 02:59 AM, Juri Linkov wrote:

> ...and allowing switching
> to another navigation.

Are you coming around to my suggestion now?

>> The rule#1, as written, also poorly interacts with Flycheck-like use
>> cases. Are you going to comment on that part discussion?
>
> Flycheck provides its own keybinding ‘C-c ! n’ for ‘flycheck-next-error’,
> so really there is no problem.

That's basically giving up.

Do you expect me to repeatedly type `C-c ! n' to move across errors in
the current buffer? It's not like it's inconvenient or anything.
next-error-function was added exactly so that the user doesn't have to
learn a bunch of different key bindings for basically the same thing.

There's also e.g. js2-mode, which doesn't have a custom key binding for
this. And probably other modes that I just don't know about.

> A real problem is when a navigational buffer does exist, but it's hidden.
> IIUC, due to this problem you reverted next-error integration in xref, right?

No: http://lists.gnu.org/archive/html/emacs-devel/2016-01/msg01286.html

See the first sentence there.

>> We can also realize that the rule #1 is an attempt to do the following: if
>> next-error-last-buffer is no longer visible, try to pick a navigational
>> buffer among the currently visible ones.
>
> You mean next-error-last-buffer is no longer visible _on the selected frame_?

I don't really care either way. This question doesn't seem to add any
big constraints on the final solution.

> Yes, this is because it's hard to find a better way, and I'm not sure
> how next-error-function-nonlocal could help, because sometimes a navigation
> might visit another non-file navigational buffer, e.g. multi-occur
> visiting a *compilation* buffer.

What is the exact problem you have in mind there?

When *multi-occur* jumps to *compilation*, next-error-last-buffer keeps
referring to *multi-occur*.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Juri Linkov-2
> Do you expect me to repeatedly type `C-c ! n' to move across errors in the
> current buffer? It's not like it's inconvenient or
> anything. next-error-function was added exactly so that the user doesn't
> have to learn a bunch of different key bindings for basically the
> same thing.

Not repeatedly, it's enough to type is only once, and subsequent invocations
of next-error will pick up a new navigation.

>> A real problem is when a navigational buffer does exist, but it's hidden.
>> IIUC, due to this problem you reverted next-error integration in xref, right?
>
> No: http://lists.gnu.org/archive/html/emacs-devel/2016-01/msg01286.html
>
> See the first sentence there.

I reread it every time you reference it, but it adds nothing to the discussion.
Could you provide more details about this problem.  I imagine you meant the case
when *xref* is hidden, but *compilation* is visible.  Is it so?  What are the
preconditions for this situation to occur?

>> Yes, this is because it's hard to find a better way, and I'm not sure
>> how next-error-function-nonlocal could help, because sometimes a navigation
>> might visit another non-file navigational buffer, e.g. multi-occur
>> visiting a *compilation* buffer.
>
> What is the exact problem you have in mind there?
>
> When *multi-occur* jumps to *compilation*, next-error-last-buffer keeps
> referring to *multi-occur*.

But after you hide *compilation*, *multi-occur* will kick in.
This is why I proposed to use window-local values, and your counter-arguments
against it (indication/switching) apply to the already used global value
of next-error-last-buffer as well: its current state is not discoverable
and it's not easy to switch to another navigation.  This issue is real,
but orthogonal to the subject of bug#20489.



Reply | Threaded
Open this post in threaded view
|

bug#20489: 25.0.50; next-error-find-buffer chooses non-current buffer without good reason

Dmitry Gutov
On 01/30/2016 02:44 AM, Juri Linkov wrote:

> Not repeatedly, it's enough to type is only once, and subsequent invocations
> of next-error will pick up a new navigation.

Fair enough. But the complaint about memorizing different key bindings
still stands.

>>> A real problem is when a navigational buffer does exist, but it's hidden.
>>> IIUC, due to this problem you reverted next-error integration in xref, right?

Why is that a problem? Depending on the approach, we either keep using
it, or switch to the visible one.

>> No: http://lists.gnu.org/archive/html/emacs-devel/2016-01/msg01286.html
>>
>> See the first sentence there.
>
> I reread it every time you reference it, but it adds nothing to the discussion.
> Could you provide more details about this problem.  I imagine you meant the case
> when *xref* is hidden, but *compilation* is visible.  Is it so?  What are the
> preconditions for this situation to occur?

You really should ask Eli what exactly he meant there, I'm just
guessing. I didn't want to keep inquiring at that point. Eli said
disable, so I disabled.

But IMHO, (eq (length window-buffers) 1) is counter-intuitive: take the
configuration with three buffers with next-error-function set visible.
Hide the current last-buffer: nothing changes, `next-error' continues
working as it did. Hide the next one: and suddenly, `next-error' starts
behaving differently.

The user is expected to understand too much.

>> When *multi-occur* jumps to *compilation*, next-error-last-buffer keeps
>> referring to *multi-occur*.
>
> But after you hide *compilation*, *multi-occur* will kick in.

So? It's you who's advocating to stop using the non-visible
last-buffer's. My first choice is to only switch next-error-last-buffer
when the user requests this explicitly.

On the other hand, if we choose the semantics "not visible => bad
last-buffer", that would be understandable, too.

I don't see why you consider the case "multi-occur references
compilation" to be more special than others. It seems no different from
"both grep and compilation are visible".

> This is why I proposed to use window-local values, and your counter-arguments
> against it (indication/switching) apply to the already used global value
> of next-error-last-buffer as well: its current state is not discoverable
> and it's not easy to switch to another navigation.

Your proposal _complicates_ the current state, making it more of a
problem. If the global value of next-error-last-buffer is used
consistently, at least the current state is easier to remember.

I'm also not a big fan of window-local semantics here, personally.

> This issue is real,
> but orthogonal to the subject of bug#20489.

Would you like me to rename the subject to something? The actual problem
is that `next-error' exhibits surprising behavior, and doesn't properly
support `next-error-function' being set in file-visiting buffers, which
is a common situation these days.

Since filing this bug, I've somewhat warmed up to using buffer
visibility as a condition to choose next-error-last-buffer.



1234