0

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)
  • Perhaps you would rather use [?] :initialize: gnu.org/software/emacs/manual/html_node/elisp/… – lawlist Jan 20 at 4:45
  • Initialize only seems to run once, not after changing. – ideasman42 Jan 20 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. – Stefan Jan 20 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). – Stefan Jan 20 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. – ideasman42 Jan 20 at 14:57
1

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.

| improve this answer | |
  • 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. – ideasman42 Jan 20 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. – phils Jan 20 at 12:04
  • I do, although I thought this is what custom-initialize-changed supported, I must have misunderstood. – ideasman42 Jan 20 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. – phils Jan 21 at 0:16
0

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.

| improve this answer | |
  • Doesn't this require the user to use customize-set-variable instead of setq or setq-default ? – ideasman42 Jan 20 at 6:05
  • Added example to question. – ideasman42 Jan 20 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. – Drew Jan 20 at 15:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.