all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Psionic K <psionik@positron.solutions>
To: Emacs developers <emacs-devel@gnu.org>
Subject: Re: Delegating user-reserved key binding space definition to users
Date: Thu, 24 Nov 2022 20:48:04 -0600	[thread overview]
Message-ID: <CADQMGATUUz6pNjQNobgfx+K98zZ_swy_OuJ8-NKVWTZGVOMQDw@mail.gmail.com> (raw)
In-Reply-To: <57b69c22e167d429d21bb969feb22887@webmail.orcon.net.nz>

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

The problem I'm working to reach is allowing packages to correctly shadow
the user's bindings (and not incorrectly shadow) instead of ad-hoc
imitation of the global map defaults.  Ad-hoc imitation makes it very
tedious to, for instance, change the key sequence for expressing "next"
without losing coherence among all packages with a corresponding "next"
concept.

The solution we're discussing is to provide "abstract" commands.  I will
discuss the solution and then discuss what I'm currently working on.

Abstract commands are just command remap targets in the global map.  The
concrete global commands would directly command remap in the global map.
Abstract command bindings would be consumed when modes generate keymaps for
major & minor modes.  A Corfu map generator would for example see an
abstract command like "user-next" bound with the C-n sequence and choose to
shadow C-n in its map.  If the user rebinds the global abstract command,
the other modes could easily follow this change, perhaps even though a hook
to immediately propagate the change.

This scheme would scale much better than imitating global map defaults.
Any user or emulation system desiring to re-bind basic concepts like next
and undo could achieve and maintain coherence.  Such a mechanism should
also make it easier to maintain modes in the future.  Expressing abstract
commands could be a basis for coordinating special mode behavior in ways
that would currently be likely to break with many users' modifications.

I will not introduce a modal system I've worked on, but it has a quirky
notion of next / previous, and yet it will adapt fine to abstract key
bindings.  When switching keyboards to an alternative layout, I lose
physical correspondence.  "J" is a good high-frequency binding unless "J"
is moved to a physically inconvenient location.  Switching abstract maps
and regenerating is a solution for this as well.

Expressing "never shadow this key" would need a distinct map from the
global map.  The problem is that an abstract command like "user-nomap"
would not distinctly map to a concrete command if 20 sequences were to be
protected from shadowing.  There needs to be a global-no-map where all
sequences bound to user-nomap are prohibited by convention.

For generating maps where a binding would collide with an abstract binding,
a configurable successor function could be made available.  It could be set
to nil or return nil to flatly reject all sequence suggestions that were
bad to begin with instead of finding places to place every command.  We
have really good command completions these days, so personally I would opt
for a nil successor.

Abstract key definition would be adopted by first providing map generators
for many modes (similar to Evil collection) and then expecting those map
generators to migrate out to the modes themselves if the abstract map
support were to be adopted into Emacs itself.

Regarding where I'm starting out:

I'm working on a more modest and immediate goal of depopulating unwanted
bindings, focusing on overly complex or high-priority bindings first.  I
will define my future abstract keys implementation in the same package.
While users in the future should not have to battle with so many bindings
in the many mode maps, for now it will be appropriate to generate
mass-unbind statements for packages like general to consume.

I'm using a report-and-configure workflow.  This is the lowest effort
implementation to identify "bad" bindings and provide a fast remedy to the
user.  While I can see many maps in for example minor-mode-map-alist, I was
unsure of where to find a list of major modes except from inferring while
using mapatoms.  I could notice the cost of calling this to find major
modes / maps.

State tracking is necessary to differentiate user defined bindings from
defaults.  While I had not wanted to add the complexity, inheriting keymaps
may provide an elegant solution.  My hunch is to first destructively clean
out default maps and then define inheriting maps and swap the inheriting
maps into the keymap variables.  If the user adds bindings afterward, it's
almost clearly visible.  Is there a way I could add a sentinel to an
inherited map to indicate that I've cleaned the parent map already?  What
are some good choices for list elements of no consequence?  This would also
tell me that the child was created for the user.  I don't want to implement
package-private state tracking if possible.

I have no ambition to work with non-list maps at this time.  So far every
map I want to work with is just a plain list.

While working on my implementation, I have encountered the kinds of issue
that make me believe that alternatives such as key-sequence translation are
also not scalable.  (key-binding "\M-g") is incorrect after remapping M-g
to C-g unless I collect a key sequence interactively.   Keeping this kind
of indirection around has consequences.  I believe key sequence remapping
is a solution more aimed at misbehaving input systems where correct
bindings cannot accommodate the situation.

On Mon, Nov 21, 2022 at 8:07 PM Phil Sainty <psainty@orcon.net.nz> wrote:

> AFAIK...
>
> You can't arbitrarily prevent key sequences from being bound in
> keymaps, because you can't control how or when that happens.
>
> You can't control when it happens because that time might be "before
> you started (or even installed) Emacs".  Keymaps are sometimes
> generated at byte-compilation time, and thus even if you were to take
> the extreme measure of preventing define-key from doing anything at
> all, you will still acquire populated keymaps when certain libraries
> are loaded (although if the libraries were byte-compiled while the
> neutralised define-key was in place, you would then typically be
> loading empty keymaps; but you would need to recompile everything to
> get to that point; and of course most installations of Emacs will
> include pre-compiled .elc files).
>
> Native compilation might preclude even that, as IIRC it compiles
> everything asynchronously in isolation, so the intended clobbering
> of define-key might not actually be in effect when the native code
> was being generated.  You would then have to edit the core code to
> enforce your override irrespective of whether your custom code was
> loaded.
>
> You can't control how it happens because libraries can set bindings
> without using define-key.  In the simplest case `use-local-map' for
> one of the aforementioned pre-generated keymaps may easily occur; but
> also a keymap is, after all, just a list, so it can be manipulated in
> any number of ways.
>
> (In practice I think that messing with define-key and recompiling All
> Of The Things would affect almost all keymaps; but in general there's
> no guarantee.)
>
> I would suggest that your best option is to instead ensure that the
> key lookup sequence always finds your preferred bindings.  Despite
> your concerns about that approach, it seems more viable to me.
>
>

-- 

Psionic K <psionik@positron.solutions>
Software Engineer

*Positron Solutions <https://positron.solutions>*

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

  reply	other threads:[~2022-11-25  2:48 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-21 14:40 Delegating user-reserved key binding space definition to users Psionic K
2022-11-21 19:37 ` Stefan Monnier
2022-11-22  2:07   ` Phil Sainty
2022-11-25  2:48     ` Psionic K [this message]
2022-11-25  3:31       ` Ihor Radchenko
2022-11-25 13:53         ` xenodasein--- via Emacs development discussions.
2022-11-25 15:16       ` Stefan Monnier
2022-11-26  6:44         ` Ihor Radchenko
2022-11-26 17:29           ` Stefan Monnier
2022-11-27  5:45             ` Ihor Radchenko
2022-11-27 11:26               ` Psionic K
2022-11-27 11:53                 ` Psionic K
2022-11-28 18:15               ` Stefan Monnier
2022-11-28 18:37                 ` Eli Zaretskii
2022-11-29  2:38                 ` Psionic K
2022-11-29  4:01                   ` Stefan Monnier
2022-11-29  5:22                     ` Psionic K
2022-11-29 13:03                       ` Eli Zaretskii
2022-11-30  6:23                         ` Psionic K
2022-11-30  9:01                           ` xenodasein--- via Emacs development discussions.
2022-11-30 13:44                           ` Eli Zaretskii
2022-11-29 11:54                 ` John Yates

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

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

  git send-email \
    --in-reply-to=CADQMGATUUz6pNjQNobgfx+K98zZ_swy_OuJ8-NKVWTZGVOMQDw@mail.gmail.com \
    --to=psionik@positron.solutions \
    --cc=emacs-devel@gnu.org \
    /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 external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.