EDIT: на дворе 2019 год и я давным-давно пользуюсь projectile, чего и вам советую. :)
У Емакса какое-то подобие проектов из коробки появилось только в 23 версии, и то
очень простое - только переменные директорий (directory variables, что-то типа
file variables, только хранящиеся в отдельном файле - .dir-locals.el
). По
большей части потому, что über-решения нету, и разным людям нравятся разные
решения. Вот я и решил вкратце рассказать о том, что нравится мне.
Пару лет назад я прочитал статью в каком-то блоге об одном из подобных решений и
попробовал его использовать. Как-то это решение (это был eproject
, что ли) не
прижилось и я пошëл искать альтернативы. Перепробовав какое-то количество, я
взял project-root
, прикрутив к нему несколько понравившихся фич от других
проектов. Теперь можно сказать, что мне действительно удобно - использую эту
штуку уже больше года и доволен. :)
Вся идея заключается в том, что вручную указывать путь к проекту (как это
сделано в большинстве - если не всех - IDE) - не очень удобно. У большинства
проектов есть какой-то характерный файл (или набор файлов) в корне. К примеру,
manage.py
у джанговых проектов, или директория .hg
у проекта, который лежит
в репозитории меркуриала. В результате можно определять проект по наличию таких
файлов; моя текущая конфигурация выглядит примерно таким образом:
(setq project-roots
`(("Django project"
:root-contains-files ("manage.py")
:filename-regex ,(regexify-ext-list '(py html css js sh))
:exclude-paths '("contrib"))
("Sphinx documentation"
:root-contains-files ("Makefile" "conf.py")
:filename-regex ,(regexify-ext-list '(py rst))
:exclude-paths '("_build"))
("Python project with buildout"
:root-contains-files ("../../buildout.cfg")
:filename-regex ,(regexify-ext-list '(py)))
("Generic Python project"
:root-contains-files ("setup.py")
:filename-regex ,(regexify-ext-list '(py)))
("Generic Mercurial project"
:root-contains-files (".hg"))
("Generic git project"
:root-contains-files (".git"))))
Интересно посмотреть на определение проекта с билдаутом - из-за того, что обычно расположение директорий там выглядит как
proj/
buildout.cfg
src/
proj/
то приходится так извращаться, чтоб лишние файлы не попадали. :) Кроме того, легко видно, что можно задать директории, которые нужно игнорировать и регулярное выражение для файлов, которые хочется найти. :)
Что это даëт? Это даëт возможность project-root
‘у определить, что он находится
в проекте, и включает работу клëвого макроса with-project-root
. В принципе он
практически ничем не занимается, кроме как изменением текущей директории на
корень проекта - но этого хватает, чтоб заработали предопределëнные команды,
которые я повесил на кнопки вот так:
(global-set-key (kbd "C-c p f") 'project-root-find-file)
(global-set-key (kbd "C-c p g") 'project-root-grep)
(global-set-key (kbd "C-c p a") 'project-root-ack)
(global-set-key (kbd "C-c p d") 'project-root-goto-root)
(global-set-key (kbd "C-c p l") 'project-root-browse-seen-projects)
Наиболее часто используемая из них - find-file
, которая показывает в
минибуфере список файлов (в виде file\parentdir\parentdir
- обратный путь к
корню проекта), давая выбрать один из них с помощью ido-mode - т.е. вся
вкуснотища типа flex matching’а работает1. :)
Отступлю от темы и вкратце расскажу, что такое ido. Это такой клëвый пакет в
емаксе, который позволяет сильно облегчить работу в минибуфере своим
автодополнением и удобным переходом между соседними значениями (он показывает
сразу все возможные значения одновременно - и это удобно). Я его использую
вместо обычного открытия файла, для перехода между буферами, и вот с той же
целью он используется в project-root
.
Не думаю, что нужно описывать grep
или ack
, которые просто запускают
соответствующую программу от корня проекта - результаты запуска, как обычно,
показываются в буфере со ссылками на найденные значения (так что можно легко
перейти к нужному файлу/строке). goto-root
тоже не делает ничего особенного,
просто открывает dired
в корне проекта.
А вот browse-seen-projects
- очень интересная штука. Дело в том, что
project-root-find-file
при первом открытия проекта добавляет его в список
проектов в файле ~/.emacs.d/.project-roots
и сохраняет этот файл. А
browse-seen-projects
создаëт новый буфер в режиме org-mode
и добавляет туда
все проекты - в виде ссылок на их директории, конечно. ;) Так что можно довольно
быстро и удобно прыгнуть к нужному проекту.
В основном функциональность этого кусочка кода я описал, еще информацию можно почерпнуть на страничке project-root’a и в его исходниках. Естественно, что до идеального состояния его можно точить и точить, так что патчи - велкам. :)
-
надо только не забыть установить
ido-enable-flex-matching
вt
. ↩︎