使用regexp为imenu索引文件,性能是不可接受的

时间:2011-05-25 16:40:08

标签: emacs elisp

我正在为imenu-create-index-function生成一个函数,为csharp-mode.el

索引源代码模块

它可以工作,但提供完全不可接受的性能。有任何解决方法吗?

背景

我看了js.el,这是现在包含的重新加载的“espresso”,从第23版开始,进入emacs。它非常好地索引Javascript文件,使用匿名函数和常用的各种编码样式和模式做得很好。例如,在javascript中可以做到:

(function() {
    var x = ... ; 
    function foo() {
       if (x == 1) ...
    }
})();

...定义x为“私有”或其他代码无法访问的范围。 js.el使用regexp很好地索引它,并且它也在该范围内索引内部函数(匿名或非匿名)。它运作迅速。一个大模块可以在不到一秒的时间内建立索引。

我尝试在csharp模式下使用类似的方法,但它要复杂得多。在Js中,索引的所有内容都是函数。因此,起始正则表达式是“功能”,在任何一端都有一些细节。找到function关键字后,会有4到8个其他正则表达式通过looking-at进行尝试 - 数量取决于设置。关于js模式的一个好处是你可以打开或关闭各种编码风格的regexp,以加快我想的速度。默认的“样式”适用于我尝试过的大多数代码。

这在csharp模式下不起作用。它工作,但它的性能很差,不足以使它变得不可用。我认为原因是

  • C#中没有单个标记关键字,因为function在javascript中表现。在C#中,我需要查找命名空间,类,结构,接口,枚举等。

  • 有很多灵活性可以定义csharp结构。作为一个示例,类可以定义基类以及实现的接口。另一个例子:方法的返回类型不是简单的类似字符串的字符串,但可能像Dictionary<String, List<String>>那样混乱。索引例程需要处理所有这些情况,并捕获匹配项。这使得它运行起来很懒散。

  • 我使用了很多looking-back。我在当前方法中使用的标记是开放的大括号。一旦我找到其中一个,我使用looking-back来确定卷曲是一个类,接口,枚举,方法等。我读到looking-back可能很慢;我不清楚它比looking-at慢多少。

  • 一旦我找到一对开合的curlies,我会调用narrow-to-region来索引里面的内容。不确定这是否会杀死性能。我怀疑它不是主要的罪魁祸首,因为我看到的perf问题发生在具有一个命名空间和2或3个类的模块中,这意味着narrow总共被称为3或4次。

问题是什么?

我的问题是:您是否有任何关于加快C#缓冲区中类似imenu索引的提示?

我在考虑:

  • 避免looking-back。我不确切知道如何执行此操作,因为当re-search-forward找到关键字class时,游标已经位于类声明的中间。 looking-back似乎很重要。

  • 而不是使用open-curly作为标记,使用enum,interface,namespace,class等关键字

  • 避免narrow-to-region

任何艰难的建议?进一步的建议?

我尝试过的东西,我并不热衷于重新访问:为C#构建一个基于智慧的解析器,并依靠语义来进行索引。我发现语义非常非常(等)难以使用,难以发现和有问题。我有一段时间的语义工作,但后来升级到v23.2,它破了,我再也不能让它工作了。简单的事情 - 比如索引命名空间关键字 - 需要很长时间才能解决。我对此非常不满意,不想再试一次。

1 个答案:

答案 0 :(得分:0)

我真的不知道C#语法,如果没有查看你的elisp,很难给出答案,但无论如何都要进行。

looking-back可能会非常慢。这是我试验的第一件事。有一点很重要的是使用limit arg来限制搜索到当前行的开头。另一种方法是,当你点击开放的卷曲做backward-char然后backward-sexp(或其他)来到前一个单词的前面,然后使用looking-at

使用关键字搜索而不是开放卷曲可能就是我要做的。也许类似于(re-search-forward "\\(enum\\|interface\\|namespace\\|class\\)[ \t\n]*{" nil t),然后在第一个捕获组上使用match-string-no-properties来查看找到了哪些关键字。这也可能有助于解决looking-back问题。

我不知道narrow-to-region有多贵,但是当你找到一个开放的卷曲做save-excursion forward-sexp并保持point作为限制时,可以避免您(我假设递归)搜索的当前迭代。