0
votes

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.

1
I don't use evil or ivy, but I am aware that there is a minibuffer-exit-hook and a minibuffer-setup-hook that may be helpful. I have set up custom functions that change appearances if I want to move into or out of the minibuffer (leaving it open with something still happening, such as waiting for the user to type additional information or press the return key). I also set a timer function that fires just before I send a quit signal so that it doesn't get canceled -- i.e., about three different custom keyboard-quit functions that all launch my timer function.lawlist
Your suggestion inspired the answer I posted below.Piglet

1 Answers

0
votes

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.