Clojure Emacs etags

时间:2009-09-26 18:27:24

标签: emacs clojure

我想使用etags索引clojure文件,以便我可以使用Emacs的标记功能。 但是etags不承认clojure功能。是否可以扩展etags以包含clojure定义?

4 个答案:

答案 0 :(得分:8)

基于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/'

答案 1 :(得分:6)

查看源代码,您似乎只需使用etags标志运行--language=lisp,因为Lisp识别器会查找字符串'def'。

如果这不起作用,则必须修改etags,以便它可以识别Clojure并为其生成标记文件。 Here is the source of etags in htmlized form。它看起来不像那么困难或者长期工作。以下是以识别Python为例的规则:

/*
* Python support
* Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
* Idea by Eric S. Raymond <esr@thyrsus.com> (1997)
* More ideas by seb bacon <seb@jamkit.com> (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 ();
                }
            }
        }
    }
}

答案 2 :(得分:5)

改进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)))
 )

另一个障碍是我的盒子粘液覆盖了M-。使用它自己的查找函数而不是find-tag,并且该函数无法正常工作。它是自己的查找函数而不是find-tag,并且该函数无法正常工作。你可以调用find-tag seperatley 从TAG文件中查找标签,但内置函数在连接到slime / swank服务器时跳转到内置函数的源,这非常简洁。 我的elisp技能未能巩固这两个。 slime希望find-tag返回nil如果失败似乎不会发生,所以下面的

(add-hook 'slime-edit-definition-hooks 'find-tag)

带回基于TAGS的搜索,但会破坏swank-server搜索。

答案 3 :(得分:2)

@miller49r的答案非常好。我修改了一下以识别元数据和一些更可接受的clojure符号字符:

find . \! -name '.*' -name '*.clj' \
    | xargs etags \
    --regex='/[ \t\(]*def[a-zA-Z!$%&*+\-.\/:<=>?@^_~]*[ \n\t]+\(\^{[^}]*}[ \n\t]+\|\)\([a-zA-Z!$%&*+\-.\/:<=>?@^_~]+\)/\2/s' \
    --regex='/[ \t\(]*ns \([a-z.]+\)/\1/'