Я хочу индексировать файлы clojure, используя etags, чтобы я мог использовать функциональные возможности тегов Emacs. Но etags не распознает функции clojure. возможно ли расширить etags, чтобы включить определения clojure?
Clojure Emacs etags
Ответ 1
На основе http://nakkaya.com/2009/12/13/getting-etags-to-index-clojure-files/
следующая команда находится в одной строке
find . \! -name '.*' -name '*.clj' | xargs etags --regex='/[ \t\(]*def[a-z]* \([a-z-!]+\)/\1/' --regex='/[ \t\(]*ns \([a-z.]+\)/\1/'
Ответ 2
Посмотрев на источник, кажется, что вам просто нужно запустить etags
с помощью флага --language=lisp
, так как распознаватель Lisp ищет строку "def".
Если это не сработает, вам придется изменить etags
, чтобы он мог распознать Clojure и создать для него файл тегов. Вот источник etags
в htmlized форме. Не похоже, что это будет трудная или долгая работа. Ниже приведены правила распознавания Python в качестве примера:
/*
* Python support
* Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
* Idea by Eric S. Raymond <[email protected]> (1997)
* More ideas by seb bacon <[email protected]> (2002)
*/
static void
Python_functions (inf)
FILE *inf;
{
register char *cp;
LOOP_ON_INPUT_LINES (inf, lb, cp)
{
cp = skip_spaces (cp);
if (LOOKING_AT (cp, "def") || LOOKING_AT (cp, "class"))
{
char *name = cp;
while (!notinname (*cp) && *cp != ':')
cp++;
make_tag (name, cp - name, TRUE,
lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
}
}
}
Поддержка Lisp немного задействована:
/*
* Lisp tag functions
* look for (def or (DEF, quote or QUOTE
*/
static void L_getit __P((void));
static void
L_getit ()
{
if (*dbp == '\'') /* Skip prefix quote */
dbp++;
else if (*dbp == '(')
{
dbp++;
/* Try to skip "(quote " */
if (!LOOKING_AT (dbp, "quote") && !LOOKING_AT (dbp, "QUOTE"))
/* Ok, then skip "(" before name in (defstruct (foo)) */
dbp = skip_spaces (dbp);
}
get_tag (dbp, NULL);
}
static void
Lisp_functions (inf)
FILE *inf;
{
LOOP_ON_INPUT_LINES (inf, lb, dbp)
{
if (dbp[0] != '(')
continue;
if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
{
dbp = skip_non_spaces (dbp);
dbp = skip_spaces (dbp);
L_getit ();
}
else
{
/* Check for (foo::defmumble name-defined ... */
do
dbp++;
while (!notinname (*dbp) && *dbp != ':');
if (*dbp == ':')
{
do
dbp++;
while (*dbp == ':');
if (strneq (dbp, "def", 3) || strneq (dbp, "DEF", 3))
{
dbp = skip_non_spaces (dbp);
dbp = skip_spaces (dbp);
L_getit ();
}
}
}
}
}
Ответ 3
Чтобы улучшить ответ miner49:
У меня это в моих .emacs(обратите внимание на небольшое изменение в регулярном выражении, ctags орал имея "-" в середине регулярного выражения, когда он не используется для указания диапазона)
; Recursively generate tags for all *.clj files,
; creating tags for def* and namespaces
(defun create-clj-tags (dir-name)
"Create tags file."
(interactive "Directory: ")
(shell-command
(format "%s --langdef=Clojure --langmap=Clojure:.clj --regex-Clojure='/[ \t\(]*def[a-z]* \([a-z!-]+\)/\1/' --regex-Clojure='/[ \t\(]*ns \([a-z.]+\)/\1/' -f %s/TAGS -e -R %s" path-to-ctags dir-name (directory-file-name dir-name)))
)
Еще одно препятствие заключалось в том, что на моей коробке слизь переопределяет М-. использовать его собственную функцию поиска, а не find-tag, и эта функция не работает должным образом. e его собственная функция поиска, а не find-tag, и эта функция не работает должным образом. вы можете вызвать find-tag seperatley для поиска тегов из файла TAG, но встроенная функция переходит к источнику встроенных функций при подключении к серверу slime/swank, что довольно аккуратно. мои навыки elisp не смогли укрепить их. slime ожидает, что find-tag вернет nil, если это не удастся, что, похоже, не произойдет, поэтому следующие
(add-hook 'slime-edit-definition-hooks 'find-tag)
возвращает запросы на основе TAGS, но уничтожает поиски swank-сервера.
Ответ 4
@miller49r ответить wan действительно приятно. Я немного изменил его, чтобы распознать метаданные и некоторые более приемлемые символы символа clojure:
find . \! -name '.*' -name '*.clj' \
| xargs etags \
--regex='/[ \t\(]*def[a-zA-Z!$%&*+\-.\/:<=>[email protected]^_~]*[ \n\t]+\(\^{[^}]*}[ \n\t]+\|\)\([a-zA-Z!$%&*+\-.\/:<=>[email protected]^_~]+\)/\2/s' \
--regex='/[ \t\(]*ns \([a-z.]+\)/\1/'