在仍然支持较旧的emacsen的同时,我如何从prog-mode继承?


10

我正在为一种编程语言编写主要模式,但是我想支持较旧的Emacs版本。prog-mode比较新。如果要prog-mode定义,我想继承它,但否则还是要做些明智的事情。

最好的方法是什么?我应该defalias prog-mode使用较旧的Emacsen,还是如果它们执行相同的操作,会干扰其他模式吗?


我建议您简单地放弃对Emacs <24的支持。在我看来,这不再是值得的工作,您必须放弃比更为重要的功能prog-mode。值得注意的是,您将缺少词汇绑定。
lunaryorn 2014年

我正在为julia-mode做出贡献,一些核心团队使用了较旧的Emacsen,希望我们支持它。
2014年

1
@lunaryorn Emacs 24仍然很新。Emacs 23是许多操作系统上的当前版本。Emacs 22仍然是最新的。并非每个人都疯狂升级软件。放弃对Emacs 23的支持会将您限制为渴望获得最新技术的少数用户。
吉尔斯(Gilles)'所以

1
使用旧版Emacs的原因很多。例如,在Windows上,Emacs 23变得非常缓慢,因此我选择在那里坚持使用Emacs 22。
Lindydancer 2014年

@吉尔斯我怀疑这只是一个“很少的用户”。Flycheck最初从未支持Emacs 23,但仍然成为MELPA上最受欢迎的软件包之一……
lunaryorn 2014年

Answers:


11

以额外的顶级符号绑定为代价,有一个非常简洁的解决方案,它避免了重复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,因为较早的版本已经过时了。


2
不错的解决方案!请注意:此功能适用于prog-mode,但不适用于所有模式。define-derived-modemode-classsymbol属性复制到子模式。在defalias转让该物业。如果mode-class与您的用例相关,则需要手动复制/设置。
JorgenSchäfer2014年

约尔根(Jorgen)感谢您的到来-我将不得不深入研究并进一步了解该mode-class物业的含义。
sanityinc 2014年

3

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
Wilfred Hughes 2014年

@Jorgen还是我们可以fboundp仅使用以下define-derived-mode语句使用first 派生中间模式?那么,可以从该中间模式中得出具有完整清晰度的实际模式吗?这样,整个模式就不必定义两次。
考沙尔·莫迪2014年

1
@WilfredHughes,没有。从推导fundamental-mode等同于从推导nil(事实上,define-derived-mode内容替换fundamental-modenil),同时text-mode是不恰当的,因为程序代码不是文本。text-mode在注释之外的编程模式下,大多数默认设置都没有意义。这就是为什么prog-mode在Emacs的24.介绍
约尔根·舍费尔

@kaushalmodi,您可以派生一个中间模式,但是仍然需要define-derived-mode一个if形式的两个定义,仅用于中间模式而不是最终模式。您将用final模式defun的in 替换init函数define-derived-mode。我认为这不是特别可取的。您也可以prog-mode按照原始问题的建议定义自己,但是这很容易使其他依赖于fboundp检查该模式是否存在的模式感到困惑。
JorgenSchäfer2014年

我认为不需要两个不同的define-derived-mode陈述。几年前,我想出了作为单独答案发布的解决方案,它在Emacs 23和24中似乎都可以正常工作。类似的代码已在许多流行的主要模式中使用。
sanityinc 2014年


0

您可以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))

(警告:仅经过最低程度的测试。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.