Skip to content

Advice of set-window-buffer unconditionally enables evil-local-mode #1561

@condy0919

Description

@condy0919

Issue type

  • Bug report

Environment

Emacs version: Emacs 29.0.50
Operating System: archlinux
Evil version: 1.14.0
Evil installation type: melpa
Graphical/Terminal: GUI
Tested in a make emacs session (see CONTRIBUTING.md): No

Reproduction steps

  • Start Emacs

Eval the following recipe.

(package-initialize)
(setq evil-want-minibuffer nil)
(require 'evil)
(evil-mode +1)

(defun test-setup ()
  (let* ((temp (generate-new-buffer "*temp*"))
         (win (with-minibuffer-selected-window (display-buffer temp))))
    (message "BEFORE %S" evil-local-mode)
    (set-window-buffer win (current-buffer))
    (message "AFTER %S" evil-local-mode)
    (kill-buffer temp)))

(defun test ()
  (interactive)
  (minibuffer-with-setup-hook #'test-setup
    (read-from-minibuffer "Prompt: ")))

M-x test

Expected behavior

ESC could exit the minibuffer.

Actual behavior

ESC is bound to evil-force-normal-state since evil-local-mode is enabled.

Further notes

It's originally reported at minad/vertico#171, minad has identified the bug:

evil/evil-core.el

Lines 362 to 373 in 652d726

;; When a buffer is created in a low-level way, it is invisible to
;; Evil (as well as other globalized minor modes) because no hooks are
;; run. This is appropriate since many buffers are used for throwaway
;; purposes. Passing the buffer to `set-window-buffer' indicates
;; otherwise, though, so advise this function to initialize Evil.
(defadvice set-window-buffer (before evil)
"Initialize Evil in the displayed buffer."
(when evil-mode
(when (get-buffer (ad-get-arg 1))
(with-current-buffer (ad-get-arg 1)
(unless evil-local-mode
(evil-local-mode 1))))))

The advice of set-window-buffer unconditionally enable evil-local-mode. IMHO, the buffer (ad-get-arg 1) shouldn't be evilfied if it satisfies (minibufferp) and evil-want-minibuffer is t.

See

evil/evil-core.el

Lines 167 to 178 in 652d726

;; The function `evil-initialize' should only be used to initialize
;; `evil-local-mode' from the globalized minor-mode `evil-mode'. It is
;; called whenever evil is enabled in a buffer for the first time or
;; when evil is active and the major-mode of the buffer changes. In
;; addition to enabling `evil-local-mode' it also sets the initial
;; evil-state according to the major-mode.
(defun evil-initialize ()
"Enable Evil in the current buffer, if appropriate.
To enable Evil globally, do (evil-mode 1)."
(unless (and (minibufferp) (not evil-want-minibuffer))
(evil-local-mode 1)
(evil-initialize-state)))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions