2

Is it possible to run code when setting an option defined by defcustom?

For example, I would like (setq my-package-option t) to install a hook.

While defcustom has a :set keyword, it's documented only to run in the user interface.


This is close to working, it has an error about a recursive function call.

(defcustom my-boolean-example nil "Docs." :set #'(lambda (var value) (if (set-default var value) (turn-thing-on) (turn-thing-off))) :initialize 'custom-initialize-changed :type 'boolean) 
6
  • Perhaps you would rather use [?] :initialize: gnu.org/software/emacs/manual/html_node/elisp/… Commented Jan 20, 2020 at 4:45
  • Initialize only seems to run once, not after changing. Commented Jan 20, 2020 at 6:33
  • 2
    Running code when the user wrote (setq pkg-var <foo>) is considered a bad idea. If the user wants to allow pkg's author to do that, they should use customize-set-variable insterad of setq. Commented Jan 20, 2020 at 13:38
  • 2
    BTW, if your variable is boolean, then the canonical way to do what you want is to use a minor mode (and tell the user to call the minor mode function instead of setqing the variable). Commented Jan 20, 2020 at 14:30
  • This is meant to be an option for an existing mode, so I'd rather not have a new mode, although I suppose it could be an additional minor mode. Commented Jan 20, 2020 at 14:57

2 Answers 2

2

It's not true that :set is used only for interactive use of Customize.

Functions customize-set-variable and customize-save-variable respect the :set function of the defcustom.

customize-set-variable is an interactive autoloaded compiled Lisp function in cus-edit.el.

(customize-set-variable VARIABLE VALUE &optional COMMENT)

Set the default for VARIABLE to VALUE, and return VALUE.

VALUE is a Lisp object.

If VARIABLE has a custom-set property, that is used for setting VARIABLE, otherwise set-default is used.

If VARIABLE has a variable-interactive property, that is used as if it were the arg to interactive (which see) to interactively read the value.

If VARIABLE has a custom-type property, it must be a widget and the :prompt-value property of that widget will be used for reading the value.

If given a prefix (or a COMMENT argument), also prompt for a comment.

3
  • Doesn't this require the user to use customize-set-variable instead of setq or setq-default ? Commented Jan 20, 2020 at 6:05
  • Added example to question. Commented Jan 20, 2020 at 6:06
  • Yes, it requires you to use one of the functions I mentioned. You indicated that you wanted to take advantage of defcustom's :set function. Your question has now morphed into a different question. Clearly setq cannot take advantage of defcustom's :set function. Had you made clear your intention I would have mentioned what @phils mentioned: variable watchers. Commented Jan 20, 2020 at 15:28
2

In a comment to @Drew's answer you've said:

Doesn't this require the user to use customize-set-variable instead of setq or setq-default ?

Indicating that you want your function to be called even when a variable is set by the likes of setq, which means you're looking for the variable-watcher functionality.

Refer to C-hig (elisp)Watching Variables for details.

Note that this feature has been available only since Emacs 26.1. Prior to that you cannot do what you're asking for.

4
  • Are you sure this is needed? :initialize 'custom-initialize-changed and :set seemed to get me some ways toward running code when setting a value. Commented Jan 20, 2020 at 11:25
  • 1
    Well do you, or do you not, want the function to run when setq is used to set a variable? You indicated that you did. If you don't, then the comment I quoted is confusing. Commented Jan 20, 2020 at 12:04
  • I do, although I thought this is what custom-initialize-changed supported, I must have misunderstood. Commented Jan 20, 2020 at 12:45
  • custom-initialize-changed is a value for :initialize which "should be a function used to initialize the variable when the ‘defcustom’ is evaluated" -- it has no bearing on any other assignment to that variable's value. Commented Jan 21, 2020 at 0:16

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.