Given a Kolasu parser, create a language server that communicates with lsp compliant code editors. Essentially providing editors for the language.
This repository contains four projects:
library
contains the code to create a language server and respond to lsp requests. Also contains helpers to test language server. These are published as JARs to Github packages.plugin
contains the code of a gradle plugin that takes care of adding all the dependencies and adds two tasks: One to create the vscode extension and another to launch it as development extension in an editor.examples/entity
is a toy example that uses the language server in its default configuration. Thanks to some conventions, a single line is enough to configure the language server in this case.examples/rpg
uses Strumenta's RPG parser and this library to create an editor for RPG files. It supports go to definition and references requests thanks to its symbol resolution module.
The easiest way to use this library is to:
- add this repository to the sources where gradle looks for plugins
- add the
com.strumenta.kolasu.language-server-plugin
versionx.y.z
to the list of gradle plugins - optionally configure the language server by adding a gradle extension called
languageServer
- run the
createVscodeExtension
gradle task - run the
launchVscodeEditor
gradle task
To enable debugging, specify the debugPort
property in the languageServer
gradle extension.
By default, it is set to null
to run in production mode.
When set to a valid port number, the underlying java process will listen on that port for debugger attachments.
To attach a debugger from idea
, create a Remote JVM Debug
debug configuration with the default configuration, but pointing to the port specified.
Now, run the launchVscodeEditor
task to open the editor and start the language server process.
While the editor is running, one can attach the debugger using the idea
task and the execution will stop in the language server breakpoints.
The debugger can be detached and reattached any number of times.
When the language server extension deactivates, for example because the editor is closed, the underlying java process is stopped and also the debugger task if attached.
If interested in debugging the initializing code, one can enable the suspendExecutionUntilDebuggerAttached
flag in the languageServer
gradle extension.
This way, the server process won't start until a debugger is attached.
Only a subset of the Language Server Protocol messages are supported for now.
Thankfully, most of the infrastructure messages are covered. These include:
- Lifecycle messages like initialize and exit
- Document synchronization messages like did open or change a file
- Workspace features like workspace symbols and file watchers
- Window features like showing notifications and progress of tasks
From here on, development can focus on implementing language features. For now, only definition
, references
and documentSymbols
are implemented and tested.
Many issues exist on the Github repository with considerations on where to take this project next.
Here is a table to explain the initialization process of the language server:
Client | Server | Notes |
---|---|---|
initialize(folders) | store folders | |
initialize(capabilities) | capabilities increase with symbol resolution module | |
didOpen(uri, text) | ignored since index is not initialized | |
documentSymbol(uri) | ignored since index is not initialized | |
setTrace(level) | store level | |
initialized() | ||
registerFileWatchers(folders, extensions) | client detects even files created outside the editor | |
registerConfigurationWatchers(section) | parsing behavior can be configured from the editor | |
didChangeConfiguration(configuration) | store configuration, reset index, parse all files in workspace and for each: | |
publishDiagnostics(uri, diagnostics[]) | ||
reportProgress(percent) | based on the amount of bytes parsed / total amount to parse |
If the language server has a symbol resolution module, its capabilities will include the definition
and find usages
features, otherwise only parsing errors and document outlines are reported.
These two are opposite operations and both rely on having a symbol resolution module in place.
They make heavy use of the lucene index that can be crafted to retrieve information from abstract syntax trees quickly.
Please note that the information in the index is stored more similarly to non-sql databases rather than a traditional tree.
This has its own benefits and problems. For showcasing both scenarios, outlines are creating traversing the tree. However, symbols are looked up using the index.
From the main branch run:
./gradlew release
This should move from the snapshot version to a normal version, create a git tag, publish the package on GitHub Packages, and move to the next snapshot version.