Я буду писать большей частью про Emacs, потому что пользуюсь им, но буду давать ссылки на соответствующие плагины для Vim. Главное донести принцип работы и основные возможности инструментов и отговорить вас от неумеренного использования ack, ag и grep.
Ctags и Gnu global работают примерно одинаково — вы скармливаете им папку с исходниками проекта, и в ней появляются файлы индексов под названием tags, TAGS, GTAGS. В этих файлах хранятся все найденные в проекте символы: классы, методы, функции, переменные и т.п. и их позиции в файле исходного кода. Т.е. компактная информация достаточная для того, чтобы ввести в редакторе имя класса и перескочить в место его объявления. Или получить список файлов, где объявлен класс с таким именем.
Ctags
Ctags — это утилита, которая каждый раз сканирует все файлы проекты, не разбирая менялись они или нет. Для проектов в несколько тысяч файлов работает довольно шустро — до 10 секунд. Можно создавать отдельные файлы индексов для библиотек и для проекта, или для библиотек, бэкенда и фронтенда, и обновлять только тот индекс, который нужно.
Emacs использует файлы индексов Ctags одного формата, а вот Vim и Sublime Text Editor — другой. Поэтому если вы будете генерировать индексы для последующего использования в Emacs, то не забудьте добавить опцию
-e
.Эта утилита довольно старая, и бывает двух… нет даже трех видов. Они мало различаются по сути, но сильно различаются по качеству вычленения символов. Самый примитивный из них — ctags идущий в комплекте с Emacs, так называемый etags. Его стоит использовать если больше ничего нет — поддерживает много языков, но мне понравилась только поддержка perl, C, Java. Команда называется
etags
или ctags
.Второй вариант — это exuberrant ctags. Та версия, которая поддерживается вашим дистрибутивом, и будет поддерживать еще пару лет, устаревшая. Но она гораздо лучше поддерживает парсинг PHP и JS. Команда называется
ctags-exuberant
.Самый совершенный вариант — universal ctags. Данная версия поддерживает внешние парсеры типа coffeetags и вообще имеет самые лучшие парсеры для других языков. Желательно использовать именно эту утилиту, пусть и собирать ее придется вручную.
Итак вы определились какую версию будете использовать, а значит можете перейти в папку с проектом и запустить в терминале:
ctags -e
— если вы используете Emacs, или же просто ctags
, если речь идет о другом редакторе.Использование в Emacs
M-x
visit-tags-table и выбираете файл TAGS. Дальше наводите курсор на имя метода и нажимаете M-.
, затем Enter. Если понимаете, что вы перескочили не на тот символ, то нажимаете C-u M-.
— таким образом вы перейдете к следующему определению этого символа, но уже в другом файле. Советую установить helm
для удобного выбора из списка тэгов, правда удобным он станет только после того как вы привыкнете к helm
во всех остальных местах Emacs...Если вы пользуетесь Emacs и пишите на PHP, то загляните сюда.
Использование в Vim
- Статья про Vim и Ctags на хабре
- Хорошая подробная статья про Vim и ctags
- Плагин для Vim делающий автообновление тэгов и их привязку к проекту
Gnu Global
Gnu Global был создан для работы с кодовыми базами проектов размером в несколько гигабайт в то время, когда IDE требующих нескольких гигабайт для работы еще не изобрели. Он работает примерно как и ctags, более того, он даже может использовать ctags в качестве бэкенда для парсинга — это очень удобно, потому что нативным образом Gnu Global поддерживает не так много языков. Однако есть одно важное отличие — Gnu Global не предполагает, что ваш редактор будет загружать файл индексов, а использует для поиска символов специальную утилиту
global
, которую редактор вызывает при поиске символа.Также файл индексов оптимизирован таким образом, чтобы его можно было дополнять не переписывая с нуля. Благодаря этому если в проекте поменялся один файл, то парсингу будет подвергнут только он, а не весь проект, что драматически сказывается на скорости обновления. Это удобно, если у вас кода на сотни мегабайт, вы постоянно переключаете ветки или тянете последние изменения.
Для создания файла индексов перейдите в папку проекта и вызовите
gtags
. Ждите… Но вообще скорость хорошая — исходники JIdea Community Edition, а это порядка 150 мб чистого Java-кода, индексируются меньше чем за минуту. Последующие индексирования следует запускать при помощи gtags -i
, чтобы индексировались только изменившиеся файлы.Использование в Emacs
Лучше всего установить плагин
ggtags
, взять его можно здесь или в elpa, melpa или marmalade. Потом откройте один из файлов проекта и нажмите M-x ggtags-mode
, затем M-x ggtags-visit-project-root
и выберите папку где тэги лежат. Все, дальше в рамках файлов проекта если вы нажмете M-.
, то сработает переход к определению символа, который в данный момент под курсором. Хотите ввести имя символа вручную — C-u M-.
. Если у символа больше одного определения, то нажимайте M-n
и M-p
для переключения между определениями. Чтобы обновить файл тэгов нажмите M-x ggtags-update-tags
находясь на одном из файлов проекта.Несмотря на то что ggtags и progectile оба покушаются на работу с проектами и индексацию оных, они не конфликтуют.
Использование в Vim
- Туториал для Vim на сайте самого Gnu Global
- Плагин для базовой поддержки Gnu global в Vim
- Более сложный плагин, работает как часть unite.vim
Приятного скакания по файлам.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (19)
maydjin
28.08.2015 20:33Как мне кажется, будущее сей области за server side code model. Если кто-то смотрел сорцы QtCreator — он меня поймёт.
Это сильно масштабируемей, может быть разделяемо, и тратит только дешёвые ресурсы (диск и память), притом, может тратить их совершенно на другой, физической машине.
Один из пророков сего подхода — rtags.
ali_aliev
29.08.2015 04:53+1Для навигации по файлу в vim-е использую ctags + fzf + ag. Без дополнительных плагинов.
Вот как это выглядит у меняigrishaev
29.08.2015 20:29Обычно хватает ctags, только надо вешать хуки на гит, иначе теги устаревают.
Спасибо за global, буду пробовать.
n0dwis
01.09.2015 20:57Скажите, а как можно настроить индексацию с помощью ctags по emacs? Для моего проекта файл TAGS получается порядка 150Мб, но туда попадает всё — сжатые js файлы того же jquery, кеши symfony, библиотеки, установленные с помощью composer-а и т.п.
В документации есть что-то насчёт projectile-globally-ignored-files/projectile-globally-ignored-directories в .dir-locals.el, но, кажется, они никакого влияния на индексацию не оказывают.PerlPower
01.09.2015 21:36Исключать файлы по шаблону можно при помощи опции --exclude. Но как передать ее в projectile не скажу, сам использую Makefile в корне проекта, где есть цель для генерации тэгов.
PerlPower
01.09.2015 21:47projectile-ignored-directories — правильная переменная, но убедитесь, что она правда выставляется через .dir-locals.el, и что она имеет верный формат, и что директории, которые вы туда засовываете имеют верный *относительный* путь относительно корня проекта.
n0dwis
02.09.2015 14:41projectile-ignored-directories — такого не нашел.
А вот так получилось
((nil . ((projectile-globally-ignored-directories . ("app/cache" ".idea" "vendor" "bin" ".git")))))
CONSTantius
Спасибо за статью.
С разными тегами самая назойливая для меня проблема — это когда один и тот же символ определён в очень большом числе мест. Поскольку я занимаюсь системным программированием на Си, и часто работаю с кастомными тулчейнами, у нас много где определены всякие вещи типа memcpy. exuberant-ctags в таком случае предлагает просто первое попавшееся определение и перебирать их (даже пусть с помощью helm) не хочется.
А как с этим у Global? Пытается ли там индекс учитывать то, откуда какие определение видны?
PerlPower
Не знаю, но я столкнулся с этой проблемой в PHP — написал свой кастомный генератор тэгов на базе ctags, чтобы он к имени тэга добавлял пространство имен в котором тэг расположен. habrahabr.ru/post/182252
Delphinum
Насколько я знаю, ни та, ни другая этим не занимается, оставляя ответственность на редакторе. Так, расширенный ctags формат позволяет хранить инфу об отношениях, на пример принадлежность метода определенному классу. Редактору остается разобраться в этих отношениях и отфильтровать ненужные результаты. К сожалению, сделать это очень не просто, так как сам редактор не знает, к кому относится метод под указателем. Замкнутый круг.
lorc
Почему в статье ничего не сказано про cscope? Он как раз решает именно эту проблему:
PerlPower
А как у нее с языками отличными от С?
lorc
частично поддежривается C++ и Java
PerlPower
Ну вот я тоже не нашел широкой поддержки языков, поэтому решил не писать. А ctags и gnu global универсальные вещи. Кстати вы пробовали helm-cscope?
CONSTantius
Спасибо что напомнили, я кажется видел что csope можно использовать в качестве бэкенда для global.