Subject: bug#77510: 31.0.50; help-customize fails with multiply defined symbols

From: Dmitry Gutov <[email-masked]>
Date: Sun, 13 Apr 2025 03:44:49 +0300

Hi! Thanks for reporting.

On 04/04/2025 01:16, Stephen Berman via Bug reports for GNU Emacs, the 
Swiss army knife of text editors wrote:
> 0. emacs -Q
> 1. Type `C-h o fringe-mode RET' to pop up a *Help* buffer displaying
>     help for both the function fringe-mode and the variable fringe-mode.
> 2. In the *Help* buffer type `c'.
> => Emacs dings and displays the message "No variable or face to customize"
> 
> When executing this recipe in emacs-30, after step 2 Emacs switches to a
> *Customize* buffer for the variable fringe-mode, which is the expected
> behavior after typing `c' (help-customize) in *Help*.  This is broken in
> master.  The breakage is due to this commit:
> 
> commit e776df2a3eae0454ea85287e15ebba649bf8e918
> Author:     Dmitry Gutov <[email-masked]>
> Commit:     Dmitry Gutov <[email-masked]>
> CommitDate: Sun Oct 6 04:32:00 2024 +0300
> 
>      help-setup-xref: Keep the local values only of some variables
> 
>      * lisp/help-mode.el (help-setup-xref): Kill all local variables,
>      saving ones that are known to need to be preserved (bug#73637).
> 
> and the breakage remained after the two followup commits, which is the
> current code state.
> 
> According to my debugging, calling help-setup-xref at the end of
> describe-symbol after the function definition help has been added to the
> *Help* buffer nullifies the property list of help-mode--current-data
> (this happens on evaluating `(funcall major-mode)' in help-setup-xref
> when the value of major-mode is 'help-mode), which renders
> help-customize a noop.  The following patch fixes the breakage according
> to my brief testing, though I'm not sure it doesn't have unwanted
> side-effects (but at least I get the same test results on running make
> check with the patch as without it).

It seems like your proposal would regress the bug report that's 
referenced in the above commit message. The change has the goal to reset 
some buffer-local variables, and the current means to do that is to call 
the major mode function again.

If the major-mode function is not called, the vars are not reset.

What are the other options we could use?

help-setup-xref's docstring says it should be called very early - 
perhaps before the value of help-mode--current-data is assigned?

Making help-mode--current-data would also be an option, but it won't 
work alone because help-mode function sets it to nil explicitly as well. 
I wonder what will happen if we remove that assignment.

Finally, if 'describe-symbol' is the only main exception (where 
help-setup-xref is called late), we could save and restore the current 
value of help-mode--current-data just there.

Like this:

diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 6c4c3f4da97..fa7241d3e9d 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -1965,7 +1965,8 @@ describe-symbol
          (unless single
            ;; Don't record the `describe-variable' item in the stack.
            (setq help-xref-stack-item nil)
-          (help-setup-xref (list #'describe-symbol symbol) nil))
+          (let ((help-mode--current-data help-mode--current-data))
+            (help-setup-xref (list #'describe-symbol symbol) nil)))
          (goto-char (point-max))
          (help-xref--navigation-buttons)
          (goto-char (point-min))))))