unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Dmitry Gutov <dmitry@gutov.dev>
To: "João Távora" <joaotavora@gmail.com>,
	"Eli Zaretskii" <eliz@gnu.org>, "Philip K." <philipk@posteo.net>,
	"Stefan Monnier" <monnier@iro.umontreal.ca>
Cc: emacs-devel@gnu.org
Subject: Re: Adding refactoring capabilities to Emacs
Date: Fri, 8 Sep 2023 01:39:51 +0300	[thread overview]
Message-ID: <5ddf5fe1-e5c9-2105-5cb8-a96bc8cecc86@gutov.dev> (raw)
In-Reply-To: <CALDnm51nS0R6mnRP9jiHVzAQj8t6cKWWn8C+3mxM5L59HWWeGQ@mail.gmail.com>

On 07/09/2023 17:39, João Távora wrote:
> On Thu, Sep 7, 2023 at 2:00 AM Dmitry Gutov <dmitry@gutov.dev> wrote:
>>
>> On 02/09/2023 12:55, João Távora wrote:
>>> Anyway I invite everyone to have a look and try to improve it, perhaps
>>> moving it out of Eglot into the shiny new "refactoring interface" if
>>> those ever become a thing.
>>
>> Regarding the diff approach vs. "shiny new", I've run a little
>> comparison with VS Code: doing a rename of 'glyph_row' across the Emacs
>> codebase (a moderately sized project) takes about ~1.44s to produce the
>> diff.
> 
> FWIW, I got 0.85s on that same test on a GNU/Linux VM running on a 6
> yo laptop with 4 cores assigned.  IMO this is more than acceptable for
> this contrived example which renames a symbol across many files.

Not that many: these are 260 edits just across 3 files.

And I see nothing contrived about such an example. There exist much 
bigger projects anyway, which we should ideally support well too.

> A much more typical example of renaming a symbol in a single function
> resolved in 0.02s.  Most examples of applying quick fixes and moving
> .hpp inlined member functions to out-of-line in .cpp resolve in similar
> quasi-instantaneous fashion.

That's great, but for such small examples one could almost do without 
advanced interfaces too, couldn't they?

> Now, let me clarify what I meant by "shiny new refactoring interface".
> It's not what you think I meant, I believe. What I meant is a framework
> for:
> 
> 1. collecting 'potential sets of changes' -- for clarity let's call
>     "actions" after LSP nomenclature -- from a number of different
>     backends.  Examples of actions: "rename thing at point", "organize
>     imports", "write as while loops as cl-loop"
> 
> 2. presenting actions names to the user -- either via the minibuffer
>     or by annotating buffer position where these tweaks apply.

These could be split into two:

- A hook which would return the available actions at point. This seems 
to be the primary mode of operations of LSP editors: first you choose 
the location, and then find out which which operations apply to it.

- Some way (possibly also a hook) to find all the "points of interest" 
in a buffer -- these could also be annotated with a lightbulb or etc in 
the margin or fringe. Not sure which place this has when using LSP 
(perhaps some diagnostics with edits attached?), but I vaguely remember 
being suggested lists of refactorings by IDEs I tried in the past (<10 
years ago).

Aside from "renames", which would probably apply almost everywhere 
(though e.g. clangd doesn't know how to rename macros; I wonder at what 
step that we would indicate that to the user).

> 3. after the user chooses an action, develop it into a set of changes
>     -- again, for clarity and consonance with LSP nomenclature, we
>     may call these "edits".

Sure. Possibly carrying more-or-less same information that LSP's edits 
do. Though we could see whether it can be useful to annotate them with 
additional info, e.g. name/type/etc (where we'd deduce that a function 
called X is being renamed, or a file is being moved, or both; which 
could be reflects in the changeset's display more intelligently).

> 4. presenting these edits to the user via a number of different
>     user-confirmation strategies.
> 
> For very common "rename" or "organize imports" actions, steps 1
> and 2 may be coalesced and a special command may be provided that
> goes directly to step 3.  LSP supports these "shortcuts".

Sure. I wouldn't know what position "organize imports" should apply to 
anyway. But to do with backends which don't support it?

> Regarding 4 (which seems to be the current focal point of the
> discussion) Eglot has three main types of confirmation strategies
> available.  See eglot-confirm-server-edits for more.
> 
> * 'diff', which just presents the edits
> * 'summary', which summarizes the edits in the minibuffer and prompts
>    to apply.
> * nil, which means no confirmation at all
> 
> There is also 'maybe-diff' and 'maybe-summary' which behave like
> nil if all the files in the change list are already visited buffers.

Not sure why the cutoff is there: and not for example "if all the 
changes are in the current file", or "are all visible on the screen".

Anyway, the more the merrier, I suppose.

> That said, it's the whole sequence 1 to 4, not just 4, that needs
> to be generalized out of Eglot and into Emacs.  Note that some parts
> of 1..4, like the annotation of actions in buffers or the support for
> file creation and deletion, aren't yet in Eglot, so there's good work
> to be done.  Some of the "annotation" logic already exists in Flymake,
> and Flymake must be taken into the equation too, and early.

The reason for talking about 4 first is twofold:

- I understand 4 better than the rest at this point of time, and it 
could be plugged into some existing bits of functionality already (e.g. 
Eglot's refactorings and Xref/Project names).

- There will likely be two entry points to the new library, just like 
with Xref we have xref-backend-functions and xref-show-xrefs. The former 
depends on the latter. By choosing a good enough data model for step 4 
(e.g. how changes are represented), we can better build requirements for 
step 1, given that whatever hook(s) we add, they would already need to 
be documented with the details about the data in/out flow.

> Also, it would be very good if we could have an early backend which is
> *not* LSP.  An obvious candidate is Elisp.  I'd like to know what is
> the minimal effort to write a lisp function based on the new
> macroexpanding tricks that Stefan Monnier developed that says
> precisely where a given symbol is used as a variable in a function.
> As far as I understand,  these techniques are currently being used for
> accurate completion, but they could maybe be used for accurate
> refactorings.

Xref could easily be an early backend which supports renaming only. 
Eglisp's xref-backend-references could make use of the macroexpanding 
thing to include local variables too.

>> Not to belittle the new addition, though - it's a good step for Eglot.
> 
> As someone who actually uses Eglot daily and is an avid consumer
> of refactoring functionality, my opinion is that the "diff"
> confirmation strategy that Philip proposed and implemented is freaking
> great, even if the implementation is a bit contorted (though mostly
> isolated).
> 
> IMO diff is the lingua franca for communicating changes to source
> code around the world, even in those pretty web interfaces that
> you and many others like.  So it makes full sense to support it
> and to support it well.

I'm okay with diffs myself obviously, and we should keep this UI option 
if feasible, but I'd also prefer to have something more compact 
available, for the "web interface lovers" of the world. Diffs do have 
some barrier to understanding, even we are very much used to them. And 
diff-with-context can be pretty long too.

>> - I would probably want to bind the originally proposed
>> 'diff-apply-everything' to 'C-c C-c' (e.g. "commit the change to disk"),
>> but that's already taken in diff-mode.
> 
>> - 'git diff' has a less-frequently used option called '--word-diff'
>> which could reduce the length of the diff in the case I am testing (but
>> I guess diff-mode would have to be updated to support that output). And
>> another way in that direction would be to reduce the size of the diff
>> context (e.g. to 0).
> 
> I'm not at all opposed to implementing other confirmation strategies
> that look more like what VSCode or other editors show users.  Or
> augmenting the existing 'diff' strategy with new shortcuts and stuff.
> But I wouldn't overthink UI details at this point in the game either.

The first suggestion in particular looked like a modest enough tweak 
that does not depend on the rest of this discussion (and it would likely 
have a diff-specific implementation). But if we try to make it atomic, 
that's an increase in complexity, of course.



  parent reply	other threads:[~2023-09-07 22:39 UTC|newest]

Thread overview: 147+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-19  6:03 Adding refactoring capabilities to Emacs Eli Zaretskii
2023-08-19 10:58 ` Eshel Yaron
2023-08-19 11:18   ` Eli Zaretskii
2023-08-20  1:19 ` Dmitry Gutov
2023-08-20  6:39   ` Eli Zaretskii
2023-08-20  6:42     ` Ihor Radchenko
2023-08-20  8:44   ` Yuri Khan
2023-08-20 22:51     ` Dmitry Gutov
2023-08-29 10:53       ` João Távora
2023-08-29 11:35         ` Dr. Arne Babenhauserheide
2023-08-30  0:52         ` Dmitry Gutov
2023-08-30 18:46           ` Stefan Kangas
2023-08-30 19:59             ` Dmitry Gutov
2023-08-30 20:37           ` João Távora
2023-08-30 21:49             ` Dmitry Gutov
2023-08-30 22:01               ` Stefan Kangas
2023-08-30 22:04                 ` Dmitry Gutov
2023-09-04  6:03                 ` Rudolf Schlatte
2023-09-04 11:04                   ` João Távora
2023-09-04 12:18                     ` Rudolf Schlatte
2023-08-31  5:03               ` Eli Zaretskii
2023-08-31  8:02                 ` João Távora
2023-09-04 15:45                   ` Dmitry Gutov
2023-09-04 23:34                     ` Dmitry Gutov
2023-09-04 17:23               ` Juri Linkov
2023-09-04 17:53                 ` Alfred M. Szmidt
2023-09-05  6:38                   ` Juri Linkov
2023-09-05  7:46                     ` Alfred M. Szmidt
2023-09-04 18:04                 ` Dmitry Gutov
2023-09-05  6:43                   ` Juri Linkov
2023-09-04 20:49                 ` Philip Kaludercic
2023-09-04 17:15   ` Juri Linkov
2023-09-04 18:02     ` Dmitry Gutov
2023-09-05 13:56       ` Alexander Adolf
2023-09-05 14:00         ` Dmitry Gutov
2023-09-06 13:25           ` Alexander Adolf
2023-08-20 13:00 ` sbaugh
2023-09-07 14:39 ` João Távora
2023-09-07 16:20   ` Stefan Monnier
2023-09-07 16:49     ` João Távora
2023-09-07 17:06       ` Stefan Monnier
2023-09-07 17:24         ` João Távora
2023-09-07 17:54           ` Stefan Monnier
2023-09-07 18:12             ` João Távora
2023-09-07 21:56               ` Stefan Monnier
2023-09-07 23:46         ` Lynn Winebarger
2023-09-07 20:41     ` Dmitry Gutov
2023-09-07 22:03       ` Stefan Monnier
2023-09-07 22:43         ` Dmitry Gutov
2023-09-07 22:18     ` João Távora
2023-09-07 22:39       ` Dmitry Gutov
2023-09-08  6:18         ` Eli Zaretskii
2023-09-08 18:25           ` Dmitry Gutov
2023-09-08 18:35             ` João Távora
2023-09-08 18:38               ` Dmitry Gutov
2023-09-08 18:44                 ` João Távora
2023-09-08 19:29                   ` Dmitry Gutov
2023-09-08 18:57               ` Eli Zaretskii
2023-09-08 19:01                 ` João Távora
2023-09-08  6:55         ` João Távora
2023-09-08 15:42           ` Stefan Monnier
2023-09-08 16:05             ` João Távora
2023-09-08 16:20               ` João Távora
2023-09-25 23:11                 ` Dmitry Gutov
2023-09-25 23:32                   ` Dmitry Gutov
2023-09-26  5:36                   ` Alfred M. Szmidt
2023-09-26  8:06                     ` João Távora
2023-09-26 10:57                       ` Dmitry Gutov
2023-09-26 11:24                         ` João Távora
2023-09-26 11:33                           ` Alfred M. Szmidt
2023-09-26 11:34                           ` Dmitry Gutov
2023-09-26 12:57                             ` João Távora
2023-09-26 13:09                               ` Alfred M. Szmidt
2023-09-26 13:52                                 ` Dmitry Gutov
2023-09-26 13:38                           ` Philip Kaludercic
2023-09-26 14:06                             ` João Távora
2023-09-26 14:31                               ` Dmitry Gutov
2023-09-26 14:51                                 ` João Távora
2023-09-26 14:54                                   ` Dmitry Gutov
2023-09-26 15:17                                     ` João Távora
2023-09-26 15:35                                       ` Alfred M. Szmidt
2023-09-26 15:38                                         ` Dmitry Gutov
2023-09-26 15:47                                           ` Alfred M. Szmidt
2023-09-26 16:01                                             ` Dmitry Gutov
2023-09-26 16:10                                               ` Alfred M. Szmidt
2023-09-29 10:55                                                 ` Eli Zaretskii
2023-09-29 12:36                                                   ` Alfred M. Szmidt
2023-09-29 15:32                                                     ` Eli Zaretskii
2023-09-26 16:31                                               ` Yuri Khan
2023-09-26 17:28                                                 ` Dmitry Gutov
2023-09-29 11:10                                                 ` Eli Zaretskii
2023-09-29 10:49                                             ` Eli Zaretskii
2023-09-29 12:36                                               ` Alfred M. Szmidt
2023-09-26 15:01                                 ` [External] : " Drew Adams
2023-09-26 15:22                                   ` Alfred M. Szmidt
2023-09-29 10:36                                     ` Eli Zaretskii
2023-09-29 12:30                                       ` Robert Pluim
2023-09-29 13:11                                         ` Stefan Monnier
2023-09-29 13:13                                           ` Alfred M. Szmidt
2023-09-29 13:16                                           ` João Távora
2023-09-29 13:19                                             ` João Távora
2023-09-29 15:20                                               ` Stefan Monnier
2023-10-01 12:07                                                 ` Stefan Kangas
2023-10-01 18:43                                                   ` Howard Melman
2023-09-29 15:47                                           ` Drew Adams
2023-09-29 15:30                                         ` Eli Zaretskii
2023-09-26 15:27                                   ` Alfred M. Szmidt
2023-09-29 10:40                                     ` Eli Zaretskii
2023-09-29 12:36                                       ` Alfred M. Szmidt
2023-09-29 15:34                                         ` Eli Zaretskii
2023-09-29 15:40                                           ` Alfred M. Szmidt
2023-09-29 16:22                                             ` Eli Zaretskii
2023-09-29 16:32                                               ` Alfred M. Szmidt
2023-09-29 16:51                                                 ` Eli Zaretskii
2023-09-29 17:32                                                   ` Alfred M. Szmidt
2023-09-29 17:56                                                     ` Eli Zaretskii
2023-09-29 18:02                                                   ` Stefan Monnier
2023-09-26 10:55                     ` Dmitry Gutov
2023-09-26 12:03                       ` Alfred M. Szmidt
2023-09-26 12:11                         ` Dmitry Gutov
2023-09-26 12:20                           ` Alfred M. Szmidt
2023-09-29  6:52                           ` Eli Zaretskii
2023-09-29 10:21                             ` Dmitry Gutov
2023-09-29 15:20                               ` Eli Zaretskii
2023-09-29 17:20                                 ` Dmitry Gutov
2023-09-29 17:36                                   ` Eli Zaretskii
2023-09-29 17:44                                     ` Dmitry Gutov
2023-09-08 18:35               ` Dmitry Gutov
     [not found]                 ` <CALDnm52Wtat24JFu=o6m_eJVamub+1H1BxNd5eELQ2j--7OetA@mail.gmail.com>
     [not found]                   ` <da4cb294-39eb-c4a1-a625-da5ee183170c@gutov.dev>
2023-09-08 18:57                     ` João Távora
2023-09-07 19:06   ` Felician Nemeth
2023-09-07 19:19     ` João Távora
2023-09-07 19:25     ` Ihor Radchenko
2023-09-07 19:28       ` Ihor Radchenko
2023-09-07 22:14         ` João Távora
2023-09-07 20:43     ` Dmitry Gutov
2023-09-07 22:39   ` Dmitry Gutov [this message]
2023-09-08 11:10     ` João Távora
2023-09-08 22:35       ` Dmitry Gutov
2023-09-08 23:17         ` João Távora
2023-09-08 12:46   ` Eshel Yaron
2023-09-08 12:52     ` João Távora
2023-09-08 13:18       ` Eshel Yaron
2023-10-01 15:07         ` Extract to new definition (was: Adding refactoring capabilities to Emacs) Eshel Yaron
2023-09-08 13:30       ` [semi off topic] grep-based refactoring [was: Adding refactoring capabilities to Emacs] tomas
2023-09-08 17:53         ` João Távora
2023-09-08 18:24           ` Dmitry Gutov
2023-09-08 18:51             ` tomas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5ddf5fe1-e5c9-2105-5cb8-a96bc8cecc86@gutov.dev \
    --to=dmitry@gutov.dev \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=joaotavora@gmail.com \
    --cc=monnier@iro.umontreal.ca \
    --cc=philipk@posteo.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).