This guide walks through integrating lsp4intellij into your custom JetBrains plugin in detail. For the minimum viable integration, see the Quick Start in the README.
- 1. Add the
lsp4intellijdependency - 2. Add a
plugin.xmlfile - 3. Configure a startup activity
- 4. Confirm the language server connection
- Alternative ways to connect to a language server
- Custom initialization parameters
- Configuration
- Appendix: Legacy components-based setup
Include lsp4intellij in your project's build file. Instructions for popular build tools are available at jitpack/lsp4intellij.
Supported build tools:
- Gradle
- Maven
- SBT
Info: Maven Central publishing is a work in progress. Support for Maven Central will be available soon.
Define the required configurations in your plugin.xml file. Copy the example from resources/plugin.xml.example, place it under src/resources/META-INF, and adjust it as needed.
Add a startup activity to initialize and configure LSP support. On IntelliJ 2024.3+, PreloadingActivity is no longer run, so implement ProjectActivity and register it through the postStartupActivity extension point:
public class BallerinaStartupActivity implements ProjectActivity {
@Nullable
@Override
public Object execute(@NotNull Project project, @NotNull Continuation<? super Unit> continuation) {
IntellijLanguageClient.addServerDefinition(new RawCommandServerDefinition("bal", new String[]{"path/to/launcher-script.sh"}));
return Unit.INSTANCE;
}
}addServerDefinition registers the server application-wide and reconnects any editors that are already open, so running it once per project open is sufficient.
Update your plugin.xml to include the startup activity:
<extensions defaultExtensionNs="com.intellij">
<postStartupActivity implementation="io.ballerina.plugins.idea.preloading.BallerinaStartupActivity" />
</extensions>Tip: For other options instead of a startup activity, see IntelliJ Plugin initialization on startup.
After successfully connecting to the language server, a green icon will appear in the bottom-right corner of your IDE. Clicking on the icon will display connection details and timeouts.
Tip: A green icon in the IDE's bottom-right corner indicates a successful connection to the language server. Clicking on the icon will display connection details and timeouts.
In addition to RawCommandServerDefinition, several classes implement LanguageServerDefinition, allowing you to connect to a language server in different ways.
Note: All implementations use stdin/stdout for server communication.
The first argument is a file extension or a comma-separated list of file extensions (e.g., "ts,js"). Matching is based on file extensions only; filename patterns or regex-style values such as "application*.properties" are not supported by this API.
Example usage:
new RawCommandServerDefinition("bal", new String[]{"path/to/launcher-script.sh"});String[] command = new String[]{"java", "-jar", "path/to/language-server.jar"};
new RawCommandServerDefinition("bsl,os", command);This definition is an extended form of RawCommandServerDefinition that accepts java.lang.ProcessBuilder instances, giving you more control over the language server process.
You can specify one or more file extensions for a server definition. To associate multiple extensions with the same server, separate them with a comma (e.g., "ts,js").
Example usage:
ProcessBuilder process = new ProcessBuilder("path/to/launcher-script.sh");
new ProcessBuilderServerDefinition("bal", process);ProcessBuilder process = new ProcessBuilder("java", "-jar", "path/to/language-server.jar");
new ProcessBuilderServerDefinition("bsl,os", process);If your language server requires custom initialization options, extend ProcessBuilderServerDefinition or RawCommandServerDefinition and override the customizeInitializeParams method:
public class MyServerDefinition extends ProcessBuilderServerDefinition {
public MyServerDefinition(String ext, ProcessBuilder process) {
super(ext, process);
}
@Override
public void customizeInitializeParams(InitializeParams params) {
params.setClientInfo(new ClientInfo("MyName", "MyVersion"));
}
}Then assign your class as a server definition:
ProcessBuilder process = new ProcessBuilder("path/to/launcher-script.sh");
IntellijLanguageClient.addServerDefinition(new MyServerDefinition("xxx", process));See #311 for more details.
The LSP4IntelliJ language client applies the following default timeouts to LSP requests:
| Type | Default timeout (ms) |
|---|---|
| Code Actions | 2000 |
| Completion | 1000 |
| Goto Definition | 2000 |
| Execute Command | 2000 |
| Formatting | 2000 |
| Hover Support | 2000 |
| Initialization | 10000 |
| References | 2000 |
| Shutdown | 5000 |
| WillSave | 2000 |
The client exposes the following methods for inspecting and overriding these values at runtime:
-
getTimeouts()— returns the current timeout values (in milliseconds).Map<Timeouts, Integer> timeouts = IntellijLanguageClient.getTimeouts();
-
getTimeout(Timeouts timeoutType)— returns the current timeout value for a given type (in milliseconds).int timeout = IntellijLanguageClient.getTimeout(Timeouts.INIT);
-
setTimeouts(Map<Timeouts, Integer> newTimeouts)— overrides the defaults with a given set of timeout values.Map<Timeouts, Integer> newTimeouts = new HashMap<>(); newTimeouts.put(Timeouts.INIT, 15000); newTimeouts.put(Timeouts.COMPLETION, 1000); IntellijLanguageClient.setTimeouts(newTimeouts);
-
setTimeout(Timeouts timeout, int value)— overrides a single timeout value.IntellijLanguageClient.setTimeout(Timeouts.INIT, 15000);
Deprecated: This setup style is no longer recommended. New plugins should use the modern extension-based setup above. This appendix is preserved for older plugins that still use application components.
-
Add
IntellijLanguageClientas an application component:<application-components> <component> <implementation-class>org.wso2.lsp4intellij.IntellijLanguageClient</implementation-class> </component> </application-components>
-
Add the following extensions to enable individual features:
-
Code completion (replace the
languageattribute if you have your own custom language implementation):<extensions defaultExtensionNs="com.intellij"> <completion.contributor implementationClass="org.wso2.lsp4intellij.contributors.LSPCompletionContributor" id="LSPCompletionContributor" language="any"/> </extensions>
-
Code formatting:
<actions> <action class="org.wso2.lsp4intellij.actions.LSPReformatAction" id="ReformatCode" use-shortcut-of="ReformatCode" overrides="true" text="Reformat Code"/> <action class="org.wso2.lsp4intellij.actions.LSPShowReformatDialogAction" id="ShowReformatFileDialog" use-shortcut-of="ShowReformatFileDialog" overrides="true" text="Show Reformat File Dialog"/> </actions>
-
Diagnostics and code actions (replace the
languageattribute if you have your own custom language implementation):<extensions defaultExtensionNs="com.intellij"> <externalAnnotator id="LSPAnnotator" language="TEXT" implementationClass="org.wso2.lsp4intellij.contributors.annotator.LSPAnnotator"/> </extensions>
-
Find Usages:
<actions> <action class="org.wso2.lsp4intellij.actions.LSPReferencesAction" id="LSPFindUsages"> <keyboard-shortcut first-keystroke="shift alt F7" keymap="$default"/> </action> </actions>
-
Workspace symbols:
<extensions defaultExtensionNs="com.intellij"> <gotoSymbolContributor implementation="org.wso2.lsp4intellij.contributors.symbol.LSPSymbolContributor" id="LSPSymbolContributor"/> </extensions>
-
Renaming Support:
<extensions defaultExtensionNs="com.intellij"> <renameHandler implementation="org.wso2.lsp4intellij.contributors.rename.LSPRenameHandler" id="LSPRenameHandler" order="first"/> <renamePsiElementProcessor implementation="org.wso2.lsp4intellij.contributors.rename.LSPRenameProcessor" id="LSPRenameProcessor" order="first"/> </extensions>
-
Signature Help:
<extensions defaultExtensionNs="com.intellij"> <typedHandler implementation="org.wso2.lsp4intellij.listeners.LSPTypedHandler" id="LSPTypedHandler"/> </extensions>
-
Note: No additional configuration is required for the other features.

