用ctags索引Android资源定义的.xml和.png文件

看着Android的那一堆资源定义文件,真是头疼啊,只能一点一点的grep,有点不 便呢。

今日突发奇想,能不能把它当成一种编程语言,用编程语言索引之王—— ctags-exuberant来处理它呢?试试看!

先打开man手册看一眼?不用了,我以前搞过linux kernel kconfig脚本的ctags 处理,这回打开 $HOME/.ctags 复习一下先:

--langdef=kconfig
--langmap=kconfig:(Kconfig)
--regex-kconfig=/^(menu)?config[ \t]*([a-zA-Z0-9_]+)/CONFIG_\2/d,definition/

照葫芦画瓢,所以我们的layout、strings等xml可以这样写它们的语言定义之正则表达式:

--langdef=androidxml
--langmap=androidxml:.xml
--regex-androidxml=/android:id="@\+id\/([^"]*)"/\1/d,id/
--regex-androidxml=/name[ \t]*=[ \t]*"([^"]*)"/\1/d,resource/

试了一下,嗯,索引之王ctags-exuberant,果然是,行!科科科…

接下来,要对.png文件进行索引!什麻?你问有没有听错?.png文件不是图片吗, 怎么可能把它当成编程语言文件进行索引呢?是这样的,.png图片文件是一种资 源,而Android会为每一项资源生成一个id,放在它自动生成的R.java文件中。但 你索引这些R.java的话,就真的是“索”然无味啊,找到一堆id,根本不明白它们哪个是哪个:

public static final int app_name=0x7f050000;
public static final int eglconfig_prompt=0x7f050001;
public static final int eglconfig_text=0x7f050002;
public static final int logging_prompt=0x7f050003;
public static final int logging_text=0x7f050004;

BUT!人生最厉害就是这个BUT!png资源对应的id名字就是该png文件名去掉.png 扩展名而已啊!(请问这是什么编程模式?真的是,行!)

但这个功能没法简单的hack ctags-exuberant来搞定了,但是因为我是通过 gtags-plugin来调用ctags的,所以我们可以掉头去搞gtags的plugin-example, 结果见图:

grep-png.png

尤其爽的是,在Emacs底下,“编辑”.png文件的话,会把它以图片方式打开,而不 是一堆乱码。这样才够直观嘛!另外,很多layout下的.xml文件名也会被当作一 个id出现在源码中,所以我们也一并处理了,gtags的patch如下(已经checkin到 我的配置系统 ):

diff --git a/gcode/global/plugin-example/exuberant-ctags.c b/gcode/global/plugin-example/exuberant-ctags.c
index b7ea5dd..09048d0 100644
--- a/gcode/global/plugin-example/exuberant-ctags.c
+++ b/gcode/global/plugin-example/exuberant-ctags.c
@@ -249,16 +249,42 @@ put_line(char *ctags_x, const struct parser_param *param)
        param->put(PARSER_DEF, tagname, lineno, param->file, p, param->arg);
 }

+static int handle_special_files(const struct parser_param *param, int filename_len, const char* ext, const char* fakeline)
+{
+       int extlen = strlen(ext);
+       if (filename_len > extlen && ! strcmp(param->file + filename_len - extlen, ext)) {
+               char filename[1024];
+               char* p = param->file + filename_len - extlen;
+               while (p > param->file && *--p != '/')
+                       ;
+               p++;
+               strncpy(filename, p, sizeof filename);
+               filename[param->file + filename_len - p - extlen] = '\0';
+               param->put(PARSER_DEF, filename, 1, param->file, fakeline, param->arg);
+               return 1;
+       }
+       return 0;
+}
+
 void
 parser(const struct parser_param *param)
 {
        char *ctags_x;
+       int filename_len;

        assert(param->size >= sizeof(*param));

        if (op == NULL)
                start_ctags(param);

+       filename_len = strlen(param->file);
+
+       handle_special_files(param, filename_len, ".xml", "xml:\t***");
+       if (handle_special_files(param, filename_len, ".9.png", "9png:\t***") ||
+           handle_special_files(param, filename_len, ".png", "png:\t***")) {
+               return;
+       }               
+
        /* Write path of input file to pipe. */
        fputs(param->file, op);
        putc('\n', op);

事实上,我还想把Android的颜色资源id真的用它所代表的颜色画出来呢。下次吧!

<color name="link_text_dark">#5c5cff</color>