unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Performing an operation on any other key press
@ 2024-03-24 20:32 Aaron Jensen
  0 siblings, 0 replies; only message in thread
From: Aaron Jensen @ 2024-03-24 20:32 UTC (permalink / raw)
  To: Emacs developers

[-- Attachment #1: Type: text/plain, Size: 4041 bytes --]

Hi,

This topic may be more appropriate for the users list, but it involves a
technique used in a few Emacs core packages, so I thought this would be the
best place to discuss it.

First, some context. I use both Evil and a package called Corfu. Corfu is
similar to company-mode in that it is an implementation of auto-complete.
Evil has a function called evil-repeat that enables recording sequences of
commands and then replaying them, usually with the "." key. Doing this
requires a fair bit of machinery that may very well be hacks, as you can
imagine. One of the things that it does is it requires commands to be
associated with a strategy for recording the outcome of that command. There
are a few strategies, but the primary ones that concern this question are
the strategy that records the key sequence and the strategy that records
buffer changes during the evaluation of the command.

For example, self-insert may record just the key sequence, as replaying it
will be deterministic. Another, more sophisticated command (perhaps one
that requires user input from the minibuffer) may record buffer changes
instead so that replaying can be deterministic.

If that's not clear, please let me know. I know that not everyone here is
familiar with how evil and evil-repeat work.

Next, we have Corfu, which has a capability where-in it displays the
highlighted completion in the buffer before that completion is truly
selected. One of the strategies it implements is, in company, called
company-tng (tab and go), where in once that completion is displayed,
pressing any key other than a key in corfu's map will cause the completion
to be inserted into the buffer (rather than just being displayed as an
overlay) and then the key that was pressed will do whatever it typically
does. Imagine that key was a ";". In that case, the completion would
complete and there would be a ; inserted.

Corfu does this by adding a pre-command hook. If the corfu menu is
displayed, and there is a selection, then that selection is inserted.
That's the gist of what the pre-command hook does as far as I know.

The problem comes in when both evil-repeat and Corfu are combined. In that
case, because Corfu modifies the buffer during a command in a way that is
not repeatable, that specific command would need to be recorded by
evil-repeat as "change", but if it is the default keypress recording, it
won't be.

This means that the repeat will only play the keypresses, and not include
the text that Corfu inserted.

As far as I know, it wouldn't be a good idea to change evil-repeat to
ensure that everything is recorded with the "change" strategy just to
support Corfu.

The only thing so far that I have found that works is, within
Corfu's pre-command hook, to override this-command to a command that is
configured to the "change" strategy, and then copy this-command-keys to the
head of unread-command-events (or, effectively, unread the command keys).
As far as I can tell, this technique is used in a few places within Emacs
(isearch and electric-buffer-menu at least).

My question is, is there any other way to ensure that Corfu can insert its
text under the guise of a corfu command and not impact the next command
such that evil-repeat (or something like it) can work. Unreading commands
seems like a bit of a hack, and the author of Corfu is understandably not
interested in implementing that except as a last resort.

It's been mentioned that using menu-items could help, but I fail to see how
a conditional menu item could do the thing I'm describing, and it seems
like adding side effects in a menu item filter is an even more egregious
hack than unreading a command and allowing the command loop to process it
anew.

I'd love to understand if there's a better way that evil-repeat could do
its job as well. Any and all ideas are welcome.

Here's some additional context if interested:

https://github.com/emacs-evil/evil-collection/pull/798
https://github.com/minad/corfu/pull/169
https://github.com/minad/corfu/pull/225

Thank you,


Aaron

[-- Attachment #2: Type: text/html, Size: 5338 bytes --]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-03-24 20:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-24 20:32 Performing an operation on any other key press Aaron Jensen

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).