Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cursor color does not persist #1835

Open
pietroiusti opened this issue Sep 9, 2023 · 6 comments
Open

Cursor color does not persist #1835

pietroiusti opened this issue Sep 9, 2023 · 6 comments

Comments

@pietroiusti
Copy link

pietroiusti commented Sep 9, 2023

Issue type

  • Bug report

Environment

Emacs version: GNU Emacs 29.1.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.38, cairo version 1.17.8) of 2023-09-02
Operating System: Arch Linux
Evil version: Evil version evil-git-5fc1677
Evil installation type: I'm using make emacs in Evil's source directory
Graphical/Terminal: Graphical
Tested in a make emacs session (see CONTRIBUTING.md): Yes

Reproduction steps

  • Start Emacs
  • switch to the scratch buffer
  • switch to Emacs state using C-z
  • yank the following lines:
     (setq evil-disable-insert-state-bindings t)
     (setq evil-default-state 'emacs)
     (setq evil-normal-state-cursor '("#e80000" box)) ;; red
     (setq evil-insert-state-cursor '("#e80000" bar)) ;; red
     (setq evil-emacs-state-cursor '("#839496" box)) ;; grey
    
  • M-x eval-buffer
  • Press C-z. The cursor correctly becomes red.
  • Place the cursor on any characters of evil-emacs-state-cursor on the last line.

Expected behavior

Cursor's color should remain red.

Actual behavior

Cursor's color becomes grey.

Further notes

I suspect the color change is triggered in other contexts as well. This was the easiest way to replicate.

Here is the backtrace using debug-on-entry on set-cursor-color:

Debugger entered--entering a function:
* set-cursor-color("#839496")
  (if (equal (frame-parameter nil 'cursor-color) color) nil (set-cursor-color color))
  evil-set-cursor-color("#839496")
  (cond ((functionp spec) (condition-case nil (progn (funcall spec)) (error nil))) ((stringp spec) (evil-set-cursor-color spec)) (t (setq cursor-type spec)))
  (let ((spec (car tail))) (cond ((functionp spec) (condition-case nil (progn (funcall spec)) (error nil))) ((stringp spec) (evil-set-cursor-color spec)) (t (setq cursor-type spec))) (setq tail (cdr tail)))
  (while tail (let ((spec (car tail))) (cond ((functionp spec) (condition-case nil (progn (funcall spec)) (error nil))) ((stringp spec) (evil-set-cursor-color spec)) (t (setq cursor-type spec))) (setq tail (cdr tail))))
  (let ((tail specs)) (while tail (let ((spec (car tail))) (cond ((functionp spec) (condition-case nil (progn (funcall spec)) (error nil))) ((stringp spec) (evil-set-cursor-color spec)) (t (setq cursor-type spec))) (setq tail (cdr tail)))))
  evil-set-cursor(("#839496" box))
  (save-current-buffer (set-buffer (or buffer (current-buffer))) (evil-set-cursor (if (and color (listp default)) (cl-remove-if #'stringp default) default)) (evil-set-cursor cursor))
  (let* ((state (or state evil-force-cursor evil-state 'normal)) (default (or evil-default-cursor t)) (cursor (evil-state-property state :cursor t)) (color (or (and (stringp cursor) cursor) (and (listp cursor) (evil-member-if #'stringp cursor)) (frame-parameter nil 'cursor-color)))) (save-current-buffer (set-buffer (or buffer (current-buffer))) (evil-set-cursor (if (and color (listp default)) (cl-remove-if #'stringp default) default)) (evil-set-cursor cursor)))
  (progn (let* ((state (or state evil-force-cursor evil-state 'normal)) (default (or evil-default-cursor t)) (cursor (evil-state-property state :cursor t)) (color (or (and (stringp cursor) cursor) (and (listp cursor) (evil-member-if #'stringp cursor)) (frame-parameter nil 'cursor-color)))) (save-current-buffer (set-buffer (or buffer (current-buffer))) (evil-set-cursor (if (and color (listp default)) (cl-remove-if #'stringp default) default)) (evil-set-cursor cursor))))
  (if evil-local-mode (progn (let* ((state (or state evil-force-cursor evil-state 'normal)) (default (or evil-default-cursor t)) (cursor (evil-state-property state :cursor t)) (color (or (and (stringp cursor) cursor) (and (listp cursor) (evil-member-if ... cursor)) (frame-parameter nil 'cursor-color)))) (save-current-buffer (set-buffer (or buffer (current-buffer))) (evil-set-cursor (if (and color (listp default)) (cl-remove-if #'stringp default) default)) (evil-set-cursor cursor)))))
  evil-refresh-cursor(emacs)
  (if evil-no-display nil (evil-refresh-cursor 'emacs) (evil-refresh-mode-line 'emacs))
  (let ((evil-state 'emacs)) (evil-normalize-keymaps) (if 't (activate-input-method evil-input-method) (if deactivate-current-input-method-function (progn (deactivate-input-method)))) (if evil-no-display nil (evil-refresh-cursor 'emacs) (evil-refresh-mode-line 'emacs)) (run-hooks 'evil-emacs-state-entry-hook) (if (and evil-echo-state arg (not evil-no-display) evil-emacs-state-message) (progn (if (functionp evil-emacs-state-message) (funcall evil-emacs-state-message) (evil-echo "%s" evil-emacs-state-message)))))
  (let ((evil-next-state 'emacs) input-method-activate-hook input-method-deactivate-hook) (evil-change-state nil) (setq evil-state 'emacs) (progn (let* ((p (if (and #'equal (not ...)) (assoc 'emacs evil-previous-state-alist #'equal) (assq 'emacs evil-previous-state-alist))) (v evil-previous-state)) (progn (if p (setcdr p v) (setq evil-previous-state-alist (cons (setq p ...) evil-previous-state-alist))) v)) evil-previous-state-alist) (let ((evil-state 'emacs)) (evil-normalize-keymaps) (if 't (activate-input-method evil-input-method) (if deactivate-current-input-method-function (progn (deactivate-input-method)))) (if evil-no-display nil (evil-refresh-cursor 'emacs) (evil-refresh-mode-line 'emacs)) (run-hooks 'evil-emacs-state-entry-hook) (if (and evil-echo-state arg (not evil-no-display) evil-emacs-state-message) (progn (if (functionp evil-emacs-state-message) (funcall evil-emacs-state-message) (evil-echo "%s" evil-emacs-state-message))))))
  (cond ((and (numberp arg) (< arg 1)) (progn (setq evil-previous-state evil-state) (setq evil-state nil)) (let ((evil-state 'emacs)) (run-hooks 'evil-emacs-state-exit-hook) (setq evil-state nil) (evil-normalize-keymaps))) (t (if evil-local-mode nil (evil-local-mode)) (let ((evil-next-state 'emacs) input-method-activate-hook input-method-deactivate-hook) (evil-change-state nil) (setq evil-state 'emacs) (progn (let* ((p (if ... ... ...)) (v evil-previous-state)) (progn (if p (setcdr p v) (setq evil-previous-state-alist ...)) v)) evil-previous-state-alist) (let ((evil-state 'emacs)) (evil-normalize-keymaps) (if 't (activate-input-method evil-input-method) (if deactivate-current-input-method-function (progn (deactivate-input-method)))) (if evil-no-display nil (evil-refresh-cursor 'emacs) (evil-refresh-mode-line 'emacs)) (run-hooks 'evil-emacs-state-entry-hook) (if (and evil-echo-state arg (not evil-no-display) evil-emacs-state-message) (progn (if (functionp evil-emacs-state-message) (funcall evil-emacs-state-message) (evil-echo "%s" evil-emacs-state-message))))))))
  evil-emacs-state(nil)
  funcall(evil-emacs-state nil)
  (progn (funcall func (if state (and message 1) -1)))
  (if (and (functionp func) (or message (not (eq state evil-state)))) (progn (funcall func (if state (and message 1) -1))))
  (let ((func (evil-state-property (or state evil-state) :toggle))) (if (and (functionp func) (or message (not (eq state evil-state)))) (progn (funcall func (if state (and message 1) -1)))))
  evil-change-state(emacs)
  evil-initialize-state()
  (progn (if (memql 'evil-mode-map-alist emulation-mode-map-alists) (with-no-warnings emulation-mode-map-alists) (setq emulation-mode-map-alists (cons 'evil-mode-map-alist emulation-mode-map-alists))) (evil-initialize-local-keymaps) (if (minibufferp) (progn (set (make-local-variable 'evil-default-state) 'insert) (set (make-local-variable 'evil-echo-state) nil))) (setq evil-input-method current-input-method) (evil-initialize-state) (add-hook 'input-method-activate-hook #'evil-activate-input-method t t) (add-hook 'input-method-deactivate-hook #'evil-deactivate-input-method t t) (add-hook 'activate-mark-hook 'evil-visual-activate-hook nil t) (add-hook 'pre-command-hook 'evil-repeat-pre-hook) (add-hook 'post-command-hook 'evil-repeat-post-hook))
  (if evil-local-mode (progn (if (memql 'evil-mode-map-alist emulation-mode-map-alists) (with-no-warnings emulation-mode-map-alists) (setq emulation-mode-map-alists (cons 'evil-mode-map-alist emulation-mode-map-alists))) (evil-initialize-local-keymaps) (if (minibufferp) (progn (set (make-local-variable 'evil-default-state) 'insert) (set (make-local-variable 'evil-echo-state) nil))) (setq evil-input-method current-input-method) (evil-initialize-state) (add-hook 'input-method-activate-hook #'evil-activate-input-method t t) (add-hook 'input-method-deactivate-hook #'evil-deactivate-input-method t t) (add-hook 'activate-mark-hook 'evil-visual-activate-hook nil t) (add-hook 'pre-command-hook 'evil-repeat-pre-hook) (add-hook 'post-command-hook 'evil-repeat-post-hook)) (evil-refresh-mode-line) (remove-hook 'activate-mark-hook 'evil-visual-activate-hook t) (remove-hook 'input-method-activate-hook #'evil-activate-input-method t) (remove-hook 'input-method-deactivate-hook #'evil-deactivate-input-method t) (activate-input-method evil-input-method) (evil-change-state nil))
  (let ((last-message (current-message))) (setq evil-local-mode (cond ((eq arg 'toggle) (not evil-local-mode)) ((and (numberp arg) (< arg 1)) nil) (t t))) (if (boundp 'local-minor-modes) (progn (setq local-minor-modes (delq 'evil-local-mode local-minor-modes)) (if evil-local-mode (progn (setq local-minor-modes (cons 'evil-local-mode local-minor-modes)))))) (if evil-local-mode (progn (if (memql 'evil-mode-map-alist emulation-mode-map-alists) (with-no-warnings emulation-mode-map-alists) (setq emulation-mode-map-alists (cons 'evil-mode-map-alist emulation-mode-map-alists))) (evil-initialize-local-keymaps) (if (minibufferp) (progn (set (make-local-variable 'evil-default-state) 'insert) (set (make-local-variable 'evil-echo-state) nil))) (setq evil-input-method current-input-method) (evil-initialize-state) (add-hook 'input-method-activate-hook #'evil-activate-input-method t t) (add-hook 'input-method-deactivate-hook #'evil-deactivate-input-method t t) (add-hook 'activate-mark-hook 'evil-visual-activate-hook nil t) (add-hook 'pre-command-hook 'evil-repeat-pre-hook) (add-hook 'post-command-hook 'evil-repeat-post-hook)) (evil-refresh-mode-line) (remove-hook 'activate-mark-hook 'evil-visual-activate-hook t) (remove-hook 'input-method-activate-hook #'evil-activate-input-method t) (remove-hook 'input-method-deactivate-hook #'evil-deactivate-input-method t) (activate-input-method evil-input-method) (evil-change-state nil)) (run-hooks 'evil-local-mode-hook (if evil-local-mode 'evil-local-mode-on-hook 'evil-local-mode-off-hook)) (if (called-interactively-p 'any) (progn nil (if (and (current-message) (not (equal last-message (current-message)))) nil (let ((local " in current buffer")) (message "%s %sabled%s" "Evil-Local mode" (if evil-local-mode "en" "dis") local))))))
  evil-local-mode()
  (or (and (minibufferp) (not evil-want-minibuffer)) (evil-disabled-buffer-p) (evil-local-mode))
  (if evil-local-mode (evil-initialize-state) (or (and (minibufferp) (not evil-want-minibuffer)) (evil-disabled-buffer-p) (evil-local-mode)))
  evil-initialize()
  (progn (evil-local-mode -1) (evil-initialize))
  (if evil-local-mode (progn (evil-local-mode -1) (evil-initialize)) (evil-initialize))
  (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode (progn (evil-local-mode -1) (evil-initialize)) (evil-initialize)))
  (if evil-local-mode-set-explicitly nil (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode (progn (evil-local-mode -1) (evil-initialize)) (evil-initialize))))
  (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode (progn (evil-local-mode -1) (evil-initialize)) (evil-initialize)))) (setq evil-local-mode-major-mode major-mode))
  (progn (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode (progn (evil-local-mode -1) (evil-initialize)) (evil-initialize)))) (setq evil-local-mode-major-mode major-mode)))
  (if (buffer-live-p buf) (progn (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode (progn (evil-local-mode -1) (evil-initialize)) (evil-initialize)))) (setq evil-local-mode-major-mode major-mode))))
  (let ((buf (car tail))) (if (buffer-live-p buf) (progn (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode (progn ... ...) (evil-initialize)))) (setq evil-local-mode-major-mode major-mode)))) (setq tail (cdr tail)))
  (while tail (let ((buf (car tail))) (if (buffer-live-p buf) (progn (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil (if (eq evil-local-mode-major-mode major-mode) nil (if evil-local-mode ... ...))) (setq evil-local-mode-major-mode major-mode)))) (setq tail (cdr tail))))
  (let ((tail buffers)) (while tail (let ((buf (car tail))) (if (buffer-live-p buf) (progn (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil (if ... nil ...)) (setq evil-local-mode-major-mode major-mode)))) (setq tail (cdr tail)))))
  (let ((buffers evil-mode-buffers)) (setq evil-mode-buffers nil) (let ((tail buffers)) (while tail (let ((buf (car tail))) (if (buffer-live-p buf) (progn (save-current-buffer (set-buffer buf) (if evil-local-mode-set-explicitly nil ...) (setq evil-local-mode-major-mode major-mode)))) (setq tail (cdr tail))))))
  evil-mode-enable-in-buffers()
  run-hooks(after-change-major-mode-hook)
  run-mode-hooks(special-mode-hook)
  special-mode()
  eldoc--format-doc-buffer((("Cursor for Emacs state." :thing evil-emacs-state-cursor :face font-lock-variable-name-face)))
  eldoc-display-in-echo-area((("Cursor for Emacs state." :thing evil-emacs-state-cursor :face font-lock-variable-name-face)) nil)
  run-hook-with-args(eldoc-display-in-echo-area (("Cursor for Emacs state." :thing evil-emacs-state-cursor :face font-lock-variable-name-face)) nil)
  #f(compiled-function () #<bytecode 0x1d63293ec8df93a>)()
  #f(compiled-function (string &rest plist) #<bytecode 0x138508dae21649a6>)("Cursor for Emacs state." :thing evil-emacs-state-cursor :face font-lock-variable-name-face)
  elisp-eldoc-var-docstring(#f(compiled-function (string &rest plist) #<bytecode 0x138508dae21649a6>))
  eldoc-documentation-default()
  eldoc--invoke-strategy(nil)
  eldoc-print-current-symbol-info()
  #<subr F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_12>()
  apply(#<subr F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_12> nil)
  timer-event-handler([t 0 0 500000 nil #<subr F616e6f6e796d6f75732d6c616d626461_anonymous_lambda_12> nil idle 0 nil])

@pietroiusti
Copy link
Author

pietroiusti commented Sep 17, 2023

I'm temporarily fixing the issue, at least in emacs-lisp-mode buffers and typescript-ts-mode buffers (where I use eglot, which uses eldoc) with this:

(defun gp/is-buffer-to-ignore (orig-fun &rest args)
  (if (or (string-match "*eldoc" (buffer-name))
          (string-match " *temp*" (buffer-name))
          (string= " markdown-code-fontification:typescript-ts-mode" (buffer-name)))          
      nil
    (apply orig-fun args)))

(advice-add 'evil-initialize-state :around #'gp/is-buffer-to-ignore)

@einsiedlerspiel
Copy link

The issue seems to be that the cursor colour doesn't update after emacs visited a buffer without displaying it. You can replicate this by evaluating for example

(with-temp-buffer 
  (special-mode))

After evaluation your cursor colour will match whatever motion state the mode you invoked for the temp buffer defaults to.

@kommen
Copy link

kommen commented Feb 4, 2024

I can confirm this issue persists with Emacs 29.2. Disabling eldoc-mode makes the issue go away. But the workaround from #1835 (comment) works for me while keeping eldoc-mode enabled. Thanks @pietroiusti!

@pietroiusti
Copy link
Author

pietroiusti commented Feb 8, 2024

Happy it works, @kommen. This, though, might be a better fix: (add-hook 'special-mode-hook (lambda () (turn-off-evil-mode)))

update:
Actually that doesn't take into account the ``text enrichment'' eglot does when you start a buffer of a certain mode for the first time. So I'm using this:

  (add-hook 'special-mode-hook (lambda () (turn-off-evil-mode)))
  (defun gp/is-buffer-to-ignore (orig-fun &rest args)
    (if (string-match " markdown-code-fontification" (buffer-name))
        nil
      (apply orig-fun args)))
  (advice-add 'evil-initialize-state :around #'gp/is-buffer-to-ignore)

@kommen
Copy link

kommen commented Feb 14, 2024

@pietroiusti also (add-hook 'special-mode-hook (lambda () (turn-off-evil-mode))) breaks my evil keybindings for various other modes, most importantly from magit. So I'm back to an adapted version of your snippet from #1835 (comment)

@pietroiusti
Copy link
Author

Thanks for letting me know @kommen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants