Creating the SyntaxDocumentation Command - Part 3: VSCode Platform Extension
Software Engineer
In the final installment of our series on the SyntaxDocumentation
command, we delve into its integration within the OCaml VSCode Platform extension. Building on our previous discussions about Merlin and OCaml LSP, this article explores how to make SyntaxDocumentation
an opt-in feature in the popular VSCode editor.
In the first part of this series, Creating the SyntaxDocumentation Command - Part 1: Merlin, we explored how to create a new command in Merlin, particularly the SyntaxDocumentation
command. In the second part, Creating the SyntaxDocumentation Command - Part 2: OCaml LSP, we looked at how to implement this feature in OCaml LSP in order to enable visual editors to trigger the command with actions such as hovering. In this third and final installment, you will learn how SyntaxDocumentation
integrates into the OCaml VSCode Platform extension as an opt-in feature, enabling users to toggle it on/off depending on their preference.
VSCode Editor
Visual Studio Code is a free open-source, cross-platform code editor from Microsoft that is very popular among developers. Some of its features include:
- Built-in Git support
- Easy debugging of code right from the editor with an interactive console
- Built-in extension manager with lots of available extensions to download
- Supports a huge number of programming languages, including syntax highlighting
- Integrated terminal and many more features
OCaml Platform Extension for VSCode
The VSCode OCaml Platform extension enhances the development experience for OCaml programmers. It is itself written in the OCaml programming language using bindings to the VSCode API and then compiled into Javascript with js_of_ocaml
. It provides language support features such as syntax-highlighting
, go-to-definition
, auto-completion
, and type-on-hover
. These key functionalities are powered by the OCaml Language Server (ocamllsp
), which can be installed using popular package managers like opam and esy. Users can easily configure the extension to work with different sandbox environments, ensuring a tailored setup for various project needs. Additionally, the extension includes comprehensive settings and command options, making it very versatile for both beginner and advanced OCaml developers.
The OCaml Platform Extension for VSCode gives us a nice UI for interacting with OCaml-LSP. We can configure settings for the server as well as interact with switches, browse the AST, and many more features. Our main focus is on adding a checkbox
that allows users to activate or deactivate SyntaxDocumentation
in OCaml LSP's hover
response. I limited this article's scope to just the files relevant in implementing this, while giving a brief tour of how the extension is built.
The Implementation
Extension Manifest
Every VSCode extension has a manifest file, package.json, at the root of the extension directory. The package.json
contains a mix of Node.js fields, such as scripts and devDependencies
, and VS Code specific fields, like publisher
, activationEvents
, and contributes
.
Our manifest file contains general information such as:
- Name: OCaml Platform
- Description: Official OCaml language extension for VSCode
- Version: 1.14.2
- Publisher: OCaml Labs
- Categories: Programming Languages, Debuggers
We also have commands that act as action events for our extension. These commands are used to perform a wide range of things, like navigating the AST, upgrading packages, deleting a switch, etc. An example of a command to open the AST explorer is written as:
{
"command": "ocaml.open-ast-explorer-to-the-side",
"category": "OCaml",
"title": "Open AST explorer"
}
For our case, enabling/disabling SyntaxDocumentation
is a configuration setting for our language server, so we indicate this in the configurations section:
"ocaml.server.syntaxDocumentation": {
"type": "boolean",
"default": false,
"markdownDescription": "Enable/Disable syntax documentation"
}
Extension Instance
The file extension_instance.ml
handles the setup and configuration of various components of the OCaml VSCode extension and ensures that features like the language server and documentation are properly initialised. Its key functionalities are:
- Managing the Extension State: It uses a record type that encapsulates the state of the extension, holding information about the sandbox, REPL, OCaml version, LSP client, documentation server, and various other settings.
type t = {
mutable sandbox : Sandbox.t;
mutable repl : Terminal_sandbox.t option;
mutable ocaml_version : Ocaml_version.t option;
mutable lsp_client : (LanguageClient.t * Ocaml_lsp.t) option;
mutable documentation_server : Documentation_server.t option;
documentation_server_info : StatusBarItem.t;
sandbox_info : StatusBarItem.t;
ast_editor_state : Ast_editor_state.t;
mutable codelens : bool option;
mutable extended_hover : bool option;
mutable dune_diagnostics : bool option;
mutable syntax_documentation : bool option;
}
-
Interacting With the Language Server: This extension needs to interact with the OCaml language server (
ocamllsp
) to provide features like code completion, diagnostics, and other language-specific functionalities. -
Documentation Server Management: The file includes functionality to start, stop, and manage the documentation server, which provides documentation lookup for installed OCaml packages.
-
Handling Configuration: This extension allows users to configure settings such as code lens, extended hover, diagnostics, and syntax documentation. These settings are sent to the language server to adjust its behaviour accordingly. For
SyntaxDocumentation
, whenever the user toggles the checkbox, the server should set the correct configuration parameters. This is done mainly using two functionsset_configuration
andsend_configuration
.
...
(* Set configuration *)
let set_configuration t ~syntax_documentation =
t.syntax_documentation <- syntax_documentation;
match t.lsp_client with
| None -> ()
| Some (client, (_ : Ocaml_lsp.t)) ->
send_configuration ~syntax_documentation client
...
...
(* Send configuration *)
let send_configuration ~syntax_documentation client =
let syntaxDocumentation =
Option.map syntax_documentation ~f:(fun enable ->
Ocaml_lsp.OcamllspSettingEnable.create ~enable)
in
let settings =
Ocaml_lsp.OcamllspSettings.create
~syntaxDocumentation
in
let payload =
let settings =
LanguageClient.DidChangeConfiguration.create
~settings:(Ocaml_lsp.OcamllspSettings.t_to_js settings)
()
in
LanguageClient.DidChangeConfiguration.t_to_js settings
in
LanguageClient.sendNotification
client
"workspace/didChangeConfiguration"
payload
...
Interacting With OCaml LSP:
The ocaml_lsp.ml
file ensures that ocamllsp
is set up correctly and up to date. For SyntaxDocumentation
, two important modules used from this file are: OcamllspSettingEnable
and OcamllspSettings
.
OcamllspSettingEnable
defines an interface for enabling/disabling specific settings in ocamllsp
.
...
module OcamllspSettingEnable = struct
include Interface.Make ()
include
[%js:
val enable : t -> bool or_undefined [@@js.get]
val create : enable:bool -> t [@@js.builder]]
end
...
The annotation [@@js.get]
is a PPX used to bind OCaml functions to JavaScript property accessors. This allows OCaml code to interact seamlessly with JavaScript objects, accessing properties directly as if they were native OCaml fields, while [@@js.builder]
facilitates the creation of JavaScript objects from OCaml functions. They both come from the LexFi/gen_js_api
library.
OcamllspSettings
aggregrates multiple OcamllspSettingEnable
settings into a comprehensive settings interface for ocamllsp
.
...
module OcamllspSettings = struct
include Interface.Make ()
include
[%js:
val syntaxDocumentation : t ->
OcamllspSettingEnable.t or_undefined [@@js.get]
val create : ?syntaxDocumentation:OcamllspSettingEnable.t ->
unit -> t [@@js.builder]]
let create ~syntaxDocumentation = create ?syntaxDocumentation ()
end
...
Workspace Configuration
The file settings.ml
provides a flexible way to manage workspace-specific settings, including:
- Creating settings with JSON serialisation and deserialisation
- Retrieving and updating settings from the workspace configuration
- Resolving and substituting workspace variables within settings
- Defining specific settings for the OCaml language server, such as extra environment variables, server arguments, and features like
codelens
andSyntaxDocumentation
...
let create_setting ~scope ~key ~of_json ~to_json =
{ scope; key; to_json; of_json }
let server_syntaxDocumentation_setting =
create_setting
~scope:ConfigurationTarget.Workspace
~key:"ocaml.server.syntaxDocumentation"
~of_json:Jsonoo.Decode.bool
~to_json:Jsonoo.Encode.bool
...
Activating the Extension
The vscode_ocaml_platform.ml
file initialises and activates the OCaml Platform extension for VSCode. The key tasks include:
- Suggesting users select a sandbox environment
- Notifying the extension instance of configuration changes
- Registering various components and features of the extension
- Setting up the sandbox environment and starting the OCaml language server
In the context of SyntaxDocumentation
, this code ensures that the extension is correctly configured to handle SyntaxDocumentation
settings. The notify_configuration_changes
function listens for changes to the server_syntaxDocumentation_setting
and updates the extension instance accordingly. This means that any changes the user makes to the SyntaxDocumentation
settings in the VSCode workspace configuration will be reflected in the extension's behaviour, ensuring that SyntaxDocumentation
is enabled or disabled as per the user's preference.
let notify_configuration_changes instance =
Workspace.onDidChangeConfiguration
~listener:(fun _event ->
let syntax_documentation =
Settings.(get server_syntaxDocumentation_setting)
in
Extension_instance.set_configuration instance ~syntax_documentation)
()
Conclusion
In this final article, we explored how to integrate SyntaxDocumentation
into OCaml VSCode Platform extension as a configurable option for OCaml LSP's hover
command. We covered key components such as configuring the extension manifest, managing the extension state, interacting with the OCaml language server, and handling workspace configurations. By enabling users to toggle the SyntaxDocumentation
feature on or off, we can ensure a flexible and customisable development experience for all users.
Feel free to contribute to this extension on the GitHub repository: vscode-ocaml-platform
. Thank you for following along in this series, and happy coding with OCaml and VSCode!
Open-Source Development
Tarides champions open-source development. We create and maintain key features of the OCaml language in collaboration with the OCaml community. To learn more about how you can support our open-source work, discover our page on GitHub.
Stay Updated on OCaml and MirageOS!
Subscribe to our mailing list to receive the latest news from Tarides.
By signing up, you agree to receive emails from Tarides. You can unsubscribe at any time.