I change my cursor based on state in evil. However I notice that when I type in the minibuffer I'm in normal mode.
I'm trying to make code that change the state from whatever it's in to insert state while I type in the minibuffer and switch back when I exit the minibuffer. Note, I use ivy for minibuffer completion (though I don't think it makes a difference).
(setq evil-insert-state-cursor '((bar . 3) "chartreuse3"))
(defun void-ivy-insert-state (orig-func &rest args)
"Wrapper around ivy, so it goes into insert state."
;; minibuffer is different so I have to manually change the state
(let ((saved-evil-state evil-state))
(evil-insert-state)
(setq cursor-type (elt evil-insert-state-cursor 0))
(set-cursor-color (elt evil-insert-state-cursor 1))
(apply orig-func args)
(evil-change-state saved-evil-state)))
(advice-add 'ivy-read :around #'void-ivy-insert-state)
I expect the cursor to be the right color and the write shape while typing something into the minibuffer. And to return to the appropriate shape of the state I was in before entering the minibuffer.
What actually happens is that the cursor is the right color, but it's the wrong shape. And if I exit the minibuffer with C-g
insert state persists. It never returns to the original state. I think C-g
aborts the execution of my advice.
I achieved the desired behavior with this code.
(add-hook 'minibuffer-setup-hook (lambda () (evil-insert-state)))
(add-hook 'minibuffer-exit-hook (lambda () (evil-normal-state)))
(define-key evil-insert-state-map [escape] (lambda () (interactive)
(evil-normal-state)
(minibuffer-keyboard-quit)))
The only annoying side effect is that whenever ESC
is pressed No recursive edit is in progress
is printed to the output.
The version below is the one I use in my code. Instead of returning to normal state, it uses a variable to return to the previous evil-state before the minibuffer was opened. Also it only uses minibuffer-keyboard-quit
if the minibuffer is active.
(defvar evil-state-before-minibuffer-setup 'normal)
(add-hook 'minibuffer-setup-hook
(lambda () (setq evil-state-before-minibuffer-setup evil-state)
(evil-insert-state)))
(add-hook 'minibuffer-exit-hook (lambda ()
(evil-change-state evil-state-before-minibuffer-setup)))
(define-key evil-insert-state-map [escape]
(lambda () (interactive) (evil-normal-state)
(when (eq (active-minibuffer-window))
(selected-window))
(minibuffer-keyboard-quit))))
I make sure I only quit when the minibuffer is the selected window. Otherwise, the minibuffer would quit if we were to, say, edit a buffer while viewing the contents of the minibuffer.