zoukankan      html  css  js  c++  java
  • 实例分析SharpDevelop代码完成功能

    介绍

    SharpDevelop源代码里自带一个CSharp代码自动完成功能(Code Completion)的例子。如下图所示:

     

    1. 代码完成

    看上去似乎好像挺不好做的,理论上要做词法分析、语法分析,还要解析一些如mscorlib之类的DLL。但是事实上SharpDevelop已经为我们做了这些,上面的例子只要写几个类就可以完成。整个Solution如下图所示:

    2. 代码完成例子的Solution

    3. Code Metrics Results

    直接使用SharpDevelop里的分析器,就可以很简单地完成Code Completion的功能。平均每个文件只有100行的代码。也许有人要说这样没有意思,但是我们不应该“重新做个轮子”对吗?而且就算要深入地学习,也要先来把这个例子弄明白的。

    这个例子里的Code Completion并不象SharpDevelop里的那么完成,没有提供下面的功能。

    4. 缺失的ToolTip提示

    在输入左括号时,应该在ToolTip中给出这个函数的所有重载,但是这个例子里并没有给出这个功能的实现。下面在介绍代码完成的同时,会给出这个ToolTip的实现。

    博客园的Michael Zhang在其SharpDevelop浅析系列文章中也介绍了代码完成功能。如果对整个SharpDevelop有兴趣可以参考一下。下面进入正题……

    第一部分 Code Completion的实现

    下图是这个例子里的类体系

    5. 整个例子的类体系

    从类的结构来看,其实与SharpDevelop本身的实现不是一个层次的,这个类结构的耦合性很强,还好要看的是如何实现Code Completion,而不是它的设计。要看设计,还是看SharpDevelop好了。

    下面逐个介绍一下里面的类。

    CodeCompletionData类:是用于表示代码完成列表中每个项的Visual Object。看看它的父类会更明显一些。

    6. DefaultCompletionData类图

    MainForm类:就是看到的整个窗体。里面有三个控件,一个是SharpDevelopTextEditorControl,一个状态栏,一个ImageList。主窗体加载之后会开启一个Parser线程,每2秒对整个文档做一次Parse。(汗,用Stopwatch测试了一下,对一个很小的文件的一次Parse50ms左右。)Parse之后,用于做Code Completion的数据就有了。在哪儿?没去认真找过。应该是在ProjectContent里。下面是Parse的步骤:

     

    Code

     

    CodeCompletionKeyHandler类:看名字就知道,就是针对CodeCompletion处理窗体的键盘事件的,如果点了”.”,就实例化一个CodeCompletionProvider并显示CodeCompletion窗口。按VS的分析,这个只有22行代码的文件就不细介绍了。

     

    ShowCodeCompletionList

     

    HostCallbackImplementation类:这个更少,就13行代码。做的事件就是后台分析出错的时候,把消息显示出来。

    CodeCompletionProvider类:虽然最重要的部分,却也只有51行代码。主要完成了两件事情:1. 生成CodeCompletion列表。2. 用户触发一个Item的时候把相应的内容插入(就2行)。

    生成CodeCompletion列表的功能也十分简单,大致分成三个步骤:

    a.       FindExpression:就是找到当前用户的点”.”之前的那个东西到底是个什么东西。

    b.       Resolve:得到找到的那个东西的Memeber列表。

    c.       GenerateData:从得到的列表生成用于在UI上显示的CodeCompletionData

    ToolTipProvider类:这个可不是那个缺失的功能哦。这个只是在MouseOver一个Member时,显示出一些信息。在图1的上面的那个就是了。(好像ToolTip还错了……)这个过程和CodeCompletionProvider大致相同。就不再赘述了。

    这样,整个CodeCompletion的功能就完成了。整个例子359行代码。(仔细看看代码,你会有信心把它到缩减到200行。)

    第二部分 添加Code Insight功能

    什么是Code Insight?就是之前提到的缺失的ToolTip啊。在SharpDevelop里给了它一个更专业的名字叫“Code Insight”。

    一向奉行“Don’t recreate the wheel”,这次也不例外。Sample没有,SharpDevelop有啊。Ctrl+V过来不就行了?(当然商业项目不行哦,连Sample也不行。人家是GPL

    然后就在SharpDevelop的源代码中找到了一个名为MethodInsightDataProvider的文件(在ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor名字空间下)加了进来,然后在KeyHandler里加入对InsightWindow的支持。

     

    ShowInsightWindow

    再把SharpDevelop里的CodeCompletionData里的GetDocumentation函数也Copy到这个SampleCodeCompletionData类中。

    这样所有的类的准备完了。

    然而在MethodInsightDataProvider中使用到的ParserServiceAmbienceServiceLoggingServiceMessageService都没有找到引用。又去看了一下SharpDevelop的运行流程,找到了开启这几个Service的地方,发现差不多也已经同时把整个IDE开启了。这个可不是我想要的。而且很多类都是protected sealed类。从外界是Call不到的。看来必须要”Recreate the wheel”,把那个DataProvider重新写一个了。还好那个Provider只有100多行代码,自己写一个并不复杂。把LoggingServiceMessageService的代码都删除。而ParserServiceAmbienceService的作用不过是ParserAmbience的工厂类,自己实例化一个不就得了?这样,DataProvider中所引用的所有Service都被剥离了。

    整个MethodInsightDataProvider的代码如下所示:

     

    MethodInsightDataProvider

    运行一下。

    7. Method Insight

    大功告成。

    其实还有一种Insight——IndexerInsight。就是在输入‘[’的时候给出ToolTip提示。这个就留给有兴趣的读者吧。

    /Files/nankezhishi/source/CSharpCodeCompletion.zip这里是改版的代码完成的所有代码。

    下一篇中,将为这个示例添加Boo语言的支持。

  • 相关阅读:
    几种任务调度的 Java 实现方法与比较
    nginx配置
    生产消费_lock和阻塞队列
    阻塞队列
    countdownlatch+cyclicbarrier+semphore
    01背包
    skiplist
    lru
    按序打印_lock和condition
    按序打印_volatile 无法保证顺序
  • 原文地址:https://www.cnblogs.com/nankezhishi/p/1338959.html
Copyright © 2011-2022 走看看