Closed emacksnotes closed 5 years ago
A better way to integrate X windows into Emacs is to use the line-mode, which allows users to use nearly every keybindings they want and translate inconsistent keybindings with simulation keys. That said, there should be an easy way to access a bunch of keybindings in char-mode. I believe the following command can do the work (if we publish it as an public interface):
(defun invoke-ctl-x-map ()
(interactive)
(exwm-input--cache-event ?\C-x t)
(exwm-input--unread-event ?\C-x))
A better way to integrate X windows into Emacs is to use the line-mode, which allows users to use nearly every keybindings they want and translate inconsistent keybindings with simulation keys. That said, there should be an easy way to access a bunch of keybindings in char-mode. I believe the following command can do the work (if we publish it as an public interface):
(defun invoke-ctl-x-map () (interactive) (exwm-input--cache-event ?\C-x t) (exwm-input--unread-event ?\C-x))
I have been experimenting with the above suggestion. This is what I have come up with
(defmacro exwm--wrap-event (arg)
(let* ((evlist (eval `(listify-key-sequence ,arg)))
(ev (elt evlist 0)))
`(defun ,(intern (format "exwm--invoke-%s-map" (key-description evlist))) ()
,(format "Invoke `%s' map zzz." (key-description evlist))
(interactive)
(exwm-input--cache-event ,ev t)
(exwm-input--unread-event ,ev))))
(exwm--wrap-event (kbd "C-h"))
(exwm--wrap-event (kbd "C-x"))
(exwm--wrap-event (kbd "M-x"))
;; exwm-input-prefix-keys
;; '(?\C-x ?\C-u ?\C-h ?\M-x ?\M-` ?\M-& ?\M-:)
(custom-set-variables
'(exwm-input-global-keys
'(([33554456] ; "C-S-x"
. exwm--invoke-C-x-map)
([33554440] ; "C-S-h"
. exwm--invoke-C-h-map)
([134217816] ; "M-X"
. exwm--invoke-M-x-map))))
It is easier to migrate C-x
to C-X
, C-h
to C-H
and M-x
to M-X
. For regular use, having the commands in ctl-x-map
is the most useful in EXWM buffers. Since I am actively exploring EXWM, and running in to issues I have found a need for having access to C-h
and M-x
commands.
That said ...
(defun invoke-ctl-x-map () (interactive) (exwm-input--cache-event ?\C-x t) (exwm-input--unread-event ?\C-x))
I wonder what would be the recipe, when the prefix key is not a single key but multiple keys.
Put in other words, the example above assumes a ctl-x-map
, what if one wants to "migrate" a set of commands say in a (hypothetical) ctl-x-ctl-y-map
.
If you notice carefully, my macro which does event
->command
mapping assumes that event is a vector with just a single key.
I had to do a lot of trial error to genericize
(defun invoke-ctl-x-map ()
(interactive)
(exwm-input--cache-event ?\C-x t)
(exwm-input--unread-event ?\C-x))
to
(defmacro exwm--wrap-event (arg)
(let* ((evlist (eval `(listify-key-sequence ,arg)))
(ev (elt evlist 0)))
`(defun ,(intern (format "exwm--invoke-%s-map" (key-description evlist))) ()
,(format "Invoke `%s' map zzz." (key-description evlist))
(interactive)
(exwm-input--cache-event ,ev t)
(exwm-input--unread-event ,ev))))
In the numerous trials I leading up to the above macro, I got the /type/ of the first parameter of exwm-input--cache-event
and exwm-input--unread-event
wrong. EVENT
in your suggestion is actually a number. And it took some time to figure this fact out. i.e., I misread ?\C-x
as a string, but is in fact an integer. My brain interpolated "double quotes" in what /appeared/ like a string.
Here is the MOST IMPORTANT part.
When I got the type of the EVENT
parameter wrong, not just the EXWM but the whole GNOME session went for a toss. There were numerous instances where my laptop stopped responding to /any/ key & mouse, and I had to forcibly power cycle the laptop. At one point I was even worried about my hard disk getting broke.
To cut the long story short, here is my request. And it is simple ...
Any user error that may happen in the above path should be demoted, and EXWM should do it's best to remain in the working state.
The bug description is vague, but I hope the maintainers can figure out what needs to be done.
cf. Gracefully handle xmodmap -e "clear mod4" · Issue #655 · ch11ng/exwm
This theme of "Graceful handling of user errors" came up (and subsequently fixed) in https://github.com/ch11ng/exwm/issues/612#issuecomment-526913074 too. So, I think it would be a good idea to review the code path that gets triggered from user's custom-set-variables
and ensure that any fault on user's part doesn't result in an unusable system. Unless one is an expert user, getting Emacs key sequences right is an arduous task, and there is a high probability that one gets the syntax wrong rather than right.
Put in other words, the example above assumes a
ctl-x-map', what if one wants to "migrate" a set of commands say in a (hypothetical)
ctl-x-ctl-y-map'.
That's quite straightforward:
(defun invoke-ctl-x-ctl-y-map ()
(interactive)
(exwm-input--cache-event ?\C-x t)
(exwm-input--unread-event ?\C-x)
(exwm-input--cache-event ?\C-y t)
(exwm-input--unread-event ?\C-y))
Basically a key sequence can be represented as a vector a key event(s). exwm-input--cache-event
and exwm-input--unread-event
deal with key events so just feed them with each key event in order.
Any user error that may happen in the above path should be demoted, and EXWM should do it's best to remain in the working state.
I'm afraid there's no generic way but to proofread all codes, as most X requests have side effects (it's hard to rollback). But I'll try. That specific problem is fixed of course.
I prefer putting non-Emacs buffers like Firefox or Gnome-Terminal etc in char-mode. This way I can continue using those apps as I have always used them in ancient times.
Whenever I work with these char mode buffers within EXWM, I want to be able to
C-x b' .
C-x C-f', or invoke many of the other buffer, window and frame commands in ctl-x-map.If I were to make the above ctl-x-map commands actionable in char mode buffers, I need to "migrate" those commands to exwm-input-global-keys in single "swoop".
A better way to integrate X windows into Emacs is to use the line-mode, which allows users to use nearly every keybindings they want and translate inconsistent keybindings with simulation keys. That said, there should be an easy way to access a bunch of keybindings in char-mode. I believe the following command can do the work (if we publish it as an public interface):
(defun invoke-ctl-x-map () (interactive) (exwm-input--cache-event ?\C-x t) (exwm-input--unread-event ?\C-x))
(defun invoke-ctl-x-ctl-y-map () (interactive) (exwm-input--cache-event ?\C-x t) (exwm-input--unread-event ?\C-x) (exwm-input--cache-event ?\C-y t) (exwm-input--unread-event ?\C-y))
This is what I have right now:
(defmacro exwm--with-gensyms (symbols &rest body)
"Same as `org-with-gensyms.'"
(declare (debug (sexp body)) (indent 1))
`(let ,(mapcar (lambda (s)
`(,s (make-symbol (concat "--" (symbol-name ',s)))))
symbols)
,@body))
(defmacro exwm--invoke-map (kbd)
`(eval ,(exwm--with-gensyms (evlist keydesc)
`(let* ((,evlist (listify-key-sequence ,kbd))
(,keydesc (key-description ,evlist)))
`(defun ,(intern (format "exwm--invoke-%s-map" ,keydesc)) ()
,(format "Invoke `%s' map." ,keydesc)
(interactive)
,@(cl-loop for event in ,evlist
append `((exwm-input--cache-event ,event t)
(exwm-input--unread-event ,event))))))))
(customize-set-variable
'exwm-input-global-keys
(append exwm-input-global-keys
(cl-loop for (from-keys . to-keys) in '(("C-x" . "C-S-x")
("C-h" . "C-S-h")
("M-x" . "M-X")
("M-:" . "C-M-:")
;; ("C-x w" . "s-w")
)
collect (cons (vconcat (listify-key-sequence (kbd to-keys)))
(exwm--invoke-map (kbd from-keys))))))
With the above snippets in .emacs
, this is what M-: exwm-input-global-keys RET
looks like
(([33554456]
. exwm--invoke-C-x-map)
([33554440]
. exwm--invoke-C-h-map)
([134217816]
. exwm--invoke-M-x-map)
([201326650]
. exwm--invoke-M-:-map)
([8388727]
. exwm--invoke-C-x\ w-map))
Note the following:
I believe the following command can do the work (if we publish it as an public interface)
Please make the interface public. I will be a happy consumer.
The macro exwm--invoke-map
that you see in the previous message, gives you a hint on what /form/ the public interface could be i.e., it should work with multiple prefix keys. It /may/ install a /invoke function/ in runtime, and have it return a /name/ for it (as opposed to it returning a anonymous function). With a named function, the custom-set-variable
blob in .emacs
will be short and comprehensible.
The macro exwm--invoke-map that you see in the previous message, gives you a hint on what /form/ the public interface could be i.e., it should work with multiple prefix keys.
When given a multiple prefix keys, you /may/ want to check for emacs-version
,
>= 27
(or whatever)user-error
otherwiseI compile Emacs from git, so I would very much want to see the above interface take multiple key events.
I've added this as exwm-input-invoke-factory
. Please check it out. One downside of this is the resulting name can contain strange characters like space, but it's probably acceptable for display purpose only. Note that I didn't do the check against Emacs version as 26.3 is already released.
I've added this as
exwm-input-invoke-factory
.
Thanks. I am closing this bug.
This is what I have in my .emacs
.
(customize-set-variable
'exwm-input-global-keys
(append exwm-input-global-keys
(cl-loop for (from-keys . to-keys) in '(("C-x" . "C-S-x" )
("C-h" . "C-S-h" )
("M-x" . "M-X" )
("M-:" . "C-M-:" )
;; ("C-x w" . "s-w" )
)
collect (cons (vconcat (listify-key-sequence (kbd to-keys)))
(eval `(exwm-input-invoke-factory ,from-keys))))))
One can also go with the following in their .emacs
.
(exwm-input-invoke-factory "C-x" ) ; exwm-input--invoke--C-x
(exwm-input-invoke-factory "C-h" ) ; exwm-input--invoke--C-h
(exwm-input-invoke-factory "M-x" ) ; exwm-input--invoke--M-x
(exwm-input-invoke-factory "M-:" ) ; exwm-input--invoke--M-:
(exwm-input-invoke-factory "C-x w" ) ; exwm-input--invoke--C-x\ w
(custom-set-variables
'(exwm-input-global-keys
'(([33554456]
. exwm-input--invoke--C-x)
([33554440]
. exwm-input--invoke--C-h)
([134217816]
. exwm-input--invoke--M-x)
([201326650]
. exwm-input--invoke--M-:)
([8388727]
. exwm-input--invoke--C-x\ w))))
Please review
:value-type
ofexwm-input-global-keys
Suggested fix
Make the
:value-type
asexp
or arestricted-sexp
that tests forkeymapp
.Only affects users that rely on
defcustom
widget to configureexwm-input-global-keys
.If you are a user who directly
setq
-s the user option, then my complaint will make no sense to you. Since the variable has aset
-tter, using asetq
will be of little use in a running session anyways.The note below outlines what forced me to my turn my radar on
exwm-input-global-keys
. My hope is that the note below will be of use to others.(The rest of the report is more a conversation, than an issue per-se.)
TLDR
The
:set
function ofexwm-input-global-keys
ultimately callsThe 3rd arg of
define-key
need not be acommand
, but it can be akeymap
too.Currently
exwm-input-global-keys
restricts:value-type
to afunction
, and it is too limiting. Specifically it wouldn't allow me to specify akeymap
for the:valuetype
.Motivation
I prefer putting non-Emacs buffers like Firefox or Gnome-Terminal etc in char-mode. This way I can continue using those apps as I have always used them in ancient times.
Whenever I work with these char mode buffers within EXWM, I want to be able to
C-x b
C-x C-f
C-x d
or invoke many of the other buffer, window and frame commands inctl-x-map
.If I were to make the above
ctl-x-map
commands actionable in char mode buffers, I need to "migrate" those commands toexwm-input-global-keys
in single "swoop". And the easiest way to do it is to do something likeDefine a
keymap
widgetNote:
keymap
deserves a widget of it's own. Stock Emacs doesn't provide one. I am providing this widget only so that it is for you to try and test the validity and usefulness of my suggestion here.Use the
keymap
widget typeOnce that is done, I can have customization like this
With that in no time I would be able to do
s-x b
,s-x C-f
,s-x d
,s-x 1
etc. when in char mode buffers too.Note that
Control-X-Prefix
used above was only an example. It could be any keymap, either well-known or even a user-defined one. I have usedControl-X-Prefix
only as an example. It is available to everyone using Emacs, and someone reading this note can test it immediately. The keymap here need not be a well-known one. I anticipate that in most cases will be a user-defined one.How I hope to use the suggested feature
For example, I have bound all the window management commands in a sparse map which is bound to
C-x w
key. Now with the suggestion above, it is child's game to move over myC-x w
map tos-w
map, for example.With that the value of
exwm-input-global-keys
can have the following entryand I will be able to use
s-w
to manage the windows.Advantage: "migrate" a set of commands mapped to a prefix to a exwm-only prefix.
In the above example, I migrated
C-x w
commands tos-w
commands in a single swoop. Such wholesale migration not possible if the:value-type
ofexwm-input-global-keys
is restricted to afunction
.More note
I have more ideas in regard to
exwm-input-global-keys
, and I will use this issue tracker to record them.