Настройка режима через функцию в Emacs Lisp - PullRequest
2 голосов
/ 06 января 2012

В моем файле .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 является недействительным и поэтому не может быть передан функции, но может быть cons в пару?

Любые указатели (хе) будут с благодарностью.

Ответы [ 3 ]

4 голосов
/ 06 января 2012

В форме:

(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.Внутри вашей функции эти символы должны быть оценены , чего не происходит, когда они заключаются в кавычки!В результате вместо добавления каждой отдельной строки из вашего списка в auto-mode-alist вместо этого вы получите символ filename-pattern.

Чтобы это исправить, вы должны признать, что '(filename-pattern. mode) предназначен для создания cons-ячейки со значениями , равными filename-pattern и mode.Который мы можем производить (минусы имя файла-режим).Таким образом, исправленная функция будет:

(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 голос
/ 25 июня 2012

Я думаю 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))`

Это будет работать с тем жеcall:

(set-mode-for-filename-patterns 
   'ruby-mode
   '("\\.rb$"
     "\\.rsel$"
     "\\.rhtml$"
     "\\.erb$" 
     "\\.prawn$"
     "Rakefile$"
     "Gemfile$"))

Если вы посмотрите на значение auto-mode-alist, вы увидите, что многие из встроенных режимов используют регулярные выражения по той же причине производительности.

Кстати, япосоветуйте, чтобы вы просто доверяли regexp-opt, чтобы поступать правильно.Это регулярное выражение довольно тяжело для глаз (и мозга).

1 голос
/ 06 января 2012

Смотрите здесь:

(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) и затем передайте его функции.

...