commit 6d24a8e626f1c7553c90b579c399aeae8c82dd8c (HEAD, refs/remotes/origin/master) Author: Michael Albinus Date: Tue May 11 09:27:14 2021 +0200 ; Fix typo in erc.texi diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 9342a26b88..213b69e1ef 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -557,7 +557,7 @@ and the second element is the file name of the client certificate itself to use when connecting over TLS, or @code{t}, which means that @code{auth-source} will be queried for the private key and the certificate. Authenticating using a TLS client certificate is also -refered to as ``CertFP'' (Certificate Fingerprint) authentication by +referred to as ``CertFP'' (Certificate Fingerprint) authentication by various IRC networks. Examples of use: commit 59fca4e8cdcea3191abcce4b5a500b925946870c Author: Glenn Morris Date: Mon May 10 18:55:19 2021 -0700 * doc/misc/erc.texi (Connecting): Fix cross reference. diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 18f0ce4eca..9342a26b88 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -589,7 +589,7 @@ line like the following to your authinfo file machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt @end example -See (info "(auth) Help for users") for more on the +@xref{Help for users,,,auth, Emacs auth-source Library}, for more on the @file{.authinfo}/@file{.netrc} backend of @code{auth-source}. @end defun commit c38b4a9beffe7304dcee724f701276766d80d59d Author: Amin Bandali Date: Mon May 10 21:32:42 2021 -0400 Tweak documentation relating to 'erc-tls' * doc/misc/erc.texi (Connecting): Add a reference to the auth manual. * etc/NEWS: Remove the verbose, detailed example of client certificate specification and refer to the ERC manual instead. * lisp/erc/erc.el (erc-tls): Fix leftover path example in docstring. diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 45a753d43e..18f0ce4eca 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -588,6 +588,9 @@ line like the following to your authinfo file @example machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt @end example + +See (info "(auth) Help for users") for more on the +@file{.authinfo}/@file{.netrc} backend of @code{auth-source}. @end defun @subheading Server diff --git a/etc/NEWS b/etc/NEWS index 4870ca8ced..de3779cd73 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1804,36 +1804,10 @@ activity overview sidebar for joined IRC channels is now part of ERC. The 'erc-tls' function has been updated to allow specifying a TLS client certificate for authentication, as an alternative to NickServ password-based authentication. This is referred to as "CertFP" (short -for Certificate Fingerprint) by several IRC networks. - -To use a certificate with 'erc-tls', specify the ':client-certificate' -optional parameter, whose value should be as described in the -documentation of 'open-network-stream': if non-nil, it should either -be a list where the first element is the file name of the private key -corresponding to a client certificate and the second element is the -file name of the client certificate itself to use when connecting over -TLS, or t, which means that 'auth-source' will be queried for the -private key and the certificate. - -Examples of use: - - (erc-tls :server "chat.freenode.net" :port 6697 - :client-certificate - '("/home/bandali/my-cert.key" - "/home/bandali/my-cert.crt")) - - (erc-tls :server "chat.freenode.net" :port 6697 - :client-certificate - `(,(expand-file-name "~/cert-freenode.key") - ,(expand-file-name "~/cert-freenode.crt"))) - - (erc-tls :server "chat.freenode.net" :port 6697 - :client-certificate t) - -In the case of ':client-certificate t', you will need to add a line -like the following to your authinfo file (e.g. "~/.authinfo.gpg"): - - machine chat.freenode.net key /home/bandali/my-cert.key cert /home/bandali/my-cert.crt +for Certificate Fingerprint) by several IRC networks. See the Info +node "(erc) Connecting" in the ERC manual for more details and +examples on how to specify and use TLS client certificates with +'erc-tls'. ** Battery diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 6717ee37cc..547056361a 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2278,8 +2278,8 @@ Example usage: (erc-tls :server \"chat.freenode.net\" :port 6697 :client-certificate - '(\"/data/bandali/my-cert.key\" - \"/data/bandali/my-cert.crt\"))" + '(\"/home/bandali/my-cert.key\" + \"/home/bandali/my-cert.crt\"))" (interactive (let ((erc-default-port erc-default-port-tls)) (erc-select-read-args))) (let ((erc-server-connect-function 'erc-open-tls-stream)) commit 28bed069a7cc0f9d6937276b5a1eec949abc280a Author: Glenn Morris Date: Mon May 10 13:31:08 2021 -0700 * lib/Makefile.in (maintainer-clean): Fully ignore rmdir errors. diff --git a/lib/Makefile.in b/lib/Makefile.in index 825b3131d5..6c7a443099 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -113,7 +113,7 @@ distclean bootstrap-clean: mostlyclean rm -fr $(DEPDIR) maintainer-clean: distclean rm -f TAGS gnulib.mk - -rmdir malloc sys 2>/dev/null + -rmdir malloc sys 2>/dev/null || true .PHONY: mostlyclean clean distclean bootstrap-clean maintainer-clean commit 9117b42e68c9241d4a420e48cbdf46c50ea31764 Author: Glenn Morris Date: Mon May 10 13:30:00 2021 -0700 * Makefile.in: Simplify maintainer-clean. (maintainer_clean_dirs): Remove. (maintainer-clean): Don't duplicate clean by running bootstrap-clean, which can lead to issues with parallel clean. diff --git a/Makefile.in b/Makefile.in index 21e6336a7d..65eceb2a0c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -917,12 +917,9 @@ top_maintainer_clean=\ ${top_distclean}; \ rm -fr ${srcdir}/autom4te.cache -maintainer_clean_dirs = src leim lisp admin/charsets admin/grammars \ - admin/unidata test +$(foreach dir,$(distclean_dirs),$(eval $(call submake_template,$(dir),maintainer-clean))) -$(foreach dir,$(maintainer_clean_dirs),$(eval $(call submake_template,$(dir),maintainer-clean))) - -maintainer-clean: bootstrap-clean $(maintainer_clean_dirs:=_maintainer-clean) +maintainer-clean: $(distclean_dirs:=_maintainer-clean) rm -rf ${srcdir}/info rm -f ${srcdir}/etc/refcards/emacsver.tex ${top_maintainer_clean} commit dd031f311f279b3179681a6668cff358db1f2370 Author: Glenn Morris Date: Mon May 10 11:37:40 2021 -0700 * test/src/emacs-module-tests.el (mod-test-file): Unbreak out-of-tree. diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el index 0a68d51e3e..a4d858113e 100644 --- a/test/src/emacs-module-tests.el +++ b/test/src/emacs-module-tests.el @@ -37,7 +37,9 @@ "File name of the Emacs binary currently running.") (eval-and-compile - (defconst mod-test-file (ert-resource-file "mod-test") + (defconst mod-test-file + (expand-file-name "../test/src/emacs-module-resources/mod-test" + invocation-directory) "File name of the module test file.")) (require 'mod-test mod-test-file) commit 6be77eefa614186091bb29f06d9bcd5b9d4ae525 Author: Glenn Morris Date: Mon May 10 11:17:14 2021 -0700 * test/Makefile.in (clean): Remove generated mml-sec file. diff --git a/test/Makefile.in b/test/Makefile.in index 4bcfee7bad..c1518d3dcd 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -340,6 +340,7 @@ mostlyclean: clean: find . '(' -name '*.log' -o -name '*.log~' ')' $(FIND_DELETE) + rm -f ${srcdir}/lisp/gnus/mml-sec-resources/random_seed rm -f $(test_module_dir)/*.o $(test_module_dir)/*.so \ $(test_module_dir)/*.dll commit dc151c000128cef231dfd88c6da43ad76cc08aeb Author: Glenn Morris Date: Mon May 10 10:42:53 2021 -0700 Always include the test/ directory in tarfiles In hindsight, it's hard to see why not including it was ever an option. * make-dist: Always include the test/ directory. (with_tests): Remove. (--tests, --no-tests): Make these options no-ops. * Makefile.in (mostlyclean_dirs, maintainer_clean_dirs): Add "test". (mostlyclean, clean, distclean, maintainer-clean): Remove special-casing for "test". ($(CHECK_TARGETS)): Simplify. diff --git a/Makefile.in b/Makefile.in index 6bde5e5f05..21e6336a7d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -845,12 +845,11 @@ endef ### target for GCC does not delete 'libgcc.a', because recompiling it ### is rarely necessary and takes a lot of time. mostlyclean_dirs = src oldXMenu lwlib lib lib-src nt doc/emacs doc/misc \ - doc/lispref doc/lispintro + doc/lispref doc/lispintro test $(foreach dir,$(mostlyclean_dirs),$(eval $(call submake_template,$(dir),mostlyclean))) mostlyclean: $(mostlyclean_dirs:=_mostlyclean) - [ ! -d test ] || $(MAKE) -C test $@ ### 'clean' ### Delete all files from the current directory that are normally @@ -865,7 +864,6 @@ clean_dirs = $(mostlyclean_dirs) nextstep admin/charsets admin/unidata $(foreach dir,$(clean_dirs),$(eval $(call submake_template,$(dir),clean))) clean: $(clean_dirs:=_clean) - [ ! -d test ] || $(MAKE) -C test $@ -rm -f ./*.tmp etc/*.tmp* -rm -rf info-dir.* -rm -rf native-lisp @@ -891,7 +889,6 @@ distclean_dirs = $(clean_dirs) leim lisp admin/grammars $(foreach dir,$(distclean_dirs),$(eval $(call submake_template,$(dir),distclean))) distclean: $(distclean_dirs:=_distclean) - [ ! -d test ] || $(MAKE) -C test $@ ${top_distclean} ### 'bootstrap-clean' @@ -900,7 +897,6 @@ distclean: $(distclean_dirs:=_distclean) $(foreach dir,$(distclean_dirs),$(eval $(call submake_template,$(dir),bootstrap-clean))) bootstrap-clean: $(distclean_dirs:=_bootstrap-clean) - [ ! -d test ] || $(MAKE) -C test $@ [ ! -f config.log ] || mv -f config.log config.log~ rm -rf ${srcdir}/info rm -f ${srcdir}/etc/refcards/emacsver.tex @@ -922,12 +918,11 @@ top_maintainer_clean=\ rm -fr ${srcdir}/autom4te.cache maintainer_clean_dirs = src leim lisp admin/charsets admin/grammars \ - admin/unidata + admin/unidata test $(foreach dir,$(maintainer_clean_dirs),$(eval $(call submake_template,$(dir),maintainer-clean))) maintainer-clean: bootstrap-clean $(maintainer_clean_dirs:=_maintainer-clean) - [ ! -d test ] || $(MAKE) -C test $@ rm -rf ${srcdir}/info rm -f ${srcdir}/etc/refcards/emacsver.tex ${top_maintainer_clean} @@ -958,12 +953,7 @@ TAGS tags: lib lib-src # src CHECK_TARGETS = check check-maybe check-expensive check-all .PHONY: $(CHECK_TARGETS) $(CHECK_TARGETS): all -ifeq ($(wildcard test),test) $(MAKE) -C test $@ -else - @echo "You do not seem to have the test/ directory." - @echo "Maybe you used a release tarfile that lacks tests." -endif test/%: $(MAKE) -C test $* diff --git a/make-dist b/make-dist index 606fdd9e3a..7074bb801b 100755 --- a/make-dist +++ b/make-dist @@ -52,7 +52,6 @@ make_tar=no default_gzip=gzip newer="" with_info=yes -with_tests=yes changelog=yes verbose=no @@ -109,16 +108,10 @@ while [ $# -gt 0 ]; do update=no ;; - ## Include the test/ directory. - ## This is for backward compatibility to when --no-tests was the default. - "--tests") - with_tests=yes + "--tests"|"--no-tests") + echo "The option $1 no longer does anything" ;; - ## Exclude the test/ directory. - "--no-tests") - with_tests=no - ;; "--verbose") verbose=yes @@ -136,7 +129,6 @@ while [ $# -gt 0 ]; do echo " --no-update don't recompile or do analogous things" echo " --no-changelog don't generate the top-level ChangeLog" echo " --no-info don't include info files" - echo " --no-tests don't include the test/ directory" echo " --snapshot same as --clean-up --no-update --tar" echo " --tar make a tar file" echo " --verbose noisier output" @@ -402,11 +394,7 @@ manifest=MANIFEST # if .git is present. if ( [ $update = yes ] || [ ! -f $manifest ] ) && [ -r .git ]; then echo "Updating $manifest" - if [ $with_tests = yes ]; then - git ls-files > $manifest - else - git ls-files | grep -v '^test' >$manifest - fi || exit + git ls-files > $manifest || exit printf '%s\n' $possibly_non_vc_files $info_files >>$manifest || exit sort -u -o $manifest $manifest || exit fi commit 02c80307f13f7ffe3dc024aee72e47060b4a1996 Author: Michael Albinus Date: Mon May 10 13:42:48 2021 +0200 Extend meaning of UNIQUIFY `auto-save-file-name-transforms'. (Bug#47493) * doc/lispref/backups.texi (Auto-Saving): Explain UNIQUIFY being a secure hash in auto-save-file-name-transforms. * etc/NEWS: Mention change in `auto-save-file-name-transforms'. * lisp/files.el (auto-save-file-name-transforms): Adapt docstring. (make-auto-save-file-name): Care, if UNIQ is a secure hash symbol. diff --git a/doc/lispref/backups.texi b/doc/lispref/backups.texi index c0a4065bdb..85a4f9e0ac 100644 --- a/doc/lispref/backups.texi +++ b/doc/lispref/backups.texi @@ -481,6 +481,12 @@ all directory separators were changed to @samp{!} to prevent clashes. (This will not work correctly if your filesystem truncates the resulting name.) +If @var{uniquify} is one of the members of +@code{secure-hash-algorithms}, Emacs constructs the nondirectory part +of the auto-save file name by applying that @code{secure-hash} to the +buffer file name. This avoids any risk of excessively long file +names. + All the transforms in the list are tried, in the order they are listed. When one transform applies, its result is final; no further transforms are tried. diff --git a/etc/NEWS b/etc/NEWS index e797d69a9d..4870ca8ced 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3083,6 +3083,13 @@ It is written as '(:success BODY...)' where BODY is executed whenever the protected form terminates without error, with the specified variable bound to the the value of the protected form. ++++ +** 'The 'uniquify' argument in 'auto-save-file-name-transforms' can be a symbol. +If this symbol is one of the members of 'secure-hash-algorithms', +Emacs constructs the nondirectory part of the auto-save file name by +applying that 'secure-hash' to the buffer file name. This avoids any +risk of excessively long file names. + * Changes in Emacs 28.1 on Non-Free Operating Systems diff --git a/lisp/files.el b/lisp/files.el index 7fb1320269..47c5fc133c 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -391,6 +391,10 @@ constructed by taking the directory part of the replaced file-name, concatenated with the buffer file name with all directory separators changed to `!' to prevent clashes. This will not work correctly if your filesystem truncates the resulting name. +If UNIQUIFY is one of the members of `secure-hash-algorithms', +Emacs constructs the nondirectory part of the auto-save file name +by applying that `secure-hash' to the buffer file name. This +avoids any risk of excessively long file names. All the transforms in the list are tried, in the order they are listed. When one transform applies, its result is final; @@ -6647,14 +6651,20 @@ See also `auto-save-file-name-p'." uniq (car (cddr (car list))))) (setq list (cdr list))) (if result - (if uniq - (setq filename (concat - (file-name-directory result) - (subst-char-in-string - ?/ ?! - (replace-regexp-in-string "!" "!!" - filename)))) - (setq filename result))) + (setq filename + (cond + ((memq uniq (secure-hash-algorithms)) + (concat + (file-name-directory result) + (secure-hash uniq filename))) + (uniq + (concat + (file-name-directory result) + (subst-char-in-string + ?/ ?! + (replace-regexp-in-string + "!" "!!" filename)))) + (t result)))) (setq result (if (and (eq system-type 'ms-dos) (not (msdos-long-file-names))) commit fafe912bd3e952835bb5876aab8c7bda2f4fee24 Author: Michael Albinus Date: Mon May 10 13:36:06 2021 +0200 ; Fix oddities in etc/NEWS diff --git a/etc/NEWS b/etc/NEWS index c421073c96..e797d69a9d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -184,7 +184,7 @@ commands. ** Support for '(box . SIZE)' 'cursor-type'. By default, 'box' cursor always has a filled box shape. But if you specify 'cursor-type' to be '(box . SIZE)', the cursor becomes a hollow -box if the point is on an image larger than 'SIZE' pixels in any +box if the point is on an image larger than SIZE pixels in any dimension. +++ @@ -280,7 +280,7 @@ commands. The new keystrokes are 'C-x x g' ('revert-buffer'), input using the minibuffer. --- -** New user option 'bookmark-menu-confirm-deletion' +** New user option 'bookmark-menu-confirm-deletion'. In Bookmark Menu mode, Emacs by default does not prompt for confirmation when you type 'x' to execute the deletion of bookmarks that have been marked for deletion. However, if this new option is @@ -299,10 +299,10 @@ prompt, and how you can tweak the file size threshold. * Editing Changes in Emacs 28.1 +++ -** A prefix arg now causes 'delete-other-frames' to only iconify frames +** A prefix arg now causes 'delete-other-frames' to only iconify frames. +++ -** The "Edit => Clear" menu item now obeys a rectangular region +** The "Edit => Clear" menu item now obeys a rectangular region. +++ ** New command 'execute-extended-command-for-buffer'. @@ -526,7 +526,7 @@ indentation is done using SMIE or with the old ad-hoc code. ** Icomplete +++ -*** New minor mode Icomplete-Vertical mode. +*** New minor mode 'icomplete-vertical-mode'. This mode is intended to be used with Icomplete or Fido, to display the list of completions candidates vertically instead of horizontally. @@ -1147,7 +1147,6 @@ the variables 'bookmark-bmenu-use-header-line' and If non-nil, setting a bookmark will colorize the current line with 'bookmark-face'. - ** Edebug *** Obsoletions @@ -1231,7 +1230,8 @@ command line under point (and any following output). --- *** Environment variable 'INSIDE_EMACS' is now copied to subprocesses. -Its value equals the result of evaluating '(format "%s,eshell" emacs-version)'. +Its value contains the result of evaluating '(format "%s,eshell" +emacs-version)'. Other package names, like "tramp", could also be included. --- *** Eshell no longer re-initializes its keymap every call. @@ -1345,16 +1345,16 @@ See the new user options 'package-name-column-width', *** gdb-mi can now store and restore window configurations. Use 'gdb-save-window-configuration' to save window configuration to a file and 'gdb-load-window-configuration' to load from a file. These -commands can also be accessed through the menu bar under 'Gud -- -GDB-Windows'. 'gdb-default-window-configuration-file', when non-nil, +commands can also be accessed through the menu bar under "Gud => +GDB-Windows". 'gdb-default-window-configuration-file', when non-nil, is loaded when GDB starts up. +++ *** gdb-mi can now restore window configuration after quit. Set 'gdb-restore-window-configuration-after-quit' to non-nil and Emacs will remember the window configuration before GDB started and restore -it after GDB quits. A toggle button is also provided under 'Gud -- -GDB-Windows'. +it after GDB quits. A toggle button is also provided under "Gud => +GDB-Windows". +++ *** gdb-mi now has a better logic for displaying source buffers. @@ -1625,7 +1625,7 @@ This feature relies on librsvg 2.48 or above being available. Size image properties, for example ':height', ':max-height', etc., can be given a cons of the form '(SIZE . em)', where SIZE is an integer or float which is multiplied by the font size to calculate the image -size, and em is a symbol. +size, and 'em' is a symbol. ** EWW @@ -1732,8 +1732,8 @@ If chosen, file names in "*xref*" buffers will be displayed relative to the 'project-root' of the current project, when available. +++ -*** The TAB key binding in *xref* buffers is obsolete. -Use 'C-u RET' instead. The TAB binding in *xref* buffers is still +*** The 'TAB' key binding in "*xref*" buffers is obsolete. +Use 'C-u RET' instead. The 'TAB' binding in "*xref*" buffers is still supported, but we plan on removing it in a future version; at that time, the command 'xref-quit-and-goto-xref' will no longer have a key binding in 'xref--xref-buffer-mode-map'. @@ -2397,10 +2397,11 @@ You can type 'C-x u u' instead of 'C-x u C-x u' to undo many changes, 'M-g n n p p' to navigate next-error matches. Any other key exits transient mode and then is executed normally. 'repeat-exit-key' defines an additional key to exit mode like 'isearch-exit' ('RET'). -With 'repeat-keep-prefix' you can keep the prefix arg of the previous command. -For example, this can help to reverse the window navigation direction -with e.g. 'C-x o M-- o o'. Also it can help to set a new step with -e.g. 'C-x { C-5 { { {' will set the window resizing step to 5 columns. +With 'repeat-keep-prefix' you can keep the prefix arg of the previous +command. For example, this can help to reverse the window navigation +direction with e.g. 'C-x o M-- o o'. Also it can help to set a new +step with e.g. 'C-x { C-5 { { {', which will set the window resizing +step to 5 columns. * New Modes and Packages in Emacs 28.1 @@ -2498,7 +2499,7 @@ in the minibuffer instead of being set via a global let-binding. +++ ** The use of positional arguments in 'define-minor-mode' is obsolete. -These were actually rendered obsolete in Emacs-21 but were never +These were actually rendered obsolete in Emacs 21 but were never marked as such. ** 'facemenu-color-alist' is now obsolete, and is not used. @@ -2686,8 +2687,8 @@ back in Emacs 23.1. The affected functions are: 'make-obsolete', +++ ** The '&define' keyword in an Edebug specification now disables backtracking. -The implementation was buggy, and multiple &define forms in an &or -form should be exceedingly rare. See the Info node 'Backtracking' in +The implementation was buggy, and multiple '&define' forms in an '&or' +form should be exceedingly rare. See the Info node "(elisp) Backtracking" in the Emacs Lisp reference manual for background. @@ -3078,9 +3079,9 @@ The special events 'dbus-event' and 'file-notify' are now ignored in +++ ** 'condition-case' now allows for a success handler. -It is written as (:success BODY...) where BODY is executed whenever -the protected form terminates without error, with the specified -variable bound to the the value of the protected form. +It is written as '(:success BODY...)' where BODY is executed +whenever the protected form terminates without error, with the +specified variable bound to the the value of the protected form. * Changes in Emacs 28.1 on Non-Free Operating Systems commit 779c615f333a01d11ab930b030d61545fb048f3d Author: Mauro Aranda Date: Mon May 10 13:33:32 2021 +0200 Avoid saving session customizations in the custom-file * lisp/custom.el (custom-theme-recalc-variable): Only stash theme settings for void variables. (custom-declare-variable): After initializing a variable, unstash a theme setting, if present. (disable-theme): When disabling a theme, maybe unstash a theme setting. * test/lisp/custom-resources/custom--test-theme.el: Add two settings for testing the fix. diff --git a/lisp/custom.el b/lisp/custom.el index 614f8cf822..078e3a8cf8 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -207,7 +207,22 @@ set to nil, as the value is no longer rogue." (put symbol 'custom-requests requests) ;; Do the actual initialization. (unless custom-dont-initialize - (funcall initialize symbol default)) + (funcall initialize symbol default) + ;; If there is a value under saved-value that wasn't saved by the user, + ;; reset it: we used that property to stash the value, but we don't need + ;; it anymore. + ;; This can happen given the following: + ;; 1. The user loaded a theme that had a setting for an unbound + ;; variable, so we stashed the theme setting under the saved-value + ;; property in `custom-theme-recalc-variable'. + ;; 2. Then, Emacs evaluated the defcustom for the option + ;; (e.g., something required the file where the option is defined). + ;; If we don't reset it and the user later sets this variable via + ;; Customize, we might end up saving the theme setting in the custom-file. + ;; See the test `custom-test-no-saved-value-after-customizing-option'. + (let ((theme (caar (get symbol 'theme-value)))) + (when (and theme (not (eq theme 'user)) (get symbol 'saved-value)) + (put symbol 'saved-value nil)))) (when buffer-local (make-variable-buffer-local symbol))) (run-hooks 'custom-define-hook) @@ -1516,7 +1531,15 @@ See `custom-enabled-themes' for a list of enabled themes." (custom-push-theme prop symbol theme 'reset) (cond ((eq prop 'theme-value) - (custom-theme-recalc-variable symbol)) + (custom-theme-recalc-variable symbol) + ;; We might have to reset the stashed value of the variable, if + ;; no other theme is customizing it. Without this, loading a theme + ;; that has a setting for an unbound user option and then disabling + ;; it will leave this lingering setting for the option, and if then + ;; Emacs evaluates the defcustom the saved-value might be used to + ;; set the variable. (Bug#20766) + (unless (get symbol 'theme-value) + (put symbol 'saved-value nil))) ((eq prop 'theme-face) ;; If the face spec specified by this theme is in the ;; saved-face property, reset that property. @@ -1565,8 +1588,16 @@ This function returns nil if no custom theme specifies a value for VARIABLE." (defun custom-theme-recalc-variable (variable) "Set VARIABLE according to currently enabled custom themes." (let ((valspec (custom-variable-theme-value variable))) - (if valspec - (put variable 'saved-value valspec) + ;; We used to save VALSPEC under the saved-value property unconditionally, + ;; but that is a recipe for trouble because we might end up saving session + ;; customizations if the user loads a theme. (Bug#21355) + ;; It's better to only use the saved-value property to stash the value only + ;; if we really need to stash it (i.e., VARIABLE is void). + (condition-case nil + (default-toplevel-value variable) ; See if it doesn't fail. + (void-variable (when valspec + (put variable 'saved-value valspec)))) + (unless valspec (setq valspec (get variable 'standard-value))) (if (and valspec (or (get variable 'force-value) diff --git a/test/lisp/custom-resources/custom--test-theme.el b/test/lisp/custom-resources/custom--test-theme.el index 122bd79569..36424cdfcc 100644 --- a/test/lisp/custom-resources/custom--test-theme.el +++ b/test/lisp/custom-resources/custom--test-theme.el @@ -6,6 +6,8 @@ (custom-theme-set-variables 'custom--test '(custom--test-user-option 'bar) - '(custom--test-variable 'bar)) + '(custom--test-variable 'bar) + '(custom--test-bug-21355-before 'before) + '(custom--test-bug-21355-after 'after)) (provide-theme 'custom--test) diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el index 02a9239824..e93c96e1d9 100644 --- a/test/lisp/custom-tests.el +++ b/test/lisp/custom-tests.el @@ -230,4 +230,108 @@ Ensure the directory is recursively deleted after the fact." (should (eq (default-value 'custom--test-local-option) 'initial)) (should (eq (default-value 'custom--test-permanent-option) 'initial))))) +;; The following three tests demonstrate Bug#21355. +;; In this one, we set an user option for the current session and then +;; we enable a theme that doesn't have a setting for it, ending up with +;; a non-nil saved-value property. Since the `caar' of the theme-value +;; property is user (i.e., the user theme setting is active), we might +;; save the setting to the custom-file, even though it was meant for the +;; current session only. So there should be a nil saved-value property +;; for this test to pass. +(ert-deftest custom-test-no-saved-value-after-enabling-theme () + "Test that we don't record a saved-value property when we shouldn't." + (let ((custom-theme-load-path `(,(ert-resource-directory)))) + (customize-option 'mark-ring-max) + (let* ((field (seq-find (lambda (widget) + (eq mark-ring-max (widget-value widget))) + widget-field-list)) + (parent (widget-get field :parent))) + ;; Move to the editable widget, modify the value and save it. + (goto-char (widget-field-text-end field)) + (insert "0") + (widget-apply parent :custom-set) + ;; Just setting for the current session should not store a saved-value + ;; property. + (should-not (get 'mark-ring-max 'saved-value)) + ;; Now enable and disable the test theme. + (load-theme 'custom--test 'no-confirm) + (disable-theme 'custom--test) + ;; Since the user customized the option, this is OK. + (should (eq (caar (get 'mark-ring-max 'theme-value)) 'user)) + ;; The saved-value property should still be nil. + (should-not (get 'mark-ring-max 'saved-value))))) + +;; In this second test, we load a theme that has a setting for the user option +;; above. We must check that we don't end up with a non-nil saved-value +;; property and a user setting active in the theme-value property, which +;; means we might inadvertently save the session setting in the custom-file. +(defcustom custom--test-bug-21355-before 'foo + "User option for `custom-test-no-saved-value-after-enabling-theme-2'." + :type 'symbol :group 'emacs) + +(ert-deftest custom-test-no-saved-value-after-enabling-theme-2 () + "Test that we don't record a saved-value property when we shouldn't." + (let ((custom-theme-load-path `(,(ert-resource-directory)))) + (customize-option 'custom--test-bug-21355-before) + (let* ((field (seq-find + (lambda (widget) + (eq custom--test-bug-21355-before (widget-value widget))) + widget-field-list)) + (parent (widget-get field :parent))) + ;; Move to the editable widget, modify the value and save it. + (goto-char (widget-field-text-end field)) + (insert "bar") + (widget-apply parent :custom-set) + ;; Just setting for the current session should not store a saved-value + ;; property. + (should-not (get 'custom--test-bug-21355-before 'saved-value)) + ;; Now load our test theme, which has a setting for + ;; `custom--test-bug-21355-before'. + (load-theme 'custom--test 'no-confirm 'no-enable) + (enable-theme 'custom--test) + ;; Since the user customized the option, this is OK. + (should (eq (caar (get 'custom--test-bug-21355-before 'theme-value)) + 'user)) + ;; But the saved-value property has to be nil, since the user didn't mark + ;; this variable to save for future sessions. + (should-not (get 'custom--test-bug-21355-before 'saved-value))))) + +(defvar custom--test-bug-21355-after) + +;; In this test, we check that stashing a theme value for a not yet defined +;; option works, but that later on if the user customizes the option for the +;; current session, we might save the theme setting in the custom file. +(ert-deftest custom-test-no-saved-value-after-customizing-option () + "Test for a nil saved-value after setting an option for the current session." + (let ((custom-theme-load-path `(,(ert-resource-directory)))) + ;; Check that we correctly stashed the value. + (load-theme 'custom--test 'no-confirm 'no-enable) + (enable-theme 'custom--test) + (should (and (not (boundp 'custom--test-bug-21355-after)) + (eq (eval + (car (get 'custom--test-bug-21355-after 'saved-value))) + 'after))) + ;; Now Emacs finds the defcustom. + (defcustom custom--test-bug-21355-after 'initially "..." + :type 'symbol :group 'emacs) + ;; And we used the stashed value correctly. + (should (and (boundp 'custom--test-bug-21355-after) + (eq custom--test-bug-21355-after 'after))) + ;; Now customize it. + (customize-option 'custom--test-bug-21355-after) + (let* ((field (seq-find (lambda (widget) + (eq custom--test-bug-21355-after + (widget-value widget))) + widget-field-list)) + (parent (widget-get field :parent))) + ;; Move to the editable widget, modify the value and save it. + (goto-char (widget-field-text-end field)) + (insert "bar") + (widget-apply parent :custom-set) + ;; The user customized the variable, so this is OK. + (should (eq (caar (get 'custom--test-bug-21355-after 'theme-value)) + 'user)) + ;; But it was only for the current session, so this should not happen. + (should-not (get 'custom--test-bug-21355-after 'saved-value))))) + ;;; custom-tests.el ends here commit 5bedbe6b1d5f4b801abf91b4d023d5c4e66418f0 Author: Lars Ingebrigtsen Date: Mon May 10 12:40:11 2021 +0200 Always heed the `lexical-binding' local variable * doc/lispref/variables.texi (File Local Variables): Document `permanently-enabled-local-variables'. * lisp/files.el (enable-local-variables): Mention the new variable. (set-auto-mode): Always call `hack-local-variables'. (hack-local-variables): Factor out the variable gathering into its own function, and respect the new variable (bug#47843). (hack-local-variables--find-variables): Factored out from `hack-local-variables'. (permanently-enabled-local-variables): New variable. diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index b25eea12a5..36abc316cb 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -1885,6 +1885,14 @@ any form of file-local variable. For examples of why you might want to use this, @pxref{Auto Major Mode}. @end defvar +@defvar permanently-enabled-local-variables +Some local variable settings will, by default, be heeded even if +@code{enable-local-variables} is @code{nil}. By default, this is only +the case for the @code{lexical-binding} local variable setting, but +this can be controlled by using this variable, which is a list of +symbols. +@end defvar + @defun hack-local-variables &optional handle-mode This function parses, and binds or evaluates as appropriate, any local variables specified by the contents of the current buffer. The variable diff --git a/etc/NEWS b/etc/NEWS index 6efadfec6f..c421073c96 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2484,6 +2484,13 @@ This is to keep the same behavior as Eshell. * Incompatible Lisp Changes in Emacs 28.1 ++++ +** The 'lexical-binding' local variable is always enabled. +Previously, if 'enable-local-variables' was nil, a 'lexical-binding' +local variable would not be heeded. This has now changed, and a file +with a 'lexical-binding' cookie is always heeded. To revert to the +old behavior, set 'permanently-enabled-local-variables' to nil. + +++ ** 'completing-read-default' sets completion variables buffer-locally. 'minibuffer-completion-table' and related variables are now set buffer-locally diff --git a/lisp/files.el b/lisp/files.el index 93a0e07aba..7fb1320269 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -577,7 +577,9 @@ a -*- line. The command \\[normal-mode], when used interactively, always obeys file local variable specifications and the -*- line, -and ignores this variable." +and ignores this variable. + +Also see the `permanently-enabled-local-variables' variable." :risky t :type '(choice (const :tag "Query Unsafe" t) (const :tag "Safe Only" :safe) @@ -3198,13 +3200,8 @@ we don't actually set it to the same mode the buffer already has." (or (set-auto-mode-0 mode keep-mode-if-same) ;; continuing would call minor modes again, toggling them off (throw 'nop nil)))))) - ;; hack-local-variables checks local-enable-local-variables etc, but - ;; we might as well be explicit here for the sake of clarity. (and (not done) - enable-local-variables - local-enable-local-variables - try-locals - (setq mode (hack-local-variables t)) + (setq mode (hack-local-variables t (not try-locals))) (not (memq mode modes)) ; already tried and failed (if (not (functionp mode)) (message "Ignoring unknown mode `%s'" mode) @@ -3503,6 +3500,10 @@ function is allowed to change the contents of this alist. This hook is called only if there is at least one file-local variable to set.") +(defvar permanently-enabled-local-variables '(lexical-binding) + "A list of local variables that are always enabled. +This overrides any `enable-local-variables' setting.") + (defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars dir-name) "Get confirmation before setting up local variable values. ALL-VARS is the list of all variables to be set up. @@ -3716,25 +3717,26 @@ DIR-NAME is the name of the associated directory. Otherwise it is nil." ;; TODO? Warn once per file rather than once per session? (defvar hack-local-variables--warned-lexical nil) -(defun hack-local-variables (&optional handle-mode) +(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. -Uses `hack-local-variables-apply' to apply the variables. -If HANDLE-MODE is nil, we apply all the specified local -variables. If HANDLE-MODE is neither nil nor t, we do the same, -except that any settings of `mode' are ignored. +Uses `hack-local-variables-apply' to apply the variables. -If HANDLE-MODE is t, all we do is check whether a \"mode:\" -is specified, and return the corresponding mode symbol, or nil. -In this case, we try to ignore minor-modes, and return only a -major-mode. +See `hack-local-variables--find-variables' for the meaning of +HANDLE-MODE. -If `enable-local-variables' or `local-enable-local-variables' is nil, -this function does nothing. If `inhibit-local-variables-regexps' +If `enable-local-variables' or `local-enable-local-variables' is +nil, or INHIBIT-LOCALS is non-nil, this function disregards all +normal local variables. If `inhibit-local-variables-regexps' applies to the file in question, the file is not scanned for -local variables, but directory-local variables may still be applied." +local variables, but directory-local variables may still be +applied. + +Variables present in `permanently-enabled-local-variables' will +still be evaluated, even if local variables are otherwise +inhibited." ;; We don't let inhibit-local-variables-p influence the value of ;; enable-local-variables, because then it would affect dir-local ;; variables. We don't want to search eg tar files for file local @@ -3742,9 +3744,18 @@ local variables, but directory-local variables may still be applied." ;; to them. The real meaning of inhibit-local-variables-p is "do ;; not scan this file for local variables". (let ((enable-local-variables - (and local-enable-local-variables enable-local-variables)) - result) - (unless (eq handle-mode t) + (and (not inhibit-locals) + local-enable-local-variables enable-local-variables))) + (if (eq handle-mode t) + ;; We're looking just for the major mode setting. + (and enable-local-variables + (not (inhibit-local-variables-p)) + ;; If HANDLE-MODE is t, and the prop line specifies a + ;; mode, then we're done, and have no need to scan further. + (or (hack-local-variables-prop-line t) + ;; Look for the mode elsewhere in the buffer. + (hack-local-variables--find-variables t))) + ;; Normal handling of local variables. (setq file-local-variables-alist nil) (when (and (file-remote-p default-directory) (fboundp 'hack-connection-local-variables) @@ -3755,133 +3766,138 @@ local variables, but directory-local variables may still be applied." (connection-local-criteria-for-default-directory)))) (with-demoted-errors "Directory-local variables error: %s" ;; Note this is a no-op if enable-local-variables is nil. - (hack-dir-local-variables))) - ;; This entire function is basically a no-op if enable-local-variables - ;; is nil. All it does is set file-local-variables-alist to nil. - (when enable-local-variables - ;; This part used to ignore enable-local-variables when handle-mode - ;; was t. That was inappropriate, eg consider the - ;; (artificial) example of: - ;; (setq local-enable-local-variables nil) - ;; Open a file foo.txt that contains "mode: sh". - ;; It correctly opens in text-mode. - ;; M-x set-visited-file name foo.c, and it incorrectly stays in text-mode. - (unless (or (inhibit-local-variables-p) - ;; If HANDLE-MODE is t, and the prop line specifies a - ;; mode, then we're done, and have no need to scan further. - (and (setq result (hack-local-variables-prop-line - handle-mode)) - (eq handle-mode t))) - ;; Look for "Local variables:" line in last page. - (save-excursion - (goto-char (point-max)) - (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) - 'move) - (when (let ((case-fold-search t)) - (search-forward "Local Variables:" nil t)) - (skip-chars-forward " \t") - ;; suffix is what comes after "local variables:" in its line. - ;; prefix is what comes before "local variables:" in its line. - (let ((suffix - (concat - (regexp-quote (buffer-substring (point) - (line-end-position))) - "$")) - (prefix - (concat "^" (regexp-quote - (buffer-substring (line-beginning-position) - (match-beginning 0)))))) - - (forward-line 1) - (let ((startpos (point)) - endpos - (thisbuf (current-buffer))) - (save-excursion - (unless (let ((case-fold-search t)) - (re-search-forward - (concat prefix "[ \t]*End:[ \t]*" suffix) - nil t)) - ;; This used to be an error, but really all it means is - ;; that this may simply not be a local-variables section, - ;; so just ignore it. - (message "Local variables list is not properly terminated")) - (beginning-of-line) - (setq endpos (point))) - - (with-temp-buffer - (insert-buffer-substring thisbuf startpos endpos) - (goto-char (point-min)) - (subst-char-in-region (point) (point-max) ?\^m ?\n) - (while (not (eobp)) - ;; Discard the prefix. - (if (looking-at prefix) - (delete-region (point) (match-end 0)) - (error "Local variables entry is missing the prefix")) - (end-of-line) - ;; Discard the suffix. - (if (looking-back suffix (line-beginning-position)) - (delete-region (match-beginning 0) (point)) - (error "Local variables entry is missing the suffix")) - (forward-line 1)) - (goto-char (point-min)) - - (while (not (or (eobp) - (and (eq handle-mode t) result))) - ;; Find the variable name; - (unless (looking-at hack-local-variable-regexp) - (error "Malformed local variable line: %S" - (buffer-substring-no-properties - (point) (line-end-position)))) - (goto-char (match-end 1)) - (let* ((str (match-string 1)) - (var (intern str)) - val val2) - (and (equal (downcase (symbol-name var)) "mode") - (setq var 'mode)) - ;; Read the variable value. - (skip-chars-forward "^:") - (forward-char 1) - ;; As a defensive measure, we do not allow - ;; circular data in the file-local data. - (let ((read-circle nil)) - (setq val (read (current-buffer)))) - (if (eq handle-mode t) - (and (eq var 'mode) - ;; Specifying minor-modes via mode: is - ;; deprecated, but try to reject them anyway. - (not (string-match - "-minor\\'" - (setq val2 (downcase (symbol-name val))))) - (setq result (intern (concat val2 "-mode")))) - (cond ((eq var 'coding)) - ((eq var 'lexical-binding) - (unless hack-local-variables--warned-lexical - (setq hack-local-variables--warned-lexical t) - (display-warning - 'files - (format-message - "%s: `lexical-binding' at end of file unreliable" - (file-name-nondirectory - ;; We are called from - ;; 'with-temp-buffer', so we need - ;; to use 'thisbuf's name in the - ;; warning message. - (or (buffer-file-name thisbuf) "")))))) - ((and (eq var 'mode) handle-mode)) - (t - (ignore-errors - (push (cons (if (eq var 'eval) - 'eval - (indirect-variable var)) - val) - result)))))) - (forward-line 1)))))))) - ;; Now we've read all the local variables. - ;; If HANDLE-MODE is t, return whether the mode was specified. - (if (eq handle-mode t) result - ;; Otherwise, set the variables. - (hack-local-variables-filter result nil) - (hack-local-variables-apply))))) + (hack-dir-local-variables)) + (let ((result (append (hack-local-variables-prop-line) + (hack-local-variables--find-variables)))) + (if (and enable-local-variables + (not (inhibit-local-variables-p))) + (progn + ;; Set the variables. + (hack-local-variables-filter result nil) + (hack-local-variables-apply)) + ;; Handle `lexical-binding' and other special local + ;; variables. + (dolist (variable permanently-enabled-local-variables) + (when-let ((elem (assq variable result))) + (push elem file-local-variables-alist))) + (hack-local-variables-apply)))))) + +(defun hack-local-variables--find-variables (&optional handle-mode) + "Return all local variables in the ucrrent buffer. +If HANDLE-MODE is nil, we gather all the specified local +variables. If HANDLE-MODE is neither nil nor t, we do the same, +except that any settings of `mode' are ignored. + +If HANDLE-MODE is t, all we do is check whether a \"mode:\" +is specified, and return the corresponding mode symbol, or nil. +In this case, we try to ignore minor-modes, and return only a +major-mode." + (let ((result nil)) + ;; Look for "Local variables:" line in last page. + (save-excursion + (goto-char (point-max)) + (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) + 'move) + (when (let ((case-fold-search t)) + (search-forward "Local Variables:" nil t)) + (skip-chars-forward " \t") + ;; suffix is what comes after "local variables:" in its line. + ;; prefix is what comes before "local variables:" in its line. + (let ((suffix + (concat + (regexp-quote (buffer-substring (point) + (line-end-position))) + "$")) + (prefix + (concat "^" (regexp-quote + (buffer-substring (line-beginning-position) + (match-beginning 0)))))) + + (forward-line 1) + (let ((startpos (point)) + endpos + (thisbuf (current-buffer))) + (save-excursion + (unless (let ((case-fold-search t)) + (re-search-forward + (concat prefix "[ \t]*End:[ \t]*" suffix) + nil t)) + ;; This used to be an error, but really all it means is + ;; that this may simply not be a local-variables section, + ;; so just ignore it. + (message "Local variables list is not properly terminated")) + (beginning-of-line) + (setq endpos (point))) + + (with-temp-buffer + (insert-buffer-substring thisbuf startpos endpos) + (goto-char (point-min)) + (subst-char-in-region (point) (point-max) ?\^m ?\n) + (while (not (eobp)) + ;; Discard the prefix. + (if (looking-at prefix) + (delete-region (point) (match-end 0)) + (error "Local variables entry is missing the prefix")) + (end-of-line) + ;; Discard the suffix. + (if (looking-back suffix (line-beginning-position)) + (delete-region (match-beginning 0) (point)) + (error "Local variables entry is missing the suffix")) + (forward-line 1)) + (goto-char (point-min)) + + (while (not (or (eobp) + (and (eq handle-mode t) result))) + ;; Find the variable name; + (unless (looking-at hack-local-variable-regexp) + (error "Malformed local variable line: %S" + (buffer-substring-no-properties + (point) (line-end-position)))) + (goto-char (match-end 1)) + (let* ((str (match-string 1)) + (var (intern str)) + val val2) + (and (equal (downcase (symbol-name var)) "mode") + (setq var 'mode)) + ;; Read the variable value. + (skip-chars-forward "^:") + (forward-char 1) + ;; As a defensive measure, we do not allow + ;; circular data in the file-local data. + (let ((read-circle nil)) + (setq val (read (current-buffer)))) + (if (eq handle-mode t) + (and (eq var 'mode) + ;; Specifying minor-modes via mode: is + ;; deprecated, but try to reject them anyway. + (not (string-match + "-minor\\'" + (setq val2 (downcase (symbol-name val))))) + (setq result (intern (concat val2 "-mode")))) + (cond ((eq var 'coding)) + ((eq var 'lexical-binding) + (unless hack-local-variables--warned-lexical + (setq hack-local-variables--warned-lexical t) + (display-warning + 'files + (format-message + "%s: `lexical-binding' at end of file unreliable" + (file-name-nondirectory + ;; We are called from + ;; 'with-temp-buffer', so we need + ;; to use 'thisbuf's name in the + ;; warning message. + (or (buffer-file-name thisbuf) "")))))) + ((and (eq var 'mode) handle-mode)) + (t + (ignore-errors + (push (cons (if (eq var 'eval) + 'eval + (indirect-variable var)) + val) + result)))))) + (forward-line 1))))))) + result)) (defun hack-local-variables-apply () "Apply the elements of `file-local-variables-alist'. diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index 921e2c80f3..dc96dff639 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el @@ -151,6 +151,19 @@ form.") (dolist (subtest (cdr test)) (should (file-test--do-local-variables-test str subtest))))))) +(ert-deftest files-tests-permanent-local-variables () + (let ((enable-local-variables nil)) + (with-temp-buffer + (insert ";;; test-test.el --- tests -*- lexical-binding: t; -*-\n\n") + (hack-local-variables) + (should (eq lexical-binding t)))) + (let ((enable-local-variables nil) + (permanently-enabled-local-variables nil)) + (with-temp-buffer + (insert ";;; test-test.el --- tests -*- lexical-binding: t; -*-\n\n") + (hack-local-variables) + (should (eq lexical-binding nil))))) + (defvar files-test-bug-18141-file (ert-resource-file "files-bug18141.el.gz") "Test file for bug#18141.")