面向插件开发者的语言服务器协议(LSP)| 技术解析

语言服务器协议 (LSP) 是 Microsoft 开发的一项开放标准协议,用于开发工具与语言服务器之间的通信。我们将 LSP 整合到 IntelliJ 平台,使插件开发者能够使用特定 LSP 服务器集成引入自定义语言支持。语言服务器可以提供针对特定语言的功能,例如代码补全、文档和格式设置,这比从头开始实现语言支持要容易得多,省时省力。它还减少了持续维护和跟踪相关语言与工具更改的需要,使不同开发环境更易获得一致的语言支持。

但是,请记住,与处理和呈现语言服务器提供的数据相比,IntelliJ 平台提供的规范自定义语言支持仍然提供了与 IDE 功能更广泛的集成。因此,LSP 方式不应被视为现有语言 API 的替代方案,而应被视为附加值。

从 2023.2 发布周期开始,LSP API 作为 IntelliJ 平台的一部分在以下 IDE 中公开提供:

  • IntelliJ IDEA Ultimate

  • WebStorm

  • PhpStorm

  • PyCharm Professional

  • DataSpell

  • RubyMine

  • CLion

  • Aqua

  • DataGrip

  • GoLand

  • Rider

下面几部分将解释如何构建与语言服务器的简单集成,发现可用的功能和文档,以及了解基于 IntelliJ 的 IDE 中 LSP 支持的当前状态。


插件配置

为了在基于 Gradle 构建系统的第三方插件中充分利用语言服务器协议 API,我们建议将 Gradle IntelliJ Plugin 升级到 1.15.0 或更高版本。此插件会将 LSP API 源和代码文档附加到项目中。

LSP 在基于 IntelliJ 的 IDE 的 2023.2 EAP7 中可用,因此插件必须以 IntelliJ IDEA Ultimate 232-EAP-SNAPSHOT 或更高版本为目标,或者在全面推出后以 v2023.2 为目标。

示例 build.gradle.kts 配置:

plugins {
   // ...
   id("org.jetbrains.intellij") version "1.15.0"
}   


intellij {
   version = "232-EAP-SNAPSHOT"
   type = "IU"
}

对于基于 IntelliJ Platform Plugin Template 的项目,将 Gradle IntelliJ Plugin 更新到最新版本,并按如下所示修改 gradle.properties 文件:

platformType = IU
platformVersion = 232-EAP-SNAPSHOT
pluginSinceBuild = 232
pluginUntilBuild = 232.*

plugin.xml 配置文件需要指定对 IntelliJ IDEA Ultimate 模块的依赖:

   <!-- ... -->


   com.intellij.modules.platform
   com.intellij.modules.ultimate

通过以上更改,我们可以访问 LSP API 及其源代码和文档。

LSP API 源捆绑在 IntelliJ IDEA Ultimate 中,可以在 [IDE]/lib/src/src_lsp-openapi.zip 归档中找到。如果您使用的是 Gradle IntelliJ Plugin 1.15.0+,它们会自动解析和映射。


支持的功能

IntelliJ 平台内的初始 LSP 支持涵盖以下功能:

更多功能即将公布。


基本实现

最低限度的 LSP 集成必须实现 LspServerSupportProvider 以及服务描述符,并将其注册为 com.intellij.platform.lsp.serverSupportProvider 扩展点

import com.intellij.platform.lsp.api.LspServerSupportProvider
import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor


class FooLspServerSupportProvider : LspServerSupportProvider {
   override fun fileOpened(project: Project, file: VirtualFile, serverStarter: LspServerStarter) {
       if (file.extension == "foo") {
           serverStarter.ensureServerStarted(FooLspServerDescriptor(project))
       }
   }
}


private class FooLspServerDescriptor(project: Project) : ProjectWideLspServerDescriptor(project, "Foo") {
   override fun isSupportedFile(file: VirtualFile) = file.extension == "foo"
   override fun createCommandLine() = GeneralCommandLine("foo", "--stdio")
}

提供 LSP 服务器支持提供程序扩展点的实现后,将其注册到 plugin.xml 文件中,如下所示:

   <!-- ... -->


   com.intellij.modules.platform
   com.intellij.modules.ultimate

作为参考,请查看 Prisma ORM 开源插件实现:https://github.com/JetBrains/intellij-plugins/tree/master/prisma/src/org/intellij/prisma/ide/lsp


语言服务器集成

语言服务器是一个独立进程,用于分析源代码并向开发工具提供针对特定语言的功能。在 IDE 中创建使用 LSP 的插件时,可以通过两种方式向最终用户提供语言服务器:

  • 语言服务器实现二进制文件捆绑为随插件交付的资源。

  • 为用户提供定义语言服务器二进制文件在其环境中的位置的功能。

Prisma ORM 插件采用第一种方式,分发 prisma-language-server.js 脚本并使用本地 Node.js 解释器来运行。

对于更复杂的情况,您可能需要带有专属设置实现的详细配置。

要实现最低限度但功能齐全的插件,请执行以下步骤:

  • LspServerSupportProvider.fileOpened() 方法中,启动相关 LSP 服务器描述符,它可以使用 LspServerDescriptor.isSupportedFile() 检查方法来确定给定文件是否受支持。

  • 说明如何通过实现 LspServerDescriptor.createCommandLine() 启动服务器。



自定义


  • 为了微调或禁用基于 LSP 的功能的实现,插件可以重写 LspServerDescriptor 类的相应属性。请参阅属性文档,了解更多详细信息:

    • lspGoToDefinitionSupport

    • lspCompletionSupport

    • lspDiagnosticsSupport

    • lspCodeActionsSupport

    • lspCommandsSupport

  • 要处理来自 LSP 服务器的自定义(未记录)请求和通知,请重写 LspServerDescriptor.createLsp4jClient

  • 要将自定义(未记录)请求和通知发送到 LSP 服务器,请重写 LspServerDescriptor.lsp4jServerClass 并实现 LspClientNotification 和/或 LspRequest 类。

如需了解详情,请参见捆绑的 LSP API 源代码及其代码文档。


测试

用于测试的实用程序类尚未提取供公众使用,但我们将尽快提供合适的方法来测试基于 LSP 的第三方插件。


故障排除

所有 IDE 和 LSP 服务器通信日志均传递到 IDE 日志文件。

要将其包含以供预览,请将以下条目添加到 Help | Diagnostic Tools | Debug Log Settings…(帮助 | 诊断工具 | 调试日志设置…)配置对话框中:

#com.intellij.platform.lsp

有关详情,请参阅 IntelliJ 平台 SDK 文档中的 Logging 部分。


限制




结论

将语言服务器协议 (LSP) 集成到基于 IntelliJ 的 IDE 的插件中时,需要在简单快速的语言支持和具有 IDE 功能的复杂自定义语言支持插件之间做出权衡。

考虑基于 LSP 的方式时,务必按以下标准评估向最终用户提供的语言服务器:

  • 语言服务器的操作系统依赖。

  • 最新版本在线可用性。

  • 与版本间重大更改的兼容性。

  • 请求用户提供语言服务器二进制路径的可行性。

解决与语言服务器进程的集成问题后,查阅 IntelliJ SDK 文档仍然很重要。这将全面概述与 IntelliJ 平台内 LSP 标准无缝集成的可用功能。

请注意,与语言服务器协议的集成作为基于 IntelliJ 的付费 IDE 的扩展而创建。因此,使用语言服务器集成的插件可能无法在 JetBrains 产品的 Community 版本和 Google 的 Android Studio 中使用。

如果您遇到问题或需要帮助,请通过 JetBrains Platform Slack 工作区中的 #intellij-platform 频道联系我们或在 YouTrack 中提交问题。


本博文英文原作者:Jakub Chrzanowski

IntelliJ Plugins 阅读

⏬ 戳「阅读原文」了解更多

本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Redis 7.2.0 发布,影响最深远的版本 中国程序员拒写赌博程序被拔 14 颗牙,全身损伤达 88% Flutter 3.13 发布 System Initiative 宣布将其所有软件全部开源 字节首个大模型独立 App 亮相,Grace 更名“豆包” Spring 6.1 已兼容虚拟线程和 JDK 21 Linux 平板电脑 StarLite 5:默认搭载 Ubuntu、12.5 英寸 Chrome 116 正式发布 红帽重新部署桌面 Linux 开发,主要开发者被调离 Kubernetes 1.28 正式发布
{{o.name}}
{{m.name}}

猜你喜欢

转载自my.oschina.net/u/5494143/blog/10100302