【问题标题】:Clojure Emacs etagsClojure Emacs 电子标签
【发布时间】:2010-12-01 16:43:22
【问题描述】:

我想索引 clojure 文件,使用 etags 以便我可以使用 Emacs 的标签功能。 但是 etags 不识别 clojure 函数。是否可以扩展 etags 以包含 clojure 定义?

【问题讨论】:

    标签: emacs clojure


    【解决方案1】:

    @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/'
    

    【讨论】:

      【解决方案2】:

      改进 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-。使用它自己的查找功能而不是查找标签,并且该功能无法正常工作。 e 它是自己的查找功能而不是查找标签,并且该功能无法正常工作。你可以调用 find-tag seperatley 从 TAG 文件中查找标签,但是当连接到 slime/swank 服务器时,内置函数会跳转到内置函数的源,这非常简洁。 我的 elisp 技能未能巩固这两者。 slime 期望 find-tag 在失败时返回 nil 似乎没有发生,所以以下

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

          查看源代码,您似乎只需要使用 --language=lisp 标志运行 etags,因为 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 ();
                          }
                      }
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-24
            • 2020-01-21
            • 2017-07-31
            相关资源
            最近更新 更多