bug-gnu-emacs
[Top][All Lists]
Advanced

[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 ()

reply via email to

[Prev in Thread] Current Thread [Next in Thread]