我正在为一种编程语言编写主要模式,但是我想支持较旧的Emacs版本。prog-mode
比较新。如果要prog-mode
定义,我想继承它,但否则还是要做些明智的事情。
最好的方法是什么?我应该defalias
prog-mode
使用较旧的Emacsen,还是如果它们执行相同的操作,会干扰其他模式吗?
我正在为一种编程语言编写主要模式,但是我想支持较旧的Emacs版本。prog-mode
比较新。如果要prog-mode
定义,我想继承它,但否则还是要做些明智的事情。
最好的方法是什么?我应该defalias
prog-mode
使用较旧的Emacsen,还是如果它们执行相同的操作,会干扰其他模式吗?
Answers:
以额外的顶级符号绑定为代价,有一个非常简洁的解决方案,它避免了重复define-derived-mode
表格:
(defalias 'my-fancy-parent-mode
(if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode))
(define-derived-mode my-fancy-mode my-fancy-parent-mode
...)
在任何大于等于23的Emacs中都可以正常工作。我在haml-mode
IIRC上提出了这几年,它似乎已经从那里传播到了其他几种主要模式。define-derived-mode
宏对父模式符号所做的主要工作是生成调用其函数的代码:从这个意义上讲,defalias
使新变量与别名函数完全等效。
一个警告是,这可能会造成混淆derived-mode-p
,因此检查您的模式是否源自的代码prog-mode
可能无法正常工作。在实践中,我没有遇到任何问题:将此类代码挂接到prog-mode-hook
,这仍然会运行,这是更常见的情况。
(正如Jorgen在注释中指出的那样,它define-derived-mode
也使用mode-class
父模式符号中的属性,并且defalias
不会复制它。在撰写本文时,该属性似乎仅用于special-mode
。)
更新:这些天我只是建议至少需要Emacs 24,因为较早的版本已经过时了。
prog-mode
,但不适用于所有模式。define-derived-mode
将mode-class
symbol属性复制到子模式。在defalias
将不转让该物业。如果mode-class
与您的用例相关,则需要手动复制/设置。
mode-class
物业的含义。
tl; dr:使用if
和您自己的init函数:
(if (fboundp 'prog-mode)
(define-derived-mode your-cool-mode prog-mode "Cool"
"Docstring"
(your-cool--init))
(define-derived-mode your-cool-mode nil "Cool"
"Docstring"
(your-cool--init)))
然后在中进行所有模式的初始化your-cool-init
。
更长的解释:
问题在于,编写派生的主模式的正式方法是使用define-derived-mode
宏:
(define-derived-mode your-cool-mode prog-mode ...)
在较早的Emacsen(24岁以下)上,此设置在中断prog-mode
。而且您不能在此使用(if (fboundp 'prog-mode) ...)
它,因为宏需要一个文字符号,并将在扩展中为您引用它。
define-derived-mode
以多种方式使用父级。您需要复制自己模式定义中的所有内容以使用它们,这既繁琐又容易出错。
因此,唯一的方法是define-derived-mode
根据是否prog-mode
存在使用两个不同的语句。这样就剩下了编写两次初始化代码的问题。这当然是不好的,因此您如上所述将其提取到其自身的功能中。
(最好的解决方案当然是放弃对23.x的支持并使用词法作用域。但是我想您已经考虑并放弃了该选项。:-))
prog-mode
旧版Emacsen 最接近的等效词是什么?从中获取text-mode
或不存在,fundamental-mode
是否有意义prog-mode
?
fboundp
仅使用以下define-derived-mode
语句使用first 派生中间模式?那么,可以从该中间模式中得出具有完整清晰度的实际模式吗?这样,整个模式就不必定义两次。
fundamental-mode
等同于从推导nil
(事实上,define-derived-mode
内容替换fundamental-mode
用nil
),同时text-mode
是不恰当的,因为程序代码不是文本。text-mode
在注释之外的编程模式下,大多数默认设置都没有意义。这就是为什么prog-mode
在Emacs的24.介绍
define-derived-mode
一个if
形式的两个定义,仅用于中间模式而不是最终模式。您将用final模式defun
的in 替换init函数define-derived-mode
。我认为这不是特别可取的。您也可以prog-mode
按照原始问题的建议定义自己,但是这很容易使其他依赖于fboundp
检查该模式是否存在的模式感到困惑。
define-derived-mode
陈述。几年前,我想出了作为单独答案发布的解决方案,它在Emacs 23和24中似乎都可以正常工作。类似的代码已在许多流行的主要模式中使用。
您可以define-derived-mode
为其定义一个包装宏,以评估其参数。
(defmacro define-derived-mode* (child parent name &optional docstring &rest body)
(macroexpand `(define-derived-mode ,(eval child) ,(eval parent) ,(eval name)
,(eval docstring) . ,body)))
(define-derived-mode* 'toy-mode
(if (fboundp 'prog-mode) 'prog-mode 'fundamental-mode)
"Toy"
"Major mode for my favorite toy language"
(toy-mode-setup))
(警告:仅经过最低程度的测试。)
prog-mode
。值得注意的是,您将缺少词汇绑定。