unifying emacs "go to definition" functionality

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

unifying emacs "go to definition" functionality

Brendan Miller-5
Right now emacs has several modules that offer "go to definition"
functionality, all of which have different implementations, and
different behavior.

1. Etags uses M-. and M-* to push and pop from a pair of tag stacks
(find-tag-marker-ring, and tags-location-ring).

2. elisp uses C-h f TAB RETURN to jump to definition. It has no tag
stack, so there's no way to jump back.

3. CEDET uses C-c , J to jump to definition. It has no tag stack,
though it pushes to the global mark ring.

4. Jedi (jump to definition/autocompletion for python) uses C-. It has
no tag stack.

5. SLIME uses etags keybindings, but I don't think it uses etags stack.

By far the etags interface (M-. to jump to definition and push the
location, M-* to pop back), is the easiest interface to use, though
the underlying tagging engine is less precise than the others.

My suggestion is that the etags key bindings and tag stack be made
generic, and that M-. trigger some kind of callback through a buffer
local variable, so that jump to definition can be handled in a mode
specific way.

Note that in addition to reusing the same keybindings, reusing the
same tag stack gives that added benefits that it's possible to
navigate through a high level language into a lower level language,
and then pop back out with M-*. I have this mocked up (in kind of a
hacky way) with elisp and C, where I can jump from elisp into the C
definition of a native function, navigate around C with etags or
CEDET, and then pop back out back into elisp again.

I'd be interested in taking a look at the implementation work behind
this in the future, but initially I just wanted to put the idea out
there for feedback.

Brendan Miller

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Stefan Monnier
> My suggestion is that the etags key bindings and tag stack be made
> generic, and that M-. trigger some kind of callback through a buffer
> local variable, so that jump to definition can be handled in a mode
> specific way.

That sounds great!


        Stefan

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Dmitry Gutov
In reply to this post by Brendan Miller-5
Brendan Miller <[hidden email]> writes:

> Right now emacs has several modules that offer "go to definition"
> functionality, all of which have different implementations, and
> different behavior.
>
> 1. Etags uses M-. and M-* to push and pop from a pair of tag stacks
> (find-tag-marker-ring, and tags-location-ring).
>
> 2. elisp uses C-h f TAB RETURN to jump to definition. It has no tag
> stack, so there's no way to jump back.

It's actually C-x F for Elisp if your use which-func, or whatever
binding you have for find-function (by default, none).

> 3. CEDET uses C-c , J to jump to definition. It has no tag stack,
> though it pushes to the global mark ring.
>
> 4. Jedi (jump to definition/autocompletion for python) uses C-. It has
> no tag stack.
>
> 5. SLIME uses etags keybindings, but I don't think it uses etags stack.
>
> By far the etags interface (M-. to jump to definition and push the
> location, M-* to pop back), is the easiest interface to use, though
> the underlying tagging engine is less precise than the others.

I agree than etags's push/pop interface is the easiest in this list, but
it also has room for improvement.

> My suggestion is that the etags key bindings and tag stack be made
> generic, and that M-. trigger some kind of callback through a buffer
> local variable, so that jump to definition can be handled in a mode
> specific way.

The "callback" part seems to be the easiest (you add a
save-buffer-position-function variable and make sure all navigation
functions call it), and also the most important, I think.

This way, the user we can have a navigation system that is a drop-in
replacement for mark and tag rings.

I have a small package that does that through advice, but that means I
need to hardcode every function that does navigation, by hand, and/or
ask any potential user to do that, too.

https://github.com/dgutov/point-stack

> Note that in addition to reusing the same keybindings, reusing the
> same tag stack gives that added benefits that it's possible to
> navigate through a high level language into a lower level language,
> and then pop back out with M-*. I have this mocked up (in kind of a
> hacky way) with elisp and C, where I can jump from elisp into the C
> definition of a native function, navigate around C with etags or
> CEDET, and then pop back out back into elisp again.

Using the same keybindings for the jump commands is, on one hand,
something that each user can set up themselves (it's customary to expect
users to set their own keybindings), on the other, I looks hard to do
something about this and retain backward compatibility at the same time.

Unless everybody agrees that M-. is the way to go, of course. If you'd
like to standardize on M-* too, then everybody would also need to agree
which storage facility to use (e.g. mark ring or tag ring, and we have
two mark rings, so the two ways are not exactly equivalent).

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Andreas Röhler-2
In reply to this post by Brendan Miller-5
Am 20.02.2013 01:28, schrieb Brendan Miller:

> Right now emacs has several modules that offer "go to definition"
> functionality, all of which have different implementations, and
> different behavior.
>
> 1. Etags uses M-. and M-* to push and pop from a pair of tag stacks
> (find-tag-marker-ring, and tags-location-ring).
>
> 2. elisp uses C-h f TAB RETURN to jump to definition. It has no tag
> stack, so there's no way to jump back.
>
> 3. CEDET uses C-c , J to jump to definition. It has no tag stack,
> though it pushes to the global mark ring.
>
> 4. Jedi (jump to definition/autocompletion for python) uses C-. It has
> no tag stack.
>
> 5. SLIME uses etags keybindings, but I don't think it uses etags stack.
>
> By far the etags interface (M-. to jump to definition and push the
> location, M-* to pop back), is the easiest interface to use, though
> the underlying tagging engine is less precise than the others.
>
> My suggestion is that the etags key bindings and tag stack be made
> generic, and that M-. trigger some kind of callback through a buffer
> local variable, so that jump to definition can be handled in a mode
> specific way.
>
> Note that in addition to reusing the same keybindings, reusing the
> same tag stack gives that added benefits that it's possible to
> navigate through a high level language into a lower level language,
> and then pop back out with M-*. I have this mocked up (in kind of a
> hacky way) with elisp and C, where I can jump from elisp into the C
> definition of a native function, navigate around C with etags or
> CEDET, and then pop back out back into elisp again.
>
> I'd be interested in taking a look at the implementation work behind
> this in the future, but initially I just wanted to put the idea out
> there for feedback.
>
> Brendan Miller
>
>

Are backsides of etags:

need to run in advance, hard to follow when changing Emacs version

My favourite is a solution based on

find-function-noselect

http://repo.or.cz/w/elbb.git/blob/HEAD:/code/Go-to-Emacs-Lisp-Definition.el

Andreas

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Helmut Eller-2
In reply to this post by Brendan Miller-5
On Wed, Feb 20 2013, Brendan Miller wrote:

> 5. SLIME uses etags keybindings, but I don't think it uses etags stack.

SLIME does use the etags stack but with different keybindings.  We use
M-. to push and M-, to pop.  M-* is bound to the same command as M-, for
compatibility but most people prefer M-, because , and . are adjacent on
their keyboards and M-* is usually quite hard to type.

I think M-, is the better choice and it should be the standard.

[...]
> I'd be interested in taking a look at the implementation work behind
> this in the future, but initially I just wanted to put the idea out
> there for feedback.

Using the etags stack is pretty easy.  A more difficult problem is how
to deal with names that have multiple definitions or definitions that
have multiple source locations.  E.g. in Emacs Lisp a variable and a
function can have the same name or in C a function can have a prototype
definition in a .h file and the actual definition is a .c file.  This
problem is especially important with languages that have multiple
methods with the same name.

In SLIME, when a name has multiple definitions we display all
definitions (one per line with some context) in a special buffer and the
user must then choose which one he wants (the next/previous-line
commands in that buffer automatically displays the source of the current
definition in the other buffer).

The autocomplete package uses something like a menu for this problem.

etags jumps to the first candidate and provides something like
next/previous-definition commands, but I think that solution is very
hard to use.  At least it drives me nuts, because I never know how many
more definitions there are and I can't remember the key bindings.

Helmut


Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Andreas Schwab-2
Helmut Eller <[hidden email]> writes:

> I think M-, is the better choice and it should be the standard.

M-, is already taken.

Andreas.

--
Andreas Schwab, [hidden email]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Helmut Eller-2
On Wed, Feb 20 2013, Andreas Schwab wrote:

> Helmut Eller <[hidden email]> writes:
>
>> I think M-, is the better choice and it should be the standard.
>
> M-, is already taken.

Keybindings aren't cast in stone.  Despite that, etags is too hard to
use.

Helmut


Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Andreas Schwab-2
Helmut Eller <[hidden email]> writes:

> On Wed, Feb 20 2013, Andreas Schwab wrote:
>
>> Helmut Eller <[hidden email]> writes:
>>
>>> I think M-, is the better choice and it should be the standard.
>>
>> M-, is already taken.
>
> Keybindings aren't cast in stone.

There must be a very strong reason to throw out such a useful binding.

> Despite that, etags is too hard to use.

I cannot disagree more.

Andreas.

--
Andreas Schwab, [hidden email]
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Helmut Eller-2
On Wed, Feb 20 2013, Andreas Schwab wrote:

>> Keybindings aren't cast in stone.
>
> There must be a very strong reason to throw out such a useful binding.

We already threw it out in SLIME and most people say that they love the
M-./M-, combo.

Helmut


Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Lawrence Mitchell
In reply to this post by Helmut Eller-2
Helmut Eller wrote:

[...]

> Using the etags stack is pretty easy.  A more difficult problem is how
> to deal with names that have multiple definitions or definitions that
> have multiple source locations.  E.g. in Emacs Lisp a variable and a
> function can have the same name or in C a function can have a prototype
> definition in a .h file and the actual definition is a .c file.  This
> problem is especially important with languages that have multiple
> methods with the same name.

> In SLIME, when a name has multiple definitions we display all
> definitions (one per line with some context) in a special buffer and the
> user must then choose which one he wants (the next/previous-line
> commands in that buffer automatically displays the source of the current
> definition in the other buffer).

FWIW this is what I do for multiple generic interfaces in the
fortran code browsing support I wrote
(ELPA:f90-interface-browser).  It also hooks into the etags stack
so that you can pop back, and falls back to etags themselves if
no generic interfaces are found.

Interfacing with the etags stack would have been easier with
callbacks I think, but as with Helmut, I don't like etags'
interface for jumping through multiple definitions and prefer a
method which allows the user to see and pick which definition
they want.

Lawrence

--
Lawrence Mitchell <[hidden email]>


Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Jambunathan K-3
Lawrence Mitchell <[hidden email]> writes:

> I don't like etags' interface for jumping through multiple definitions
> and prefer a method which allows the user to see and pick which
> definition they want.

I suggest a grep-like interface where one can get an overview of the
results and also persist the results.

Search results for a tag should stack one on top of one another in the
search buffer.

There is a unique search buffer at the project root to which results are
prepended or appended.

Provide outline capabities in the search buffer - For example, that
which is searched could be level-1 org heading and the results of search
could be level-2 org headings.  One can imagine a command that
automagically populates a level-1 heading with level-2 headings which
are look-up-references.

One can edit (this is important) and get a quick overview of one's
treasure hunt buffer through org/outline navigation.  One can type quick
notes outside of codebase right within the search buffer.

I am quite used to M-g M-n and M-g M-p for navigating between the search
results while getting an overview in the grep results buffer.

IMNSHO, the Emacs tying together of search results with
compilation-regexps is "too tight".  What I mean is that one can in no
way annotate the "search results" richly - function names in search
results, is an example of such an annotation - without at all messing
with search results themselves.  For example, I use 'after-string
property to display function names while I would have actually wanted to
get the function name right within the buffer itself for reasons of
persistence to disk.

        See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=13549

and an enhanced rgrep at

        http://debbugs.gnu.org/cgi/bugreport.cgi?msg=5;filename=grep-proof-of-concept-cf-cscope.png;att=3;bug=13549


I propose that the right way to think about what is being discussed is
this: Look at the "search results buffer" as a single-window controlling
dashboard for making sense of huge code bases.  The search interface is
very important for people who want to make sense of code base that they
haven't written themselves.
--

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Jambunathan K-3
Jambunathan K <[hidden email]> writes:

> Look at the "search results buffer" as a single-window controlling
> dashboard for making sense of huge code bases.

Look at the "search results buffer" as a single-window
controlling-dashboard for making sense of huge code bases.

I have used Emacs-with-Cscope extensively at work.  Cscope is the
"search/results provider" and Emacs is the "results displayer and
navigator".  Define lisp-based data interchange format (Remember it is a
lisp-based interface) and some command primitives between Emacs and
cscope/etags/semantic/what-have-you.

I usually don't jump to definition but usually do lookup refernces.  In
large commercial code bases - I am primarily a C programmer - calls are
dispatched via function pointers and lookup references offer
completeness that "go to definition" cannot.

ps: The current compiler-regexp interfaces of rgrep etc is text-based as
opposed to being lisp-based.

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Dmitry Gutov
In reply to this post by Andreas Röhler-2
Andreas Röhler <[hidden email]> writes:
> Are backsides of etags:
>
> need to run in advance, hard to follow when changing Emacs version
>
> My favourite is a solution based on
>
> find-function-noselect
>
> http://repo.or.cz/w/elbb.git/blob/HEAD:/code/Go-to-Emacs-Lisp-Definition.el

Not sure why you're writing about this ELisp-specific package, but
here's a similar one that AFAIK is more popular and includes the
"describe thing at point" command: https://github.com/purcell/elisp-slime-nav

It's also easier to install, by the virtue of being published at Melpa.

Reply | Threaded
Open this post in threaded view
|

Re: unifying emacs "go to definition" functionality

Stefan Monnier
In reply to this post by Andreas Schwab-2
>>>> I think M-, is the better choice and it should be the standard.
>>> M-, is already taken.
>> Keybindings aren't cast in stone.
> There must be a very strong reason to throw out such a useful binding.

Since tags-loop-continue can't always work, the M-, binding can partly
be shared with another without too many conflicts.

Whether sharing it with pop-tag-mark is a good idea, I don't know, tho.


        Stefan

Reply | Threaded
Open this post in threaded view
|

RE: unifying emacs "go to definition" functionality

Drew Adams
In reply to this post by Lawrence Mitchell
> I don't like etags' interface for jumping through multiple
> definitions and prefer a method which allows the user to see
> and pick which definition they want.

Icicles does exactly that.  It provides the tags hits as completion candidates.
Emacs could easily do likewise.

   With 'icicle-find-tag', you enter (using 'RET') a regexp to
   match the tags you want to visit.  By default, all tags in
   all tags files are searched, and the matches become
   completion candidates (which you can of course match further
   by typing another pattern).

   As always, you can use progressive completion, chip away the
   non-elephant, and so on.  Just as with Icicles search
   commands, you use 'C-RET', 'C-mouse-2', 'C-next', and so on,
   to visit the search hits.  You can use `M-*'
   ('icicle-pop-mark') to return to the place you invoked `M-.'.

The second paragraph (except the last sentence) would not apply to vanilla
Emacs, but the first easily could.

http://www.emacswiki.org/Icicles_-_Emacs_Tags_Enhancements