如何code完成工作? [英] How does code completion work?

查看:170
本文介绍了如何code完成工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很多编辑器和IDE有code完成。其中有些是非常聪明人是不是真的。我感兴趣的是更智能的类型。比如我所看到的集成开发环境,只有提供了一个功能,如果它是一个),可以在当前范围内二)其返回值是有效的。 (例如后5 +富[标签]它只是提供了返回可以添加到一个整数或正确类型的变量名的东西的功能。)我还看到他们未来将更多地使用或最长选项的列表。

Lots of editors and IDEs have code completion. Some of them are very "intelligent" others are not really. I am interested in the more intelligent type. For example I have seen IDEs that only offer a function if it is a) available in the current scope b) its return value is valid. (For example after "5 + foo[tab]" it only offers functions that return something that can be added to an integer or variable names of the correct type.) I have also seen that they place the more often used or longest option ahead of the list.

我知道你需要解析code。但通常在编辑当前code是无效的窗口里有语法错误。你如何解析的东西,当它是不完整的,包含错误?

I realize you need to parse the code. But usually while editing the current code is invalid there are syntax errors in it. How do you parse something when it is incomplete and contains errors?

也有时间限制。完成是无用的,如果它需要几秒钟拿出一个名单。有时,在完成算法处理数千个类。

There is also a time constraint. The completion is useless if it takes seconds to come up with a list. Sometimes the completion algorithm deals with thousands of classes.

什么是好的算法和数据结构呢?

What are the good algorithms and data structures for this?

推荐答案

在我的虚幻脚本语言服务产品的智能感知引擎是复杂的,但我会在这里给作为最好的概述,我可以。在VS2008 SP1中的C#语言服务(有很好的理由),我的绩效目标。它现在还没有,但它的快速/准确的不多,所以我可以放心地提供建议后,单字符输入,无需等待Ct​​rl +空格键或键入用户(点)。信息越多的人[工作语言服务]获得关于这个主题,更好的最终用户体验,我得到我应该永远使用他们的产品。有一些产品我已经与该工作没有支付等密切注意细节的不幸遭遇,并作为一个结果,我在IDE中的战斗比我更被编码。

The IntelliSense engine in my UnrealScript language service product is complicated, but I'll give as best an overview here as I can. The C# language service in VS2008 SP1 is my performance goal (for good reason). It's not there yet, but it's fast/accurate enough that I can safely offer suggestions after a single character is typed, without waiting for ctrl+space or the user typing a . (dot). The more information people [working on language services] get about this subject, the better end-user experience I get should I ever use their products. There are a number of products I've had the unfortunate experience of working with that didn't pay such close attention to details, and as a result I was fighting with the IDE more than I was coding.

在我的语言服务,它奠定了类似如下:

In my language service, it's laid out like the following:

  1. 获得EX pression在光标处。这从走的的成员访问EX pression 应用于标识符年底开始光标已经结束。成员访问EX pression一般的形式是 aa.bb.cc ,也可以包含方法调用,如 aa.bb( 3 + 2)的.cc
  2. 获取的上下文的周围的光标。这是非常棘手的,因为它并不总是遵循相同的规则,因为编译器(长的故事),但这里假定它。通常,这意味着获取方法/类的缓存信息光标之内。
  3. 说上下文对象实现 IDeclarationProvider ,在那里你可以叫 GetDeclarations()来获得的IEnumerable< IDeclaration> 在可见范围内的所有项目。就我而言,这个列表包含了当地人/参数(如果方法)的成员,全局(类型和常量的语言,我(字段和方法,只有除非在实例方法和基本类型没有私有成员静态) 'M上工作),以及关键字。在这个名单将是一个名为 AA 的项目。由于在评价前pression在#1的第一步,我们从上下文枚举该项目名为 AA ,给我们一个 IDeclaration 进行下一步。
  4. 接下来,我申请了操作者的 IDeclaration 重presenting AA 来获得另一个的IEnumerable< IDeclaration> 包含 AA的成员(在某种意义上)。 ,因为 运营商是从不同 - > 运营商,我称之为 declaration.GetMembers (。)并期望 IDeclaration 对象正确适用列出的运营商。
  5. 在此继续进行,直到我打 CC ,其中声明列表的可能会或可能不会的包含对象的名称 CC 。正如我敢肯定,你知道,如果有多个项目开始于 CC ,他们应该会出现为好。予解决这个通过采取最终枚举和通过我的记录算法以向用户提供的最有用的信息成为可能。
  1. Get the expression at the cursor. This walks from the beginning of the member access expression to the end of the identifier the cursor is over. The member access expression is generally in the form aa.bb.cc, but can also contain method calls as in aa.bb(3+2).cc.
  2. Get the context surrounding the cursor. This is very tricky, because it doesn't always follow the same rules as the compiler (long story), but for here assume it does. Generally this means get the cached information about the method/class the cursor is within.
  3. Say the context object implements IDeclarationProvider, where you can call GetDeclarations() to get an IEnumerable<IDeclaration> of all items visible in the scope. In my case, this list contains the locals/parameters (if in a method), members (fields and methods, static only unless in an instance method, and no private members of base types), globals (types and constants for the language I'm working on), and keywords. In this list will be an item with the name aa. As a first step in evaluating the expression in #1, we select the item from the context enumeration with the name aa, giving us an IDeclaration for the next step.
  4. Next, I apply the operator to the IDeclaration representing aa to get another IEnumerable<IDeclaration> containing the "members" (in some sense) of aa. Since the . operator is different from the -> operator, I call declaration.GetMembers(".") and expect the IDeclaration object to correctly apply the listed operator.
  5. This continues until I hit cc, where the declaration list may or may not contain an object with the name cc. As I'm sure you're aware, if multiple items begin with cc, they should appear as well. I solve this by taking the final enumeration and passing it through my documented algorithm to provide the user with the most helpful information possible.

下面是一些附加说明的智能感知后端:

  • 在我广泛使用LINQ的懒惰评估机制实施 GetMembers 。在我的缓存中的每个对象是能够提供一个仿函数计算结果为它的成员,因此,执行复杂的操作与树近微不足道。
  • 而不是保存每个对象名单,其中,IDeclaration&GT; 成员,我保持一个名单,其中,名称&gt; ,其中名称是包含描述构件的特殊格式的字符串的散列结构。有名称映射为对象的一个​​巨大的缓存。这样,当我重新解析文件,我可以从缓存中删除的文件中声明的所有项目,并与更新的成员重新填充它。由于这样的仿函数配置,所有前pressions马上对新的项目。
  • I make extensive use of LINQ's lazy evaluation mechanisms in implementing GetMembers. Each object in my cache is able to provide a functor that evaluates to its members, so performing complicated actions with the tree is near trivial.
  • Instead of each object keeping a List<IDeclaration> of its members, I keep a List<Name>, where Name is a struct containing the hash of a specially-formatted string describing the member. There's an enormous cache that maps names to objects. This way, when I re-parse a file, I can remove all items declared in the file from the cache and repopulate it with the updated members. Due to the way the functors are configured, all expressions immediately evaluate to the new items.

智能感知前端

随着用户类型,该文件是语法上的不正确的往往是正确的。因此,我不想随意删除用户类型,当缓存的部分。我必须到位,以尽快处理增量更新了大量的特殊情况下的规则。增量缓存只有保持本地打开的文件,并有助于使确保用户不会意识到他们的打字导致后端缓存持有不正确的行/列信息之类的文件中的每个方法。

As the user types, the file is syntactically incorrect more often than it is correct. As such, I don't want to haphazardly remove sections of the cache when the user types. I have a large number of special-case rules in place to handle incremental updates as quickly as possible. The incremental cache is only kept local to an open file and helps make ensure the user doesn't realize that their typing is causing the backend cache to hold incorrect line/column information for things like each method in the file.

  • 在一个聊以自慰的是我的解析器的快速的。它可以处理20000行的源文件的完整缓存更新在150毫秒同时经营自足的低优先级后台线程。每当这个解析器完成了在一个开放的文件一传成功(语法),该文件的当前状态移动到全局高速缓存。
  • 如果文件不是语法正确,我用一个 ANTLR过滤分析器(抱歉链接 - 大多数信息是在邮件列表上或从阅读源)聚集来重新分析文件寻找:
    • 变量/字段声明。
    • 的类/结构定义签名。
    • 的方法定义的签名。
    • One redeeming factor is my parser is fast. It can handle a full cache update of a 20000 line source file in 150ms while operating self-contained on a low priority background thread. Whenever this parser completes a pass on an open file successfully (syntactically), the current state of the file is moved into the global cache.
    • If the file is not syntactically correct, I use an ANTLR filter parser (sorry about the link - most info is on the mailing list or gathered from reading the source) to reparse the file looking for:
      • Variable/field declarations.
      • The signature for class/struct definitions.
      • The signature for method definitions.
      • 在确保我可以识别光标的正确的上下文,因为方法/不动全解析之间的文件中。
      • 在确保转至声明/定义/引用正确打开的文件位于项目。

      code段为previous部分:

      Code snippet for the previous section:

      class A
      {
          int x; // linked to A
      
          void foo() // linked to A
          {
              int local; // linked to foo()
      
          // foo() ends here because bar() is starting
          void bar() // linked to A
          {
              int local2; // linked to bar()
          }
      
          int y; // linked again to A
      

      我想我会加我这个布局实现的智能感知功能的列表。 图片每个都设在这里。

      • 自动完成
      • 工具提示
      • 方法技巧
      • 类视图
      • code定义窗口
      • 在调用浏览器(Visual Studio 2010最终其加入到C#)
      • 在语义正确查找所有引用

      这篇关于如何code完成工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆