Subject: bug#76912: 31.0.50; hack-local-variables docstring inaccurate about directory-local variables

From: Sean Whitton <[email-masked]>
Date: Tue, 11 Mar 2025 14:36:07 +0800

Hello,

On Mon 10 Mar 2025 at 06:51pm +02, Eli Zaretskii wrote:

> The code clearly calls hack-dir-local-variables, and has been doing so
> since 2008, AFAICT.  As usual, we changed the code, but failed pt
> update the doc string.
>
> Note that the ELisp manual keeps silence about this aspect of
> hack-local-variables.
>
> It would be good to document which directory is used for non-file
> buffers, btw.

How's this -- targeting the emacs-30 branch.

-- 
Sean Whitton
>From 843579380a5d0d5015fe1883deec7c70a72e5897 Mon Sep 17 00:00:00 2001
From: Sean Whitton <[email-masked]>
Date: Tue, 11 Mar 2025 14:35:48 +0800
Subject: [PATCH] Correct some outdated docs for hack-local-variables

* doc/lispref/modes.texi (Major Mode Conventions, Mode Hooks):
Don't say that hack-local-variables is called for only buffers
visiting files.
* doc/lispref/variables.texi (File Local Variables):
<hack-local-variables>: Say that it applies directory-local
variables too.
<dir-local-variables-alist>: New entry for this variable.
* lisp/files.el (hack-local-variables): Say that it always puts
into effect directory-local variables.
---
 doc/lispref/modes.texi     |  9 ++++-----
 doc/lispref/variables.texi | 28 +++++++++++++++++++++-------
 lisp/files.el              |  5 +++--
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 31d420eedb6..a748e76ea4f 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -546,7 +546,7 @@ Major Mode Conventions
 @code{@var{modename}-mode-hook}.  The very last thing the major mode command
 should do is to call @code{run-mode-hooks}.  This runs the normal
 hook @code{change-major-mode-after-body-hook}, the mode hook, the
-function @code{hack-local-variables} (when the buffer is visiting a file),
+function @code{hack-local-variables},
 and then the normal hook @code{after-change-major-mode-hook}.
 @xref{Mode Hooks}.
 
@@ -1124,10 +1124,9 @@ Mode Hooks
 Major modes should run their mode hook using this function.  It is
 similar to @code{run-hooks} (@pxref{Hooks}), but it also runs
 @code{change-major-mode-after-body-hook}, @code{hack-local-variables}
-(when the buffer is visiting a file) (@pxref{File Local Variables}),
-and @code{after-change-major-mode-hook}.  The last thing it does is to
-evaluate any @code{:after-hook} forms declared by parent modes
-(@pxref{Derived Modes}).
+(@pxref{File Local Variables}), and @code{after-change-major-mode-hook}.
+The last thing it does is to evaluate any @code{:after-hook} forms
+declared by parent modes (@pxref{Derived Modes}).
 
 When this function is called during the execution of a
 @code{delay-mode-hooks} form, it does not run the hooks or
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 7bc9243649c..d8dd08691c2 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -2014,14 +2014,20 @@ File Local Variables
 @w{@samp{-*-}} line.  @code{set-auto-mode} does that, also taking
 @code{enable-local-variables} into account (@pxref{Auto Major Mode}).
 
-This function works by walking the alist stored in
-@code{file-local-variables-alist} and applying each local variable in
-turn.  It calls @code{before-hack-local-variables-hook} and
+This function also puts into effect directory-local variables as
+specified in @file{.dir-locals.el}.  If the buffer is not visiting any
+file, then the directory-local variables that apply are those which
+would be applicable to files in the @code{default-directory}.
+
+This function works by walking the alists stored in
+@code{file-local-variables-alist} and @code{dir-local-variables-alist}
+and applying each local variable in turn.  It calls
+@code{before-hack-local-variables-hook} and
 @code{hack-local-variables-hook} before and after applying the
-variables, respectively.  It only calls the before-hook if the alist
-is non-@code{nil}; it always calls the other hook.  This
-function ignores a @samp{mode} element if it specifies the same major
-mode as the buffer already has.
+variables, respectively.  It only calls the before-hook if
+@code{file-local-variables-alist} is non-@code{nil}; it always calls the
+other hook.  This function ignores a @samp{mode} element if it specifies
+the same major mode as the buffer already has.
 
 If the optional argument @var{handle-mode} is @code{t}, then all this
 function does is return a symbol specifying the major mode, if the
@@ -2044,6 +2050,14 @@ File Local Variables
 one.
 @end defvar
 
+@defvar dir-local-variables-alist
+This buffer-local variable holds the alist of directory-local variable
+settings.  Its elements have the same structure as those of
+@code{file-local-variables-alist}.  When Emacs visits a file, it
+collects all the directory-local variables into this alist, and then the
+@code{hack-local-variables} function applies them one by one.
+@end defvar
+
 @defvar before-hack-local-variables-hook
 Emacs calls this hook immediately before applying file-local variables
 stored in @code{file-local-variables-alist}.
diff --git a/lisp/files.el b/lisp/files.el
index 007fd23a5f5..bd2c7c44e12 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -4163,8 +4163,9 @@ hack-local-variables--warned-lexical
 
 (defun hack-local-variables (&optional handle-mode inhibit-locals)
   "Parse and put into effect this buffer's local variables spec.
-For buffers visiting files, also puts into effect directory-local
-variables.
+Also puts into effect directory-local variables.
+For buffers not visiting files, apply the directory-local variables that
+would be applicable to files in `default-directory'.
 
 Uses `hack-local-variables-apply' to apply the variables.
 
-- 
2.45.2