Switch state through a chosen keysequence (jj, jk or fd)
Started using Boon and I really like the setup. But ofcourse the issue with a modal system is the switching between the states. Personally I dont like switching through Ctrl, Meta or Esc ...it just doesnt feel natural ..especially when you will be switching continously. I started using Devil-mode (I know strange name..well its what it is) by which I could map the " ; " key to Ctrl globally .. so I bound C-j in the insert-map to call the "boon-command-set-state" and thus I could switch easily to the command-state by pressing " ; - j " from the insert mode. This was an adjustment that made switching much better and easy on the finger as " ; " and j are used to move left and right. But recently I found another way which from my perspective is even better ... and this is by using a hydra. When I was using Evil mode ...you have the possiblity to use Evil-escape ..and in there I could use jj, jk or even fd as my switch sequence and I wanted to have something like that (without using keychord.el ..somehow this package slows down emacs). So with a hydra you can do it ...which is beautiful I think:) ... Hereby an example for "fd" ...if clicked on f from the INS state the hydra is activated, the user will have 1 sec to either switch to CMD or the char "f" will be printed (of course you could change the time to whatever you like)
from abo-abo https://github.com/abo-abo/hydra/issues/34 ` ;; a timer function that runs whenever the hydra is selected or an option is selected (defun hydra-generic-timeout (timer secs fun) (when (and (boundp timer) (timerp (symbol-value timer))) (cancel-timer (symbol-value timer))) (setq timer (set timer (timer-create))) (timer-set-time timer (timer-relative-time (current-time) secs)) (timer-set-function timer fun) (timer-activate timer))
;; needed as a global var to keep track of wether an option has been selected (setq state-validator nil)
(defun hydra-timed-switch ()
(hydra-generic-timeout
'hydra-cv-timer
1.0
(lambda ()
(unless state-validator (insert "f"))
(setq state-validator nil)
(setq hydra-deactivate t)
(hydra-keyboard-quit))))
(defhydra hydra-state (:pre hydra-timed-switch
:color blue
:hin:t nil)
("d" (progn (setq state-validator t) (boon-set-comand-state))))
(bind-key "d" #'hydra-state/body boon-insert-map)
`
an update on the above:
it seems that hydra already takes care of the modal switching ...which is great. This is a better solution:
I am using "fd" as my switch from boon-insert-mode to command-mode:
step 1: create a hydra with you preferred key:
(defhydra hydra-change-mode (:color blue :body-pre (insert "f") :idle 1.0) ("d" (progn (delete-char -1) (boon-set-command-state))) )
step 2: create a binding in the boon-insert-map:
(bind-key "f" #'hydra-change-mode/body boon-insert-map)
I adapted this solution for Meow for Boon. It works great for me:
(setq boon-two-char-escape-sequence "kt")
(setq boon-two-char-escape-delay 0.2)
(defun boon--two-char-exit-insert-state (s)
(when boon-insert-state
(let ((modified (buffer-modified-p)))
(insert (elt s 0))
(let* ((second-char (elt s 1))
(event
(if defining-kbd-macro
(read-event nil nil)
(read-event nil nil boon-two-char-escape-delay))))
(when event
(if (and (characterp event) (= event second-char))
(progn
(backward-delete-char 1)
(set-buffer-modified-p modified)
(boon-set-command-state))
(push event unread-command-events)))))))
(defun boon-two-char-exit-insert-state ()
(interactive)
(boon--two-char-exit-insert-state boon-two-char-escape-sequence))
(define-key boon-insert-map (substring boon-two-char-escape-sequence 0 1)
#'boon-two-char-exit-insert-state)