generated from redhat-developer/new-project-template
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #24 Signed-off-by: azerr <[email protected]>
- Loading branch information
1 parent
6b6e01d
commit 2b933c6
Showing
6 changed files
with
295 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
# Developer guide | ||
|
||
This section explains step by step how to add your own LSP language server in your IntelliJ plugin. | ||
|
||
## Reference LSP4IJ | ||
|
||
### plugin.xml | ||
|
||
The first step is to reference LSP4IJ. LSP4IJ uses `com.redhat.devtools.lsp4ij` as plugin Id. | ||
|
||
You need [to declare dependency in your plugin.xml](https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html#3-dependency-declaration-in-pluginxml) like this: | ||
|
||
```xml | ||
<idea-plugin> | ||
... | ||
|
||
<depends>com.redhat.devtools.lsp4ij</depends> | ||
|
||
... | ||
</idea-plugin> | ||
``` | ||
|
||
### Exclude all LSP4J dependencies | ||
|
||
LSP4IJ depends on [Eclipse LSP4J](https://github.com/eclipse-lsp4j/lsp4j) (Java binding for the [Language Server Protocol](https://microsoft.github.io/language-server-protocol) and the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol).). It uses a given version of LSPJ and their classes are loaded in the LSP4IJ plugin class loader. | ||
|
||
Your IntelliJ Plugin should use `the same LSP4J classes than LSP4IJ` to avoid some `ClassCastException` errors. To do that you need to `exclude all LSP4J dependencies` from your plugin. | ||
|
||
Here a sample used in [Quarkus Tools](https://github.com/redhat-developer/intellij-quarkus) in [build.gradle.kts](https://github.com/redhat-developer/intellij-quarkus/blob/main/build.gradle.kts) to exclude LSP4J dependency from the [Qute Language Server](https://github.com/redhat-developer/quarkus-ls/tree/master/qute.ls) which have a dependency to LSP4J: | ||
|
||
``` | ||
implementation("com.redhat.microprofile:com.redhat.qute.ls:0.17.0) { | ||
exclude("org.eclipse.lsp4j") | ||
} | ||
``` | ||
|
||
## Declare server | ||
|
||
|
||
### StreamConnectionProvider Implementation | ||
|
||
You need to implement the [StreamConnectionProvider](https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/server/StreamConnectionProvider.java) API which manages: | ||
|
||
* start of your language server | ||
* returns the input/error stream of LSP requests, responses, notifications. | ||
|
||
Generally, the language server is started with a process by using a runtime like Java, NodeJS, etc. In this case you need to extend [ProcessStreamConnectionProvider](https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/server/ProcessStreamConnectionProvider.java) | ||
|
||
Here a basic sample which starts the `path/to/my/language/server/main.js` language server written in JavaScript with NodeJS runtime "path/to/nodejs/node.exe": | ||
|
||
```java | ||
package my.language.server; | ||
|
||
import com.redhat.devtools.lsp4ij.server.ProcessStreamConnectionProvider; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class MyLanguageServer extends ProcessStreamConnectionProvider { | ||
|
||
public MyLanguageServer() { | ||
List<String> commands = Arrays.asList("path/to/nodejs/node.exe", "path/to/my/language/server/main.js"); | ||
super.setCommands(commands); | ||
} | ||
} | ||
``` | ||
|
||
If your language server is written in Java, to build the command, you can use [JavaProcessCommandBuilder](https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/server/JavaProcessCommandBuilder.java): | ||
|
||
```java | ||
package my.language.server; | ||
|
||
import com.intellij.openapi.project.Project; | ||
import com.redhat.devtools.lsp4ij.server.JavaProcessCommandBuilder; | ||
import com.redhat.devtools.lsp4ij.server.ProcessStreamConnectionProvider; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class MyLanguageServer extends ProcessStreamConnectionProvider { | ||
|
||
public MyLanguageServer(Project project) { | ||
List<String> commands = new JavaProcessCommandBuilder(project, "myLanguageServerId") | ||
.setJar("path/to/my/language/server/main.java") | ||
.create(); | ||
super.setCommands(commands); | ||
} | ||
} | ||
``` | ||
|
||
This builder takes care of filling command with Java runtime and generate the command with debug if the settings of the language server `myLanguageServerId` defines a debug port. | ||
|
||
You can see a full sample with [QuteServer](https://github.com/redhat-developer/intellij-quarkus/blob/main/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteServer.java) | ||
|
||
### LanguageClientImpl | ||
|
||
It is not required but you can override the [LanguageClientImpl](https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/client/LanguageClientImpl.java) to for instance: | ||
|
||
* some IJ listeners when language client is created | ||
* override some LSP methods | ||
|
||
```java | ||
package my.language.server; | ||
|
||
import com.intellij.openapi.project.Project; | ||
import com.redhat.devtools.lsp4ij.client.LanguageClientImpl; | ||
|
||
public class MyLanguageClient extends LanguageClientImpl { | ||
public MyLanguageClient(Project project) { | ||
super(project); | ||
} | ||
} | ||
``` | ||
|
||
If your language server manages custom LSP requests, it is advised to extend [IndexAwareLanguageClient](https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/client/IndexAwareLanguageClient.java) | ||
|
||
You can see a full sample with [QuteLanguageClient](https://github.com/redhat-developer/intellij-quarkus/blob/main/src/main/java/com/redhat/devtools/intellij/qute/lsp/QuteLanguageClient.java) | ||
|
||
## Declare server with extension point | ||
|
||
The last step is to declare the server in your plugin.xml with `com.redhat.devtools.lsp4ij.server` extension point | ||
to use your `my.language.server.MyLanguageServer` and `my.language.server.MyLanguageClient`: | ||
|
||
```xml | ||
<idea-plugin> | ||
|
||
<extensions defaultExtensionNs="com.redhat.devtools.lsp4ij"> | ||
<server id="myLanguageServerId" | ||
label="My Language Server" | ||
class="my.language.server.MyLanguageServer" | ||
clientImpl="my.language.server.MyLanguageClient" | ||
scope="project"> | ||
<description><![CDATA[ | ||
Some description written in HTML to display it in LSP consoles and Language Servers settings. | ||
]]> | ||
</description> | ||
</server> | ||
</extensions> | ||
|
||
</idea-plugin> | ||
``` | ||
|
||
Once the declaration is done, your server should appear in the LSP console: | ||
|
||
![My LanguageServer in LSP Console](./images/MyLanguageServerInLSPConsole.png) | ||
|
||
## Declare language mapping with extension point | ||
|
||
Once server is defined, you need to associate an IntelliJ language with the `server` defined by the id attribute | ||
with `com.redhat.devtools.lsp4ij.languageMapping` extension point. | ||
|
||
Here a sample which associates the `XML` language with the `myLanguageServerId` server: | ||
|
||
```xml | ||
</idea-plugin> | ||
|
||
<extensions defaultExtensionNs="com.redhat.devtools.lsp4ij"> | ||
|
||
<languageMapping language="XML" | ||
serverId="myLanguageServerId" /> | ||
|
||
</extensions> | ||
``` | ||
|
||
If the language check is not enough, you can implement a [DocumentMatcher](https://github.com/redhat-developer/lsp4ij/blob/main/src/main/java/com/redhat/devtools/lsp4ij/DocumentMatcher.java) to implement some check in Java code. | ||
For instance our language server could map `Java` as language and you could implement a DocumentMatcher | ||
to check if the module of the file have some Java class in the classpath. | ||
|
||
The DocumentMatcher is executed in a non blocking read action. | ||
|
||
A document matcher looks like this: | ||
|
||
```java | ||
package my.language.server; | ||
|
||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.vfs.VirtualFile; | ||
import com.redhat.devtools.lsp4ij.AbstractDocumentMatcher; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class MyDocumentMatcher extends AbstractDocumentMatcher { | ||
|
||
@Override | ||
public boolean match(@NotNull VirtualFile virtualFile, @NotNull Project project) { | ||
return true; | ||
} | ||
} | ||
``` | ||
|
||
and it must be registered in language mapping with `documentMatcher` attribute: | ||
|
||
```xml | ||
</idea-plugin> | ||
|
||
<extensions defaultExtensionNs="com.redhat.devtools.lsp4ij"> | ||
|
||
<languageMapping language="XML" | ||
serverId="myLanguageServerId" | ||
documentMatcher="my.language.server.MyDocumentMatcher" /> | ||
|
||
</extensions> | ||
``` | ||
|
||
## Supported LSP features | ||
|
||
Here the current supported LSP features: | ||
|
||
| LSP support | Implemented with | Action required | | ||
|---------------------------------|--------------------------------------------|-----------------| | ||
| textDocument/publishDiagnostics | externalAnnotator | No | | ||
| textDocument/completion | completion.contributor | No | | ||
| textDocument/definition | gotoDeclarationHandler | No | | ||
| textDocument/documentLink | externalAnnotator + gotoDeclarationHandler | No | | ||
| textDocument/documentHighlight | highlightUsagesHandlerFactory | No | | ||
| textDocument/hover | lang.documentationProvider | Yes | | ||
| textDocument/codeLens | codeInsight.inlayProvider | Yes | | ||
| textDocument/inlayHint | codeInsight.inlayProvider | Yes | | ||
|
||
When it is possible, LSP4IJ declare the IJ feature with language any (see Action required with No). | ||
For instance `textDocument/publishDiagnostics` is managed with `externalAnnotator` in LSP4IJ with empty language to support any language: | ||
|
||
```xml | ||
<!-- LSP textDocument/publishDiagnostics notification support --> | ||
<externalAnnotator | ||
id="LSPDiagnosticAnnotator" | ||
language="" | ||
implementationClass="com.redhat.devtools.lsp4ij.operations.diagnostics.LSPDiagnosticAnnotator"/> | ||
``` | ||
|
||
Some IJ feature cannot use any language, so you need to declare it in your plugin (see Action required with Yes): | ||
|
||
* `textDocument/hover`: | ||
|
||
```xml | ||
<lang.documentationProvider | ||
language="MyLanguage" | ||
implementationClass="com.redhat.devtools.lsp4ij.operations.documentation.LSPDocumentationProvider" | ||
order="first"/> | ||
``` | ||
|
||
* `textDocument/codeLens`: | ||
|
||
```xml | ||
<codeInsight.inlayProvider | ||
language="MyLanguage" | ||
implementationClass="com.redhat.devtools.lsp4ij.operations.codelens.LSPCodelensInlayProvider"/> | ||
``` | ||
|
||
* `textDocument/inlayHint`: | ||
|
||
```xml | ||
<codeInsight.inlayProvider | ||
language="MyLanguage" | ||
implementationClass="com.redhat.devtools.lsp4ij.operations.codelens.LSPInlayHintInlayProvider"/> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# User guide | ||
|
||
## LSP console | ||
|
||
|
||
|
||
## Language Servers preferences | ||
|
||
The preference page under `Preferences | Languages & Frameworks | Language Servers` allows power users | ||
to configure language servers debugging and tracing: | ||
|
||
: |
File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters