defcustom 如何定义一个动态的字符串可选列表?

例如需要定义这样一个 custom:

(defcustom test-font-famly "Invalid font"
  "Font family of test."
  :group 'test
  :type ...
  :options ...)

我希望在 costomize 界面操作的时候:

  1. 虽然 value 是字符串,但不提供编辑框,而是从列表选择
  2. 列表内容是动态的,由 (font-family-list) 提供
  3. 允许初始值不匹配,但用户修改的时候必须从列表选择,不能输入意料之外的值

相关讨论:

我知道有一个choice关键字,但是不知道能不能动态生成(之前帖子里有人说过了)

choice 会给出一个选项框:

(defcustom foo "Arial"
  "Docstring goes here."
  :type `(choice
          ,@(mapcar
             (lambda (font) `(const ,font))
             (font-family-list))))

但是不满足第 3 点要求,即提示「mismatch」,不显示上面的「Value Menu」:

假如把 "Invalid font" 也加到 choice 之中,那么不会 mismatch 了,但多了一个错误选项。

不过 Custom 界面弄出来的配置很难管理,我是不会用的,如果是我开发的话:

(defcustom foo "Arial"
  "Docstring goes here."
  :type 'string)
1 个赞

不如用custom保存变量。再写一个交互函数用completing-read用来修改

1 个赞

所以还是简单的字符串就好了。


我看 emacs 源代码(lisp/textmodes/tex-mode.el)里有这样的写法:

236 (defcustom tex-open-quote (purecopy "``")
237   "String inserted by typing \\[tex-insert-quote] to open a quotation."
238   :type 'string
239   :options '("``" "\"<" "\"`" "<<" "«")
240   :group 'tex)
241 
242 ;;;###autoload
243 (defcustom tex-close-quote (purecopy "''")
244   "String inserted by typing \\[tex-insert-quote] to close a quotation."
245   :type 'string
246   :options '("''" "\">" "\"'" ">>" "»")
247   :group 'tex)

不知道是不是也是打算约束用户输入,然而实际上是做不到的。

对,这么写用不上 Custom Widge,像是个无关紧要的「误用」。不过如果用户看代码的话,会明白应该设置哪些值。