30 июл. 2007 г.

Сокращения/snippets и лучший редактор этой вселенной

Что я подразумеваю под сокращениями (abbrevs)? Возможно, вы уже видели это в TextMate для MacOS X или в какой-нибудь интегрированной среде разработки. В общем случае выглядит это так: вы набираете в редакторе for, а он (редактор) сразу после набора этого слова заменяет его на соответствующий ему шаблон, например такой:


for (_;_;_) {
    _
}

Причем курсор появляется в местах, помеченных как "_" (я буду называть их "точками перехода"). Между такими местами можно переключаться с помощью какой-нибудь клавиши (обычно это Tab). Демонстрацию работы такой функции можно посмотреть здесь.

По умолчанию в Emacs (по крайней мере в последних версиях) есть так называемые skeleton'ы, но с ними не очень удобно работать, поскольку точка перехода может быть только одна. В таких условиях после каждого банального if'а вам придется орудовать стрелками, чтобы перейти в тело цикла. Как по мне, так проще и быстрее код пишется без таких вот сокращений. Кроме того, при использовании skeleton'ов текст вставляетя без нормального форматирования отступов. Приходится либо делать indent вручную, либо дописывать костыли.

Что касается сторонних скриптов (в которых проблема с единственной точкой перехода решена), то их вполне достаточно; самые популярные - snippet.el и smart-snippet. Второй является надстройкой над первым. Однако ни тот, ни другой, мне настроить так и не удалось. Да, для С/С++ все замечательно (кроме форматирования отступов, к которому эти скрипты относятся прямо скажем очень своеобразно), но к ruby-mode приделать их так и не получилось. Поэтому я расскажу о другом, не столь популярном скрипте - msf-abbrev.el, который гораздо проще в настройке (как мне показалось).

У меня в домашнем каталоге есть директория, куда я складываю все сторонние скрипты для Emacs (у меня это ~/emacs). Если у вас еще нет такой, рекомендую ее создать и добавить в ваш ~/.emacs следующую строку:

(add-to-list 'load-path "~/emacs")

После этого чтобы загрузить какой-нибудь сторонний скрипт (foobar.el), вам нужно будет поместить его в этот каталог и дописать в конфиг что-нибудь вроде (require 'foobar) или (load "foobar"). Я рассчитываю на то, что вы скачали msf-abbrev.el и поместили его в свой аналог ~/emacs. На сайте автора есть архив с его сокращениями, но мне они показались не очень удобными. Там же есть ссылка на архив сокращений для всех функций glibc.

Что ж, приступим к настройке собственно скрипта. Открывайте ~/.emacs и добавляйте туда такие строки:


(require 'msf-abbrev)
(setq-default abbrev-mode t)
(setq save-abbrevs nil)
(setq msf-abbrev-root "~/emacs/abb")
(global-set-key (kbd "C-c a") 'msf-abbrev-define-new-abbrev-this-mode)
(add-hook 'ruby-mode-hook 'msf-abbrev-load)

В первой строке подгружается сам скрипт (если он еще не был загружен раньше), после чего все его функции становятся доступными. Во второй строке мы говорим, чтобы Emacs по умолчанию включал подрежим abbrev (сокращения будут работать в этом режиме). Если деятельность скрипта начнет вам мешать, выполните M-x abbrev-mode. В третьей строке мы говорим, чтобы Emacs не записывал наши сокращения в ~/.abbrevs. По умолчанию эта функция включена, но при использвании msf-abbrevs в ней нет необходимости. Далее мы определяем каталог, где будут храниться наши сокращения (создайте свой и вставьте вместо "~/emacs/abb").
После этого мы задаем клавиатурное сочетание "C-c a", которая будет создавать для нас новое сокращение для текущего режима. В последней строке добавляем новый хук к ruby-mode (я буду показывать все на примере Ruby). Вообще можно обойтись и без хука, вставив вместо этого строку (msf-abbrev-load), но я люблю, чтобы скрипт загружался только в нужных режимах. Если вы пишете на других языках, то вместо ruby-mode-hook вставьте хук для своего языка (c-mode-hook, java-mode-hook, python-mode-hook).

Все, больше никакой правки .emacs не потребуется. Теперь будем обучать редактор нашим сокращениям. Загружайте по-новой Emacs, переходите в нужный режим (тот, для которого будете задавать сокращения и для которого настроили загрузку скрипта через хук: M-x ruby-mode). Теперь жмите "C-c a". В минибуфере появится сообщение о том, что директория ~/emacs/abb/ххх-mode не найдена и тут же вам предложат ее создать. Соглашайтесь. Дальше вас спросят об имени сокращения. Имя сокращения соответствует его вызову. То есть если вы дадите ему имя for, то и вызываться оно будет после набора в редакторе слова "for" (разумеется, только в том режиме, для которого оно определено). После ввода имени сокращения (пусть для определенности это будет тот же for), откроется новый буфер. Вставьте в него что-то вроде этого (напомню, что примеры у меня для Ruby):


for <field "name"> in <field "exp"> do
    <endpoint>
end

Теперь сохраняйте буфер, переходите в нужный режим и пробуйте. Скрипт должен на лету подхватить свежесозданное сокращение и, если вы все сделали правильно, после ввода for появится что-то похожее:


for name in exp do

end

То, что я выделил наклонным шрифтом, скорее всего будет выделено в самом редакторе каким-нибудь цветом (у меня это серый). Это точки перехода. В между ними можно перемещаться по клавишам Tab и Shift-Tab (вперед и назад, соответственно). После нажатия Tab в последней точке перехода, курсор переместится в то место, где мы указали endpoint. Думаю, в целом смысл понятен. Теперь давайте заглянем в ~/emacs/abb/ruby-mode/ и посмотрим, что же там появилось. А появился там обычный текстовый файл с именем for, содержащий наш шаблон.

Кроме field и endpoint скрипт принимает еще несколько ключевых слов: cursor, varlookup, elisp, query, choose и comment. Из них отмечу query, который вместо создания точки перехода просто спрашивает вас в минибуфере, что вставить в этом месте и choose, с помощью которого можно организовать комбо-бокс с несколькими вариантами выбора. Про остальные можете почитать на странице проекта.

Надеюсь, настроив сокращения, вы станете получать от написания исходников (а может и не только их?) в своем любимом редакторе еще больше удовольствия. (:

1 комментарий:

spariev комментирует...

а чем не подошел http://dima-exe.ru/rails-on-emacs
?
Сниппеты работают без проблем, правда я не пробовал новых добавлять ...