0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Rust重写的LSP:KCL IDE 插件的功能介绍与设计解析

jf_wN0SrCdH 来源:Rust语言中文社区 2023-05-11 09:39 次阅读

在上周,KCL 发布了 v0.4.6 版本,这个版本在语言、工具链、社区集成&扩展支持等方面进行了重点更新。本文包含 KCL IDE 插件的功能特性和 LSP 的介绍、KCL LSP Server 端的设计和实现以及未来的规划和期望。

功能特性

在这次更新中,我们发布了全新的 KCL VS Code 插件,并且用 Rust 重写了 LSP 的 Server 端。我们提供了 IDE 中常用的代码辅助功能,如高亮、跳转、补全、Outline、悬停、错误提示等。

  • 高亮

fa1a0f0e-ef67-11ed-90ce-dac502259ad0.png

  • 补全

fa23ddea-ef67-11ed-90ce-dac502259ad0.png

  • Outline

fa4dc182-ef67-11ed-90ce-dac502259ad0.png

  • 悬停 & 跳转

fa700efe-ef67-11ed-90ce-dac502259ad0.png

  • 错误/警告提示

fa7c9020-ef67-11ed-90ce-dac502259ad0.png

欢迎到 https://kcl-lang.io/docs/tools/Ide/vs-code/ 了解更多

什么是 LSP?

在这次更新中,我们基于 LSP 实现了以上能力。LSP 指的是 Language Server Protocol,它是由微软在 2016 年推出的一种用于编程语言工具的协议。借用一张图,很容易就可以理解 LSP。

fa96447a-ef67-11ed-90ce-dac502259ad0.pngLSP

通过 LSP ,编辑器和 IDE 可以通过 JSON-RPC 通信协议与后端运行的语言服务器(Server 端)进行通信。语言服务器可以提供代码分析、自动补全、语法高亮、定义跳转等功能。基于 LSP,开发者可以在不同的编辑器和 IDE 之间迁移,使得语言工具的开发从 M(语言数量) * N(编辑器/IDE数量) 降低为 M + N


为什么用Rust重写?

KCL 编译器和其他工具最初由 Python 实现,因为性能原因,我们用 Rust 语言重写了编译器(性能提升 40 倍!我们用 Rust 重写了自己的项目)。在此之后,我们使用 Rust 逐步重写了 KCL 的其他工具,如测试工具、Format 工具等。在这次更新中,我们用 Rust 重写了 LSP Server 端,其主要考虑因素也是性能。

fa9fc9f0-ef67-11ed-90ce-dac502259ad0.png

过去,Python 版本的 Server 端在处理一些复杂的场景(编译文件数量超过200个)时,处理一个跳转的请求,Server 端从接收到请求到计算结果并响应,时间长达 6 秒以上,几乎是不可用状态。由于 Server 端的实现主要基于语言编译器前中端的词法解析和语义分析,在我们使用 Rust 重写以后,这部分性能分别提升了 20 和 40 倍, 带来的显著结果就是 Server 端的响应时间得到了巨大提升,对于同样的场景,响应时间缩短至 100 毫秒左右。而对于一些简单的场景,响应时间只有几毫秒,做到了用户无感。

KCL LSP Server的设计与实现

KCL LSP Server 的设计如下图所示:

fbda7824-ef67-11ed-90ce-dac502259ad0.png

主要流程可以分为几个阶段:

  1. 建立连接,初始化 LSP 能力。在 IDE 的 Client 端,打开特定文件(KCL的 *.k)时,IDE 会启动本地的 kcl_language_server 二进制文件,启动 Server 端。这个文件与 KCL 一起发布,并安装在 KCL 的 bin 目录下。Server 启动后会建立 standard IO 的 Connection,并等待 Client 发送的初始化请求。Server 端接收初始化请求后会定义 Server 端信息和能力,并返回给 Client,以此完成 LSP 的初始化连接。
  2. 建立连接后,Server 端会启动一个轮询函数,不断接收来自 Client 的 LSP Message,例如 Notification(打开/关闭/变更/删除文件等)和 Request(跳转、悬停等),以及来自 Server 端自身的 Task。并统一封装成事件(Event)交给下一步处理。
  3. 对于各种事件,按照以下步骤处理:
///Handlesaneventfromoneofthemanysourcesthatthelanguageserversubscribesto.
fnhandle_event(&mutself,event:Event)->anyhow::Result<()>{
//1.Processtheincomingevent
matchevent{
Event::Task(task)=>self.handle_task(task)?,
Event::Lsp(msg)=>matchmsg{
lsp_server::Request(req)=>self.on_request(req,start_time)?,
lsp_server::Notification(not)=>self.on_notification(not)?,
_=>{}
},
};

//2.Processchanges
letstate_changed:bool=self.process_vfs_changes();

//3.HandleDiagnostics
ifstate_changed{
letmutsnapshot=self.snapshot();
lettask_sender=self.task_sender.clone();
//Spawnthediagnosticsinthethreadpool
self.thread_pool.execute(move||{
 handle_diagnostics(snapshot, task_sender)?;
});
}

Ok(())
}

3.1 任务分发:根据任务类型,做函数分发。在子函数中,会进一步基于 Request 或 Notification 的类型继续分发到最终的处理函数中,如处理文件变更、处理跳转请求等。这些函数会根据基于编译器中前端编译出的语义模型(AST,符号表,错误信息等)做分析,计算生成对应的 Response(如跳转请求的目标位置)。

3.2 处理变更:用户在修改代码或更改文件时,会发送对应的 Notification。在前一步的处理中,会将变更保存在虚拟文件系统(VFS)中。Server 端会根据新的源代码,进行重新编译,保存新的语义模型,以供下一个请求做处理。

3.3 错误处理:这里的错误并非指 Server 端的运行错误,而是代码编译中的语法、语义错误,编译警告等。Client 端并没有对应的请求类型来请求这些错误,而是由 Server 端主动发送 Diagnostics。因此,在发生变更后,同步地将错误信息更新至 Client 端。

遇到的问题

1.为什么需要虚拟文件系统?

在最初的设计中,并没有考虑使用虚拟文件系统。我们每次从文件系统中获取源代码,进行编译和分析。对于一些“静态”的任务,如跳转,可以在变更代码后保存到文件系统,然后再进行跳转的操作。配合到 VS Code 的自动保存功能,体验上并没有明显的差距。但对于代码补全这一功能,IDE 中输入的补全trigger(如 “.”)会触发文件变更的通知和代码补全的请求,但对应的代码还未保存到文件系统中,编译后的语义模型无法做对应的分析。因此,我们借助 Rust Analyzer 对应的 vfs 的create,在 Server 端引入了虚拟文件系统,将编译的入口从文件路径变为了 source code。Client 端输入代码后,文件变更的通知会先更新虚拟文件系统,重新编译文件,生成新的语义模型,然后再处理补全请求。

2. 如何处理不完整的代码?

我们遇到的另一个比较大的问题是如何处理不完整的代码。同样的,对于跳转这类“静态”的任务,可以假定代码是完整、正确的。但对于补全操作,如以下代码,希望在输入.后,补全字符串的函数。对于编译流程,第二行实际上是不完整的代码,无法编译出正常的 AST 树。

s:str="hellokcl"
len=s.

为此,我们在 KCL 的编译中实现了语法和语义上的多种错误恢复,保证编译过程始终能产生完整的 AST 和符号表。在这个例子中,我们新增了一个表示空的 AST 节点作为占位符,使得第二行能够生成完整的 AST。在处理补全的请求时,会根据 s 的类型和其他语义信息,补全函数名、schema attr 或 pkg 中定义的 schema 名。

Rust Analyzer architecture:

Architecture Invariant: parsing never fails, the parser produces (T, Vec) rather than Result.

总结与展望

KCL 的 IDE 插件目前已经实现高亮、跳转、补全、Outline、悬停、错误提示等功能。这些功能提升了 KCL 用户的开发效率。然而,作为一款 IDE 插件,它的功能还不够完整。在未来的开发中,我们会继续完善,未来的工作有以下几个方向:

  1. 更多的语言能力:提供更多的功能,如代码重构,错误的quick fix,代码 fmt等,进一步完善功能,提升开发效率
  2. 更多的 IDE 接入:目前,KCL 虽然提供了 LSP,只接入了 VS Code,未来会基于 LSP 的能力为 KCL 用户提供更多选择。
  3. AI 能力的集成:目前,ChatGPT 风靡全网,各行各业都在关注。我们也在探索 AI×KCL 的结合,提供更智能的研发体验。总之,我们会继续完善和优化 KCL 的 IDE 插件,让它更加成熟和实用。为KCL用户带来更加方便和高效的开发体验。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 编程语言
    +关注

    关注

    10

    文章

    1945

    浏览量

    34732
  • LSP
    LSP
    +关注

    关注

    0

    文章

    13

    浏览量

    9778
  • KCL
    KCL
    +关注

    关注

    0

    文章

    8

    浏览量

    4068

原文标题:Rust 重写的 LSP:KCL IDE 插件的功能介绍与设计解析

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Eclipse IDE插件研发工程师

    、 基于Eclipse IDE进行二次开发,将已有的工具链集成到Eclipse IDE中 。3、 根据需求开发新的功能插件。4、 解决开发过程中遇到的技术难点。岗位要求1、 计算机专业
    发表于 04-20 15:22

    IDE为S32 Design Studio安装Lauterbach插件无法解析位置是为什么?

    我正在尝试通过我的 IDE 为 S32 Design Studio 安装 Lauterbach 插件无法解析位置。  
    发表于 06-08 06:01

    Rust代码中加载静态库时,出现错误 ` rust-lld: error: undefined symbol: malloc `怎么解决?

    我正在 MCUXpresso IDE 中创建一个静态库。我正在使用 redlib 在我的代码中导入 ` [i]stdlib.h`。它成功地构建了一个静态库。但是,静态库中未定义一些标准库函数,例如
    发表于 06-09 08:44

    jquery插件写法及用法(jQuery插件开发全解析

    如今做web开发,jquery 几乎是必不可少的,同时jquery插件也是不断的被大家所熟知,以及运用。最近在搞这个jquery插件,发现它的牛逼之处,所以讲一讲jQuery插件的写法、使用jQuery
    发表于 12-03 09:21 1w次阅读
    jquery<b class='flag-5'>插件</b>写法及用法(jQuery<b class='flag-5'>插件</b>开发全<b class='flag-5'>解析</b>)

    用于MPLAB X IDE代码性能分析插件的工作原理和代码性能分析参考

    MPLAB X IDE提供收集有关C代码函数的函数级性能分析(Function Level Profiling, FLP)数据的功能。但是,该数据无法在未安装MPLAB X IDE插件
    发表于 06-11 04:28 11次下载
    用于MPLAB X <b class='flag-5'>IDE</b>代码性能分析<b class='flag-5'>插件</b>的工作原理和代码性能分析参考

    微软开发基于Rust的新编程语言,将很快开源

    此前,微软表示正探索将Rust作为C和C++的安全替代方案,并且也对外展示了使用Rust重写Windows组件的体验,根据微软的说法,Rust是一种从根本上考虑安全性的编程语言,他们将
    的头像 发表于 12-03 10:36 3920次阅读

    用于MPLABX IDE的代码性能分析插件

    MPLAB X IDE提供收集有关C代码函数的函数级性能分析(Function Level Profiling,FLP)数据的功能。但是,该数据无法在未安装MPLAB X IDE插件
    发表于 05-12 10:38 15次下载

    Rust重写了自己的项目

    一年前,我们使用 Python 语言构建了整个 KCL 语言编译器的实现,虽然在一开始的时候运行良好,Python 简单易上手,生态丰富,团队的研发效率也很高,但是随着代码库的扩张和工程师人数的增加,代码维护起来愈加困难。
    的头像 发表于 02-02 16:45 1183次阅读

    Cloudflare用Rust重写Nginx C模块,构建没有Nginx的未来

    近日,Cloudflare 工程师介绍了如何使用 Rust 重写基于 C 语言的 Nginx 模块。Cloudflare 工程师在博客写道,他们用 Rust 为 Cloudflare
    的头像 发表于 03-08 09:36 720次阅读

    Windows 11初尝Rust,36000行内核代码已重写

    更早些时候,微软用 Rust 重写了 DirectWrite Core 库的概念验证,它是 Windows 的 DWrite 引擎的 Windows App SDK 实现,用于文本分析、布局和渲染
    的头像 发表于 05-19 16:39 1012次阅读
    Windows 11初尝<b class='flag-5'>Rust</b>,36000行内核代码已<b class='flag-5'>重写</b>!

    用于Arduino IDE插件Blockly@rduino

    电子发烧友网站提供《用于Arduino IDE插件Blockly@rduino.zip》资料免费下载
    发表于 06-20 11:27 2次下载
    用于Arduino <b class='flag-5'>IDE</b>的<b class='flag-5'>插件</b>Blockly@rduino

    Rust构建QEMU插件的框架

    Cannonball 是一个用 Rust 构建 QEMU 插件的框架!您可以在 C 语言的 QEMU TCG 插件中执行的任何操作,都可以使用cannonball。编写以最小的开销和尽可能多的
    的头像 发表于 07-21 16:57 902次阅读

    JetBrains发布独立Rust IDE:RustRover

    在推出 RustRover 之前,JetBrains 以插件形式在 IntelliJ IDEA 和 CLion 中支持 Rust 功能。现在他们开发多年的开源插件已成为 RustRov
    的头像 发表于 09-18 16:47 1049次阅读
    JetBrains发布独立<b class='flag-5'>Rust</b> <b class='flag-5'>IDE</b>:RustRover

    一次Rust重写基础软件的实践

    受到2022年“谷歌使用Rust重写Android系统且所有Rust代码的内存安全漏洞为零” [1] 的启发,最近笔者怀着浓厚的兴趣也顺应Rust 的潮流,尝试着将一款C语言开发的基础
    的头像 发表于 01-25 11:21 641次阅读

    SOLIDWORKS插件功能介绍 慧德敏学

    SOLIDWORKS拥有一系列内置及第三方插件,这些插件丰富了其功能并提高了设计效率。本文为您介绍SOLIDWORKS插件
    的头像 发表于 11-23 15:56 347次阅读