Language Server Protocol for Plugin Developers
The Language Server Protocol (LSP) is an open-standard protocol developed by Microsoft that enables communication between development tools and Language Servers. By incorporating LSP into the IntelliJ Platform, we enable plugin developers to introduce support for a custom language by using specific LSP server integration. The Language Server can provide language-specific features such as code completion, documentation, and formatting, which is far easier than implementing language support from scratch and saves time and effort. It also reduces the need for constant maintenance and tracking of changes in relevant languages and tools, making it easier to bring consistent language support to various development environments.
However, we must remember that canonical custom language support provided by IntelliJ Platform still offers a wider range of integration with IDE features than handling and presenting data provided by a Language Server. Therefore, the LSP approach shouldn’t be considered as a replacement for the existing language API, but rather as an added value.
Starting with the 2023.2 release cycle, the LSP API is publicly available as part of the IntelliJ Platform in the following IDEs:
- IntelliJ IDEA Ultimate
- WebStorm
- PhpStorm
- PyCharm Professional
- DataSpell
- RubyMine
- CLion
- Aqua
- DataGrip
- GoLand
- Rider
The following sections explain how we can build a simple integration with Language Server, discover available features and documentation, and find out about the current state of LSP support in IntelliJ-based IDEs.
Plugin configuration
To fully utilize the Language Server Protocol API in a third-party plugin based on the Gradle build system, we recommend upgrading the Gradle IntelliJ Plugin to version 1.15.0 or higher. This plugin will attach the LSP API sources and code documentation to your project.
As LSP became available in the 2023.2 EAP7 of IntelliJ-based IDEs, the plugin must target IntelliJ IDEA Ultimate 232-EAP-SNAPSHOT
or later, or v2023.2 once it becomes generally available.
Example build.gradle.kts
configuration:
plugins { // ... id("org.jetbrains.intellij") version "1.15.0" } intellij { version = "232-EAP-SNAPSHOT" type = "IU" }
For projects based on the IntelliJ Platform Plugin Template, update the Gradle IntelliJ Plugin to the latest version, and amend the gradle.properties
file as follows:
platformType = IU platformVersion = 232-EAP-SNAPSHOT pluginSinceBuild = 232 pluginUntilBuild = 232.*
The plugin.xml configuration file needs to specify the dependency on the IntelliJ IDEA Ultimate module:
<idea-plugin> <!-- ... --> <depends>com.intellij.modules.platform</depends> <depends>com.intellij.modules.ultimate</depends> </idea-plugin>
With the above changes, we can access the LSP API along with its source code and documentation.
The LSP API sources are bundled in IntelliJ IDEA Ultimate and can be found within the [IDE]/lib/src/src_lsp-openapi.zip
archive. If you use Gradle IntelliJ Plugin 1.15.0+, they become automatically resolved and mapped.
Supported features
The initial LSP support within the IntelliJ Platform covers the following features:
- Errors/warnings highlighting (textDocument/publishDiagnostics)
- Quick-fixes for these errors/warnings (textDocument/codeAction)
- Code completion (textDocument/completion)
- Go to Declaration (textDocument/definition)
More features will be announced soon.
Basic implementation
A minimal LSP integration must implement LspServerSupportProvider
along with a service descriptor and register it as a com.intellij.platform.lsp.serverSupportProvider
extension point:
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") }
After providing the implementation of the LSP Server support provider extension point, register it in the plugin.xml
file as follows:
<idea-plugin> <!-- ... --> <depends>com.intellij.modules.platform</depends> <depends>com.intellij.modules.ultimate</depends> <extensions defaultExtensionNs="com.intellij"> <platform.lsp.serverSupportProvider implementation="FooLspServerSupportProvider"/> </extensions> </idea-plugin>
As a reference, check out the Prisma ORM open-source plugin implementation: https://github.com/JetBrains/intellij-plugins/tree/master/prisma/src/org/intellij/prisma/ide/lsp
Language Server integration
Language Server is a separate process that analyzes source code and provides language-specific features to development tools. When creating a plugin that utilizes LSP within the IDE, there are two possibilities for providing a Language Server to end-users:
- Bundle a Language Server implementation binary as a resource delivered with a plugin.
- Provide a possibility for users to define the location of the Language Server binary in their environment.
The Prisma ORM plugin presents the first approach, which distributes the prisma-language-server.js
script and uses a local Node.js interpreter to run it.
For more complex cases, you may request to provide a detailed configuration with a dedicated Settings implementation.
To implement a minimal but fully functional plugin, perform the following steps:
- Within the
LspServerSupportProvider.fileOpened()
method, spin up the relevant LSP server descriptor, which can decide if the given file is supported by using theLspServerDescriptor.isSupportedFile()
check method. - Tell how to start the server by implementing
LspServerDescriptor.createCommandLine()
.
Customization
- To fine-tune or disable the implementation of LSP-based features, the plugins may override the corresponding properties of the
LspServerDescriptor
class. See the properties documentation for more details:lspGoToDefinitionSupport
lspCompletionSupport
lspDiagnosticsSupport
lspCodeActionsSupport
lspCommandsSupport
- To handle custom (undocumented) requests and notifications from the LSP server, override
LspServerDescriptor.createLsp4jClient
. - To send custom (undocumented) requests and notifications to the LSP server, override
LspServerDescriptor.lsp4jServerClass
and implement theLspClientNotification
and/orLspRequest
classes.
See bundled LSP API source code and its code documentation for more information.
Testing
Utility classes used for testing are not yet extracted for public use, but we’ll provide suitable methods for testing LSP-based third-party plugins as soon as possible.
Troubleshooting
All the IDE and LSP server communication logs are passed to the IDE log file.
To include them for preview, add the following entry to the Help | Diagnostic Tools | Debug Log Settings… configuration dialog:
#com.intellij.platform.lsp
For more information, see the Logging section in the IntelliJ Platform SDK documentation.
Limitations
- The current LSP API implementation assumes that the IDE <-> LSP server communication channel is
stdio
. - The IDE doesn’t send workspace/didChangeWatchedFiles notifications to the server.
Conclusion
Integrating the Language Server Protocol (LSP) into a plugin for IntelliJ-based IDEs involves a trade-off between simple and fast language support and a complex custom language support plugin with IDE capabilities.
When considering the LSP-based approach, it is important to assess the following criteria for providing a Language Server to end users:
- OS dependency of the Language Server.
- Availability of the latest version online.
- Compatibility with breaking changes between versions.
- Feasibility of requesting the user to provide the Language Server binary path.
Once the integration with the Language Server process is resolved, referring to the IntelliJ SDK Documentation is still important. This will provide a comprehensive overview of the available features for seamless integration with the LSP standard within the IntelliJ Platform.
Please note that the integration with the Language Server Protocol is created as an extension to the paid IntelliJ-based IDEs. Therefore, plugins utilizing Language Server integration may not be available in Community releases of JetBrains products and Android Studio from Google.
If you encounter any issues or need assistance, please provide feedback by reaching out to us through the #intellij-platform
channel in our JetBrains Platform Slack workspace or by submitting an issue in YouTrack.