From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: custom-set-variables considered harmful Date: Mon, 04 Dec 2017 08:48:06 -0500 Message-ID: References: NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1512395335 8612 195.159.176.226 (4 Dec 2017 13:48:55 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 4 Dec 2017 13:48:55 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Dec 04 14:48:47 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eLr70-0001pK-W9 for ged-emacs-devel@m.gmane.org; Mon, 04 Dec 2017 14:48:47 +0100 Original-Received: from localhost ([::1]:43282 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eLr78-00032S-9w for ged-emacs-devel@m.gmane.org; Mon, 04 Dec 2017 08:48:54 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:46736) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eLr6S-00032K-IE for emacs-devel@gnu.org; Mon, 04 Dec 2017 08:48:14 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eLr6O-0007m2-K7 for emacs-devel@gnu.org; Mon, 04 Dec 2017 08:48:12 -0500 Original-Received: from pmta11.teksavvy.com ([76.10.157.34]:53376) by eggs.gnu.org with esmtps (TLS1.0:RSA_ARCFOUR_SHA1:16) (Exim 4.71) (envelope-from ) id 1eLr6O-0007lr-DB for emacs-devel@gnu.org; Mon, 04 Dec 2017 08:48:08 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A2GyNgCyUCVa/7mYWxdcHQEBBQELAYM8g?= =?us-ascii?q?VSJM4R6jxCBfX6WF4IBgguDOgKFMkIVAQEBAQEBAQEBA2gohSQBBAF+CwsNJxI?= =?us-ascii?q?UGIpeCKoSIQKKMQExhVGDP4J1NoRmhjMFkgaBFI5/U6ELKIc0mAc1JIFNMhoIM?= =?us-ascii?q?DqCKoRyI4pRAQEB?= X-IPAS-Result: =?us-ascii?q?A2GyNgCyUCVa/7mYWxdcHQEBBQELAYM8gVSJM4R6jxCBfX6?= =?us-ascii?q?WF4IBgguDOgKFMkIVAQEBAQEBAQEBA2gohSQBBAF+CwsNJxIUGIpeCKoSIQKKM?= =?us-ascii?q?QExhVGDP4J1NoRmhjMFkgaBFI5/U6ELKIc0mAc1JIFNMhoIMDqCKoRyI4pRAQE?= =?us-ascii?q?B?= X-IronPort-AV: E=Sophos;i="5.45,359,1508817600"; d="scan'208";a="11125951" Original-Received: from unknown (HELO pastel.home) ([23.91.152.185]) by smtp.teksavvy.com with ESMTP; 04 Dec 2017 08:48:06 -0500 Original-Received: by pastel.home (Postfix, from userid 20848) id AC8DD61367; Mon, 4 Dec 2017 08:48:06 -0500 (EST) In-Reply-To: (Stefan Monnier's message of "Mon, 13 Nov 2017 11:26:29 -0500") X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 76.10.157.34 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:220688 Archived-At: > Here's a sample patch to do that. Comments? Based on the feedback, I added a config var to control the use of `setq'. I also added a backward compatibility hack which makes it so that your "new style config" will partly work in Emacs<27. Any objection to installing the patch below into `master`? Stefan diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 4965adfd56..d7166294c2 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -4374,6 +4382,23 @@ custom-file if only the first line of the docstring is shown.")) :group 'customize) +(defcustom custom-mimic-plain-elisp nil + "If non-nil, save user settings with the new format. +This new format tries to mimick the code that would be written by hand +in plain Elisp. But it relies on `custom-autogenerated-user-settings' which +is a new macro in Emacs-27, so settings saved with this will not work +reliably in Emacs<27 (although a backward compatibility trick is used +which should make them work to some extent)." + :type 'boolean + :group 'customize) + +(defcustom custom-mimic-plain-elisp-use-setq nil + "If non-nil, use `setq' when possible in generated code. +If nil, `custom-mimic-plain-elisp' will only use `customize-set-variable', +which is the more reliable option." + :type 'boolean + :group 'customize) + (defun custom-file (&optional no-error) "Return the file name for saving customizations." (if (or (null user-init-file) @@ -4501,10 +4526,32 @@ custom-save-delete (defvar sort-fold-case) ; defined in sort.el +(defun custom--mimic-plain-elisp (symbol exp requests comment) + "Print the code corresponding to setting SYMBOL to EXP." + ;; Do the inverse conversion of custom-autogenerated-user-settings. + (let* ((e (cond + ((eq (get symbol 'custom-set) #'custom-set-minor-mode) + `(,symbol ,(if (memq exp '(t nil)) + (if exp 1 -1) + '(if ,exp 1 -1)))) + ((or (not custom-mimic-plain-elisp-use-setq) + (get symbol 'custom-set)) + `(customize-set-variable ',symbol ,exp)) + ((local-variable-if-set-p + symbol (get-buffer-create "*scratch*")) + `(setq-default ,symbol ,exp)) + (t `(setq ,symbol ,exp))))) + (dolist (e (nconc (mapcar (lambda (r) `(require ',r)) requests) + (if comment (list comment e) (list e)))) + (princ " ") + (pp e) + (unless (bolp) (princ "\n"))))) + (defun custom-save-variables () "Save all customized variables in `custom-file'." (save-excursion (custom-save-delete 'custom-set-variables) + (custom-save-delete 'custom-autogenerated-user-settings) (let ((standard-output (current-buffer)) (saved-list (make-list 1 0)) sort-fold-case) @@ -4519,8 +4566,21 @@ custom-save-variables (setq saved-list (sort (cdr saved-list) 'string<)) (unless (bolp) (princ "\n")) - (princ "(custom-set-variables - ;; custom-set-variables was added by Custom. + (when (and custom-mimic-plain-elisp + (not (save-excursion + (re-search-backward + "custom-autogenerated-user-settings" nil t)))) + (princ ";; Backward compatibility definition for Emacs<27") + (princ ";; auto-added by `custom-save-variables'.\n") + (pp '(unless (fboundp 'custom-autogenerated-user-settings) + (defalias 'custom-autogenerated-user-settings 'progn))) + (unless (bolp) (princ "\n"))) + (princ (if custom-mimic-plain-elisp + "(custom-autogenerated-user-settings + ;; This custom-autogenerated-user-settings was added by Custom." + "(custom-set-variables + ;; This custom-set-variables was added by Custom.")) + (princ " ;; If you edit it by hand, you could mess it up, so be careful. ;; Your init file should contain only one such instance. ;; If there is more than one, they won't work right.\n") @@ -4555,6 +4555,8 @@ ;; with the customize facility. (unless (bolp) (princ "\n")) + (if custom-mimic-plain-elisp + (custom--mimic-plain-elisp symbol (car value) requests comment) (princ " '(") (prin1 symbol) (princ " ") @@ -4576,7 +4578,7 @@ (when comment (princ " ") (prin1 comment)))) - (princ ")")))) + (princ ")"))))) (if (bolp) (princ " ")) (princ ")") diff --git a/lisp/custom.el b/lisp/custom.el index 352fc6bd53..b641740266 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -1,4 +1,4 @@ -;;; custom.el --- tools for declaring and initializing options +;;; custom.el --- tools for declaring and initializing options -*- lexical-binding:t -*- ;; ;; Copyright (C) 1996-1997, 1999, 2001-2017 Free Software Foundation, ;; Inc. @@ -926,6 +933,36 @@ custom-fix-face-spec (nreverse result)) spec))) +(defmacro custom-autogenerated-user-settings (&rest body) + "Install user customizations of variable values specified in ARGS. +Expect the format output by `custom-save-variables'." + (let* ((settings '()) + (requests '()) + (comment nil) + (mk (lambda (x e) + (push + `'(,x ,e + . ,(when (or comment requests) + `(nil ,(prog1 (nreverse requests) + (setq requests '())) + . ,(when comment + (prog1 (list comment) + (setq comment nil)))))) + settings)))) + (dolist (e body) + (pcase e + (`(,(or 'setq 'setq-default) ,x ,e) (funcall mk x e)) + (`(require ',p) (push p requests)) + (`(customize-set-variable ',x ,e) (funcall mk x e)) + (`(,x ,(and v (or 1 -1))) (funcall mk x (> v 0))) + (`(,x (if ,e 1 -1)) (funcall mk x e)) + ((pred stringp) + (and comment (message "Dropping extra comment: %S" comment)) + (setq comment e)) + (_ + (message "Unrecognized expression in custom-autogenerated-user-settings: %S" e)))) + `(custom-set-variables ,@(nreverse settings)))) + (defun custom-set-variables (&rest args) "Install user customizations of variable values specified in ARGS. These settings are registered as theme `user'.