2

I want to write a defcustom definition for a variable my-var.

my-var is an alist that maps strings to plists. Each such plists maps one of three keys (:x, :y, :z) to a list of strings. So, a member of my-var could be:

'("key" . (:x '("a" "b") :y '("c") :z '("d")))

So I want the use to be able to provide a string to be a key of the my-var alist, and lists of strings as value for the three keys of the plist.

The problem is I don't know how to do that. Specifically, I don't know where to put the :option keyword to offer :x, :y and :z as possible keys:

:type '(alist :key-type string
              :value-type (plist :key-type symbol
                                 :value-type (repeat string)))
Drew
  • 75,699
  • 9
  • 109
  • 225
efl
  • 83
  • 5
  • 1
    Good question. Not enough good questions here about specifying types for `defcustom`, IMO. – Drew Dec 10 '22 at 02:53
  • Yeah, it's one of the very few cases with Emacs where I think the documentation could be a bit clearer/richer... – efl Dec 10 '22 at 05:11
  • The doc could be better, but more importantly the Customize UI could be better. And the customize code is too complex. – Drew Dec 10 '22 at 05:15

1 Answers1

2

I think this is what you're describing:

(defcustom myvar ()
  "..."
  :group 'mygroup
  :type '(alist :key-type string
                :value-type (plist :key-type symbol
                                   :options (:x :y :z)
                                   :value-type (repeat string))))

(You can also omit :key-type symbol, for the plist, as the type is symbol by default.)

I assume you don't really want to quote the values in the plist. That is, I assume that this is an alist element that you want to allow:

("key1" :x ("a" "b") :z ("q"))

and not this:

("key1" :x '("a" "b") :z '("q"))

aka not this:

("key1" :x (quote ("a" "b")) :z (quote ("q")))

By the way, you can also use a restricted-sexp to specify that the plist keys must be keywords, not just any symbols. Here's an example:

(defcustom myvar '(("key1"))
  "..."
  :group 'emacs
  :type '(alist :key-type (string :tag "Alist key (string):")
            :value-type
        (plist :key-type
               (restricted-sexp :match-alternatives (keywordp)
                    :tag "Plist key (keyword)")
                       :options (:x :y :z)
                       :value-type (repeat string))))

However, I seem to have discovered a bug when you try to do that and also give it a nil default value. I've filed Emacs bug #59937 for that now.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • Yes! Excellent, that's what I needed. And yes, the quotes shouldn't be there. Thank you! – efl Dec 10 '22 at 05:09