我正在为一种编程语言编写主要模式,但是我想支持较旧的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-modeIIRC上提出了这几年,它似乎已经从那里传播到了其他几种主要模式。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-classsymbol属性复制到子模式。在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。值得注意的是,您将缺少词汇绑定。