Extend jupyterlab-lsp#
How to add a new LSP feature?#
Features (as well as other parts of the frontend) reuse the
JupyterLab plugins system.
Each plugin is a TypeScript package exporting
one or more JupyterFrontEndPlugins (see
the JupyterLab extesion developer tutorial
for an overview).
Each feature has to register itself with the FeatureManager (which is provided
after requesting ILSPFeatureManager token from @jupyterlab/lsp) using
register(options: IFeatureOptions) method.
The feature specification should follow the IFeature interface as of
JupyterLab 4.0, including:
id: unique identifier of the feature, we recommend@organization/project:featurepatterncapabilities: an optional object defining the client capabilities implemented by your feature,
See JupyterLab Extension Points >> LSP Features documentation for more details.
How to override the default implementation of a feature?#
You can specify a list of plugins implementing features which you want to
disable in jupyterlab.disabledExtensions stanza of
package.json, for example:
"jupyterlab": {
"disabledExtensions": ["@jupyter-lsp/jupyterlab-lsp:hover"]
}
will disable the hover feature.
How to add a custom magic or foreign extractor?#
It is now possible to register custom code replacements using
ILSPCodeOverridesManager token and to register custom foreign code extractors
using ILSPCodeExtractorsManager token, however this API is considered
provisional and subject to change.
Future plans for transclusions handling#
We welcome pull requests enabling kernels to register their custom syntax/code transformations. The frontend API will remain available for the end-users who write their custom syntax modifications with actionable side-effects (e.g. a custom IPython magic which copies a variable from the host document to the embedded document).
How to add custom icons for the completer?#
Prepare the icons in the SVG format (we use 16 x 16 pixels, but you should be fine with up to 24 x 24). You can load them for webpack in typescript using imports if you include a
typings.d.tsfile with the following content:declare module '*.svg' { const script: string; export default script; }
in your
src/. You should probably keep the icons in yourstyle/directory.Prepare
CompletionKind→IconSvgStringmapping for the light (and optionally dark) theme, implementing theICompletionIconSetinterface. We have an additionalKernelcompletion kind that is used for completions provided by kernel that had no recognizable type provided.Provide all other metadata required by the
ICompletionThemeinterface and register it onILSPCompletionThemeManagerinstance usingregister_theme()method.Provide any additional CSS styling targeting the JupyterLab completer elements inside of
.lsp-completer-theme-{id}, e.g..lsp-completer-theme-material .jp-Completer-icon svgfor the material theme. Remember to include the styles by importing the in one of the source files.
For an example of a complete theme see theme-vscode.
Migrating to v5.0#
IFeatureinterface was moved to@jupyterlab/lsplabIntegrationwas removed,editorIntegrationFactorywas removed in JupyterLab 4.0 and restored in JupyterLab 4.1 asextensionFactorywith new API (ILSPEditorExtensionFactory),supersedeswas removed; you can disable extensions using the JupyterLab nativejupyterlab.disabledExtensionsstanza ofpackage.json.
ILSPCompletionThemeManager:register_theme()was renamed toregisterTheme()all other methods were renamed to follow camelCase convention
Extend jupyter-lsp#
Language Server Specs#
Language Server Specs can be configured by Jupyter users, or distributed by third parties as python or JSON files. Since we’d like to see as many Language Servers work out of the box as possible, consider contributing a spec, if it works well for you!
Message Listeners#
Message listeners may choose to receive LSP messages immediately after being
received from the client (e.g. jupyterlab-lsp) or a language server. All
listeners of a message are scheduled concurrently, and the message is passed
along once all listeners return (or fail). This allows listeners to, for
example, modify files on disk before the language server reads them.
If a listener is going to perform an expensive activity that shouldn’t block delivery of a message, a non-blocking technique like IOLoop.add_callback and/or a queue should be used.
Add a Listener with entry_points#
Listeners can be added via entry_points by a package installed in the same
environment as notebook:
## setup.cfg
[options.entry_points]
jupyter_lsp_listener_all_v1 =
some-unique-name = some.module:some_function
jupyter_lsp_listener_client_v1 =
some-other-unique-name = some.module:some_other_function
jupyter_lsp_listener_server_v1 =
yet-another-unique-name = some.module:yet_another_function
At present, the entry point names generally have no impact on functionality aside from logging in the event of an error on import.
Add a Listener with Jupyter Configuration#
Listeners can be added via traitlets configuration, e.g.
## jupyter_server_config.jsons
{
'LanguageServerManager':
{
'all_listeners': ['some.module.some_function'],
'client_listeners': ['some.module.some_other_function'],
'server_listeners': ['some.module.yet_another_function']
}
}
Add a listener with the Python API#
lsp_message_listener can be used as a decorator, accessed as part of a
serverextension.
This listener receives all messages from the client and server, and prints them out.
from jupyter_lsp import lsp_message_listener
def load_jupyter_server_extension(nbapp):
@lsp_message_listener("all")
async def my_listener(scope, message, language_server, manager):
print("received a {} {} message from {}".format(
scope, message["method"], language_server
))
scope is one of client, server or all, and is required.
Listener options#
Fine-grained controls are available as part of the Python API. Pass these as
named arguments to lsp_message_listener.
language_server: a regular expression of language serversmethod: a regular expression of LSP JSON-RPC method names