xahlee / xah-fly-keys

the most efficient keybinding for emacs
http://xahlee.info/emacs/misc/xah-fly-keys.html
472 stars 80 forks source link

Refactoring to use multiple minor-mode keymaps #64

Closed DanLanglois closed 4 years ago

DanLanglois commented 5 years ago

[https://github.com/DanLanglois/xah-fly-keys/blob/master/xah-fly-keys.el]

Note for Xah Lee -- the basic way that xah-fly-keys currently is implemented, is that it creates a minor mode, and uses one keymap, and changes from 'insert' to 'command' mode by doing a bunch of changes to that mutable keymap, every time the user switches modes.

Your nit was that it's workable, though it seems like there is a better way. Why not just store two keymaps in memory, and switch between them?

Indeed, there is this variable (provided by emacs), 'emulation-mode-map-alists', which holds a list of keymap alists to use for emulation modes. It is intended for modes or packages using multiple minor-mode keymaps. Such as our 'control mode' vs. 'insert mode' issue, where you want to swap between two keymaps, a 'control' keymap and an 'insert' keymap.

I've forked 'xah-fly-keys' and changed xah-fly-keys.el, with some stuff like this:


  (setq xah-fly-insert-state nil)
  (setq xah-fly-command-state t)

(defconst xah-fly--states
  '(xah-fly-command-state
    xah-fly-insert-state))   

(defvar xah-fly-mode-map-alist
  (list
   (cons 'xah-fly-command-state xah-fly-manage-command-mode-map)
   (cons 'xah-fly-insert-state xah-fly-manage-insert-mode-map)))  

  (setq _emulation-mode-map-alists_
        (cons xah-fly-mode-map-alist _emulation-mode-map-alists_))  

I didn't think I'd get it working while it was raining outside, but it tests successfullly. I've commented out your mutable xah-fly-key-map, and am switching between two immutable keymaps instead: xah-fly-manage-insert-mode-map and xah-fly-manage-command-mode-map.

It's kind of in a 'scratch buffer' state, in terms of code formatting. So I am shy, but heck I'll wrap it up with a pull request..

DanLanglois commented 5 years ago

I haven't actually wrapped it up with a pull request, because I found a worry. I noticed this line, which does something involving 'your old' M-x.

xahlee/xah-fly-keys master:

3792  (define-key xah-fly-key-map (kbd (xah-fly--key-char "a"))
3793    (if (fboundp 'smex) 'smex (if (fboundp 'helm-M-x) 'helm-M-x 'execute-extended-command)))

Okay, well, first, I have stripped out the use of 'xah-fly-key-map'. So, this stuff would go into 'xah-fly-manage-command-mode-map' instead. But I wonder if I am missing something, here. I'm trying to read these lines of code, I mean. I took this, superficially, for an 'if-then-else', but maybe let's add clarity:

    (if (fboundp 'smex)          ; if-part
        ('smex)                         ; then-part
     (if (fboundp 'helm-M-x) 'helm-M-x 'execute-extended-command))) ; else-part

Well, I don't know much lisp, but in the syntax of other programming languages, one has available some sort of an implementation of multiple test-action clauses. And, when I root around in some lisp code, yes I do find it's as I expected, this kind of thing:


(setq day 4)
(case day
(1 (format t "~% Monday"))
(2 (format t "~% Tuesday"))
(3 (format t "~% Wednesday"))
(4 (format t "~% Thursday"))
(5 (format t "~% Friday"))
(6 (format t "~% Saturday"))
(7 (format t "~% Sunday")))

So I puzzle, ingenuously, and figured with your tutorial material about elisp I'd read what you have to say about 'case', in lisp. And, I typed 'xah lee case lisp' into google which just, I'm just sayin', what it pulled up for me as the first hit was this:

[https://www.google.com/search?q=xah+lee+case+lisp&oq=xah+lee+case+lisp&aqs=chrome..69i57.4919j0j4&sourceid=chrome&ie=UTF-8]

[https://news.ycombinator.com/item?id=10206306] 'Xah Lee has trolled Lisp groups for years. It's well known that much of his 'advice' is useless. The number of [bull*&^% ] posts by him is a bignum. His comp.lang.lisp trolling is legendary..'

'..his site does provide a certain amount of information. It just mixes good information with bad in a way which makes it very hard for beginners to tell one from the other..'

'Literally thousands of posts can be found on comp.lang.lisp.'

'It's just that other people do deserve to know that investing their time into studying some kind of material is not likely to pay off.'

Now hey, you may be weary of this, it's new to me. I am amused, I don't demand that you justify yourself, I'm just letting you know what happened. I'm simply being completely straightforward here, strictly truth. I only got into this because I was puzzling over these lines and doubting myself:

3792  (define-key xah-fly-key-map (kbd (xah-fly--key-char "a"))
3793    (if (fboundp 'smex) 'smex (if (fboundp 'helm-M-x) 'helm-M-x 'execute-extended-command))) 

I have pondered the logic, and I think I like better the notion of not simply replacing this with a 'case', but actually, forget it, what if you just call 'execute-extended command'? If somebody wants to remap for themselves, then you could, as it seems to me, simply let them. Like so:

(global-set-key [remap execute-extended-command] #'smex)

Thus, I have commented these lines out:

3792  #(define-key xah-fly-key-map (kbd (xah-fly--key-char "a"))
3793   # (if (fboundp 'smex) 'smex (if (fboundp 'helm-M-x) 'helm-M-x 'execute-extended-command))) 

And I'll make a pull request, pending..

Remember that I myself have stripped the 'xah-fly-key-map' out, entirely, and instead of having a mutable keymap for both 'command' and 'insert' modes, I'm swapping between two immutable keymaps. So, the original issue was that for me, these lines had to go anyways..

gcentauri commented 4 years ago

Commenting here, because it seems relevant and would like to build on Dan's work if possible. Happy to help if you need a hand Xah.

My direct issue is trying to use some Slime mode packages that are bundled in the Common Lisp layer in Spacemacs. The minor mode keymaps conflict (of-course) but in a way that is particularly annoying for xah-fly-keys user. SPC does not activate the leader key and I have to unbind it in several places:

  (with-eval-after-load 'slime
    (define-key slime-mode-map (kbd "SPC") nil)
    (define-key slime-autodoc-mode-map (kbd "SPC") nil)
    (define-key slime-editing-map (kbd "SPC") nil)
    (define-key slime-repl-mode-map (kbd "SPC") nil)
    (define-key slime-repl-mode-map (kbd ",") nil)
    )

The , key is also annoying, as i use it all the time.

I also came across the emulation-mode-map-alists variable when trying to understand how Evil and Spacemacs managed to have priority in the command mode. I am planning to play around with seeing if i can add a hook that will add and remove the xah-fly-key-map to the emulation-mode alist that might help xah-fly-keys have priority when in command mode.

Let me know if you have plans for a solution for this, or if simply doing manual configuration for key conflicts on a user basis is more appropriate for this project.

gcentauri commented 4 years ago

i found out that just pushing xah-fly-key-map to the front of the minor-mode-map-alist solves the precedence problem fairly cleanly. since i use Spacemacs, i don't necessarily have control over which minor modes are loaded when, and xah fly keys is loaded earlier than slime, since slime gets deferred.

xahlee commented 4 years ago

fixed by @DanLanglois and @wi11dey commit #89