kdb
kdb

Reputation: 4426

Emacs lisp: "Fall through" type for defcustom.

TL;DR

Is there some standard fallback handling in the customize system, for handling partially invalid composite customization variables, e.g. an alist where one entry is not a cons?

Long Version

The customize-mechanism of emacs is quite powerful by using composite :type arguments to defcustom provides a nifty unified interface for customizing variables.

However, when for whatever reason a single entry of the variable is wrong the whole system breaks down and it will just show the bare s-expression. There is then no help to fix this expect for deleting the customizations hoping that the default value matches the type description.

At least that is what I have experienced so far.

If I have a customization variable that is a complicated data structure, is there some mechanism that allows showing only the corrupted part of the variable as a bare s-expression?

Think e.g. about

(defcustom x 
  '((org-mode . "a\\|b")
    (text-mode . "b\\|c"))
  "Some variable"
  :group 'x
  :type '(repeat
          (cons :tag "Entry"
                (function :tag "Mode" :value text-mode)
                 (regexp))))

Normally M-x customize-variable x will no display a nice input mask.

Hide X:
INS DEL Entry:
            Mode: org-mode
            Regexp: a\|b
INS DEL Entry:
            Mode: text-mode
            Regexp: b\|c
INS
    State : STANDARD.
   Some variable
Groups: X

When I now do

(add-to-list 'x 1)

the mask becomes a significantly less user friendly

Hide x: 
'(1
  (org-mode . "a\\|b")
  (text-mode . "b\\|c"))
    State : CHANGED outside Customize. (mismatch)
   Some variable
Groups: X

Now of course I can include a fallback option by changing the definition to something like

(defcustom x 
  '((org-mode . "a\\|b")
    (text-mode . "b\\|c"))
  "Some variable"
  :group 'x
  :type '(repeat
          (choice
           (cons :tag "Entry"
                 (function :tag "Mode" :value text-mode)
                 (regexp))
           (sexp :tag "MISMATCHED ENTRY!"))))

which gives a customization mask

Hide X:
INS DEL Choice: Value Menu MISMATCHED ENTRY!: 1
INS DEL Choice: Value Menu Entry:
            Mode: org-mode
            Regexp: a\|b
INS DEL Choice: Value Menu Entry:
            Mode: text-mode
            Regexp: b\|c
INS
    State : CHANGED outside Customize.
   Some variable
Groups: X

However this does now include an awkward drop-down menu that gives the user the choice between an entry and an invalid value. Rather I'd have the drop down value hidden by default and shown only when there is a mismatch with the valid option. As a user my first thought seeing such would be along the lines of “”.

Is there some standard way in the customization system to handle partly invalid values? I couldn't find any in the documentation.¹


¹ http://www.gnu.org/software/emacs/manual/html_node/elisp/Customization-Types.html#Customization-Types

Upvotes: 4

Views: 653

Answers (2)

Lord Yuuma
Lord Yuuma

Reputation: 176

You might want to use/implement your widget's :validate.

From The Emacs Widget Library – 5 Basic Types (read with C-h i m Widget RET m Basic RET):

‘:validate’ A function which takes a widget as an argument, and returns ‘nil’ if the widget’s current value is valid for the widget. Otherwise it should return the widget containing the invalid data, and set that widget’s ‘:error’ property to a string explaining the error.

The following predefined function can be used:

-- Function: widget-children-validate widget
   All the ‘:children’ of WIDGET must be valid.

In your example, all widgets in use should have :validate implemented, so you need only apply it.

Upvotes: 0

Stefan
Stefan

Reputation: 28541

You can edit (and save) the "raw sexp" displayed. I agree it would be even better if the valid part were displayed using the usual widgets and only the invalid part is displayed as "raw sexp". Patches welcome.

Upvotes: 0

Related Questions