[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#58888: 28.1.90; font-lock-defaults not respected when hack-local-var
From: |
Stefan Monnier |
Subject: |
bug#58888: 28.1.90; font-lock-defaults not respected when hack-local-variables unsafe variable dialogue is displayed before setting the defaults |
Date: |
Sun, 30 Oct 2022 22:15:40 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) |
> ------------
> # -*- mode:my/test -*-
> This is test with keyword to be fontified.
>
> # Local Variables:
> # eval: (setq unsafe-variable t)
> # End:
> -------------
>
> Then, consider the following major mode:
>
> (define-derived-mode my/test-mode text-mode "Test"
> ""
> (add-hook 'hack-local-variables-hook
> (lambda ()
> (setq-local my/test-mode-keywords '(("keyword" .
> font-lock-keyword-face)))
> (setq font-lock-defaults '(my/test-mode-keywords)))
> nil 'local))
>
> 1. emacs -Q
> 2. Evaluate the major mode definition
> 3. Open the file
> 4. Answer "y" in the unsafe variable prompt
> 5. Observe "keyword" not being fontified.
> 6. Expected: "keyword" fontified using font-lock-keyword-face.
Hmm... AFAICT the problem here is that the implementation of
`global-font-lock-mode` ends up trying to enable `font-lock-mode` in
that file's buffer during execution of the
`after-major-mode-change-hook` of *another* buffer while querying
whether to obey those file-local settings, and then fails to try again
when the hook is run in the desired buffer.
I suspect the patch below might help (requires recompiling
`font-core.el` and re-dumping Emacs), but as the comment in there
explains it might not always be sufficient either.
Hmm...
Stefan
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index 7d54a84687b..4d2174fbe6a 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -485,6 +485,8 @@ define-globalized-minor-mode
(extra-keywords nil)
(MODE-variable mode)
(MODE-buffers (intern (concat global-mode-name "-buffers")))
+ (MODE-enable-in-buffer
+ (intern (concat global-mode-name "-enable-in-buffer")))
(MODE-enable-in-buffers
(intern (concat global-mode-name "-enable-in-buffers")))
(MODE-check-buffers
@@ -551,10 +553,10 @@ define-globalized-minor-mode
(if ,global-mode
(progn
(add-hook 'after-change-major-mode-hook
- #',MODE-enable-in-buffers)
+ #',MODE-enable-in-buffer)
(add-hook 'find-file-hook #',MODE-check-buffers)
(add-hook 'change-major-mode-hook #',MODE-cmhh))
- (remove-hook 'after-change-major-mode-hook #',MODE-enable-in-buffers)
+ (remove-hook 'after-change-major-mode-hook #',MODE-enable-in-buffer)
(remove-hook 'find-file-hook #',MODE-check-buffers)
(remove-hook 'change-major-mode-hook #',MODE-cmhh))
@@ -601,7 +603,32 @@ define-globalized-minor-mode
;; List of buffers left to process.
(defvar ,MODE-buffers nil)
- ;; The function that calls TURN-ON in each buffer.
+ ;; The function that calls TURN-ON in the current buffer.
+ (defun ,MODE-enable-in-buffer ()
+ ;; Remove ourselves from the list of pending buffers.
+ (setq ,MODE-buffers (delq (current-buffer) ,MODE-buffers))
+ (unless ,MODE-set-explicitly
+ (unless (eq ,MODE-major-mode major-mode)
+ (if ,MODE-variable
+ (progn
+ (,mode -1)
+ (funcall ,turn-on-function))
+ (funcall ,turn-on-function))))
+ (setq ,MODE-major-mode major-mode))
+ (put ',MODE-enable-in-buffer 'definition-name ',global-mode)
+
+ ;; In the normal case, major modes run `after-change-major-mode-hook'
+ ;; which will have called `MODE-enable-in-buffer' for us. But some
+ ;; major modes don't use `define-derived-mode' and thus fail to run
+ ;; `after-change-major-mode-hook', so have a combination of ugly hacks
+ ;; to try and catch those corner cases by listening to
+ ;; `change-major-mode-hook' to discover potential candidates and then
+ ;; checking in `post-command-hook' and `find-file-hook' if some of those
+ ;; still haven't run `after-change-major-mode-hook'.
+ ;; FIXME: We should try a get rid of this ugly hack and rely purely
+ ;; on `after-change-major-mode-hook' because they can (and do) end up
+ ;; running `MODE-enable-in-buffer' too early (when the major isn't yet
+ ;; fully setup) in some cases (see bug#58888).
(defun ,MODE-enable-in-buffers ()
(let ((buffers ,MODE-buffers))
;; Clear MODE-buffers to avoid scanning the same list of
@@ -611,14 +638,7 @@ define-globalized-minor-mode
(dolist (buf buffers)
(when (buffer-live-p buf)
(with-current-buffer buf
- (unless ,MODE-set-explicitly
- (unless (eq ,MODE-major-mode major-mode)
- (if ,MODE-variable
- (progn
- (,mode -1)
- (funcall ,turn-on-function))
- (funcall ,turn-on-function))))
- (setq ,MODE-major-mode major-mode))))))
+ (,MODE-enable-in-buffer))))))
(put ',MODE-enable-in-buffers 'definition-name ',global-mode)
(defun ,MODE-check-buffers ()