emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Generalizing find-definition


From: Stefan Monnier
Subject: Re: Generalizing find-definition
Date: Mon, 03 Nov 2014 09:30:56 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux)

> The only benefit would be that M-, is now "go back after M-.", which is
> what a lot of the packages that redefine M-. do to the key.  Hence the
> suggestion to swap the two keys, to unify that apparently rather
> widespread use of M-,.  If Emacs would prefer to keep M-, as is, that is
> fine with me, too.

I see, so it's compatibility with other packages vs. compatibility with
etags.el.  Luckily, I think there is no hurry to make this choice.
So we could poll the users.

>> So on the UI side we mostly have:
>> - "jump to *the* definition of thing at point".
>> - "list definitions of thing at point".
> Agreed. So far, I would say this is the same key binding (M-.)
> which then either jumps to the definition if there is one, or lists them
> if there is more than one.

IIUC the first is only used when there's only one definition.  I guess
it's OK, and it reduces the pressure on key-bindings.

>> - "list uses of thing at point".
> What key binding would you suggest for that? SLIME apparently uses M-_
> and M-? (i.e. the key right of . in different keyboard layouts).

AFAICT there're both unbound currently, so either is fine.  Of course,
we could also re-use M-. for that (see below).

>> And on the backend side we have:
>> - identifier-at-point-function
> Why do we need this?

I thought we already agreed that we need a language-aware way to
determine what is the identifier at point (taking into account the
current namespace/package/etc..).

> It does not make much sense for this functionality in languages with
> combined identifiers.  For example, in Python, "foo.bar()" can be
> pretty much anything, it depends heavily on the context.  Libraries for
> introspection expect a position in a file/buffer, not an identifier,
> to find the definitions.

But if we also want the user to type the identifier via `C-u M-.', then
we need find-definition-function to be able to deal with a string rather
than a buffer position.  So let's simply say that
find-definition-function will be called either with a string or with
a buffer position.  If the function prefers only working from strings,
it can call identifier-at-point-function to turn the buffer position
into a string.

>> - find-definition-function (with an argument to decide whether we want
>> a whole list or just the best/first candidate).
> I am not sure if it is generally easily possible to sort the list of
> candidates like that.  I guess tags often has the problem of knowing
> more than one possible candidate, so it would be preferable for tags to
> default to a single destination?

In etags.el, it doesn't take noticeably more time to get the full list
rather than just the first match, so I guess it's OK if we just always
return the full list.

>> Etags.el currently offers some additional functionality:
>> - jump to definition of any identifier, with TAB-completion.
> C-u M-. could call a separate function when set, which would be
> provided by the mode author to prompt for an identifier (with tab
> completion if possible) and goes to the definition of that symbol.

Right.  I guess the prompting can be part of the generic code, and the
completion-table can be provided by an appropriate foo-function set by
the backend providing find-definition-function.

[ Side note: I expect that identifier-at-point-function would pretty
  much always be provided by the major mode, but I expect that
  find-definition-function (as well as the TAB-completion function) will
  sometimes be provided by the major mode, and sometimes by
  a mode-agnostic package (like etags.el).  ]

Helmut Eller <address@hidden> writes:
> We also have a group of bindings for similar but not so important
> commands:
>
>  C-c C-w c  -- who calls (lists callers)
>  C-c C-w w  -- calls who (lists functions called by the current function)
>  C-c C-w r  -- who references (for global variables)
>  C-c C-w s  -- who sets (for global variables)
>  C-c C-w b  -- who binds (for dynamic variables)
>  C-c C-w s  -- who specializes (lists methods specialized for a specific 
> class)
>  C-c <      -- list callers
>  C-c >      -- list callees

Right, this brings up two issues:
- distinguish different kinds of uses: definitions, accesses,
  assignments, refinements (via advice-add, defmethod, ...), let-binds, ...
- distinguish different categories of "identifiers" (e.g. classes,
  variables, functions, types, methods, ...).

So far the proposal is to forget about the second distinction, tho if we
pass buffer-positions to find-definition-function,
find-definition-function can make those distinctions on its own.
We could additionally have some kind of convention for disambiguation
when using identifier strings, e.g. type "foobar variable" in the
minibuffer prompt to state explicitly that you're interested in the
foobar variable rather than the foobar type.

For the first distinction, at the UI level we could do:
- Specify the kind of use by the key-binding (M-. to find
  definitions, M-? to find uses).  This doesn't work too well if there
  are many more refinements.
- Specify the kind of use via a minibuffer prompt.
  E.g. C-u M-. would first prompt for an identifier (defaulting to the
  one at point), and then prompt for the kind of use to look for.
- Specify the use by filtering in the "found matches" buffer.
  For "definition", this kind of sucks since in many cases there'd be
  only one definition, but you'd first have to go through the complete
  list displayed in a buffer, and then use some key-binding to filter
  the sole definition out of that.
- A mix of the above.  E.g. M-. searches only for one particular subset
  of uses (e.g. definitions and refinements), while M-? search for the
  complementary subset (or for all possible uses, including the ones
  already provided under M-.), and after M-? you can filter the results
  in the buffer.

At the backend level, in order to accommodate those different possible
UIs, the find-definition-function would seem to need to receive 2 args:
one specifying the identifier, and the other specifying the kind of uses
and the elements of the returned list should not just be positions but
pairs of "position and use-kind".


        Stefan



reply via email to

[Prev in Thread] Current Thread [Next in Thread]