aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Aranda2021-05-10 13:33:32 +0200
committerLars Ingebrigtsen2021-05-10 13:33:32 +0200
commit779c615f333a01d11ab930b030d61545fb048f3d (patch)
tree493738307f960d58d525af7e1b825ec901dda12e
parent5bedbe6b1d5f4b801abf91b4d023d5c4e66418f0 (diff)
downloademacs-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.el39
-rw-r--r--test/lisp/custom-resources/custom--test-theme.el4
-rw-r--r--test/lisp/custom-tests.el104
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