widget的使用:如何validate用户输入的数据类型

比如,我想创建一个widget来收集信息,我看到在wid-edit.el里定义了:

(define-widget 'integer 'restricted-sexp
  "An integer."
  :tag "Integer"
  :value 0
  :type-error "This field should contain an integer"
  :match-alternatives '(integer))

想当然的以为创建integer类型的widget会确认输入的数据类型,但在如下的function里,无论是运行(example-widget-form "aa") 还是在生成的buffer表格里输入非integer的数据,都不会报错。如何才能让widget检测输入的数据类型呢?应该是可以的,比如基于widget的defcustom是可以 (defcustom age :type '(integer))有这个功能的。可能是我没完全搞清楚widget的使用方法……

(defun example-widget-form (&optional default)
  "A form with multiple types of widgets."
  (interactive)
  (switch-to-buffer "*Advanced Widget Form*")
  (kill-all-local-variables)
  (let ((inhibit-read-only t))
    (erase-buffer))
  (remove-overlays)

  (widget-insert "Advanced Form Example\n\n")

  ;; Integer field
  (setq int-widget (widget-create 'integer
                                  :size 5
                                  :value default
                                  :format "Age: %v "))

  ;; Submit button
  (widget-insert "\n\n")
  (widget-create 'push-button
                 :notify (lambda (&rest ignore)
                           (message "Age: %S"
                                    (widget-value int-widget)))
                 "Submit")
  (use-local-map widget-keymap)
  (widget-setup))

另外,我感觉emacs自带的widget使用得不多,官方文档介绍的也比较简略,大家有找到比较好的帖子或教程么?

比较难用,我在重写一个包含widget的插件

但现在也没有其他的解决方案……

在提交按钮的 :notify 里调用输入框的 :validate:

:notify (lambda (&rest ignore)
          (if (widget-apply int-widget :validate)
              (message (widget-get int-widget :error))
            (message "Age: %S" (widget-value int-widget))))

:match :

:notify (lambda (&rest ignore)
          (let ((value (widget-value int-widget)))
            (if (widget-apply int-widget :match value)
                (message "Age: %S" value)
              (message (widget-get int-widget :error)))))

也可以直接在输入框的 :notify 里验证。

感谢感谢!如何直接在输入框的 :notify 里验证呢?如何在输入框里获得输入的值?比如下面的代码中,int-widget 还没创建、:notify里还不能使用对吧?

;; Integer field
(setq int-widget (widget-create 'integer
                                :size 5
                                :value default
                                :format "Age: %v "
                                :notify (lambda (&rest ignore)
                                          (if (widget-apply int-widget :validate)
                                              (message (widget-get int-widget :error))
                                            (message "Age: %S" (widget-value int-widget))))))


(setq int-widget (widget-create 'integer
                                :size 5
                                :value default
                                :format "Age: %v "
                                :notify (lambda (widget &rest ignore)
                                          (when (widget-apply widget :validate)
                                            (message (widget-get widget :error))))))

虽然在文本输入框可以验证,但是并没有阻止最后的 Submit 按钮提交,这大概也是 defcustom 在 Apply 统一验证的原因吧。除非做些额外的工作,把 Submit 状态跟输入表单控件关联。