正如你们中的一些人所知,我正在开发自己的IDE。你可能会想“哦,不,另一个?!” - 别担心,没有人强迫你使用它,我怀疑它会被认真发表。
所以,从主要问题开始。我正在尝试实现自动完成系统。确切的UI不是问题。 但是,以灵活的方式存储语言/库令牌是我的主要问题。
假设我们建议用户使用CSS选择器或属性。我们有类似的东西:
- css/core
- a // anchor tag
- etc // all valid html tags
- .stuff // class name parsed from user project
- ?etc // more stuff parsed from user project (ids, classes...)
- css/properties
- border // regular css properties - we also need to associate
// <border-style> and <color> value tokens
- etc // the rest of them
- css/values/border-style // property value tokens
- solid
- dotted
- css/values/color
- red
- green
- fucshia
因此每个令牌都有一个名称空间,因此我们可以在令牌之间进行跟踪。与BNF类似,一些标记值由子标记组成,例如边框和颜色。
1。不要忘记我们需要存储可能与具有异国语法的语言相关的任何内容。 2. 另外,需要注意的是,我需要以某种方式将上述信息与依赖于上下文的信息合并,例如从项目文件中收集的类名列表。这应该快速有效,不会造成任何重复的令牌等。
因此,总而言之,这里的事情非常复杂,我不能诚实地想到一种获得通用和灵活解决方案的方法。请记住,IDE应该适应任何类型的语言,这使得它更加复杂。
我不确定这个问题是否更适合,例如programmers,所以我将把它留给mod来决定。
答案 0 :(得分:8)
我在一个名为SharpDevelop的IDE上工作。在我讨论存储问题之前,让我先进行更一般的讨论。
我认为您无法以通用方式正确解决自动填充问题。大多数IDE通过为每种语言提供插件来支持各种语言,完全取决于插件根据文档中光标的当前位置确定完成列表应该是什么样子
IDE仅提供插件实现的简单界面。例如,显示自动完成的IDE中的代码可能如下所示:
getAutocompletionList(editor) {
plugin = editor.languagePlugin;
plugin.getAutocompletionList(editor.cursorPosition, editor.parsedDocument);
}
CSSLanguagePlugin
和PHPLanguagePlugin
将完全分开getAutocompletionList
的实现 - 一个在编辑CSS时使用,另一个在编辑PHP时使用。
正如其他人所指出的,光标周围的上下文非常重要。例如,在编辑以下CSS时:
h1 {
text-align: <cursor>
上下文将是:
[cssTopLevelContext] {
[cssPropertyContext]: [cssPropertyValueContext]
}
然后CSS插件的实现将执行以下操作:
// CSSLanguageBinding
getAutocompletionList(cursorPosition, document) {
completionContext = this.getCompletionContext(cursorPosition, document);
// completionContext is {
// 'name': 'cssPropertyValueContext',
// 'propertyName': 'text-align'
// }
return this.completionDatabase.getCompletionList(completionContext);
// returns ['left', 'center', 'right'];
}
现在我们回答您的问题 - 完成数据库。同样,它可以(也可能应该)是不同语言插件的不同实现 - 在PHP中,您使用类,方法和变量,并且必须关注可见性(私有,公共,受保护)。在CSS中,您使用标签,类和属性。
正如您正确指出的那样,完成数据库应包含:
在SharpDevelop中,“常用令牌”部分不存在,因为任何项目都会导入标准库,因此在打开项目时足以分析所有导入的库。
在PHP中,你也可以这样做,你可以为已经看过的库缓存令牌数据库。
现在我们进入存储格式。要在PHP中提供自动完成功能,您需要了解当前类,其基类和接口层次结构,所有基类和接口中的方法及其可见性,当前上下文中可见的变量及其类型(在PHP中并不总是可行)和等等。
出于这个原因,我认为关系数据库不是一个好的选择。您将如何在那里存储所有类,接口和方法并导航继承层次结构? SharpDevelop将所有这些作为对象模型存储在内存中(Class具有基本类型,接口列表,成员列表等)。 8000个项目不是一个非常大的数字,如果你在关系数据库中存储了8000个项目,那么它将会非常小,以至于数据库引擎无论如何都会将它全部保存在RAM中。
SharpDevelop将所有完成信息保存在内存中,当您在SharpDevelop中打开700K线项目时,内存消耗仍然很低。我建议您在打开项目时初始化自动完成数据结构并将它们保存在内存中。正如其他人所说,你必须在用户输入时在后台更新它们(引入新方法,重命名字段等)。
这就是PHP。对于CSS,类似于您在问题中概述的数据结构似乎非常合理。您可以在IDE启动/打开项目/打开第一个CSS文件时从结构化文件将其加载到内存中。
作为结束语,为CSS实现良好的自动完成不应该那么难。对于PHP来说,它将变得更加困难,你可以从简单的东西开始 - 从标准库中提供8000个令牌,并在项目的其他地方提供用户键入的单词。像Sublime Text这样的编辑使用这种方法,效果出奇的好。
答案 1 :(得分:3)
经过各方面的仔细思考和建议,数据库是存储自动填充信息的唯一合理解决方案。
在本练习中,我编写了几个脚本来解析代码/规范以生成自动完成代码。
这里我意识到,例如,PHP已经超过至少8000个函数(=&gt;自动完成项)。
因此,将这些信息存储在PHP文件中并在IDE启动时加载是不好的。相反,我的数据库将存储此信息。
任何项目特定的自动完成都将存储在单独的数据库表中,有助于避免堵塞主文档表。
答案 2 :(得分:1)
在我以前的工作中,我们在可怕的网站上销售制成品(我是工程师,所以我发誓这种可怕不是我的错)。有一天,高层人士决定在我们所有的产品上都想要一个“推荐商品”盒子。
这方面的常识方法是在每个产品和所有其他产品之间建立一个非常酷和有趣的关系,然后向客户提供有关实际相关产品的相关,最新信息。不幸的是,我的工作中没有人知道如何让我们的预建网站这样做。
相反,他们为每个产品附加了五个产品ID的数组。这些产品ID是根据经验丰富的销售人员和常识的推荐进行硬编码的,并且没有花哨的算法。
这个故事的寓意是你可能想要关注这样一个事实,即你的IDE的最终用户只会看到十个推荐,所以也许你应该想出一些导致“非常好的“十大潜在变量列表:采用一些基本的语法规则,然后根据代码中的邻近度,每个变量的频率以及那种事情进行预测。然后你可以把这个东西放到床上,专注于IDE的更重要的部分。
答案 3 :(得分:1)
一般来说,困难的部分是收集令牌以提供并匹配它们直到正确的打字上下文。 (两者都键入部分类型行的哪个字符用什么激活,并在语言类型系统中键入。)相比之下,表示和查询选项列表很容易,并不重要;一个天真的方法非常好。
现有IDE做的一件事是它们定期接受您的代码并在后台线程中编译它,使用编译器的特殊版本或模式来生成程序中存在的函数/变量/等的列表。该列表可替代地称为“标签文件”,“浏览信息”或“程序数据库”。它存储项目中每个函数的名称,路径,类型,有时还有一些自动提取的文档;而对于性能,它需要以增量方式工作,即避免重新编译未更改的内容,至少在单个文件的粒度上。它还需要比真正的编译器更容忍错误,因为它对部分类型的代码进行操作。
然后当您键入时,编译器会知道自动填充程序应出现的某些上下文:键入“。”后对于函数,当您键入CSS属性名称的一部分时,等等。这取决于模式匹配部分类型的代码。这些没有统一的原则;它只是一堆特殊情况,因语言而异。例如,当您在“case SomeEnum.Foo:”中键入空格时,某些IDE将找到封闭的switch语句,推断其类型,查找该枚举类型的定义,并将其值作为选项提供。
所有这一切的实际结果是,你无法获得自动完成器可以提供的事物的统一表示;相反,您可以混合使用特定于语言的上下文识别黑客,各种上下文的列表以及通过解析提取的更多列表。许多上下文将几个列表合并在一起;例如,CSS选择器可以包含任何HTML标记名称或提取类名称/ ID,并且在键入HTML时也使用HTML标记名称列表。