Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When creating a customizable value with defcustom, how can I validate users' entries?

Tags:

emacs

elisp

I'm writing an elisp file that's evolving into a package, so I'm translating some of its variables into defcustom statements and documenting them. A few of these defcustom variables are related, and I'd like to validate values entered through the Customize system to ensure that the relationships hold true.

Here's an example of what I have:

(defcustom widget-canonical-names '("my_widget" . "widget_assembly 8911_j4")
  "Documentation"
  :type '(alist :key-type (string :tag "Widget's short name")
                :value-type (string :tag "Full widget name"))
  :risky nil
  :group 'widgets)
(defcustom widget-colors '("my_widget" . "brown")
  "Documentation"
  :type '(alist :key-type (string :tag "Widget's short name")
                :value-type (color :tag "color of the widget"))
  :risky nil
  :group 'widgets)
(defcustom widget-paths '("my_widget" . "~/widgets")
  "Documentation"
  :type '(alist :key-type (string :tag "Widget's short name")
                :value-type (directory :tag "support files for widget"))
  :risky nil
  :group 'widgets)

So there are widgets and they have various settings, and I need to be able to access an arbitrary setting for a widget by knowing just the widget's short name. I'd like to make a validation function of some kind (googling around for "emacs defcustom validate" hasn't helped, unfortunately) such that if the user enters a widget name in widget-paths or widget-colors that is not in the widget-canonical-names list, they get an "are you sure?" warning and are cautioned about entering mismatched names. Can I attach such a validation function to my defcustoms? If so, what's the syntax for that?

Of course, what would be ideal would be to just make the user enter the short name once, but I can't figure out how to do that from the 'Composite Types' elisp documentation. So an even better answer to my question would tell me how to arrange a defcustom that sets up a data structure similar to this Python dict:

customized_widgets = {
    "my_widget": { "canonical_name": "widget_assembly 8911_j4",
                   "widget_color": "brown",
                   "widget_path": "~/widgets",
                 },
    "another_widget": { "canonical_name" : "widget_obsolete 11.0",
                        "widget_color": "blue",
                        "widget_path": "~/blue_widgets",
                      },
     }

So: how can I get the behavior I want, where settings are grouped according to the data that'll be used to access them, or where a validation function warns users when they might be entering inconsistent data?

like image 200
Brighid McDonnell Avatar asked Sep 13 '12 20:09

Brighid McDonnell


1 Answers

This will define the closest Emacs equivalent of that Python structure, with dicts represented as alists, and fixed keys of the inner dict represented as symbols.

(defcustom my-customized-widgets ()
  "My widget customization alist"
  :type '(alist
          :tag "Widgets"
          :key-type (string :tag "Short name")
          :value-type
          (set
           :format "%v"
           :entry-format "%b %v"
           (cons :format "%v"
                 (const :format "" widget-canonical-name)
                 (string :tag "CName"))
           (cons :format "%v"
                 (const :format "" widget-color)
                 (color :tag "Color"))
           (cons :format "%v"
                 (const :format "" widget-path)
                 (directory :tag " Path"))))
  :group 'widgets)
like image 182
user4815162342 Avatar answered Sep 29 '22 07:09

user4815162342