From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Psionic K Newsgroups: gmane.emacs.devel Subject: Re: Delegating user-reserved key binding space definition to users Date: Mon, 28 Nov 2022 23:22:24 -0600 Message-ID: References: <57b69c22e167d429d21bb969feb22887@webmail.orcon.net.nz> <877czikyfa.fsf@localhost> <87o7sthrwx.fsf@localhost> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="00000000000000b34f05ee952d42" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="11167"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Ihor Radchenko , Emacs developers To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Tue Nov 29 06:24:01 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ozt68-0002fT-1L for ged-emacs-devel@m.gmane-mx.org; Tue, 29 Nov 2022 06:24:00 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ozt53-0000Mg-PG; Tue, 29 Nov 2022 00:22:53 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ozt4z-0000MK-VD for emacs-devel@gnu.org; Tue, 29 Nov 2022 00:22:51 -0500 Original-Received: from mail-pf1-x432.google.com ([2607:f8b0:4864:20::432]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ozt4o-0004wT-4v for emacs-devel@gnu.org; Tue, 29 Nov 2022 00:22:49 -0500 Original-Received: by mail-pf1-x432.google.com with SMTP id q12so8553408pfn.10 for ; Mon, 28 Nov 2022 21:22:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=positron.solutions; s=google; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=iFxI7kUkhV+u0YDrv3at7Hu/a2BTQ7dk3ckX6uSkwPQ=; b=jP95/26Wz74zC7ITE2MZIPY8SMnzhE6Lh6b8YeZcV/QoyYh15v/NP7f60+irhWYti0 ccIw4uBVZ+FaW7zRPufugggVP1gd9JanWkM5xLRDhJWccNQOLHIZmbscQch9VtoQF2Xc APTXY9fsnYFGqArNREGeyKxP5p7Zczaj2gdEUVuMc8SfQoOXG++Lm+KwaB+dOljkSiJI CC+hW88eFRJmFu0nlJeXPGWoc77SUOQiibsy+X8Aqs+zpn16dAlCzidVGvQM5oeGxi3K eESXMmk75Qhz84EBXHjbtlN/q+CqhGcNEX6CPN4UexKPu1wWIjbP1aA+0+nbywRy+yWZ 00KQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=iFxI7kUkhV+u0YDrv3at7Hu/a2BTQ7dk3ckX6uSkwPQ=; b=FtRRgTYB1pxzsDbmjP4ruvE5PSJNpaqskyPRfN87R8X0Ib/ANvFNRbyt4ObnGy5x3H uAFip25q2QbTFnRysTMEOexO8qdf6wSDd7BGeWrPmtNqs6/pw1WEKgTcYWvePBj7d011 nDkSnnfQVr1Ghyuw5k+e8LvlcyRid20BlAsw48VuHU33dhnWLXaTiLrqoHBmAvJINNcd jIZBYW1Idp+S64WcfuZUw1lH1EK2PxVqyRvn5LGMTSCsijVqaKMOpQG/hAACknxMEztF CAPd/xor+49e+h/avILDc1pVwv3uqcEr9T7DpNpo7IGVShSwfBKOqknP3UmisIMYo/XC a/Dg== X-Gm-Message-State: ANoB5pmbRD+fY7d8CkcGL4slLo57lt6VtL67rZ0FT05GQibyVwt9DVAe JiyQzpoD6gi8uIasV2V0V3vX7VRaHdjWWLLjTKP5Yg== X-Google-Smtp-Source: AA0mqf4BVDNOdvDHExMDOmWnJQlAs+E8HHl2Gaizf8l7GSBhzZBrkfasvtM1X0LvT9rOch0I6jJKMLJXLJLrUxjaGqM= X-Received: by 2002:a63:580a:0:b0:477:12e3:6e1c with SMTP id m10-20020a63580a000000b0047712e36e1cmr33036897pgb.126.1669699356105; Mon, 28 Nov 2022 21:22:36 -0800 (PST) In-Reply-To: Received-SPF: pass client-ip=2607:f8b0:4864:20::432; envelope-from=exec@positron.solutions; helo=mail-pf1-x432.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:300699 Archived-At: --00000000000000b34f05ee952d42 Content-Type: text/plain; charset="UTF-8" > Can you try and make it more > concrete with an example? ;; The user will specify concept / abstract commands -> key sequences (setq-custom concept-sequences '((user-next ?\M-n) (user-prev ?\M-p))) ;; The package will specify concepts / abstract commands -> concrete commands ;; So, something like a magit section mode intended to be derived from, the package author writes: (setq-local concept-commands '((user-next #'magit-section-next) (user-prev #'magit-section-prev))) ;; And then the package tells the implementation to consume the declarations, which might occur after the mode hook to let the user intervene (emacs-function-setup-concept-keymap) `emacs-function-setup-concept-keymap' would be an implementation that ties the user's declaration of sequence -> concept mappings together with the package's concept -> command mappings. The result is that the local map should contain some command remap shadows corresponding to what the user and the package declared. I neglected overloading in my example, but basically a user might be okay with several concepts being able to map to one key and the package might be okay with mapping the same command to one of several concepts. IMO these declarations one-to-many declarations should only be used with two specific conventions: 1. Package authors specify a list of increasingly more generic concepts, ending with `user-generic' which would just mean "any key that the user has bestowed upon packages by default.". An example of more abstract definitions would be a declaration like (#'magit-section-next (user-next user-navigation)). The implementation could try to map to user-next and if that's not available, use an available sequence from user-navigation. 2. The user's convention for one-to-many mappings is different. They might want to map a generic concept onto several key sequences in order, so they might declare something like '(user-navigation (?\M-p ?\M-n ?\M-f ?\M-b)). If a package declares a user-next, user-prev, and two more user-navigation commands, the implementation will give them all keymap elements. > I get the impression that your > SOME-INFO includes info for several commands. Yes. The reason commands should not handle this declaration is because the implementation would have to discover the commands, and this would be fragile if the user starts replacing commands or wants to specify commands that the package has no idea about. I'm also preoccupied with automating the user-driven re-mapping of commands to key sequences when those commands express an extremely similar idea, such as "next". I see this as a prerequisite for what I think you want. I don't think I agree with what I think you want, and this could be messing with my interpretation, but it is a prerequisite still. We have lots of convention, lots of similarity in mode keymaps, but we it's ad-hoc, and we just need to make it official so that the conventions are useful and user's can change one declaration to move, for example, C-g. > It should likely > include also some notion of scope (global, buffer-local, local to > a region, specific to some particular set of major mode, only > meaningful when the region is active, ...) The purpose of an abstract key mapping scheme is to allow the user to coherently move a binding whenever that binding expresses the same idea in several modes. Complex, highly configurable declarations would actually make the situation worse, requiring more user effort to accomplish the move. There are already tools available for handling 1:1 edge cases, one declaration at a time. Many commands that need such configurability tweak their behavior based on the call context or some state. We don't need new infrastructure for specifying a large number of edge cases. Such schemes become baked into modal systems like Evil. > Emacs passes that to a "procedural keymap" which will > *compute* (rather than lookup) which command to run, according to the > current keybinding style. This kind of dynamic dispatch is not actually necessary because commands already can decide to do something differently. A command can wrap several commands. Commands can react to variables. Commands can inspect their context. The big reason we want this dynamic dispatch style behavior encoded into commands themselves is because it plays well with the notion of mapping commands and sequences. Where-is doesn't work well with dynamic maps like transient. Users can't declare keys succinctly if they are supposed to make their declarations aware of state that the commands should instead know in their body. An implementation for generating the concrete bindings would be much more complex if it had to know about information that should be internal to the command. Package authors can always create the most power for users by having a good data model and good functions with which users can construct their own commands. No matter how dynamic dispatch declarations are done, they are going to be harder to understand and implement than simply re-writing new command bodies. Even writing schemes for evil, which only has to support one implementation, makes some gnarly looking declarations. The temptation to add power will harm the poor user with the humble goal to coherently move C-n to M-n in modes where it makes obvious sense because their pinky hurts. On Mon, Nov 28, 2022 at 10:01 PM Stefan Monnier wrote: > >> a solution should allow packages to declare that command FOO > >> should be bound to some key based on SOME-INFO, such that it will be > >> bound to one key in "normal Emacs mode", and to another in `evil-mode` > >> and to yet another in `god-mode`, etc... > > > > SOME-INFO will be of the form: > > ((concept command) (concept command) ...)) ; package provide > > ((concept (concept concept concept)) (concept concept)) ; overload > > remappings, perhaps user or package provided or both > > ((concept binding) (concept binding)) ; user or emulation mode etc > provided > > I'm afraid I don't know what this means. Can you try and make it more > concrete with an example? > > Note that in the text I wrote, SOME-INFO was supposed to be a piece of > information specific to the command FOO. I get the impression that your > SOME-INFO includes info for several commands. Maybe we'll have to do > that, but I was hoping we could avoid it. > > > In the beginning, before packages provide their half, the user will > provide > > it, likely through a package. This is analogous to evil collection. > > I don't want SOME-INFO to explicitly say what should happen for > `evil-mode`, vanilla Emacs mode, `god-mode`, `boon-mode`, > `ergoemacs-mode`, modalka, ... > This is the mess we already have. > > Instead SOME-INFO should give just enough data to those modes such that > they can wisely (and predictably) choose a binding for that command. > > >> To me a solution should allow packages to declare that command FOO > >> should be bound to some key based on SOME-INFO, such that it will be > >> bound to one key in "normal Emacs mode", and to another in `evil-mode` > >> and to yet another in `god-mode`, etc... > > > > This places too much emphasis on package authors. > > I hope with my above explanation you can agree that it also gives a lot > of power to the keybinding styles. And of course, ultimately the > end-user can override any of those decisions (this is Emacs we're > talking about, after all). > > > As stated above, I believe it's the job of modal systems to > > decide how to consume the package-defined half of SOME-INFO. > > IIUC we violently agree. > > I personally don't yet have a clear idea of what SOME-INFO may look > like. I suspect it could include some letters (used as hints to help > the keybinding-style choose keys) plus a set of "features" maybe (like > forward/up/down/backward for direction, or add/remove, or > char/word/symbol/sexp/buffer for granularity/subject). It should likely > include also some notion of scope (global, buffer-local, local to > a region, specific to some particular set of major mode, only > meaningful when the region is active, ...). > > > Stefan > > -- Psionic K Software Engineer *Positron Solutions * --00000000000000b34f05ee952d42 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
> Can you try and make it more
> concre= te with an example?

;; The user will specify concept / ab= stract commands -> key sequences
(setq-custom concept-sequ= ences '((user-next ?\M-n) (user-prev ?\M-p)))
;; The pack= age will specify concepts / abstract commands -> concrete commands
;; So, something like a magit section mode intended to be derived = from, the package author writes:
(setq-local concept-commands = 9;((user-next #'magit-section-next) (user-prev #'magit-section-prev= )))
;; And then the package tells the implementation to consume t= he declarations, which might occur after the mode hook to let the user inte= rvene
(emacs-function-setup-concept-keymap)

`emacs-function-setup-concept-keymap' would be an implementation that = ties the user's declaration of sequence -> concept mappings together= with the package's concept -> command mappings.=C2=A0 The result is= that the local map should contain some command remap shadows corresponding= to what the user and the package declared.

I neglected o= verloading in my example, but basically a user might be okay with several c= oncepts being able to map to one key and the package might be okay with map= ping the same command to one of several concepts.

IMO the= se declarations one-to-many declarations should only be used with two speci= fic conventions:=C2=A0
  1. Package authors specify a list of increa= singly more generic concepts, ending with `user-generic' which would ju= st mean "any key that the user has bestowed upon packages by default.&= quot;.=C2=A0 An example of more abstract definitions would be a declaration= like (#'magit-section-next (user-next user-navigation)).=C2=A0=C2=A0 T= he implementation could try to map to user-next and if that's not avail= able, use an available sequence from user-navigation.
  2. The user'= s convention for one-to-many mappings is different.=C2=A0 They might want t= o map a generic concept onto several key sequences in order, so they might = declare something like '(user-navigation (?\M-p ?\M-n ?\M-f ?\M-b)).=C2= =A0 If a package declares a user-next, user-prev, and two more user-navigat= ion commands, the implementation will give them all keymap elements.
> I get the impression that your
> SOME-INFO in= cludes info for several commands.

Yes.=C2=A0 The reason comman= ds should not handle this declaration is because the=20 implementation would have to discover the commands, and this would be=20 fragile if the user starts replacing commands or wants to specify=20 commands that the package has no idea about.

I'm also preoccupie= d with automating the user-driven re-mapping of commands to key sequences w= hen those commands express an extremely similar idea, such as "next&qu= ot;.=C2=A0 I see this as a prerequisite for what I think you want.=C2=A0 I = don't think I agree with what I think you want, and this could be messi= ng with my interpretation, but it is a prerequisite still.

We have lots of convention, lots of similarity in mode keymaps, but we it= 's ad-hoc, and we just need to make it official so that the conventions= are useful and user's can change one declaration to move, for example,= C-g.

> It should likely
> include also some notion of scop= e (global, buffer-local, local to
> a region, specific to some particular set of major mode, only
> = meaningful when the region is active, ...)

The= purpose of an abstract key mapping scheme is to allow the user to coherent= ly move a binding whenever that binding expresses the same idea in several = modes.=C2=A0 Complex, highly configurable declarations would actually make = the situation worse, requiring more user effort to accomplish the move.=C2= =A0 There are already tools available for handling 1:1 edge cases, one decl= aration at a time.=C2=A0 Many commands that need such configurability tweak= their behavior based on the call context or some state.=C2=A0 We don't= need new infrastructure for specifying a large number of edge cases.=C2=A0= Such schemes become baked into modal systems like Evil.

> Emacs = passes that to a "procedural keymap" which will
> =C2=A0 *c= ompute* (rather than lookup) which command to run, according to the
> =C2=A0 current keybinding style.

This kind of dynami= c dispatch is not actually necessary because commands already can decide to= do something differently.=C2=A0 A command can wrap several commands.=C2=A0= Commands can react to variables.=C2=A0 Commands can inspect their context.= =C2=A0 The big reason we want this dynamic dispatch style behavior encoded = into commands themselves is because it plays well with the notion of mappin= g commands and sequences.=C2=A0 Where-is doesn't work well with dynamic= maps like transient.=C2=A0 Users can't declare keys succinctly if they= are supposed to make their declarations aware of state that the commands s= hould instead know in their body.=C2=A0 An implementation for generating th= e concrete bindings would be much more complex if it had to know about info= rmation that should be internal to the command.

Package a= uthors can always create the most power for users by having a good data mod= el and good functions with which users can construct their own commands.=C2= =A0 No matter how dynamic dispatch declarations are done, they are going to= be harder to understand and implement than simply re-writing new command b= odies.=C2=A0 Even writing schemes for evil, which only has to support one i= mplementation, makes some gnarly looking declarations.

Th= e temptation to add power will harm the poor user with the humble goal to c= oherently move C-n to M-n in modes where it makes obvious sense because the= ir pinky hurts.

On Mon, Nov 28, 2022 at 10:01 PM Stefan Monnier &l= t;monnier@iro.umontreal.ca&= gt; wrote:
>&= gt; a solution should allow packages to declare that command FOO
>> should be bound to some key based on SOME-INFO, such that it will = be
>> bound to one key in "normal Emacs mode", and to another = in `evil-mode`
>> and to yet another in `god-mode`, etc...
>
> SOME-INFO will be of the form:
> ((concept command) (concept command) ...)) ; package provide
> ((concept (concept concept concept)) (concept concept)) ; overload
> remappings, perhaps user or package provided or both
> ((concept binding) (concept binding)) ; user or emulation mode etc pro= vided

I'm afraid I don't know what this means.=C2=A0 Can you try and make= it more
concrete with an example?

Note that in the text I wrote, SOME-INFO was supposed to be a piece of
information specific to the command FOO.=C2=A0 I get the impression that yo= ur
SOME-INFO includes info for several commands.=C2=A0 Maybe we'll have to= do
that, but I was hoping we could avoid it.

> In the beginning, before packages provide their half, the user will pr= ovide
> it, likely through a package.=C2=A0 This is analogous to evil collecti= on.

I don't want SOME-INFO to explicitly say what should happen for
`evil-mode`, vanilla Emacs mode, `god-mode`, `boon-mode`,
`ergoemacs-mode`, modalka, ...
This is the mess we already have.

Instead SOME-INFO should give just enough data to those modes such that
they can wisely (and predictably) choose a binding for that command.

>> To me a solution should allow packages to declare that command FOO=
>> should be bound to some key based on SOME-INFO, such that it will = be
>> bound to one key in "normal Emacs mode", and to another = in `evil-mode`
>> and to yet another in `god-mode`, etc...
>
> This places too much emphasis on package authors.

I hope with my above explanation you can agree that it also gives a lot
of power to the keybinding styles.=C2=A0 And of course, ultimately the
end-user can override any of those decisions (this is Emacs we're
talking about, after all).

> As stated above, I believe it's the job of modal systems to
> decide how to consume the package-defined half of SOME-INFO.

IIUC we violently agree.

I personally don't yet have a clear idea of what SOME-INFO may look
like.=C2=A0 I suspect it could include some letters (used as hints to help<= br> the keybinding-style choose keys) plus a set of "features" maybe = (like
forward/up/down/backward for direction, or add/remove, or
char/word/symbol/sexp/buffer for granularity/subject).=C2=A0 It should like= ly
include also some notion of scope (global, buffer-local, local to
a region, specific to some particular set of major mode, only
meaningful when the region is active, ...).


=C2=A0 =C2=A0 =C2=A0 =C2=A0 Stefan



--

Software Engineer
<= /div>
--00000000000000b34f05ee952d42--