我的.emacs
文件中有以下代码,它可以按照您的预期运行:
;; Ruby
(global-font-lock-mode 1)
(autoload 'ruby-mode "ruby-mode" "Ruby editing mode." t)
(setq auto-mode-alist (cons '("\\.rb$" . ruby-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.rsel$" . ruby-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.rhtml$" . html-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.erb$" . html-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.prawn$" . html-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("Rakefile$" . ruby-mode) auto-mode-alist))
然而,我尝试干掉它有点失败:
(defun set-mode-for-filename-patterns (mode filename-pattern-list)
(mapcar
(lambda (filename-pattern)
(setq
auto-mode-alist
(cons '(filename-pattern . mode) auto-mode-alist)))
filename-pattern-list))
;; Ruby
(global-font-lock-mode 1)
(autoload 'ruby-mode "ruby-mode" "Ruby editing mode." t)
(set-mode-for-filename-patterns
ruby-mode
'("\\.rb$"
"\\.rsel$"
"\\.rhtml$"
"\\.erb$"
"\\.prawn$"
"Rakefile$"
"Gemfile$"))
...出现以下错误:
Debugger entered--Lisp error: (void-variable ruby-mode)
(set-mode-for-filename-patterns ruby-mode (quote ("\\.rb$" "\\.rsel$" "\\.rhtml$" "\\.erb$" "\\.prawn$" "Rakefile$" "Gemfile$")))
eval-buffer(#<buffer *load*> nil "/home/duncan/.emacs" nil t) ; Reading at buffer position 1768
load-with-code-conversion("/home/duncan/.emacs" "/home/duncan/.emacs" t t)
load("~/.emacs" t t)
#[nil "\205\264
我在这里有点困惑......特别是,我不明白ruby-mode
是如何无效的&amp;所以无法传递给函数,但可以被cons
编成一对吗?
任何指针(嘿)都会非常感激。
答案 0 :(得分:4)
表格形式:
(cons '("\\.rb$" . ruby-mode) ...
ruby-mode
是引用列表的一部分。这意味着它被读作符号名称,而不是作为变量计算。换句话说,Emacs将其视为符号ruby-mode
并按原样接受它。
表格形式:
(set-mode-for-filename-patterns
ruby-mode
'("\\.rb$"
"\\.rsel$"
...
ruby-mode
未被引用,因此被读作函数的参数。函数参数被评估。这意味着Emacs读取ruby-mode
,将其识别为符号,并尝试对其进行评估。评估符号意味着查找它指向的值,在这种情况下不存在。
编辑:
你的功能仍然不起作用,还有另外一个问题。您在set-mode-for-filename-patterns
中使用了引用列表。这在原始代码中可以正常工作:
(setq auto-mode-alist (cons '("\\.rb$" . ruby-mode) auto-mode-alist))
因为您实际上为filename-pattern
和mode
提供了值。在您的函数内部,您需要评估 这些符号,这些符号在引用时不会发生!结果是,不是将列表中的每个不同字符串添加到自动模式列表中,而是改为使用符号filename-pattern
。
要解决此问题,您需要认识到'(文件名模式。模式)是为了生成包含filename-pattern
和mode
的值的cons单元格。我们可以用(cons filename-pattern模式)生成。所以纠正的功能是:
(defun set-mode-for-filename-patterns (mode filename-pattern-list)
(mapcar
(lambda (filename-pattern)
(setq
auto-mode-alist
(cons (cons filename-pattern mode) auto-mode-alist)))
filename-pattern-list))
更正的函数调用是:
(set-mode-for-filename-patterns
'ruby-mode
'("\\.rb$"
"\\.rsel$"
"\\.rhtml$"
"\\.erb$"
"\\.prawn$"
"Rakefile$"
"Gemfile$"))
答案 1 :(得分:1)
看这里:
(setq auto-mode-alist (cons '("\\.rb$" . ruby-mode) auto-mode-alist))
----------------------------^
这是quote
,这意味着您无法评估下一个
表单,因此'("\\.rb$" . ruby-mode)
相当于(cons '"hello"
'ruby-mode)
。
但是当你调用函数set-mode-for-filename-patterns
时
参数首先进行评估,然后将结果传递给
功能。这就是评估(set-mode-for-filename-patterns
ruby-mode ..)
引发错误的原因,因为emacs-lisp解释器会尝试
将ruby-mode
评估为变量,但ruby-mode
没有值
这个上下文因此错误(void-variable ruby-mode)
。你是什么
想要传递符号ruby-mode
,所以你必须引用它
像这样(set-mode-for-filename-patterns 'ruby-mode ...)
请注意,您可以使用ruby-mode
将值设置为let
模式。
(let ((ruby-mode 'ruby-mode))
(set-mode-for-filename-patterns ruby-mode ...))
这里,当评估形式(set-...)
的参数时,它会进行评估
ruby-mode
并且可以找到它的值(这是符号
ruby-mode
)然后将其传递给函数。
答案 2 :(得分:1)
我认为set-mode-for-filename-patterns
是一个有趣的功能。我要将它添加到我的配置中,但使用更优化的实现。
这里的实现都为每个文件后缀的auto-mode-alist
变量添加了一个项目。 Emacs每次找到文件时都会搜索此列表。因此auto-mode-alist
越短,Emacs找到文件的速度就越快。
此版本在启动时可能较慢,但在查找文件时速度更快:
(defun set-mode-for-filename-patterns (mode filename-pattern-list)
(push (cons (regexp-opt filename-pattern-list) mode)
auto-mode-alist))`
这将适用于同一个电话:
(set-mode-for-filename-patterns
'ruby-mode
'("\\.rb$"
"\\.rsel$"
"\\.rhtml$"
"\\.erb$"
"\\.prawn$"
"Rakefile$"
"Gemfile$"))
如果您查看auto-mode-alist
的值,您会发现许多内置模式使用regexp是出于同样的性能原因。
regexp-opt
做正确的事。它所做的正则表达对眼睛(和大脑)非常困难。