В прошлой статье я рассказал об очень позитивных впечатлениях Дональда Кнута от созданной им методологии «литературного программирования», которые не покидают его на протяжении последних двадцати лет. Мои впечатления так же весьма позитивны. Однако, я посетовал, что литературное программирование совсем не используется в сообществе программистов, и в особенности — в мире Open Source. Дабы не быть голословным, представлю вашему вниманию программу Emacs Starter Kit, которую я постарался сделать настолько литературной, насколько это возможно. Но я не супермэн и не могу действительно хорошо объяснить код, который писали несколько сотен человек, к тому же я совсем не силен в Emacs Lisp, поэтому лучшее пояснение я дал тому коду, который написал сам; если вы сильны в программировании Emacs и если у вас есть идеи и предложения по улучшению, дополнению, исправлению и объяснению приведенного здесь когда — милости прошу — форкайте и пульте коммиты; комментируйте здесь и пишите мне на почту.
Итак, это статья является Emacs Lisp-программой, основной частью пакета настроек Emacs Starter Kit, который служит мне и еще как минимум двум тысячам человек в качестве основного конфигурационного файла редактора Emacs. Этот файл хранится в моем git-репозитории на гитхабе. Мой репозиторий является форком репозитория eschulte, литературный конфиг которого я перевел и дополнил. Его репозиторий является в свою очередь форком репозитория technomacy, автора оригинального Kit.
-
Emacs. Большая и сложная программа. Ему как ничему другому подходит
это определение. Эмакс был создан очень давно в лаборатории
искуственного интллекта MIT, он несет в себе гены очень своеобразной
культуры лисп-хакеров былых времен. С тех пор он не раз переписывался,
улучшался, дополнялся и обрастал тысячами расширений в течение
десятков лет. Эмакс, если и был когда-то мощным текстовым редактором,
сейчас стал некоей универсальной программой, в нём можно делать
абсолютно всё что угодно, если это хотя бы немного затрагивает собой
задачу отображения или редактирования текста, и даже больше. Людям
знáющим универсальность играет на руку, ведь одной программой можно
делать тысячу разных дел, при этом не прилагая усилий для переучивания
к разным интерфейсам. Людей, впервые запустивших эмакс подобная
универсальность и непривычный интерфейс поначалу пугает. Научиться
пользоваться эмаксом, понять его идею и проникнуться ею задача
непростая, трудоемкая и долгая.
Напутствие начинающим пользователям подобного рода врядли вызовет у них энтузиазм, скорее наоборот, и тут главное начать — часто эмакс становится чем-то вроде игрушки.
-
Настройка эмакса это своего рода декоративно-прикладное искусство,
она — одновременно благословение и проклятье пользователя. В
отличие от vi, главная прелесть которого, на мой взгляд, в том,
что в нём всё «из коробки» прекрасно настроено — бери да пользуйся,
эмакс в своем изкоробочном состоянии далеко не так хорош и удобен,
как мог бы быть. С первого же запуска начинается эпопея: эмаксер
затачивает редактор под себя, ставит расширения, заводит свои
конфигурационные файлы, подсматривает кусочки кода у других, по
крупицам собирает свои собственные настройки по всей сети — со
временем накапливается приличная база кода. И всё бы ничего, но
процесс доводки до более-менее юзабельного состояния очень долог —
на это могут уйти целые месяцы и даже годы (на самом деле настройка
эмакса не прекращается никогда).
Всё то время, что я пользовался эмаксом я именно так и поступал: собирал конфиг по кусочкам из тысячи разных мест — форумы, ЛОР, хабр, эмакс-вики, статьи, репозитории с настройками продвинутых пользователей, страница Alex'а Ott'а, и прочее. В итоге конфиг разросся до неприличных размеров и превратился в страшную кашу. В общем, всё было плохо пока я не наткнулся на замечательный скринкаст Meet Emacs. В скринкасте автор не усердствует с базовой настройкой, а сразу после установки эмакса копирует в свою директорию
.emacs.d
репозиторий emacs-starter-kit. Сперва я скептически отнёсся к такому подходу, но попробовав Starter Kit раз, удалив, и попробовав во второй раз я проникся: его оказалось достаточно чтобы просто пользоваться эмаксом, не задумываясь о его серьезных улучшениях. Всё что мне осталось — установить через пакетный менеджер эмакса и операционной системы необходимые мне расширения, да добавить настройки шрифтов и клавиатуры для нетбука и настольного компьютера. -
Emacs Starter Kit это пакет базовых настроек редактора Emacs, он
идеален для быстрого начала работы, дополнения своими настройками и
переноса между компьютерами.
Оригинальный Emacs Starter Kit, ныне «центральный репозиторий» оного — это личный конфиг Фила Хагельберга, собранный им за долгие годы использования эмакса. Сейчас же Kit — это сотни форков и тысячи следящих за ним на гитхабе.
-
Установка. Emacs Starter Kit рассчитан на работу с Emacs от 22-ой
версии и выше. Чтобы установить Emacs воспользуйтесь пакетным
менеджером вашего дистрибутива; пользователи Mac OS X могут
получить Emacs с сайта Apple, или собрать напрямую из исходного кода,
следуя инструкциям в файле
nextstep/INSTALL
. Пользователи Windows могут скачать установщик с сайта GNU.Также вам понадобится система контроля версий git и система компьютерной верстки TeX (хотя она и необязательна).
-
Установка Emacs Starter Kit элементарна: клонируйте git-репозиторий
с гитхаба в директорию
.emacs.d
; но перед эти сохраните старые настройки и удалите.emacs
:git clone http://github.com/zahardzhan/emacs-starter-kit.git ~/.emacs.d
Затем установите git-сабмодули сторонних пакетов
cd ~/.emacs.d/ git submodule init git submodule update
и соберите последнюю версию Org-mode
cd ~/.emacs.d/src/org/ make
- Запустите Emacs.
-
Если вы хотите оставить свои старые настройки в
~/.emacs.d
на месте и просто попробовать Starter Kit, запустите его следующей командой:emacs -q -l ~/emacs-starter-kit/init.el
- После того как закончите установку вам, возможно, потребуется перезапустить Emacs несколько раз — во время загрузки пакетов с ELPA происходят ошибки разбора HTML — просто проигнорируйте их.
-
Если после очередного обновления вы потеряете некоторые
автозагрузчики, что даст знать о себе сообщениями об ошибках типа
«void function: foobar», попробуйте использовать команду
M-x regen-autoloads
. -
Устройство. Директория
.emacs.d
Kit'а устроена следующим образом:.emacs.d/ ... ... системные ... elpa/ elpa-to-submit/ src/ init.el loaddefs.el package.el starter-kit.org ... ... пользовательские ... username.el username.org username/ config1.el config2.org config3.el ... system-name.el system-name.org
Пакетный менеджер ELPA находится в файле package.el. Он усанавливает пакеты в директорию elpa/.
Библиотеки, которые ожидают отправки в ELPA передаются вместе со Starter Kit'ом в директории elpa-to-submit/. Эти файлы хранятся там временно до тех пор пока кто-нибудь не удосужится превратить их в нормальные пакеты. Как только они будут отправлены в ELPA, их можно будет удалить. Автозагрузчики для этих библиотек хранятся в файле loaddefs.el. Это позволяет им загружаться по требованию, а не при старте.
Самый главный файл — это
init.el
, с него начинается загрузка. Он загружает Org-mode и передает управление этому файлу. Дальнейшая загрузка происходит в порядке выполнения Emacs Lisp-кода в этом файле. В последнюю очередь загружаются пользовательские файлы. -
Настройка. Для многих пользователей настройки приведенные
здесь станут базой для собственных. Starter Kit предоставляет
места для дополнительных настроек, специфичных для пользователей и
для машин, на которых будет запущен Emacs. Эти места устроены
таким образом, что позволяют легко управлять своими настройками и
с легкостью, без конфликтов, получать обновления из основного
репозитория.
Чтобы сделать первый шаг к своим настройкам — создайте ветку репозитория Starter Kit для локальных изменений с помощью команды
git branch
. Оставьте главную ветку для получения обновлений и храните персональную информацию в своей ветке. -
Свои настройки вы можете хранить в файле названым именем вашего пользователя, с расширением
.el
или.org
на конце. Если вы не уверены насчет имени пользователя — выполните в консоли командуecho $USER
- Если ваша конфигурация слишком велика для одного файла — можете разбить её на несколько файлов и сохранить в директории с именем вашего пользователя. Если такая директория существует — она будет добавлена к загрузочным путям и любые Emacs Lisp-файлы и файлы Org-mode с включенными кусками Emacs Lisp-кода будут загружены.
-
Если вам нужны разные настройки для разных машин — храните их в
файлах названых именем хоста с расширением
.el
или.org
.Чтобы узнать имя хоста выполните в консоли команду
hostname
-
Прежде чем браться за создание своей конфигурации я рекомендую вам
посмотреть секцию Customization в руководстве по GNU Emacs. Оно
доступно непосредственно в самом Emacs по команде
M-x info
и сочетанию С-h i.Прочтите секцию Key Binding Conventions руководства — это поможет вам избежать проблем при определении своих сочетаний клавиш.
Starter Kit идет с набором цветовых тем. Смотрите инструкции по установке тем в секции Цветовые темы.
-
Установка дополнительных библиотек. В Starter Kit включено много
полезных Emacs Lisp-библиотек, но, возможно, вам захочется
установить еще несколько. Предпочтите установку библиотек из
Emacs Lisp Package Archive, ELPA, установке из других мест — это
избавит вас от необходимости вручную поддерживать зависимости и
обновлять установленные библиотеки при появлении новых версий. В
недалеком светлом будущем все пакеты будут устанавливаться через
ELPA — он будет включен в 24-ую версию Emacs.
Для установки пакетов вызовите меню установки и удаления командой
M-x package-list-packages
. Используйте клавишу i для отметки и x для установки отмеченых пакетов. -
Если библиотека не доступна через ELPA вы можете поместить её
исходный код в директорию
src
. Любые находящиеся там пакеты будут автоматически добавлены к загрузочным путям при старте Emacs. -
Содействие. Если вы знаете толк в Emacs — попробуйте Starter Kit
в качестве замены вашим нынешним настройкам. И если есть нечто без
чего вы не можете жить — добавте это в Kit или дайте мне об этом
знать, чтобы я это добавил.
Приветствуется помощь в отправке новых библиотек в ELPA. Есть два способа: взять новые библиотеки, подготовить их к ELPA и забросить в директорию elpa-to-submit; или взять файлы из elpa-to-submit, и убедившись в корректности зависимостей, отправить их мэйнтеинеру ELPA. О том как это осуществить можно узнать на http://tromey.com/elpa/upload.html.
-
Распространение. Файлы идущие в комплекте Starter Kit
распространяются под теми же лицензиями что и Emacs, если не
указано противное. Смотрите детали в файле
COPYING
. -
Реалиция Emacs Starter Kit. Ниже следует Emacs Lisp-код, который
выполняется при каждом старте Emacs. Мы начинем с определения
загрузочных файлов и установки загрузочных путей.
(setq dotfiles-dir (file-name-directory (or load-file-name (buffer-file-name)))) (add-to-list 'load-path dotfiles-dir) (add-to-list 'load-path (concat dotfiles-dir "/elpa-to-submit")) (add-to-list 'load-path (concat dotfiles-dir "/elpa-to-submit/jabber")) (setq autoload-file (concat dotfiles-dir "loaddefs.el")) (setq package-user-dir (concat dotfiles-dir "elpa")) (setq custom-file (concat dotfiles-dir "custom.el"))
-
Повсеместно используемые пакеты загружаются при старте Emacs, а не
по требованию, т.к. они используются практически во всех сессиях.
(require 'cl) (require 'saveplace) (require 'ffap) (require 'uniquify) (require 'ansi-color) (require 'recentf)
-
Порт для совместимости с Emacs 22.
(unless (functionp 'locate-dominating-file) (defun locate-dominating-file (file name) "Look up the directory hierarchy from FILE for a file named NAME. Stop at the first parent directory containing a file NAME, and return the directory. Return nil if not found." ;; We used to use the above locate-dominating-files code, but the ;; directory-files call is very costly, so we're much better off doing ;; multiple calls using the code in here. ;; ;; Represent /home/luser/foo as ~/foo so that we don't try to look for ;; `name' in /home or in /. (setq file (abbreviate-file-name file)) (let ((root nil) (prev-file file) ;; `user' is not initialized outside the loop because ;; `file' may not exist, so we may have to walk up part of the ;; hierarchy before we find the "initial UID". (user nil) try) (while (not (or root (null file) ;; FIXME: Disabled this heuristic because it is sometimes ;; inappropriate. ;; As a heuristic, we stop looking up the hierarchy of ;; directories as soon as we find a directory belonging ;; to another user. This should save us from looking in ;; things like /net and /afs. This assumes that all the ;; files inside a project belong to the same user. ;; (let ((prev-user user)) ;; (setq user (nth 2 (file-attributes file))) ;; (and prev-user (not (equal user prev-user)))) (string-match locate-dominating-stop-dir-regexp file))) (setq try (file-exists-p (expand-file-name name file))) (cond (try (setq root file)) ((equal file (setq prev-file file file (file-name-directory (directory-file-name file)))) (setq file nil)))) root)) (defvar locate-dominating-stop-dir-regexp "\\`\\(?:[\\/][\\/][^\\/]+\\|/\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)\\'"))
-
Функция для загрузки файлов
starter-kit-*
. Нигде не используется — весь код Kit хранится в этом файле.(defun starter-kit-load (file) "This function is to be used to load starter-kit-*.org files." (org-babel-load-file (expand-file-name file dotfiles-dir)))
-
Менеджер пакетов ELPA. Загружаем пакетный менеджер.
(require 'package) (package-initialize)
-
Проверка доступа в Сеть. При работе в Windows функция
network-interface-list
недоступна, поэтому мы предполагаем что доступ в Сеть таки есть.(defun starter-kit-is-online? () (if (and (functionp 'network-interface-list) (network-interface-list)) (some (lambda (iface) (unless (equal "lo" (car iface)) (member 'up (first (last (network-interface-info (car iface))))))) (network-interface-list)) t))
-
Устанавливает из ELPA пакеты по списку. Это потребует сетевого
подключения. Во время выполнения этого кода вам, возможно,
придется несколько раз перезапустить Emacs из-за ошибок при
получении пакетов.
(defun starter-kit-install-packages-from-elpa (list-of-packages) (when (starter-kit-is-online?) (unless package-archive-contents (package-refresh-contents)) (dolist (package list-of-packages) (unless (or (member package package-activated-list) (functionp package)) (message "Installing %s" (symbol-name package)) (package-install package)))))
-
Перечисленные ниже пакеты будут автоматически получены и
установлены из ELPA при первом запуске Emacs. Можете использовать
этот код в своем конфигурационном файле для установки нужных вам
пакетов.
(starter-kit-install-packages-from-elpa '(idle-highlight ruby-mode inf-ruby js2-mode css-mode gist paredit yaml-mode find-file-in-project magit))
-
Обход трудновоспроизводимого бага ELPA.
(autoload 'paredit-mode "paredit" "" t) (autoload 'yaml-mode "yaml-mode" "" t)
-
Установка загрузочных путей и файлов. Обход бага Mac OS X в
котором имя системы является полным именем домена.
(when (eq system-type 'darwin) (setq system-name (car (split-string system-name "\\."))))
-
Определение файлов настроек, специфичных для пользователя и
машины. Вы можете держать соответствующие настройки в простых
emacs-lisp файлах и в файлах org-mode, таких как этот.
(setq system-specific-config (concat dotfiles-dir system-name ".el") system-specific-literate-config (concat dotfiles-dir system-name ".org") user-specific-config (concat dotfiles-dir user-login-name ".el") user-specific-literate-config (concat dotfiles-dir user-login-name ".org") user-specific-dir (concat dotfiles-dir user-login-name)) (add-to-list 'load-path user-specific-dir)
-
Пакеты emacs-lisp, загруженные из директории
src
замещают те, что установленны через ELPA. Это полезно если вы используете самые свежие версии пакетов или если их нет в ELPA.(setq elisp-source-dir (concat dotfiles-dir "src")) (add-to-list 'load-path elisp-source-dir)
-
Определения функций. Далее следуют определения часто
используемых в Starter Kit функций.
(require 'thingatpt) (require 'imenu)
-
Указываем URL и открываем новый буфер с содержанием оного.
(defun view-url () "Open a new buffer containing the contents of URL." (interactive) (let* ((default (thing-at-point-url-at-point)) (url (read-from-minibuffer "URL: " default))) (switch-to-buffer (url-retrieve-synchronously url)) (rename-buffer url t) (cond ((search-forward "<?xml" nil t) (xml-mode)) ((search-forward "<html" nil t) (html-mode)))))
-
Обновляет индекс imenu и затем использует ido для выбора и
перехода к символу. Символы которые совпадают с текстом под
курсором появляются в первых позициях в списке дополнения.
(defun ido-imenu () "Update the imenu index and then use ido to select a symbol to navigate to. Symbols matching the text at point are put first in the completion list." (interactive) (imenu--make-index-alist) (let ((name-and-pos '()) (symbol-names '())) (flet ((addsymbols (symbol-list) (when (listp symbol-list) (dolist (symbol symbol-list) (let ((name nil) (position nil)) (cond ((and (listp symbol) (imenu--subalist-p symbol)) (addsymbols symbol)) ((listp symbol) (setq name (car symbol)) (setq position (cdr symbol))) ((stringp symbol) (setq name symbol) (setq position (get-text-property 1 'org-imenu-marker symbol)))) (unless (or (null position) (null name)) (add-to-list 'symbol-names name) (add-to-list 'name-and-pos (cons name position)))))))) (addsymbols imenu--index-alist)) ;; If there are matching symbols at point, put them at the beginning of `symbol-names'. (let ((symbol-at-point (thing-at-point 'symbol))) (when symbol-at-point (let* ((regexp (concat (regexp-quote symbol-at-point) "$")) (matching-symbols (delq nil (mapcar (lambda (symbol) (if (string-match regexp symbol) symbol)) symbol-names)))) (when matching-symbols (sort matching-symbols (lambda (a b) (> (length a) (length b)))) (mapc (lambda (symbol) (setq symbol-names (cons symbol (delete symbol symbol-names)))) matching-symbols))))) (let* ((selected-symbol (ido-completing-read "Symbol? " symbol-names)) (position (cdr (assoc selected-symbol name-and-pos)))) (goto-char position))))
-
Есть несколько функций для включения разнообразных режимов при
открытии буферов с исходным кодом. Здесь мы определяем эти функции
и последовательно добавляем их в ловушку
coding-hook
; λ-функции не используются — у нас нет гарантии того что они уже не добавлены в ловушку.(defvar coding-hook nil "Hook that gets run on activation of any programming mode.")
(defun local-column-number-mode () (make-local-variable 'column-number-mode) (column-number-mode t)) (defun local-comment-auto-fill () (set (make-local-variable 'comment-auto-fill-only-comments) t) (auto-fill-mode t)) (defun turn-on-hl-line-mode () (if window-system (hl-line-mode t))) (defun turn-on-save-place-mode () (setq save-place t)) (defun turn-on-whitespace () (whitespace-mode t)) (defun turn-off-tool-bar () (tool-bar-mode -1)) (defun add-watchwords () (font-lock-add-keywords nil '(("\\<\\(FIX\\|TODO\\|FIXME\\|HACK\\|REFACTOR\\):" 1 font-lock-warning-face t))))
(add-hook 'coding-hook 'local-column-number-mode) (add-hook 'coding-hook 'local-comment-auto-fill) (add-hook 'coding-hook 'turn-on-hl-line-mode) (add-hook 'coding-hook 'turn-on-save-place-mode) (add-hook 'coding-hook 'pretty-lambdas) (add-hook 'coding-hook 'add-watchwords) (add-hook 'coding-hook 'idle-highlight)
-
Запуск ловушки
coding-hook
включает в буфере соответствующие режимы для удобной работы с исходным кодом.(defun run-coding-hook () "Enable things that are convenient across all coding buffers." (run-hooks 'coding-hook))
-
Заменяет отступы табами на отступы пробелами во всем буфере.
(defun untabify-buffer () (interactive) (untabify (point-min) (point-max)))
-
Автоматически расставляет отступы во всем буфере.
(defun indent-buffer () (interactive) (indent-region (point-min) (point-max)))
-
Приводит отступы во всем буфере в порядок.
(defun cleanup-buffer () "Perform a bunch of operations on the whitespace content of a buffer." (interactive) (indent-buffer) (untabify-buffer) (delete-trailing-whitespace))
-
Находит файлы которые редактировали в прошлый раз с помощью ido.
(defun recentf-ido-find-file () "Find a recent file using ido." (interactive) (let ((file (ido-completing-read "Choose recent file: " recentf-list nil t))) (when file (find-file file))))
-
Заменяет lambda на λ.
(defun pretty-lambdas () (font-lock-add-keywords nil `(("(?\\(lambda\\>\\)" (0 (progn (compose-region (match-beginning 1) (match-end 1) ,(make-char 'greek-iso8859-7 107)) nil))))))
-
Заменяет предыдущее символьное выражение лиспа на результат его
вычисления.
(defun eval-and-replace () "Replace the preceding sexp with its value." (interactive) (backward-kill-sexp) (condition-case nil (prin1 (eval (read (current-kill 0))) (current-buffer)) (error (message "Invalid expression") (insert (current-kill 0)))))
-
Перекомпилирует файлы инициализации.
(defun recompile-init () "Byte-compile all your dotfiles again." (interactive) (byte-recompile-directory dotfiles-dir 0) ;; TODO: remove elpa-to-submit once everything's submitted. (byte-recompile-directory (concat dotfiles-dir "elpa-to-submit/" 0)))
-
Регенерирует и загружает файл автозагрузки.
(defun regen-autoloads (&optional force-regen) "Regenerate the autoload definitions file if necessary and load it." (interactive "P") (let ((autoload-dir (concat dotfiles-dir "/elpa-to-submit")) (generated-autoload-file autoload-file)) (when (or force-regen (not (file-exists-p autoload-file)) (some (lambda (f) (file-newer-than-file-p f autoload-file)) (directory-files autoload-dir t "\\.el$"))) (message "Updating autoloads...") (let (emacs-lisp-mode-hook) (update-directory-autoloads autoload-dir)))) (load autoload-file))
-
Чрезвычайно полезная функция — используйте её если вам нужно
отредактировать системные файлы от имени суперпользователя.
(defun sudo-edit (&optional arg) (interactive "p") (if arg (find-file (concat "/sudo:root@localhost:" (ido-read-file-name "File: "))) (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name))))
-
Вставляет lorem ipsum.
(defun lorem () "Insert a lorem ipsum." (interactive) (insert "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim" "ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " "aliquip ex ea commodo consequat. Duis aute irure dolor in " "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " "culpa qui officia deserunt mollit anim id est laborum."))
-
Забуривает буфер, если если это текущий буфер, в противном случае
вызывает функцию.
(defun switch-or-start (function buffer) "If the buffer is current, bury it, otherwise invoke the function." (if (equal (buffer-name (current-buffer)) buffer) (bury-buffer) (if (get-buffer buffer) (switch-to-buffer buffer) (funcall function))))
-
Вставляет текущую дату.
(defun insert-date () "Insert a time-stamp according to locale's date and time format." (interactive) (insert (format-time-string "%c" (current-time))))
-
Шутка. Бот для эмуляции парного программирования.
(defun pairing-bot () "If you can't pair program with a human, use this instead." (interactive) (message (if (y-or-n-p "Do you have a test for that? ") "Good." "Bad!")))
-
Патч для игнорирования пробелов аннотацией.
(defun vc-git-annotate-command (file buf &optional rev) (let ((name (file-relative-name file))) (vc-git-command buf 0 name "blame" "-w" rev)))
-
Включает режим paredit для не-лиспов.
(defun esk-paredit-nonlisp () "Turn on paredit mode for non-lisps." (set (make-local-variable 'paredit-space-delimiter-chars) (list ?\")) (paredit-mode 1))
-
Показывает «текущую точку в буфере» в минибуфере.
(defun message-point () (interactive) (message "%s" (point)))
-
Распахивает окно Emacs на весь экран.
(defun toggle-fullscreen () (interactive) ;; TODO: this only works for X. patches welcome for other OSes. (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 '(2 "_NET_WM_STATE_MAXIMIZED_VERT" 0)) (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 '(2 "_NET_WM_STATE_MAXIMIZED_HORZ" 0)))
-
Сочетания клавиш. Многие оригинальные сочетания клавиш в Emacs
не отличаются особой эргономичностью и функциональностью. Эта
секция имеет своей целью исправление подобных недостатков.
Следует вспомнить, что Emacs — древнейшая ныне здравствующая и широко используемая программа, и оригинальные сочетания клавиш рассчитаны вовсе не на современные клавиатуры, а на клавиатуры почивших 20 лет назад лисп-машин (например, в мануале по Zmacs для Ti Explorer 1985 года можно найти те же самые комбинации, что используются сейчас). Следует вспомнить и принять меры, иначе незадачливый эмаксер рискует стать жертвой «синдрома эмаксового мизинца» — из-за активного использования клавиши Control, которую на современных клавиатурах жуть как неудобно нажимать несколько сотен раз в час. Есть несколько способов сохранить здоровье своих рук:
-
Самый простой: поменять Caps Lock и Control. Если вы не
обладатель Happy Hacking Keyboard — меняйте, даже не думайте. Я
пользуюсь GNOME — в нем поменять не проблема — ищите опцию в
параметрах клавиатуры; в случае простого оконного менеджера
настройте клавиатуру в файле
/etc/X11/xorg.conf
. - Купить нормальную эргономичную клавиатуру; такие выпускает Kinesis. Есть парочка хороших клавиатур у Microsoft.
-
Самый простой: поменять Caps Lock и Control. Если вы не
обладатель Happy Hacking Keyboard — меняйте, даже не думайте. Я
пользуюсь GNOME — в нем поменять не проблема — ищите опцию в
параметрах клавиатуры; в случае простого оконного менеджера
настройте клавиатуру в файле
-
C-w практически во всех эмуляторах терминалов удаляет слово
слева от курсора, в эмаксе же она не делает ничего хорошего. Здесь
она удаляет предыдущее слово или вырезает регион, если он
выделен — это очень удобно, Backspace становится практически не
нужен. Эта комбинация хорошо дополняет оригинальную M-w которая
копирует выделенный регион.
(defun backward-kill-word-or-kill-region (arg) (interactive "p") (if (region-active-p) (kill-region (region-beginning) (region-end)) (backward-kill-word arg)))
(global-set-key (kbd "C-w") 'backward-kill-word-or-kill-region) (define-key minibuffer-local-map (kbd "C-w") 'backward-kill-word-or-kill-region) (add-hook 'ido-setup-hook (lambda () (define-key ido-completion-map (kbd "C-w") 'ido-delete-backward-word-updir)))
-
C-q имеет смысл сделать клавишей отмены; таким образом ряд
стандартных сочетаний, который в других системах расположен
внизу — C-z, C-x, C-c переезжает наверх — C-q, C-w,
M-w. К тому же отмена используется гораздо чаще чем
quoted-insert
, который назначается на C-z.TODO: Если кто подскажет как совместить эту клавишу с C-g я буду очень благодарен.
(global-set-key (kbd "C-q") 'undo) (global-set-key (kbd "C-z") 'quoted-insert)
-
C-x C-m и C-c C-m заменяют M-x:
(global-set-key (kbd "C-x C-m") 'execute-extended-command) (global-set-key (kbd "C-с C-m") 'execute-extended-command)
-
C-x C-k убивает буфер. Гораздо легче это делать не отпуская
клавишу Control — так можно в разы быстрее убить сразу
несколько буферов.
(defun kill-current-buffer () (interactive) (kill-buffer (current-buffer)))
(global-set-key (kbd "C-x C-k") 'kill-current-buffer)
-
C-s и C-r привязаны к поиску по регэкспу вперёд и
назад. C-M-s и C-M-r ищут просто текст, без регекспов. Эти
клавиши используются не только для поиска в буфере, но и для
перехода к следующему или предыдущему элементу в минибуфере; а в
режиме ido — для переключения между буферами, для поиска и
открытия файла. И еще в режиме выделения региона.
(global-set-key (kbd "C-s") 'isearch-forward-regexp) (global-set-key (kbd "\C-r") 'isearch-backward-regexp) (global-set-key (kbd "C-M-s") 'isearch-forward) (global-set-key (kbd "C-M-r") 'isearch-backward)
- M-Space я рекомендую использовать для переключения между языками, но это может вызвать конфликт с сочетанием «показать меню окна» в среде GNOME.
-
S-Space и M-/ используются для умного автодополнения. Иногда
достаточно просто несколько раз нажать эту комбинацию и желаемый
текст чудесным образом напишется сам.
(global-set-key (kbd "M-/") 'hippie-expand) (global-set-key (kbd "S-SPC") 'dabbrev-expand)
- F3, F4, F4 — начало записи макроса, конец записи макроса, вызов макроса.
-
С-x \ выравнивает код с помощью регулярных выражений.
(global-set-key (kbd "C-x \\") 'align-regexp)
-
C-c n очищает буфер.
(global-set-key (kbd "C-c n") 'cleanup-buffer)
-
F1 включает и отключает меню. Полезно для исследования новых
режимов Emacs.
(global-set-key [f1] 'menu-bar-mode)
-
C–, C-+ и C-= уменьшают и увеличивают размер шрифта в
буфере.
(define-key global-map (kbd "C-+") 'text-scale-increase) (define-key global-map (kbd "C-=") 'text-scale-increase) (define-key global-map (kbd "C--") 'text-scale-decrease)
-
C-x C-i и C-x Tab позволяют перейти к определению символа в
буфере.
(global-set-key (kbd "C-x C-i") 'ido-imenu)
-
Сочетания для поиска файлов.
(global-set-key (kbd "C-x M-f") 'ido-find-file-other-window) (global-set-key (kbd "C-x C-M-f") 'find-file-in-project) (global-set-key (kbd "C-x f") 'recentf-ido-find-file) (global-set-key (kbd "C-x C-p") 'find-file-at-point) (global-set-key (kbd "C-c y") 'bury-buffer) (global-set-key (kbd "C-c r") 'revert-buffer) (global-set-key (kbd "M-`") 'file-cache-minibuffer-complete) (global-set-key (kbd "C-x C-b") 'ibuffer)
-
Shift со стрелками используется для перехода между окнами.
(windmove-default-keybindings)
-
C-x O и C-x C-o — переход к предыдущему и к слудующему окну.
(global-set-key (kbd "C-x O") (lambda () (interactive) (other-window -1))) (global-set-key (kbd "C-x C-o") (lambda () (interactive) (other-window 1)))
-
C-x ^ соединяет текущую строку с предыдущей.
(global-set-key (kbd "C-x ^") 'join-line)
-
C-x m запускает eshell или переключается в уже активный.
(global-set-key (kbd "C-x m") 'eshell)
-
C-x M запускает новый eshell.
(global-set-key (kbd "C-x M") (lambda () (interactive) (eshell t)))
-
C-x M-m запускает системный шелл.
(global-set-key (kbd "C-x M-m") 'shell)
-
C-x h — указать URL и просмотреть его содержимое в новом буфере,
см. view-url.
(global-set-key (kbd "C-x h") 'view-url)
-
C-h a вызывает apropos — глобальный поиск по файлам помощи.
(global-set-key (kbd "C-h a") 'apropos)
-
C-c e вычисляет выражение и заменяет его результатами вычисления.
(global-set-key (kbd "C-c e") 'eval-and-replace)
-
Управление Jabber'ом.
(global-set-key (kbd "C-c j") (lambda () (interactive) (switch-or-start 'jabber-connect "*-jabber-*"))) (global-set-key (kbd "C-c J") 'jabber-send-presence) (global-set-key (kbd "C-c M-j") 'jabber-disconnect)
-
Запуск IRC.
(global-set-key (kbd "C-c i") (lambda () (interactive) (switch-or-start (lambda () (rcirc-connect "irc.freenode.net")) "*irc.freenode.net*")))
-
C-c g запускает gnus.
(global-set-key (kbd "C-c g") (lambda () (interactive) (switch-or-start 'gnus "*Group*")))
-
C-x g запускает magit.
(global-set-key (kbd "C-x g") 'magit-status)
-
Небольшой хак для git add internally в VC.
(eval-after-load 'vc (define-key vc-prefix-map "i" '(lambda () (interactive) (if (not (eq 'Git (vc-backend buffer-file-name))) (vc-register) (shell-command (format "git add %s" buffer-file-name)) (message "Staged changes.")))))
-
C-o активирует occur во время поиска.
(define-key isearch-mode-map (kbd "C-o") (lambda () (interactive) (let ((case-fold-search isearch-case-fold-search)) (occur (if isearch-regexp isearch-string (regexp-quote isearch-string))))))
-
C-c a запускает Org-mode agenda.
(define-key global-map "\C-ca" 'org-agenda)
-
C-c l сохраняет ссылки для Org-mode, на будущее. Смотрите секцию
Handling-links в мануале Org-mode.
(define-key global-map "\C-cl" 'org-store-link)
-
C-x C-r запускает Rgrep, который необычайно полезен в
многофайловых проектах. См. <elisp:(describe-function 'rgrep)>.
(define-key global-map "\C-x\C-r" 'rgrep)
-
Цветовые темы. Пакет Цветовых тем дает возможность изменять,
сохранять и обмениваться цветовыми темами Emacs (color themes). Чтобы посмотреть на доступные темы и применить
понравившуюся используйте команду
M-x color-theme-select
. Дополнительную информацию ищите на страницах Emacs Wiki. -
Этот код загружает цветовые темы, тем самым делая их доступными
по-умолчанию.
(add-to-list 'load-path (expand-file-name "color-theme" (expand-file-name "src" dotfiles-dir))) (require 'color-theme) (eval-after-load "color-theme" '(progn (color-theme-initialize)))
-
Когда вы выберете полюбившуюся вам тему, добавте в файл со своими
настройками строку с именем вашей темы, например следующая строка
(color-theme-charcoal-black)
включит в эмаксе тему Charcoal Black при старте.
-
Графический интерфейс. Нет скроллбара, нет тулбара, нет меню,
нет диалоговых окон. Всего этого нет, ибо принесено в жертву
экономии движения. Графические элементы управления требуют мышь, а
чтобы дотянуться до мыши нужно оторвать руку от клавиатуры. В
случае меню еще потратить уйму времени на поиск нужного пункта. От
того, что эти элементы управления отключены — от пользователя не
убудет — функционал отключеных элементов продублирован в
интерфейсе. Во время редактирования если и используются меню, то
это меню текущих режимов, а они доступны в полоске
modeline. Скроллбар прекрасно заменяется стандартными клавишами
для перемещения по буферу и колёсиком мыши. Тулбар же просто не
нужен — выполнить любое действие проще через кейбиндинг.
Следующий код устанавливает заголовок фрейма и отключает элементы графического интерфейса, если оный присутствует.
(when window-system (setq frame-title-format '(buffer-file-name "%f" ("%b"))) (when (fboundp 'scroll-bar-mode) (scroll-bar-mode nil) (setq default-vertical-scroll-bar nil)) (when (fboundp 'tool-bar-mode) (tool-bar-mode nil)) (tooltip-mode nil) (blink-cursor-mode nil))
-
Установка заголовка фрейма.
(setq frame-title-format '(buffer-file-name "%f" ("%b")))
-
Отключенение элементов графического интерфейса: полосы прокрутки,
панели инструментов, графических подсказок и мерцания курсора.
(when (fboundp 'scroll-bar-mode) (scroll-bar-mode nil) (setq default-vertical-scroll-bar nil)) (when (fboundp 'tool-bar-mode) (tool-bar-mode nil)) (tooltip-mode nil) (blink-cursor-mode nil)
-
Отключение панели инструментов в новых фреймах.
(add-hook 'before-make-frame-hook 'turn-off-tool-bar)
-
Отключение меню.
(when (fboundp 'menu-bar-mode) (menu-bar-mode nil))
-
Мерцание по краям буфера при выполнении неправильной команды.
(setq visible-bell t)
-
Установка разного рода дополнительных настроек оконной системы и
буфера.
(setq echo-keystrokes 0.1 font-lock-maximum-decoration t inhibit-startup-message t transient-mark-mode t color-theme-is-global t delete-by-moving-to-trash t shift-select-mode nil mouse-yank-at-point t require-final-newline t truncate-partial-width-windows nil uniquify-buffer-name-style 'forward whitespace-style '(trailing lines space-before-tab indentation space-after-tab) whitespace-line-column 80 ediff-window-setup-function 'ediff-setup-windows-plain oddmuse-directory (concat dotfiles-dir "oddmuse") xterm-mouse-mode t save-place-file (concat dotfiles-dir "places")) (mouse-wheel-mode t) (add-to-list 'safe-local-variable-values '(lexical-binding . t)) (add-to-list 'safe-local-variable-values '(whitespace-line-column . 80)) (set-default 'indent-tabs-mode nil) (set-default 'indicate-empty-lines t) (set-default 'imenu-auto-rescan t) (add-hook 'text-mode-hook 'turn-on-auto-fill) (add-hook 'text-mode-hook 'turn-on-flyspell) (defalias 'yes-or-no-p 'y-or-n-p) (random t) ;; Seed the random-number generator
-
Работаем с системным буфером обмена в Emacs.
(setq x-select-enable-clipboard t)
-
UTF-8 используется повсеместно.
(set-terminal-coding-system 'utf-8) (set-keyboard-coding-system 'utf-8) (prefer-coding-system 'utf-8) (ansi-color-for-comint-mode-on)
-
Хиппи-дополнение порою черезчур хиппи.
(delete 'try-expand-line hippie-expand-try-functions-list) (delete 'try-expand-list hippie-expand-try-functions-list)
-
Браузер в котором открываются ссылки. Используйте в своих
настройках одну из следующих строчек кода.
(setq browse-url-browser-function 'browse-url-firefox) (setq browse-url-browser-function 'browse-default-macosx-browser) (setq browse-url-browser-function 'browse-default-windows-browser) (setq browse-url-browser-function 'browse-default-kde) (setq browse-url-browser-function 'browse-default-epiphany) (setq browse-url-browser-function 'browse-default-w3m) (setq browse-url-browser-function 'browse-url-generic browse-url-generic-program "~/src/conkeror/conkeror")
-
Компресированные файлы просто открываются.
(auto-compression-mode t)
-
Включить подсветку синтаксиса для старых эмаксов.
(global-font-lock-mode t)
-
Хранить список ранее посещенных файлов.
(recentf-mode 1)
-
Подсвечивать совпадающие скобочки.
(show-paren-mode 1)
-
Не мешать директории с файлами.
(setq backup-directory-alist `(("." . ,(expand-file-name (concat dotfiles-dir "backups")))))
-
Ассоциировать режимы с расширениями файлов.
(add-to-list 'auto-mode-alist '("COMMIT_EDITMSG$" . diff-mode)) (add-to-list 'auto-mode-alist '("\\.css$" . css-mode)) (require 'yaml-mode) (add-to-list 'auto-mode-alist '("\\.ya?ml$" . yaml-mode)) (add-to-list 'auto-mode-alist '("\\.rb$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode)) (add-to-list 'auto-mode-alist '("\\.js\\(on\\)?$" . js2-mode)) (add-to-list 'auto-mode-alist '("\\.xml$" . nxml-mode))
-
Grep игнорирует файлы при поиске.
(eval-after-load 'grep '(when (boundp 'grep-find-ignored-files) (add-to-list 'grep-find-ignored-files "target") (add-to-list 'grep-find-ignored-files "*.class")))
-
Обобщенные диффы (unified diffs) по-умолчанию.
(setq diff-switches "-u")
-
Немного косметики.
(set-face-background 'vertical-border "white") (set-face-foreground 'vertical-border "white") (eval-after-load 'diff-mode '(progn (set-face-foreground 'diff-added "green4") (set-face-foreground 'diff-removed "red3"))) (eval-after-load 'magit '(progn (set-face-foreground 'magit-diff-add "green3") (set-face-foreground 'magit-diff-del "red3"))) (eval-after-load 'mumamo '(eval-after-load 'zenburn '(ignore-errors (set-face-background 'mumamo-background-chunk-submode "gray22"))))
-
Обходим защиту от спама в Emacs Wiki.
(add-hook 'oddmuse-mode-hook (lambda () (unless (string-match "question" oddmuse-post) (setq oddmuse-post (concat "uihnscuskc=1;" oddmuse-post)))))
-
Ido. Интеллектуальное дополнение.
(when (> emacs-major-version 21) (ido-mode t) (setq ido-enable-prefix nil ido-enable-flex-matching t ido-create-new-buffer 'always ido-use-filename-at-point t ido-max-prospects 10))
-
Flyspell. Большая часть кода перекочевала сюда из
Emacs Wiki. Этот код не включается в конечный файл.
Устанавливаем путь к aspell, возможно, его нет в
$PATH
.(setq exec-path (append exec-path '("/opt/local/bin")))
Выбираем программу для проверки орфографии.
(setq ispell-program-name "aspell" ispell-dictionary "english" ispell-dictionary-alist (let ((default '("[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B" "-d" "english" "--dict-dir" "/Library/Application Support/cocoAspell/aspell6-en-6.0-0") nil iso-8859-1))) `((nil ,@default) ("english" ,@default))))
-
Nxhtml. Nxhtml это большой пакет утилит для веб-разработки и для
интеграции нескольких главных режимов Emacs в одном буфере.
В этой версии Starter Kit Nxhtml не установлен, информацию по установке ищите на EmacsWiki-Nxhtml.
(setq mumamo-chunk-coloring 'submode-colored nxhtml-skip-welcome t indent-region-mode t rng-nxml-auto-validate-flag nil)
-
Регистры дают вам возможность быстро прыгнуть к файлу или иной
локации. Используйте C-x r j с последующей буквой регистра (i
для файла
init.el
, s для этого файла) чтобы прыгнуть к нему.Используйте подобный код в своем конфигурационном файле — добавте регистры для тех файлов, которые вы редактируете чаще всего.
(dolist (r `((?i (file . ,(concat dotfiles-dir "init.el"))) (?s (file . ,(concat dotfiles-dir "starter-kit.org"))))) (set-register (car r) (cadr r)))
-
Org-mode. Org-Mode используется для хранения заметок, ведения
списков дел, планирования проектов, публикации в блог и вообще
для быстрой и удобной работы с чистым текстом. Org-mode можно
использовать для работы в качестве системы GTD или средства для
литературного программирования.
Чтобы узнать больше об Org-mode загляните на worg, большую вики по Org-mode сделаную с помощью самого Org-mode и git.
-
Загружаем библиотеку Babel; она содержит много полезных функций
которые могут быть использованы в блоках кода в любом
файле. Информацию о функциях вы найдете в самом файле библиотеки
library-of-babel.org, сведения по использованию ищите на
worg:library-of-babel.
(org-babel-lob-ingest (expand-file-name "library-of-babel.org" (expand-file-name "babel" (expand-file-name "contrib" (expand-file-name "org" (expand-file-name "src" dotfiles-dir))))))
-
Убедимся, что последняя версия мануала Org-mode доступна по
команде
info
(она привязана к сочетанию C-h i). Для этого сделаем директориюdoc/
, которая находится в пакете Org-mode, первым элементом спискаInfo-directory-list
.(unless (boundp 'Info-directory-list) (setq Info-directory-list Info-default-directory-list)) (setq Info-directory-list (cons (expand-file-name "doc" (expand-file-name "org" (expand-file-name "src" dotfiles-dir))) Info-directory-list))
-
Документация по Starter Kit. Этот код определяет проект
starter-kit-project
, он используется для публикации html-документации по Starter Kit.(unless (boundp 'org-publish-project-alist) (setq org-publish-project-alist nil)) (let ((this-dir (file-name-directory (or load-file-name buffer-file-name)))) (add-to-list 'org-publish-project-alist `("starter-kit-documentation" :base-directory ,this-dir :base-extension "org" :style "<link rel=\"stylesheet\" href=\"emacs.css\" type=\"text/css\"/>" :publishing-directory ,this-dir :index-filename "starter-kit.org" :auto-postamble nil)))
-
Eshell это хорошая командная оболочка. Дополнительную
информацию ищите в вики.
(setq eshell-cmpl-cycle-completions nil eshell-save-history-on-exit t eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\)/\\'") (eval-after-load 'esh-opt '(progn (require 'em-prompt) (require 'em-term) (require 'em-cmpl) (setenv "PAGER" "cat") (set-face-attribute 'eshell-prompt nil :foreground "turquoise1") (when (< emacs-major-version 23) (add-hook 'eshell-mode-hook ;; for some reason this needs to be a hook '(lambda () (define-key eshell-mode-map "\C-a" 'eshell-bol))) (add-to-list 'eshell-output-filter-functions 'eshell-handle-ansi-color)) ;; TODO: submit these via M-x report-emacs-bug (add-to-list 'eshell-visual-commands "ssh") (add-to-list 'eshell-visual-commands "tail") (add-to-list 'eshell-command-completions-alist '("gunzip" "gz\\'")) (add-to-list 'eshell-command-completions-alist '("tar" "\\(\\.tar|\\.tgz\\|\\.tar\\.gz\\)\\'")))) (defun eshell/cds () "Change directory to the project's root." (eshell/cd (locate-dominating-file default-directory "src"))) (defun eshell/find (dir &rest opts) (find-dired dir (mapconcat 'identity opts " ")))
-
В директории
eshell
хранятся определения alias и история. Она служит для тех же целей, что и файл.bashrc
(если вы знакомы с bash). Ниже устанавливаем значение переменнойeshell-directory-name
так что она указывает на директорию~/.emacs.d/eshell
, в которой уже есть файлalias
с парочкой полезных алиасов.(setq eshell-directory-name (expand-file-name "./" (expand-file-name "eshell" dotfiles-dir)))
-
Lisp. Поддержим диалекты Emacs Lisp, Scheme, Common Lisp и
Clojure хорошими настройками. Для начала несколько комбинаций
клавиш для всех диалектов.
Tab и C-\ автодополняют символы в лисп-программе.
(define-key read-expression-map (kbd "TAB") 'lisp-complete-symbol) (define-key lisp-mode-shared-map (kbd "C-\\") 'lisp-complete-symbol)
Enter работает как раньше и дополнительно автоматически расставляет отступы.
(define-key lisp-mode-shared-map (kbd "RET") 'reindent-then-newline-and-indent)
C-c v вычисляет весь буфер.
(define-key lisp-mode-shared-map (kbd "C-c v") 'eval-buffer)
C-c l вставляет слово lambda.
(define-key lisp-mode-shared-map (kbd "C-c l") "lambda")
-
Тусклые скобочки.
(defface esk-paren-face '((((class color) (background dark)) (:foreground "grey50")) (((class color) (background light)) (:foreground "grey55"))) "Face used to dim parentheses." :group 'starter-kit-faces)
-
Paredit это режим структурного редактирования лиспокода. Проще
говоря, он расставляет, переставляет и удаляет скобочки с учётом
семантики кода. Возможно, сразу его освоить не получиться, потому
как этот режим выполнен в лучших традициях эмакса с добрым
десятком зубодробительных комбинаций, но после длительного
использования и привыкания без него будет уже непросто.
Рекомендую освоить базовые комбинации клавиш — они доступны в справке, дополнительно смотрите в вики.
(defun turn-on-paredit () (paredit-mode +1)) (eval-after-load 'paredit ;; need a binding that works in the terminal '(define-key paredit-mode-map (kbd "M-)") 'paredit-forward-slurp-sexp))
-
Emacs Lisp. Включаем режим показа документации elisp-функций в
минибуфере, запускаем ловушку
coding-hook
для включения удобcтв при кодировании, включаем режим paredit.(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode) (add-hook 'emacs-lisp-mode-hook 'esk-remove-elc-on-save)
-
Удаляет откомпилированный
.elc
-файл при сохранении оригинального.el
-файла.(defun esk-remove-elc-on-save () "If you're saving an elisp file, likely the .elc is no longer valid." (make-local-variable 'after-save-hook) (add-hook 'after-save-hook (lambda () (if (file-exists-p (concat buffer-file-name "c")) (delete-file (concat buffer-file-name "c"))))))
-
M-. находит определение elisp-функции.
(define-key emacs-lisp-mode-map (kbd "M-.") 'find-function-at-point)
-
Clojure.
(eval-after-load 'find-file-in-project '(add-to-list 'ffip-patterns "*.clj"))
-
Команда
clojure-project
больше не используется.(defun clojure-project (path) (interactive) (message "Deprecated in favour of M-x swank-clojure-project. Install swank-clojure from ELPA."))
-
В исходниках Clojure
fn
заменяется наƒ
для красоты и экономии места.(eval-after-load 'clojure-mode '(font-lock-add-keywords 'clojure-mode `(("(\\(fn\\>\\)" (0 (progn (compose-region (match-beginning 1) (match-end 1) "ƒ") nil))))))
-
Во всех режимах лиспа включаются тусклые скобочки, режим
paredit и общие улучшения для кодирования.
(dolist (x '(scheme emacs-lisp lisp clojure)) (when window-system (font-lock-add-keywords (intern (concat (symbol-name x) "-mode")) '(("(\\|)" . 'esk-paren-face)))) (add-hook (intern (concat (symbol-name x) "-mode-hook")) 'turn-on-paredit) (add-hook (intern (concat (symbol-name x) "-mode-hook")) 'run-coding-hook))
-
Haskell. Красивые λ в Haskell-коде.
(defun pretty-lambdas-haskell () (font-lock-add-keywords nil `((,(concat "(?\\(" (regexp-quote "\\") "\\)") (0 (progn (compose-region (match-beginning 1) (match-end 1) ,(make-char 'greek-iso8859-7 107)) nil))))))
-
Все эти прелести включаются при включении режима Haskell с
помощью ловушки
haskell-mode-hook
.(add-hook 'haskell-mode-hook 'run-coding-hook) (add-hook 'haskell-mode-hook 'pretty-lambdas-haskell)
-
Ruby. Ниже идет код в поддержку Ruby — динамического языка с
открытым исходным кодом.
(eval-after-load 'ruby-mode '(progn ;; work around possible elpa bug (ignore-errors (require 'ruby-compilation)) (setq ruby-use-encoding-map nil) (add-hook 'ruby-mode-hook 'inf-ruby-keys) (define-key ruby-mode-map (kbd "RET") 'reindent-then-newline-and-indent) (define-key ruby-mode-map (kbd "C-c l") "lambda")))
(global-set-key (kbd "C-h r") 'ri)
-
И gamespec и rake-файлы — это всё Ruby, включаем для них
соответствующий режим.
(add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode)) (add-to-list 'auto-mode-alist '("\\.gemspec$" . ruby-mode)) (add-to-list 'auto-mode-alist '("\\.ru$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Rakefile$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Gemfile$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Capfile$" . ruby-mode)) (add-to-list 'auto-mode-alist '("Vagrantfile$" . ruby-mode))
-
Мы не хотим редактировать рубиновый байткод.
(add-to-list 'completion-ignored-extensions ".rbc")
-
Rake.
(defun pcomplete/rake () "Completion rules for the `ssh' command." (pcomplete-here (pcmpl-rake-tasks))) (defun pcmpl-rake-tasks () "Return a list of all the rake tasks defined in the current projects. I know this is a hack to put all the logic in the exec-to-string command, but it works and seems fast" (delq nil (mapcar '(lambda(line) (if (string-match "rake \\([^ ]+\\)" line) (match-string 1 line))) (split-string (shell-command-to-string "rake -T") "[\n]")))) (defun rake (task) (interactive (list (completing-read "Rake (default: default): " (pcmpl-rake-tasks)))) (shell-command-to-string (concat "rake " (if (= 0 (length task)) "default" task))))
-
Очищаем буфер с результатами компиляции после каждого тестового
запуска.
(eval-after-load 'ruby-compilation '(progn (defadvice ruby-do-run-w/compilation (before kill-buffer (name cmdlist)) (let ((comp-buffer-name (format "*%s*" name))) (when (get-buffer comp-buffer-name) (with-current-buffer comp-buffer-name (delete-region (point-min) (point-max)))))) (ad-activate 'ruby-do-run-w/compilation)))
-
Ловушки.
(add-hook 'ruby-mode-hook 'run-coding-hook)
-
Flymake. Проверка синтаксиса в режиме Ruby.
(defun flymake-ruby-init () (let* ((temp-file (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace)) (local-file (file-relative-name temp-file (file-name-directory buffer-file-name)))) ;; Invoke ruby with '-c' to get syntax checking (list "ruby" (list "-c" local-file)))) (defun flymake-ruby-enable () (when (and buffer-file-name (file-writable-p (file-name-directory buffer-file-name)) (file-writable-p buffer-file-name) (if (fboundp 'tramp-list-remote-buffers) (not (subsetp (list (current-buffer)) (tramp-list-remote-buffers))) t)) (local-set-key (kbd "C-c d") 'flymake-display-err-menu-for-current-line) (flymake-mode t))) (eval-after-load 'ruby-mode '(progn (require 'flymake) (push '(".+\\.rb$" flymake-ruby-init) flymake-allowed-file-name-masks) (push '("Rakefile$" flymake-ruby-init) flymake-allowed-file-name-masks) (push '("^\\(.*\\):\\([0-9]+\\): \\(.*\\)$" 1 2 nil 3) flymake-err-line-patterns) (add-hook 'ruby-mode-hook 'flymake-ruby-enable)))
-
Rinari — минорный режим для Ruby On Rails. Ищите на
rinari.rubyforge дополнительную информацию о rinari.
(setq rinari-major-modes (list 'mumamo-after-change-major-mode-hook 'dired-mode-hook 'ruby-mode-hook 'css-mode-hook 'yaml-mode-hook 'javascript-mode-hook))
-
JavaScript.
(autoload 'espresso-mode "espresso" "Start espresso-mode" t) (add-to-list 'auto-mode-alist '("\\.js$" . espresso-mode)) (add-to-list 'auto-mode-alist '("\\.json$" . espresso-mode)) (add-hook 'espresso-mode-hook 'moz-minor-mode) (add-hook 'espresso-mode-hook 'esk-paredit-nonlisp) (add-hook 'espresso-mode-hook 'run-coding-hook) (setq espresso-indent-level 2) ;; If you prefer js2-mode, use this instead: ;; (add-to-list 'auto-mode-alist '("\\.js$" . espresso-mode)) (eval-after-load 'espresso '(progn (define-key espresso-mode-map "{" 'paredit-open-curly) (define-key espresso-mode-map "}" 'paredit-close-curly-and-newline) ;; fixes problem with pretty function font-lock (define-key espresso-mode-map (kbd ",") 'self-insert-command) (font-lock-add-keywords 'espresso-mode `(("\\(function *\\)(" (0 (progn (compose-region (match-beginning 1) (match-end 1) "ƒ") nil)))))))
-
Perl.
(eval-after-load 'cperl-mode '(progn (define-key cperl-mode-map (kbd "RET") 'reindent-then-newline-and-indent))) (global-set-key (kbd "C-h P") 'perldoc) (add-to-list 'auto-mode-alist '("\\.p[lm]$" . cperl-mode)) (add-to-list 'auto-mode-alist '("\\.pod$" . pod-mode)) (add-to-list 'auto-mode-alist '("\\.tt$" . tt-mode))
-
Регенерация автозагрузочных файлов.
(regen-autoloads)
-
По-умолчанию загружается пользовательский файл
custom.el
, его нет в комплекте Kit'a.(load custom-file 'noerror)
-
Загрузка настроек конкретного пользователя и машины. После того
как мы загрузили все настройки Starter Kit, мы можем загрузить
настройки конкретного пользователя и конкретной машины.
(if (file-exists-p elisp-source-dir) (let ((default-directory elisp-source-dir)) (normal-top-level-add-subdirs-to-load-path))) (if (file-exists-p system-specific-config) (load system-specific-config)) (if (file-exists-p system-specific-literate-config) (org-babel-load-file system-specific-literate-config)) (if (file-exists-p user-specific-config) (load user-specific-config)) (if (file-exists-p user-specific-literate-config) (org-babel-load-file user-specific-literate-config)) (when (file-exists-p user-specific-dir) (let ((default-directory user-specific-dir)) (mapc #'load (directory-files user-specific-dir nil ".*el$")) (mapc #'org-babel-load-file (directory-files user-specific-dir nil ".*org$"))))