unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Delegating user-reserved key binding space definition to users
@ 2022-11-21 14:40 Psionic K
  2022-11-21 19:37 ` Stefan Monnier
  0 siblings, 1 reply; 22+ messages in thread
From: Psionic K @ 2022-11-21 14:40 UTC (permalink / raw)
  To: Emacs developers

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

The purpose of this email is to identify if a package should be created or
if the technical implementation requires modification to Emacs.

The motivating problem was to eliminate the possibility of Emacs defaults
or packages creating many bindings sequences in two primary categories:

   - Multiple modifiers such as M-S-* or long sequences such as C-* C-* *.
   M-? is also an example of what I consider to require multiple-modifiers on
   a US key layout where '?' requires shift.
   - High-value space such as M-* and C-*

In order to enforce this choice, the user needs control over the effects of
all calls to create bindings, from an early phase and then persistently
through startup and future package loading.  The user needs a way to
express, in the same dimensions as the implementation, which keys should
receive no-op bindings if not explicitly created by the user.  A
complementary set of functions should allow the user to then make bindings
into the protected keyspace, free from any potential interference.

I was asked to relay my opinion that Emacs should ship with bindings not
much more densely populated than nano.  Nano does not have commands, so
Emacs needs M-x, for example.

It was suggested that advice might work for implementation, up to a point,
since define-key doesn't have a dedicated code of some type I'm unaware of.

The suggestion was made to live with emulation mode maps or even terminal
overriding maps.  I have two concerns about this technically.  Such a
solution provides no consultative feedback, a blind solution.  Second, it
doesn't help users who are already leaning on such maps for modal editing.

My personal preference is to find a path to a mostly complete
implementation as an independent package in order to figure out the problem
better, gaining the breadth of information necessary through incremental
adoption.

I am intending to explore a simple advice of define-key.  My implementation
will no-op any request to bind a command to a key sequence that doesn't
pass a predicate list.  Optionally a report will be stored about which
command bindings were no-op'd and by which filter predicate.  Support for
command and key translation inside of predicates would be my next feature.

If there are multiple key mechanisms I need to intercept, an enumeration of
them will be greatly appreciated.

-- 

Psionic K <psionik@positron.solutions>
Software Engineer

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

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  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
  0 siblings, 1 reply; 22+ messages in thread
From: Stefan Monnier @ 2022-11-21 19:37 UTC (permalink / raw)
  To: Psionic K; +Cc: Emacs developers

>    - Multiple modifiers such as M-S-* or long sequences such as C-* C-* *.
>    M-? is also an example of what I consider to require multiple-modifiers on
>    a US key layout where '?' requires shift.
>    - High-value space such as M-* and C-*
[...]
> It was suggested that advice might work for implementation, up to a point,
> since define-key doesn't have a dedicated code of some type I'm unaware of.

Doing it inside `define-key` is problematic because you can bind a key
to `C-a C-b C-c` via three calls to `define-key`, so you won't be able
to detect the problem reliably in all cases:

    (let* ((map1 (make-sparse-keymap))
           (map2 (make-sparse-keymap))
           (map3 (make-sparse-keymap)))
      (define-key map1 [?\C-a] map2)
      (define-key map2 [?\C-b] map3)
      (define-key map3 [?\C-c] 'foo))


-- Stefan




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-21 19:37 ` Stefan Monnier
@ 2022-11-22  2:07   ` Phil Sainty
  2022-11-25  2:48     ` Psionic K
  0 siblings, 1 reply; 22+ messages in thread
From: Phil Sainty @ 2022-11-22  2:07 UTC (permalink / raw)
  To: Psionic K; +Cc: Emacs developers

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.




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-22  2:07   ` Phil Sainty
@ 2022-11-25  2:48     ` Psionic K
  2022-11-25  3:31       ` Ihor Radchenko
  2022-11-25 15:16       ` Stefan Monnier
  0 siblings, 2 replies; 22+ messages in thread
From: Psionic K @ 2022-11-25  2:48 UTC (permalink / raw)
  To: Emacs developers

[-- 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 --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-25  2:48     ` Psionic K
@ 2022-11-25  3:31       ` Ihor Radchenko
  2022-11-25 13:53         ` xenodasein--- via Emacs development discussions.
  2022-11-25 15:16       ` Stefan Monnier
  1 sibling, 1 reply; 22+ messages in thread
From: Ihor Radchenko @ 2022-11-25  3:31 UTC (permalink / raw)
  To: Psionic K; +Cc: Emacs developers

Psionic K <psionik@positron.solutions> writes:

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

+1

Anyone who tried to re-bind default bindings for, say, C-n/C-p/n/p might
be familiar what the problem with current Emacs approach is. It is very
annoying to keep tweaking every single package bindings out there and
also deal with cascading key collisions.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-25  3:31       ` Ihor Radchenko
@ 2022-11-25 13:53         ` xenodasein--- via Emacs development discussions.
  0 siblings, 0 replies; 22+ messages in thread
From: xenodasein--- via Emacs development discussions. @ 2022-11-25 13:53 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Psionic K, Emacs developers

Nov 25, 2022, 03:31 by yantar92@posteo.net:

> Psionic K <psionik@positron.solutions> writes:
>
>> 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.
>>
>
> +1
>
> Anyone who tried to re-bind default bindings for, say, C-n/C-p/n/p might
> be familiar what the problem with current Emacs approach is. It is very
> annoying to keep tweaking every single package bindings out there and
> also deal with cascading key collisions.
>
> -- 
> Ihor Radchenko // yantar92,
> Org mode contributor,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <> https://liberapay.com/yantar92> >
>

Easy to configure key bindings?  Ugh who needs that, the bindings are
already perfect.  Emacs -Q is the supreme experience created in the
vein as a physics experiment colliding as many things as possible, so
everything has to be optimized for it's out of box magnificence!




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-25  2:48     ` Psionic K
  2022-11-25  3:31       ` Ihor Radchenko
@ 2022-11-25 15:16       ` Stefan Monnier
  2022-11-26  6:44         ` Ihor Radchenko
  1 sibling, 1 reply; 22+ messages in thread
From: Stefan Monnier @ 2022-11-25 15:16 UTC (permalink / raw)
  To: Psionic K; +Cc: Emacs developers

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

I don't think anyone doubts that it's desirable.
The question is how to get that.


        Stefan




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-25 15:16       ` Stefan Monnier
@ 2022-11-26  6:44         ` Ihor Radchenko
  2022-11-26 17:29           ` Stefan Monnier
  0 siblings, 1 reply; 22+ messages in thread
From: Ihor Radchenko @ 2022-11-26  6:44 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Psionic K, Emacs developers

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> 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.
>
> I don't think anyone doubts that it's desirable.
> The question is how to get that.

I suggest introducing a notion of "generalized" commands. Such commands
will represent common actions executed by users (like move to
next/previous element). Major and minor modes can then define specific
implementation of the actions.

In terms of OOP, I am talking about virtual methods and major/minor modes
providing the implementations. The implementations will be chosen
according to the current major mode or maybe some other condition.
Default implementation (like `next-line') can also be provided.

The generalized commands can then be freely re-bound by users with
immediate effect on all the major modes.

An example (not very clean) implementation of this concept is available
at
https://github.com/yantar92/meta-functions/blob/master/meta-functions.el:

; Quick implementation of meta-functions, which allows running multiple
;; functions, which do similar logical operations by one single "meta"
;; function in different major modes. For example, one may want to define
;; meta-next-line to call `next-line' normally, but
;; `org-agenda-next-line' in org-agenda mode. Both can be bound to, say
;; "M-j", without a need to change the key-bindings on both fundamental
;; and org-agenda modes.
;; Example usage:
;; (use-package meta-functions
;;   :config
;; (meta-defun meta-next-element ()
;;   "Go to next element."
;;   :mode org-agenda-mode (org-agenda-next-item 1) ; call org-agenda-next-item in org-agenda
;;   :cond (lambda () (and (eq major-mode 'org-mode) (org-at-heading-p))) (org-next-visible-heading 1) ; call org-next-visible-headting when at heading in org-mode
;;   (next-line)) ; call-next line in any other case
;; )
;; or the same can be written as
;; (meta-defun meta-next-element "Go to next element." next-line)
;; (meta-defun meta-next-element :mode org-agenda-mode (org-agenda-next-item 1))
;; (meta-defun meta-next-element :mode org-mode :cond org-at-heading-p (org-next-visible-heading 1))
;;
;; Similar packages:
;; https://gitlab.com/jjzmajic/handle implements similar functionality to unify functions across major modes
;; However, handle is very major-mode centric. meta-functions is more function-centric
;; Also, meta-functions is not only limited to current major mode defining which function to call.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-26  6:44         ` Ihor Radchenko
@ 2022-11-26 17:29           ` Stefan Monnier
  2022-11-27  5:45             ` Ihor Radchenko
  0 siblings, 1 reply; 22+ messages in thread
From: Stefan Monnier @ 2022-11-26 17:29 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Psionic K, Emacs developers

> I suggest introducing a notion of "generalized" commands. Such commands
> will represent common actions executed by users (like move to
> next/previous element). Major and minor modes can then define specific
> implementation of the actions.

I think it's a non-starter because it requires foresight: only those
commands defined with this mechanism will be extensible.  I agree that
an additional level of indirection is probably necessary, but I suspect
it needs to be placed elsewhere.

[ FWIW, you can get similar results with the current setup using
  command remapping.  ]


        Stefan




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-26 17:29           ` Stefan Monnier
@ 2022-11-27  5:45             ` Ihor Radchenko
  2022-11-27 11:26               ` Psionic K
  2022-11-28 18:15               ` Stefan Monnier
  0 siblings, 2 replies; 22+ messages in thread
From: Ihor Radchenko @ 2022-11-27  5:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Psionic K, Emacs developers

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> I suggest introducing a notion of "generalized" commands. Such commands
>> will represent common actions executed by users (like move to
>> next/previous element). Major and minor modes can then define specific
>> implementation of the actions.
>
> I think it's a non-starter because it requires foresight: only those
> commands defined with this mechanism will be extensible.  I agree that
> an additional level of indirection is probably necessary, but I suspect
> it needs to be placed elsewhere.

Auto-remapping will need some kind of grouping for commands one way or
another. There is no way we can do it auto-magically. Developer or users
should decide.

Currently, the commands in major mods are bound to specific key
bindings. The bindings are chosen either arbitrarily, according to major
mode author preferences, or according to semi-established default key
binding scheme (like C-f/C-M-f/C-n/C-v/etc). Either way, trying to
re-bind commands in multiple major modes is not easy.

Note that a number of commands like `comment-forward' already expect
major modes to fit into an established, pre-defined framework by
tweaking the `comment-forward' customization according to the major
mode. This also requires a foresight.

My suggestion is somewhat similar to the existing practices of major
mode writing where the author is required to configure comment handling,
paragraph handling, sentence rules, imenu, etc.

However, what I suggest is more flexible as it does not require Emacs
core developers to provide extensive configuration mechanism for, say,
`next-line' individually; `previous-line' individually, ...
Instead, it will be sufficient to declare generalized command and then
rely on major modes to hook in. Users should be able to do it easily
too.

> [ FWIW, you can get similar results with the current setup using
>   command remapping.  ]

You are absolutely right: when a major mode command is related to
built-in command in command map.

However, some major modes introduce new concepts. For example, think
about paredit-forward-slurp-sexp, which can be an equivalent of Org's
heading promotion or moving word at point forward in sentences. How
could you remap to group these 3 very different yet similar (for some
users) commands together?

I imagine that users can define a generalized command "move right"
themselves, give it a default binding in overriding global map, and then
make `paredit-forward-slurp-sexp', `org-promote', and `transpose-words'
be selected when running "move right" depending on the active major
mode. You cannot achieve this by simple remapping, AFAIK.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  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
  1 sibling, 1 reply; 22+ messages in thread
From: Psionic K @ 2022-11-27 11:26 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Stefan Monnier, Emacs developers

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

I tested remap shadowing just now, and it works in 28.2.  A higher
precedence remap will shadow a lower precedence remap.  This means the user
can bind a sequence to an abstract command, give it a remap in the global
map, and have a different remap in a mode map.  When the user rebinds the
abstract command, everything goes with it.

> I suggest introducing a notion of "generalized" commands. Such commands
will represent common actions executed by users (like move to
next/previous element). Major and minor modes can then define specific
implementation of the actions.

We can do this with shadowing in higher precedence maps.  As above, this
works for command remapping, but the issue is that we need a solid place to
remap to, not a command that the user might replace.  If the user defines a
command like "next-line-unfold" in the the global map, a mode generating a
map by looking for "next-line" would not find the correct target.

This is the situation today, with ad-hoc imitation of the default global
map.  Modes map to sequences without knowing what the user wants those
sequences to be.  We basically need a convention to name the keys through
abstract commands instead of using sequences, which really are zero
indication of what the user wants that key to do.  Binding sequences to
abstract commands completely solves this.

>You cannot achieve this by simple remapping, AFAIK.

Each major mode map would shadow the global map's shadow of the
"user-right" abstract command.  Instead of the abstract command sequence
remapping to the global concrete command, the major mode's concrete command
remap would take precedence.  Totally works.


On Sat, Nov 26, 2022 at 11:44 PM Ihor Radchenko <yantar92@posteo.net> wrote:

> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>
> >> I suggest introducing a notion of "generalized" commands. Such commands
> >> will represent common actions executed by users (like move to
> >> next/previous element). Major and minor modes can then define specific
> >> implementation of the actions.
> >
> > I think it's a non-starter because it requires foresight: only those
> > commands defined with this mechanism will be extensible.  I agree that
> > an additional level of indirection is probably necessary, but I suspect
> > it needs to be placed elsewhere.
>
> Auto-remapping will need some kind of grouping for commands one way or
> another. There is no way we can do it auto-magically. Developer or users
> should decide.
>
> Currently, the commands in major mods are bound to specific key
> bindings. The bindings are chosen either arbitrarily, according to major
> mode author preferences, or according to semi-established default key
> binding scheme (like C-f/C-M-f/C-n/C-v/etc). Either way, trying to
> re-bind commands in multiple major modes is not easy.
>
> Note that a number of commands like `comment-forward' already expect
> major modes to fit into an established, pre-defined framework by
> tweaking the `comment-forward' customization according to the major
> mode. This also requires a foresight.
>
> My suggestion is somewhat similar to the existing practices of major
> mode writing where the author is required to configure comment handling,
> paragraph handling, sentence rules, imenu, etc.
>
> However, what I suggest is more flexible as it does not require Emacs
> core developers to provide extensive configuration mechanism for, say,
> `next-line' individually; `previous-line' individually, ...
> Instead, it will be sufficient to declare generalized command and then
> rely on major modes to hook in. Users should be able to do it easily
> too.
>
> > [ FWIW, you can get similar results with the current setup using
> >   command remapping.  ]
>
> You are absolutely right: when a major mode command is related to
> built-in command in command map.
>
> However, some major modes introduce new concepts. For example, think
> about paredit-forward-slurp-sexp, which can be an equivalent of Org's
> heading promotion or moving word at point forward in sentences. How
> could you remap to group these 3 very different yet similar (for some
> users) commands together?
>
> I imagine that users can define a generalized command "move right"
> themselves, give it a default binding in overriding global map, and then
> make `paredit-forward-slurp-sexp', `org-promote', and `transpose-words'
> be selected when running "move right" depending on the active major
> mode. You cannot achieve this by simple remapping, AFAIK.
>
> --
> Ihor Radchenko // yantar92,
> Org mode contributor,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>
>


-- 

Psionic K <psionik@positron.solutions>
Software Engineer

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

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-27 11:26               ` Psionic K
@ 2022-11-27 11:53                 ` Psionic K
  0 siblings, 0 replies; 22+ messages in thread
From: Psionic K @ 2022-11-27 11:53 UTC (permalink / raw)
  To: Emacs developers; +Cc: Ihor Radchenko, Stefan Monnier

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

At this point, I'm thinking about supporting continuity and adoption.  Some
users will want to change and some will want to stay the same.

The short answer is not to define any abstract commands or forbidden /
reserved sequences if you want the current behavior.  We can start by only
defaulting abstract commands that are effectively in consensus already.

After adding the obvious abstract commands, there's not many bindings that
map to consistent concepts I can think of. However, this is not the problem
it seems like.  While a major mode author may wish to create more bindings,
they are not entitled to any of the user's keyspace.

It will suffice for mode writers to know which key sequences are:

   - designated for a purpose in other modes
   - designated for use by the user
   - never to be mapped under any circumstances

At the time of map generation, if a mode finishes mapping designated
abstract keys, they must choose keys that don't match the other two
groups.  These bindings may all be suboptimal or too few to implement the
mode writer's wishes, but this is the user's choice.  A user-overridable
sequence successor function could add bindings to a set of valid
sequences.  If a mode needs more than just a single prefix key, this should
suffice, and the user can define that function to nil to block all
extraneous bindings.

Mode authors should focus on introducing their commands through README's,
good docstrings for completions, and good command names.  Bindings are not
a good index of discovery for commands.  If a mode has a well implemented
data model and set of functions for building commands, this is much more
useful than having a bunch of maybe useful commands bound.

On Sun, Nov 27, 2022 at 5:26 AM Psionic K <psionik@positron.solutions>
wrote:

> I tested remap shadowing just now, and it works in 28.2.  A higher
> precedence remap will shadow a lower precedence remap.  This means the user
> can bind a sequence to an abstract command, give it a remap in the global
> map, and have a different remap in a mode map.  When the user rebinds the
> abstract command, everything goes with it.
>
> > I suggest introducing a notion of "generalized" commands. Such commands
> will represent common actions executed by users (like move to
> next/previous element). Major and minor modes can then define specific
> implementation of the actions.
>
> We can do this with shadowing in higher precedence maps.  As above, this
> works for command remapping, but the issue is that we need a solid place to
> remap to, not a command that the user might replace.  If the user defines a
> command like "next-line-unfold" in the the global map, a mode generating a
> map by looking for "next-line" would not find the correct target.
>
> This is the situation today, with ad-hoc imitation of the default global
> map.  Modes map to sequences without knowing what the user wants those
> sequences to be.  We basically need a convention to name the keys through
> abstract commands instead of using sequences, which really are zero
> indication of what the user wants that key to do.  Binding sequences to
> abstract commands completely solves this.
>
> >You cannot achieve this by simple remapping, AFAIK.
>
> Each major mode map would shadow the global map's shadow of the
> "user-right" abstract command.  Instead of the abstract command sequence
> remapping to the global concrete command, the major mode's concrete command
> remap would take precedence.  Totally works.
>
>
> On Sat, Nov 26, 2022 at 11:44 PM Ihor Radchenko <yantar92@posteo.net>
> wrote:
>
>> Stefan Monnier <monnier@iro.umontreal.ca> writes:
>>
>> >> I suggest introducing a notion of "generalized" commands. Such commands
>> >> will represent common actions executed by users (like move to
>> >> next/previous element). Major and minor modes can then define specific
>> >> implementation of the actions.
>> >
>> > I think it's a non-starter because it requires foresight: only those
>> > commands defined with this mechanism will be extensible.  I agree that
>> > an additional level of indirection is probably necessary, but I suspect
>> > it needs to be placed elsewhere.
>>
>> Auto-remapping will need some kind of grouping for commands one way or
>> another. There is no way we can do it auto-magically. Developer or users
>> should decide.
>>
>> Currently, the commands in major mods are bound to specific key
>> bindings. The bindings are chosen either arbitrarily, according to major
>> mode author preferences, or according to semi-established default key
>> binding scheme (like C-f/C-M-f/C-n/C-v/etc). Either way, trying to
>> re-bind commands in multiple major modes is not easy.
>>
>> Note that a number of commands like `comment-forward' already expect
>> major modes to fit into an established, pre-defined framework by
>> tweaking the `comment-forward' customization according to the major
>> mode. This also requires a foresight.
>>
>> My suggestion is somewhat similar to the existing practices of major
>> mode writing where the author is required to configure comment handling,
>> paragraph handling, sentence rules, imenu, etc.
>>
>> However, what I suggest is more flexible as it does not require Emacs
>> core developers to provide extensive configuration mechanism for, say,
>> `next-line' individually; `previous-line' individually, ...
>> Instead, it will be sufficient to declare generalized command and then
>> rely on major modes to hook in. Users should be able to do it easily
>> too.
>>
>> > [ FWIW, you can get similar results with the current setup using
>> >   command remapping.  ]
>>
>> You are absolutely right: when a major mode command is related to
>> built-in command in command map.
>>
>> However, some major modes introduce new concepts. For example, think
>> about paredit-forward-slurp-sexp, which can be an equivalent of Org's
>> heading promotion or moving word at point forward in sentences. How
>> could you remap to group these 3 very different yet similar (for some
>> users) commands together?
>>
>> I imagine that users can define a generalized command "move right"
>> themselves, give it a default binding in overriding global map, and then
>> make `paredit-forward-slurp-sexp', `org-promote', and `transpose-words'
>> be selected when running "move right" depending on the active major
>> mode. You cannot achieve this by simple remapping, AFAIK.
>>
>> --
>> Ihor Radchenko // yantar92,
>> Org mode contributor,
>> Learn more about Org mode at <https://orgmode.org/>.
>> Support Org development at <https://liberapay.com/org-mode>,
>> or support my work at <https://liberapay.com/yantar92>
>>
>
>
> --
>
> Psionic K <psionik@positron.solutions>
> Software Engineer
>
> *Positron Solutions <https://positron.solutions>*
>


-- 

Psionic K <psionik@positron.solutions>
Software Engineer

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

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-27  5:45             ` Ihor Radchenko
  2022-11-27 11:26               ` Psionic K
@ 2022-11-28 18:15               ` Stefan Monnier
  2022-11-28 18:37                 ` Eli Zaretskii
                                   ` (2 more replies)
  1 sibling, 3 replies; 22+ messages in thread
From: Stefan Monnier @ 2022-11-28 18:15 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Psionic K, Emacs developers

>>> I suggest introducing a notion of "generalized" commands. Such commands
>>> will represent common actions executed by users (like move to
>>> next/previous element). Major and minor modes can then define specific
>>> implementation of the actions.
>>
>> I think it's a non-starter because it requires foresight: only those
>> commands defined with this mechanism will be extensible.  I agree that
>> an additional level of indirection is probably necessary, but I suspect
>> it needs to be placed elsewhere.
>
> Auto-remapping will need some kind of grouping for commands one way or
> another. There is no way we can do it auto-magically. Developer or users
> should decide.

Agreed.  But it should apply to all bindings.

> Currently, the commands in major mods are bound to specific key
> bindings. The bindings are chosen either arbitrarily, according to major
> mode author preferences, or according to semi-established default key
> binding scheme (like C-f/C-M-f/C-n/C-v/etc). Either way, trying to
> re-bind commands in multiple major modes is not easy.

Yup.  I fully agree that it's a real problem.

I'd welcome a solution to it.  Even an "unrealistic" one would be good.
Currently, I don't even know what a good solution could look like.

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

Some SOME-INFO needs to provide not a specific key, but some information
from which we can compute the "natural key" that fits the keybinding
style that the user selected.

Then there are also the issues of overloading several operations on
a single key (like TAB).  So far we've solved this along the lines you
suggest (a "generalized command", such as `indent-for-tab-command`), and
maybe that's good enough for this, tho it prevents changing this
overloading according to the keybinding style.

[ BTW, another way to look at it is not "how can we compute which key to
  bind FOO to" but rather "how can we compute which command to run when
  KEY is hit".  IOW, we could make keymaps more dynamic such that when
  you hit KEY, Emacs passes that to a "procedural keymap" which will
  *compute* (rather than lookup) which command to run, according to the
  current keybinding style.
  Not sure it would be better: I just mention it as one of the many
  things that we may want to consider in order to find a good solution
  to the problem.  ]

>> [ FWIW, you can get similar results with the current setup using
>>   command remapping.  ]
> You are absolutely right: when a major mode command is related to
> built-in command in command map.

Just to be clear: I don't think command remapping solves the problem
at hand.  It can sometimes be used for that, but not in general.

> However, some major modes introduce new concepts.  For example, think
> about paredit-forward-slurp-sexp, which can be an equivalent of Org's
> heading promotion or moving word at point forward in sentences.  How
> could you remap to group these 3 very different yet similar (for some
> users) commands together?

Great example, indeed, thanks.

In this context, I'd like the package to be able to explain that this
command is about a "sexp"-granularity operation and about
"forward"-direction operation, so that the keybinding style may
automatically find a natural/consistent key (or set of keys) to use for
it depending on whether the current keybinding style uses f/b, or j/k,
or left/right, or ... for forward/backward operations.


        Stefan




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-28 18:15               ` Stefan Monnier
@ 2022-11-28 18:37                 ` Eli Zaretskii
  2022-11-29  2:38                 ` Psionic K
  2022-11-29 11:54                 ` John Yates
  2 siblings, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2022-11-28 18:37 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: yantar92, psionik, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Psionic K <psionik@positron.solutions>,  Emacs developers
>  <emacs-devel@gnu.org>
> Date: Mon, 28 Nov 2022 13:15:26 -0500
> 
> > Currently, the commands in major mods are bound to specific key
> > bindings. The bindings are chosen either arbitrarily, according to major
> > mode author preferences, or according to semi-established default key
> > binding scheme (like C-f/C-M-f/C-n/C-v/etc). Either way, trying to
> > re-bind commands in multiple major modes is not easy.
> 
> Yup.  I fully agree that it's a real problem.
> 
> I'd welcome a solution to it.  Even an "unrealistic" one would be good.
> Currently, I don't even know what a good solution could look like.
> 
> 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...
> 
> Some SOME-INFO needs to provide not a specific key, but some information
> from which we can compute the "natural key" that fits the keybinding
> style that the user selected.
> 
> Then there are also the issues of overloading several operations on
> a single key (like TAB).  So far we've solved this along the lines you
> suggest (a "generalized command", such as `indent-for-tab-command`), and
> maybe that's good enough for this, tho it prevents changing this
> overloading according to the keybinding style.
> 
> [ BTW, another way to look at it is not "how can we compute which key to
>   bind FOO to" but rather "how can we compute which command to run when
>   KEY is hit".  IOW, we could make keymaps more dynamic such that when
>   you hit KEY, Emacs passes that to a "procedural keymap" which will
>   *compute* (rather than lookup) which command to run, according to the
>   current keybinding style.
>   Not sure it would be better: I just mention it as one of the many
>   things that we may want to consider in order to find a good solution
>   to the problem.  ]

How about adding this (and more) to etc/TODO?



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  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 11:54                 ` John Yates
  2 siblings, 1 reply; 22+ messages in thread
From: Psionic K @ 2022-11-29  2:38 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Ihor Radchenko, Emacs developers

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

> 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

The overloads might be embedded in the first and second lists, but it will
make for complicated reading later.

Either a built-in implementation in Emacs or customized implementations in
packages should consume the full SOME-INFO and generate keymaps.  If that
keymap generation is dynamic or the keymap itself embeds indirection for
contextual operations, we get essentially dynamic dispatch, and there's not
much need for new implementations.  emulation-mode-map-alists has its
structure for good reason.

In the beginning, before packages provide their half, the user will provide
it, likely through a package.  This is analogous to evil collection.

There likely will not be enough concepts to support relocating every key
this way.  While the default implementation that ships with Emacs can
attempt to rearrange keys usings current behavior and a heuristic where
that is not possible, if the user configures a different implementation,
even one that ignores the mode's SOME-INFO in part or whole, commands will
be unbound.  This is good.  We have to support the notion that the provided
commands are bad and that the users wants to write better ones or else we
are choking the evolution of the interaction models.  Package authors
should focus on good functions and editing data models.  This is what makes
it easy to write good commands.  Attempting to write all the good commands
is not possible without lots of user representation, which package authors
cannot individually have.

> 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.  They should only provide
the ((concept command)) information.  Package authors and users have to
meet in the middle, and remember to put the users first in that
discussion.  As stated above, I believe it's the job of modal systems to
decide how to consume the package-defined half of SOME-INFO.

> Agreed.  But it should apply to all bindings.

The concepts that can be good targets in SOME-INFO should arise only very
naturally.  This means there will be way too few concepts to handle the
current state of keymaps.  IMO this is because package authors feel
entitled to users' keyboards or obligated to shadow all of the random
commands bound in the default global map.  The implementations should make
it easier for bad commands / bindings to die.

Lots of Emacs applications handle lists of options because lists are simply
ubiquitous, and so navigating lists is naturally a common concept.  M-x is
the gateway to commands, and Emacs without such a gateway is degenerate, so
we need that as a concept.  Aborting a command that is asking for input or
blocking on network is a concept.  Let's get these figured out and make
them easily remappable before worrying about esoteric commands that the
user might want to redefine anyway.

On Mon, Nov 28, 2022 at 12:15 PM Stefan Monnier <monnier@iro.umontreal.ca>
wrote:

> >>> I suggest introducing a notion of "generalized" commands. Such commands
> >>> will represent common actions executed by users (like move to
> >>> next/previous element). Major and minor modes can then define specific
> >>> implementation of the actions.
> >>
> >> I think it's a non-starter because it requires foresight: only those
> >> commands defined with this mechanism will be extensible.  I agree that
> >> an additional level of indirection is probably necessary, but I suspect
> >> it needs to be placed elsewhere.
> >
> > Auto-remapping will need some kind of grouping for commands one way or
> > another. There is no way we can do it auto-magically. Developer or users
> > should decide.
>
> Agreed.  But it should apply to all bindings.
>
> > Currently, the commands in major mods are bound to specific key
> > bindings. The bindings are chosen either arbitrarily, according to major
> > mode author preferences, or according to semi-established default key
> > binding scheme (like C-f/C-M-f/C-n/C-v/etc). Either way, trying to
> > re-bind commands in multiple major modes is not easy.
>
> Yup.  I fully agree that it's a real problem.
>
> I'd welcome a solution to it.  Even an "unrealistic" one would be good.
> Currently, I don't even know what a good solution could look like.
>
> 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...
>
> Some SOME-INFO needs to provide not a specific key, but some information
> from which we can compute the "natural key" that fits the keybinding
> style that the user selected.
>
> Then there are also the issues of overloading several operations on
> a single key (like TAB).  So far we've solved this along the lines you
> suggest (a "generalized command", such as `indent-for-tab-command`), and
> maybe that's good enough for this, tho it prevents changing this
> overloading according to the keybinding style.
>
> [ BTW, another way to look at it is not "how can we compute which key to
>   bind FOO to" but rather "how can we compute which command to run when
>   KEY is hit".  IOW, we could make keymaps more dynamic such that when
>   you hit KEY, Emacs passes that to a "procedural keymap" which will
>   *compute* (rather than lookup) which command to run, according to the
>   current keybinding style.
>   Not sure it would be better: I just mention it as one of the many
>   things that we may want to consider in order to find a good solution
>   to the problem.  ]
>
> >> [ FWIW, you can get similar results with the current setup using
> >>   command remapping.  ]
> > You are absolutely right: when a major mode command is related to
> > built-in command in command map.
>
> Just to be clear: I don't think command remapping solves the problem
> at hand.  It can sometimes be used for that, but not in general.
>
> > However, some major modes introduce new concepts.  For example, think
> > about paredit-forward-slurp-sexp, which can be an equivalent of Org's
> > heading promotion or moving word at point forward in sentences.  How
> > could you remap to group these 3 very different yet similar (for some
> > users) commands together?
>
> Great example, indeed, thanks.
>
> In this context, I'd like the package to be able to explain that this
> command is about a "sexp"-granularity operation and about
> "forward"-direction operation, so that the keybinding style may
> automatically find a natural/consistent key (or set of keys) to use for
> it depending on whether the current keybinding style uses f/b, or j/k,
> or left/right, or ... for forward/backward operations.
>
>
>         Stefan
>
>

-- 

Psionic K <psionik@positron.solutions>
Software Engineer

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

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-29  2:38                 ` Psionic K
@ 2022-11-29  4:01                   ` Stefan Monnier
  2022-11-29  5:22                     ` Psionic K
  0 siblings, 1 reply; 22+ messages in thread
From: Stefan Monnier @ 2022-11-29  4:01 UTC (permalink / raw)
  To: Psionic K; +Cc: Ihor Radchenko, Emacs developers

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




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-29  4:01                   ` Stefan Monnier
@ 2022-11-29  5:22                     ` Psionic K
  2022-11-29 13:03                       ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Psionic K @ 2022-11-29  5:22 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Ihor Radchenko, Emacs developers

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

> 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 <monnier@iro.umontreal.ca>
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 <psionik@positron.solutions>
Software Engineer

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

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-28 18:15               ` Stefan Monnier
  2022-11-28 18:37                 ` Eli Zaretskii
  2022-11-29  2:38                 ` Psionic K
@ 2022-11-29 11:54                 ` John Yates
  2 siblings, 0 replies; 22+ messages in thread
From: John Yates @ 2022-11-29 11:54 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Ihor Radchenko, Psionic K, Emacs developers

On Mon, Nov 28, 2022 at 1:16 PM Stefan Monnier <monnier@iro.umontreal.ca> wrote:
>
> > However, some major modes introduce new concepts.  For example, think
> > about paredit-forward-slurp-sexp, which can be an equivalent of Org's
> > heading promotion or moving word at point forward in sentences.  How
> > could you remap to group these 3 very different yet similar (for some
> > users) commands together?
>
> Great example, indeed, thanks.
>
> In this context, I'd like the package to be able to explain that this
> command is about a "sexp"-granularity operation and about
> "forward"-direction operation, so that the keybinding style may
> automatically find a natural/consistent key (or set of keys) to use for
> it depending on whether the current keybinding style uses f/b, or j/k,
> or left/right, or ... for forward/backward operations.

[I have followed this thread only intermittently.
Please forgive any repetition of things already said.]

I agree with Stefan, that is a wonderful example.

Objects:  We need a codified vocabulary.
* Display objects: char, line, column, window, . . .
* Text containers: file, buffer, register, . . .
* Text objects: char, word, sexp, sentence, . . .

How are tree-sitter provided objects accomodated?

Clearly this vocabulary would be drawn largely from
current usage.  Codification is necessary for the
proposed package to be able to reason about these
concepts.

When a package introduces a new object, its author
should be able make statements like:
* X is a new object
* Object X is most akin to but coexists with object Y
* Object X subsumes and eclipses object Y

Ordering: The available key sequences have a vague
partial order related to the number and ergonomics
of keystrokes involved.  This should be formalized.
A user should be able to weigh in on this partial order.

To aid in aligning the choices of bindings with the
preceding partial order we need to formalize partial
orders over objects that emacs users already intuit:
* char < (line | column) < window < frame < display
* char < word < (sexp | sentence) . . .

Verbs: Once you have objects you clearly need
imperative verbs.
* insert
* delete
* move
* transpose

Properties: The applicability of properties to verbs
needs to be defined.  My sense is that direction is
inapplicable to verbs such as:
* yank
* save



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-29  5:22                     ` Psionic K
@ 2022-11-29 13:03                       ` Eli Zaretskii
  2022-11-30  6:23                         ` Psionic K
  0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2022-11-29 13:03 UTC (permalink / raw)
  To: Psionic K; +Cc: monnier, yantar92, emacs-devel

> From: Psionic K <psionik@positron.solutions>
> Date: Mon, 28 Nov 2022 23:22:24 -0600
> Cc: Ihor Radchenko <yantar92@posteo.net>,
>  Emacs developers <emacs-devel@gnu.org>
> 
> ;; 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.

I think this discussion started from the wrong starting point, and that's
why the common understanding is difficult and misunderstandings abundant:
there's no reason to believe you and Stefan (and myself, and others who
read this) have the same goals and the same issues in mind.

The basic problem here is that we don't have a clear commonly-shared idea of
what we want to support with these features.

My suggestion is to start from clarifying these requirements.  A good method
of understanding requirements is to describe typical use-cases and their
variations, as you probably know.  With that in mind, would you or someone
else please describe such use-cases?  Specifically:

  . what does the user specify?
  . what should happen with key bindings to various commands as result of
    the user specifications?

For instance, with your 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)

I have no idea what will be the binding of magit-section-next.  And, since
you only gave a single command as an example, I have no idea how is what you
propose better than just saying

  (local-set-key ?\M-n #'magit-section-next)

I understand what Stefan says about "letters" (probably meaning that 'n'
should be used in "next-FOO" commands and 'p' in "prev-FOO"), but I don't
understand what you are saying, because you didn't tell enough about your
eventual goal, in practical terms.



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  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
  0 siblings, 2 replies; 22+ messages in thread
From: Psionic K @ 2022-11-30  6:23 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, yantar92, emacs-devel

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

>   (local-set-key ?\M-n #'magit-section-next)

This is a good edge case solution.  It is not a good solution for moving or
removing bindings coherently across all current and future modes.

On Tue, Nov 29, 2022 at 7:03 AM Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Psionic K <psionik@positron.solutions>
> > Date: Mon, 28 Nov 2022 23:22:24 -0600
> > Cc: Ihor Radchenko <yantar92@posteo.net>,
> >  Emacs developers <emacs-devel@gnu.org>
> >
> > ;; 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.
>
> I think this discussion started from the wrong starting point, and that's
> why the common understanding is difficult and misunderstandings abundant:
> there's no reason to believe you and Stefan (and myself, and others who
> read this) have the same goals and the same issues in mind.
>
> The basic problem here is that we don't have a clear commonly-shared idea
> of
> what we want to support with these features.
>
> My suggestion is to start from clarifying these requirements.  A good
> method
> of understanding requirements is to describe typical use-cases and their
> variations, as you probably know.  With that in mind, would you or someone
> else please describe such use-cases?  Specifically:
>
>   . what does the user specify?
>   . what should happen with key bindings to various commands as result of
>     the user specifications?
>
> For instance, with your 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)
>
> I have no idea what will be the binding of magit-section-next.  And, since
> you only gave a single command as an example, I have no idea how is what
> you
> propose better than just saying
>
>   (local-set-key ?\M-n #'magit-section-next)
>
> I understand what Stefan says about "letters" (probably meaning that 'n'
> should be used in "next-FOO" commands and 'p' in "prev-FOO"), but I don't
> understand what you are saying, because you didn't tell enough about your
> eventual goal, in practical terms.
>


-- 

Psionic K <psionik@positron.solutions>
Software Engineer

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

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-30  6:23                         ` Psionic K
@ 2022-11-30  9:01                           ` xenodasein--- via Emacs development discussions.
  2022-11-30 13:44                           ` Eli Zaretskii
  1 sibling, 0 replies; 22+ messages in thread
From: xenodasein--- via Emacs development discussions. @ 2022-11-30  9:01 UTC (permalink / raw)
  To: Psionic K; +Cc: Eli Zaretskii, monnier, yantar92, emacs-devel

Nov 30, 2022, 06:23 by psionik@positron.solutions:

> >   (local-set-key ?\M-n #'magit-section-next)
>
> This is a good edge case solution.  It is not a good solution for moving or removing bindings coherently across all current and future modes.
>
> ...
>

Eli does have some rigid expectation as to how things should be, and
instead of making these explicit would rather toy with askers over
piece by piece mails like this.  I suggest to save time stop poking
around how things are done in defaults and write something brand-new
like transient.el then similarly send it for inclusion in Emacs.




^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: Delegating user-reserved key binding space definition to users
  2022-11-30  6:23                         ` Psionic K
  2022-11-30  9:01                           ` xenodasein--- via Emacs development discussions.
@ 2022-11-30 13:44                           ` Eli Zaretskii
  1 sibling, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2022-11-30 13:44 UTC (permalink / raw)
  To: Psionic K; +Cc: monnier, yantar92, emacs-devel

> From: Psionic K <psionik@positron.solutions>
> Date: Wed, 30 Nov 2022 00:23:02 -0600
> Cc: monnier@iro.umontreal.ca, yantar92@posteo.net, emacs-devel@gnu.org
> 
> >   (local-set-key ?\M-n #'magit-section-next)
> 
> This is a good edge case solution.  It is not a good solution for moving or removing bindings coherently
> across all current and future modes.

Thanks.  But if this is an answer to my questions, I'm afraid I don't
understand it.  I asked several questions whose answers would allow me to
understand better what you have in mind.



^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2022-11-30 13:44 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
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

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