diff options
| author | Mauro Aranda | 2021-05-10 13:33:32 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-05-10 13:33:32 +0200 |
| commit | 779c615f333a01d11ab930b030d61545fb048f3d (patch) | |
| tree | 493738307f960d58d525af7e1b825ec901dda12e | |
| parent | 5bedbe6b1d5f4b801abf91b4d023d5c4e66418f0 (diff) | |
| download | emacs-779c615f333a01d11ab930b030d61545fb048f3d.tar.gz emacs-779c615f333a01d11ab930b030d61545fb048f3d.zip | |
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.
| -rw-r--r-- | lisp/custom.el | 39 | ||||
| -rw-r--r-- | test/lisp/custom-resources/custom--test-theme.el | 4 | ||||
| -rw-r--r-- | test/lisp/custom-tests.el | 104 |
3 files changed, 142 insertions, 5 deletions
diff --git a/lisp/custom.el b/lisp/custom.el index 614f8cf822d..078e3a8cf8e 100644 --- a/lisp/custom.el +++ b/lisp/custom.el | |||
| @@ -207,7 +207,22 @@ set to nil, as the value is no longer rogue." | |||
| 207 | (put symbol 'custom-requests requests) | 207 | (put symbol 'custom-requests requests) |
| 208 | ;; Do the actual initialization. | 208 | ;; Do the actual initialization. |
| 209 | (unless custom-dont-initialize | 209 | (unless custom-dont-initialize |
| 210 | (funcall initialize symbol default)) | 210 | (funcall initialize symbol default) |
| 211 | ;; If there is a value under saved-value that wasn't saved by the user, | ||
| 212 | ;; reset it: we used that property to stash the value, but we don't need | ||
| 213 | ;; it anymore. | ||
| 214 | ;; This can happen given the following: | ||
| 215 | ;; 1. The user loaded a theme that had a setting for an unbound | ||
| 216 | ;; variable, so we stashed the theme setting under the saved-value | ||
| 217 | ;; property in `custom-theme-recalc-variable'. | ||
| 218 | ;; 2. Then, Emacs evaluated the defcustom for the option | ||
| 219 | ;; (e.g., something required the file where the option is defined). | ||
| 220 | ;; If we don't reset it and the user later sets this variable via | ||
| 221 | ;; Customize, we might end up saving the theme setting in the custom-file. | ||
| 222 | ;; See the test `custom-test-no-saved-value-after-customizing-option'. | ||
| 223 | (let ((theme (caar (get symbol 'theme-value)))) | ||
| 224 | (when (and theme (not (eq theme 'user)) (get symbol 'saved-value)) | ||
| 225 | (put symbol 'saved-value nil)))) | ||
| 211 | (when buffer-local | 226 | (when buffer-local |
| 212 | (make-variable-buffer-local symbol))) | 227 | (make-variable-buffer-local symbol))) |
| 213 | (run-hooks 'custom-define-hook) | 228 | (run-hooks 'custom-define-hook) |
| @@ -1516,7 +1531,15 @@ See `custom-enabled-themes' for a list of enabled themes." | |||
| 1516 | (custom-push-theme prop symbol theme 'reset) | 1531 | (custom-push-theme prop symbol theme 'reset) |
| 1517 | (cond | 1532 | (cond |
| 1518 | ((eq prop 'theme-value) | 1533 | ((eq prop 'theme-value) |
| 1519 | (custom-theme-recalc-variable symbol)) | 1534 | (custom-theme-recalc-variable symbol) |
| 1535 | ;; We might have to reset the stashed value of the variable, if | ||
| 1536 | ;; no other theme is customizing it. Without this, loading a theme | ||
| 1537 | ;; that has a setting for an unbound user option and then disabling | ||
| 1538 | ;; it will leave this lingering setting for the option, and if then | ||
| 1539 | ;; Emacs evaluates the defcustom the saved-value might be used to | ||
| 1540 | ;; set the variable. (Bug#20766) | ||
| 1541 | (unless (get symbol 'theme-value) | ||
| 1542 | (put symbol 'saved-value nil))) | ||
| 1520 | ((eq prop 'theme-face) | 1543 | ((eq prop 'theme-face) |
| 1521 | ;; If the face spec specified by this theme is in the | 1544 | ;; If the face spec specified by this theme is in the |
| 1522 | ;; saved-face property, reset that property. | 1545 | ;; saved-face property, reset that property. |
| @@ -1565,8 +1588,16 @@ This function returns nil if no custom theme specifies a value for VARIABLE." | |||
| 1565 | (defun custom-theme-recalc-variable (variable) | 1588 | (defun custom-theme-recalc-variable (variable) |
| 1566 | "Set VARIABLE according to currently enabled custom themes." | 1589 | "Set VARIABLE according to currently enabled custom themes." |
| 1567 | (let ((valspec (custom-variable-theme-value variable))) | 1590 | (let ((valspec (custom-variable-theme-value variable))) |
| 1568 | (if valspec | 1591 | ;; We used to save VALSPEC under the saved-value property unconditionally, |
| 1569 | (put variable 'saved-value valspec) | 1592 | ;; but that is a recipe for trouble because we might end up saving session |
| 1593 | ;; customizations if the user loads a theme. (Bug#21355) | ||
| 1594 | ;; It's better to only use the saved-value property to stash the value only | ||
| 1595 | ;; if we really need to stash it (i.e., VARIABLE is void). | ||
| 1596 | (condition-case nil | ||
| 1597 | (default-toplevel-value variable) ; See if it doesn't fail. | ||
| 1598 | (void-variable (when valspec | ||
| 1599 | (put variable 'saved-value valspec)))) | ||
| 1600 | (unless valspec | ||
| 1570 | (setq valspec (get variable 'standard-value))) | 1601 | (setq valspec (get variable 'standard-value))) |
| 1571 | (if (and valspec | 1602 | (if (and valspec |
| 1572 | (or (get variable 'force-value) | 1603 | (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 122bd795692..36424cdfcc3 100644 --- a/test/lisp/custom-resources/custom--test-theme.el +++ b/test/lisp/custom-resources/custom--test-theme.el | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | (custom-theme-set-variables | 6 | (custom-theme-set-variables |
| 7 | 'custom--test | 7 | 'custom--test |
| 8 | '(custom--test-user-option 'bar) | 8 | '(custom--test-user-option 'bar) |
| 9 | '(custom--test-variable 'bar)) | 9 | '(custom--test-variable 'bar) |
| 10 | '(custom--test-bug-21355-before 'before) | ||
| 11 | '(custom--test-bug-21355-after 'after)) | ||
| 10 | 12 | ||
| 11 | (provide-theme 'custom--test) | 13 | (provide-theme 'custom--test) |
diff --git a/test/lisp/custom-tests.el b/test/lisp/custom-tests.el index 02a9239824d..e93c96e1d93 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." | |||
| 230 | (should (eq (default-value 'custom--test-local-option) 'initial)) | 230 | (should (eq (default-value 'custom--test-local-option) 'initial)) |
| 231 | (should (eq (default-value 'custom--test-permanent-option) 'initial))))) | 231 | (should (eq (default-value 'custom--test-permanent-option) 'initial))))) |
| 232 | 232 | ||
| 233 | ;; The following three tests demonstrate Bug#21355. | ||
| 234 | ;; In this one, we set an user option for the current session and then | ||
| 235 | ;; we enable a theme that doesn't have a setting for it, ending up with | ||
| 236 | ;; a non-nil saved-value property. Since the `caar' of the theme-value | ||
| 237 | ;; property is user (i.e., the user theme setting is active), we might | ||
| 238 | ;; save the setting to the custom-file, even though it was meant for the | ||
| 239 | ;; current session only. So there should be a nil saved-value property | ||
| 240 | ;; for this test to pass. | ||
| 241 | (ert-deftest custom-test-no-saved-value-after-enabling-theme () | ||
| 242 | "Test that we don't record a saved-value property when we shouldn't." | ||
| 243 | (let ((custom-theme-load-path `(,(ert-resource-directory)))) | ||
| 244 | (customize-option 'mark-ring-max) | ||
| 245 | (let* ((field (seq-find (lambda (widget) | ||
| 246 | (eq mark-ring-max (widget-value widget))) | ||
| 247 | widget-field-list)) | ||
| 248 | (parent (widget-get field :parent))) | ||
| 249 | ;; Move to the editable widget, modify the value and save it. | ||
| 250 | (goto-char (widget-field-text-end field)) | ||
| 251 | (insert "0") | ||
| 252 | (widget-apply parent :custom-set) | ||
| 253 | ;; Just setting for the current session should not store a saved-value | ||
| 254 | ;; property. | ||
| 255 | (should-not (get 'mark-ring-max 'saved-value)) | ||
| 256 | ;; Now enable and disable the test theme. | ||
| 257 | (load-theme 'custom--test 'no-confirm) | ||
| 258 | (disable-theme 'custom--test) | ||
| 259 | ;; Since the user customized the option, this is OK. | ||
| 260 | (should (eq (caar (get 'mark-ring-max 'theme-value)) 'user)) | ||
| 261 | ;; The saved-value property should still be nil. | ||
| 262 | (should-not (get 'mark-ring-max 'saved-value))))) | ||
| 263 | |||
| 264 | ;; In this second test, we load a theme that has a setting for the user option | ||
| 265 | ;; above. We must check that we don't end up with a non-nil saved-value | ||
| 266 | ;; property and a user setting active in the theme-value property, which | ||
| 267 | ;; means we might inadvertently save the session setting in the custom-file. | ||
| 268 | (defcustom custom--test-bug-21355-before 'foo | ||
| 269 | "User option for `custom-test-no-saved-value-after-enabling-theme-2'." | ||
| 270 | :type 'symbol :group 'emacs) | ||
| 271 | |||
| 272 | (ert-deftest custom-test-no-saved-value-after-enabling-theme-2 () | ||
| 273 | "Test that we don't record a saved-value property when we shouldn't." | ||
| 274 | (let ((custom-theme-load-path `(,(ert-resource-directory)))) | ||
| 275 | (customize-option 'custom--test-bug-21355-before) | ||
| 276 | (let* ((field (seq-find | ||
| 277 | (lambda (widget) | ||
| 278 | (eq custom--test-bug-21355-before (widget-value widget))) | ||
| 279 | widget-field-list)) | ||
| 280 | (parent (widget-get field :parent))) | ||
| 281 | ;; Move to the editable widget, modify the value and save it. | ||
| 282 | (goto-char (widget-field-text-end field)) | ||
| 283 | (insert "bar") | ||
| 284 | (widget-apply parent :custom-set) | ||
| 285 | ;; Just setting for the current session should not store a saved-value | ||
| 286 | ;; property. | ||
| 287 | (should-not (get 'custom--test-bug-21355-before 'saved-value)) | ||
| 288 | ;; Now load our test theme, which has a setting for | ||
| 289 | ;; `custom--test-bug-21355-before'. | ||
| 290 | (load-theme 'custom--test 'no-confirm 'no-enable) | ||
| 291 | (enable-theme 'custom--test) | ||
| 292 | ;; Since the user customized the option, this is OK. | ||
| 293 | (should (eq (caar (get 'custom--test-bug-21355-before 'theme-value)) | ||
| 294 | 'user)) | ||
| 295 | ;; But the saved-value property has to be nil, since the user didn't mark | ||
| 296 | ;; this variable to save for future sessions. | ||
| 297 | (should-not (get 'custom--test-bug-21355-before 'saved-value))))) | ||
| 298 | |||
| 299 | (defvar custom--test-bug-21355-after) | ||
| 300 | |||
| 301 | ;; In this test, we check that stashing a theme value for a not yet defined | ||
| 302 | ;; option works, but that later on if the user customizes the option for the | ||
| 303 | ;; current session, we might save the theme setting in the custom file. | ||
| 304 | (ert-deftest custom-test-no-saved-value-after-customizing-option () | ||
| 305 | "Test for a nil saved-value after setting an option for the current session." | ||
| 306 | (let ((custom-theme-load-path `(,(ert-resource-directory)))) | ||
| 307 | ;; Check that we correctly stashed the value. | ||
| 308 | (load-theme 'custom--test 'no-confirm 'no-enable) | ||
| 309 | (enable-theme 'custom--test) | ||
| 310 | (should (and (not (boundp 'custom--test-bug-21355-after)) | ||
| 311 | (eq (eval | ||
| 312 | (car (get 'custom--test-bug-21355-after 'saved-value))) | ||
| 313 | 'after))) | ||
| 314 | ;; Now Emacs finds the defcustom. | ||
| 315 | (defcustom custom--test-bug-21355-after 'initially "..." | ||
| 316 | :type 'symbol :group 'emacs) | ||
| 317 | ;; And we used the stashed value correctly. | ||
| 318 | (should (and (boundp 'custom--test-bug-21355-after) | ||
| 319 | (eq custom--test-bug-21355-after 'after))) | ||
| 320 | ;; Now customize it. | ||
| 321 | (customize-option 'custom--test-bug-21355-after) | ||
| 322 | (let* ((field (seq-find (lambda (widget) | ||
| 323 | (eq custom--test-bug-21355-after | ||
| 324 | (widget-value widget))) | ||
| 325 | widget-field-list)) | ||
| 326 | (parent (widget-get field :parent))) | ||
| 327 | ;; Move to the editable widget, modify the value and save it. | ||
| 328 | (goto-char (widget-field-text-end field)) | ||
| 329 | (insert "bar") | ||
| 330 | (widget-apply parent :custom-set) | ||
| 331 | ;; The user customized the variable, so this is OK. | ||
| 332 | (should (eq (caar (get 'custom--test-bug-21355-after 'theme-value)) | ||
| 333 | 'user)) | ||
| 334 | ;; But it was only for the current session, so this should not happen. | ||
| 335 | (should-not (get 'custom--test-bug-21355-after 'saved-value))))) | ||
| 336 | |||
| 233 | ;;; custom-tests.el ends here | 337 | ;;; custom-tests.el ends here |