noctuid / general.el

More convenient key definitions in emacs
GNU General Public License v3.0
1k stars 44 forks source link

Allow specifying context setup/teardown in key simulation commands #151

Open noctuid opened 5 years ago

noctuid commented 5 years ago

general-key and general-simulate-key should allow user-defined setup/teardown of context. General supports simulating in a state out of the box, but this would be useful if the user needed to do anything custom (e.g. simulate in context provided by alternative modal package or disabling a mode like in https://github.com/noctuid/general.el/issues/148#issuecomment-480520453).

AmaiKinono commented 5 years ago

Any news on this feature?

noctuid commented 5 years ago

I can try to work on it next week if I have time.

AmaiKinono commented 5 years ago

Actually I just started to contribute my code to some Emacs packages recently and feels like getting to have an understanding of elisp. I don't know if this is a good idea but how about you describe your design and I try to work it out this weekend? I can create a PR if I success or let you know if I fail.

noctuid commented 5 years ago

It would probably be much easier for me to do (the actual new code would be very simple, but knowing exactly where to put it might be tricky for someone not already familiar with the existing functions), but feel free to try it and make a PR if you want. It would involve adding :setup and :teardown keywords to general-key and general-simulate-key (and tests for the new keywords). Updating general-simulate-key would involve also updating general--simulate-keys.

Updating general-key would be pretty easy; updating general-simulate-key would be more difficult. Even with this functionality implemented for general-simulate-key, you couldn't do your example here without a hook or timer. With general-key, you could do it in the straightforward way by just disabling general-override-mode in :setup and enabling it in :teardown, but there is the which-key issue I mentioned before (which potentially/hopefully won't be an issue in the future). If you do want to make a PR you could also just update one of them.

AmaiKinono commented 5 years ago

I've tried to play with general-key, but found myself really not good at dealing with macros. It keeps running into errors :rofl: Sorry for giving up. I'd better watch how you do this and learn from it.

noctuid commented 5 years ago

Sorry for the long delay. I added the keywords for general-key. It looks like it's not enough to disable general-override-mode in the menu item. Are you binding C-c in an evil state and in general-override-mode? If so, something like this should work though:

(general-key "C-c" :setup (evil-local-mode -1) :teardown (evil-local-mode))
noctuid commented 5 years ago

It seems like setting emulation-mode-map-alists to nil for the duration of the lookup works:

(general-key "C-c" :let (emulation-mode-map-alists))

But this only works if lexical binding is not enabled for the file (e.g. try evaling the keybinding in the scratch buffer). Not really happy with either of these, but it's at least better than the wait to reenable general-override-mode-map method.

AmaiKinono commented 5 years ago

Are you binding C-c in an evil state and in general-override-mode?

I'm binding C-c in visual and insert state. But I would like to have it in the override keymap, so it will work without evil.

Since it's been a long time, I think it's good to first put my code here:

;; I would like these two commands to copy/cut the text when a region is active,
;; and to work as "normal" C-x and C-c otherwise.
;;
;; Now they don't work without evil. I want to modify this using general-key and
;; the new setup/teardown keywords, but currently I have no idea how to do this.
(defun toki-C-x ()
  (interactive)
  (if (region-active-p)
      (call-interactively 'kill-region)
    (funcall (general-simulate-key "C-x" :state 'emacs))))

(defun toki-C-c ()
  (interactive)
  (if (region-active-p)
      (call-interactively 'ivy-kill-ring-save)
    (funcall (general-simulate-key "C-c" :state 'emacs))))

(general-def
  :states '(visual insert)
  "C-x" 'toki-C-x
  "C-c" 'toki-C-c)

(toki-leader-def
  ;; "C-x" '(Control-X-prefix :wk "C-x")
  ;; Bind C-x like this too, just to test the new keywords.
  "C-x" (general-key "C-x" :setup (evil-local-mode -1) :teardown (evil-local-mode))
  "C-c" (general-key "C-c" :setup (evil-local-mode -1) :teardown (evil-local-mode)))

toki-leader-def is a definer like this:

(general-create-definer toki-leader-def
  ;; toki-leader-key is "M-SPC"
  :prefix toki-leader-key
  :keymaps 'override)

Now, if the general-key thing works, then pressing M-SPC C-c or M-SPC C-x when a region is active should work as a prefix, not cutting/copying the region, and that's how I should test it. Is this right?

If so, something like this should work though:

(general-key "C-c" :setup (evil-local-mode -1) :teardown (evil-local-mode))

Yes, this works. But after M-SPC C-c, normal state will be activated. I think this can be easily fixed by some coding on my side.

It looks like it's not enough to disable general-override-mode in the menu item.

But it works for me :rofl:. If I do this:

(general-def
  :keymaps 'oveerride
  "C-x" 'toki-C-x
  "C-c" 'toki-C-c)

(toki-leader-def
  "C-x" :setup (general-override-mode -1) :teardown (general-override-mode))
  "C-c" :setup (general-override-mode -1) :teardown (general-override-mode)))

Then if I press M-SPC C-c or M-SPC C-x, they work as prefix when a region is active. And I do use lexical binding in my config files. The only problem is if I press C-c or C-x directly without an active region, Emacs tells me Lisp nesting exceeds 'max-lisp-eval-depth'. To solve this I think the toki-C-c and toki-C-x functions should be rewritten to work independently with evil, but that's another thing, and I think the new keywords works perfectly.

AmaiKinono commented 4 years ago

I tried your code:

(toki-leader-def
  "C-c" (general-key "C-c" :let (emulation-mode-map-alists)))

This also works fine, and lexical binding is enabled in my configuration file. So everything works fine on my side. I don't know why it doesn't work for you :rofl: but I'm willing to offer help if you ask me to.

noctuid commented 4 years ago

Glad it works! I'm going to keep this open until I have some time to add more tests and the equivalent keywords to general-simulate-key.