mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-16 10:15:17 +00:00
Refactor external language server registration
* Apply object-oriented design * Establish common interface via protocol LanguageServerIdLike * Move all registration concerns to LanguageServerRegistry
This commit is contained in:
1 parent
6000f16680
commit
283140e7ae
26 files changed
+301
-978
No files matched your search
@@ -190,11 +190,9 @@ Some languages require additional installations or setup steps, as noted.
|
||||
* **Zig**
|
||||
(requires installation of ZLS - Zig Language Server)
|
||||
|
||||
Support for further languages can be added either as a built-in Serena language-server implementation or as an external Python adapter.
|
||||
External adapters are supplied by installed packages and registered through the
|
||||
[external language-server adapter](030_external_language_server_adapters) entry-point mechanism.
|
||||
The external mechanism does not participate in automatic language detection; add the registered ID explicitly to `project.yml`.
|
||||
For built-in integrations, see Serena's [guide for adding new language support](https://github.com/oraios/serena/blob/main/.serena/memories/adding_new_language_support_guide.md).
|
||||
Additional language servers can easily be supported by providing an adapter implementation;
|
||||
see our [contribution guide](https://github.com/oraios/serena/blob/main/CONTRIBUTING.md).
|
||||
If you need to support a custom language server which is not yet publicly available, you have the option to [register an external language server](external-ls-registration).
|
||||
|
||||
## The Serena JetBrains Plugin
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
# External Language Server Adapters
|
||||
|
||||
Serena can load language-server integrations provided by installed Python packages. This lets a project use an external language server without adding its adapter to the Serena core.
|
||||
|
||||
## How It Works
|
||||
|
||||
An adapter package exposes a Python entry point in the `serena.language_servers` group:
|
||||
|
||||
```toml
|
||||
[project.entry-points."serena.language_servers"]
|
||||
example = "example_serena_adapter:register"
|
||||
```
|
||||
|
||||
Serena discovers these entry points with Python's `importlib.metadata.entry_points()` at the regular `ProjectConfig.load()` lifecycle boundary. The loaded registration function provides the actual Python `SolidLanguageServer` implementation and calls the existing registry API:
|
||||
|
||||
```python
|
||||
from solidlsp.ls_config import FilenameMatcher, register_ls
|
||||
|
||||
|
||||
def register() -> None:
|
||||
register_ls(
|
||||
id="example",
|
||||
matcher=FilenameMatcher(".example"),
|
||||
implementation=ExampleLanguageServer,
|
||||
)
|
||||
```
|
||||
|
||||
Several external adapters can be installed and registered at the same time. Their IDs can then be used in a project's `.serena/project.yml`:
|
||||
|
||||
```yaml
|
||||
language_servers:
|
||||
- example
|
||||
```
|
||||
|
||||
The registered implementation is started and managed by Serena. Serena launches the external server using the adapter's process configuration; it does not search for already-running LSP processes.
|
||||
|
||||
## Trust and Security
|
||||
|
||||
Only entry points exposed by installed Python packages are considered. Project configuration does not import Python code, accept arbitrary module paths, or perform filesystem-based plugin discovery. Serena does not install plugins automatically or download adapters from a marketplace.
|
||||
|
||||
An installed adapter contains executable Python code and therefore has the same trust implications as any other installed Python package. Install adapters only from sources you trust. The project can reference a registered ID, but it cannot cause an arbitrary Python module to be loaded through `project.yml`.
|
||||
|
||||
## Errors and IDs
|
||||
|
||||
The first discovery is serialized across concurrent project loads and completes once entry-point metadata has been read successfully. A failure while reading the installed entry-point metadata is reported and leaves discovery retryable. If one adapter fails while loading or registering, Serena reports the entry-point name and distribution when available, rolls back that adapter's registrations, and continues loading other adapters.
|
||||
|
||||
A failed adapter ID is not available afterward. If a project references it, normal language-server configuration validation reports an unknown ID. Registered IDs must be unique and cannot replace a built-in Serena language-server ID.
|
||||
|
||||
Adapter IDs must be non-empty, trimmed, and lowercase. Each external `SolidLanguageServer` implementation class can be registered under only one external ID.
|
||||
|
||||
## Built-in and External Integrations
|
||||
|
||||
Built-in Serena language servers are implemented and mapped inside the Serena distribution and use the existing built-in language-server IDs. An external adapter is implemented in its own Python package, registers its ID through the entry-point contract above, and supplies the integration required to launch and communicate with its language server.
|
||||
|
||||
This mechanism does not change Serena's language auto-detection. External adapters are available when explicitly registered and referenced in project configuration.
|
||||
@@ -47,7 +47,7 @@ The file allows you to configure ...
|
||||
* the name by which you want to refer to the project (relevant when telling the LLM to dynamically activate the project)
|
||||
* the set of built-in language servers and explicitly registered external adapters for which servers are spawned
|
||||
(not relevant when using the JetBrains plugin). External adapter IDs become available after their Python package is installed;
|
||||
see [External Language Server Adapters](../01-about/030_external_language_server_adapters).
|
||||
see [External Language Server Adapters](../03-special-guides/external_language_server_registration.md).
|
||||
The [Dashboard](060_dashboard) can dynamically add or remove built-in language servers and installed, registered external
|
||||
adapters while Serena is running. It does not install adapter packages or offer unregistered adapter IDs.
|
||||
* the [language backend](per-project-language-backend) to use for this project (overriding the global setting)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# Special Guides
|
||||
|
||||
This section contains special guides for certain topics that require more in-depth explanations.
|
||||
This section contains special guides for certain topics that require more in-depth explanations
|
||||
or are too specific to be included in the main documentation. These guides are meant to provide additional context and instructions for users who need them.
|
||||
@@ -0,0 +1,55 @@
|
||||
(external-ls-registration)=
|
||||
# External Language Server Registration
|
||||
|
||||
SolidLSP, Serena's language server framework, is designed to be extensible.
|
||||
Sometimes, you may need to use Serena with a language server for which there can be no built-in adapter,
|
||||
e.g. because the language server in question is a custom development which is not yet released.
|
||||
|
||||
The general mechanism to make SolidLSP aware of an external language server is to use the
|
||||
`LanguageServerRegistry` in order to register an `ExternalLanguageServerId`.
|
||||
|
||||
You can either do this
|
||||
* programmatically, in your own Python code, if you are launching Serena via a custom script
|
||||
where this code can be executed before Serena itself is started, or
|
||||
* via a Python package that exposes a `solidlsp.language_server_registration` entry point.
|
||||
If the Python package is installed in the same environment as Serena,
|
||||
the language server will be automatically registered when Serena starts.
|
||||
|
||||
## Registering an External Language Server via a Python Package
|
||||
|
||||
Expose a Python entry point in the `solidlsp.language_server_registration` group (`pyproject.toml`):
|
||||
|
||||
```toml
|
||||
[project.entry-points."solidlsp.language_server_registration"]
|
||||
example = "myls:register_myls"
|
||||
```
|
||||
|
||||
Corresponding contents of `myls/__init__.py`:
|
||||
|
||||
```python
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import FilenameMatcher, LanguageServerRegistry, ExternalLanguageServerId
|
||||
|
||||
|
||||
class MyLanguageServerImpl(SolidLanguageServer):
|
||||
# implementation of the language server adapter
|
||||
pass
|
||||
|
||||
|
||||
def register_myls() -> None:
|
||||
LanguageServerRegistry.get_instance().register(
|
||||
ExternalLanguageServerId(
|
||||
key="myls",
|
||||
matcher=FilenameMatcher(".example"),
|
||||
implementation=MyLanguageServerImpl
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
The registered key `myls` can subsequently be used in a project's configuration file (`project.yml`)
|
||||
like any other language server:
|
||||
|
||||
```yaml
|
||||
language_servers:
|
||||
- myls
|
||||
```
|
||||
Reference in new issue
Block a user