diff --git a/README.md b/README.md index 7604b5446..e65c71ca5 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,26 @@ For an example of usage of the server in a VS Code extension, see OCaml Platform Extension implementation [here](https://github.com/ocamllabs/vscode-ocaml-platform/blob/master/src/vscode_ocaml_platform.ml). +### Merlin configuration (advanced) + +If you would like OCaml-LSP to respect your `.merlin` files, OCaml-LSP needs to +be invoked with `--fallback-read-dot-merlin` argument passed to it. + ## Features + + The server supports the following LSP requests: - [x] `textDocument/completion` @@ -85,14 +103,125 @@ The server supports the following LSP requests: Note that degrees of support for each LSP request are varying. +### Semantic highlighting + +OCaml-LSP implements experimental semantic highlighting support (also known as +semantic tokens support). The support can be activated by passing an evironment +variable to OCaml-LSP: + +- To enable non-incremental (expectedly slower but more stable) version, pass + `OCAMLLSP_SEMANTIC_HIGHLIGHTING=full` environment variable to OCaml-LSP. + +- To enable incremental (potentially faster but more error-prone, at least on VS + Code) version, pass `OCAMLLSP_SEMANTIC_HIGHLIGHTING=full/delta` to OCaml-LSP. + +Tip (for VS Code OCaml Platform users): You can use `ocaml.server.extraEnv` +setting in VS Code to pass various environment variables to OCaml-LSP. + +```json +{ + "ocaml.server.extraEnv": { + "OCAMLLSP_SEMANTIC_HIGHLIGHTING": "full" + }, +} +``` + +### LSP Extensions + The server also supports a number of OCaml specific extensions to the protocol: -- [Infer interface](ocaml-lsp-server/docs/ocamllsp/inferIntf-spec.md) - [Switch to implementation/interface](ocaml-lsp-server/docs/ocamllsp/switchImplIntf-spec.md) +- [Infer interface](ocaml-lsp-server/docs/ocamllsp/inferIntf-spec.md) - [Locate typed holes](ocaml-lsp-server/docs/ocamllsp/typedHoles-spec.md) - [Find wrapping AST node](ocaml-lsp-server/docs/ocamllsp/wrappingAstNode-spec.md) Note that editor support for these extensions varies. In general, the OCaml Platform extension for Visual Studio Code will have the best support. +### Unorthodox features + +#### Destructing a value + +OCaml-LSP has a code action that allows to generate an exhaustive pattern +matching for values. For example, placing a cursor near a value `(Some 10)|` +where `|` is your cursor, OCaml-LSP will offer a code action "Destruct", which +replaces `(Some 10)` with `(match Some with | None -> _ | Some _ -> _)`. +Importantly, one can only destruct a value if OCaml-LSP can infer the value's +precise type. The value can be type-annotated, e.g., if it's a function argument +with polymorphic (or yet unknown) type in this context. In the code snippet +below, we type-annotate the function parameter `v` because when we type `let f v += v|`, the type of `v` is polymorphic, so we can't destruct it. + +You can also usually destruct the value by placing the cursor on the wildcard +(`_`) pattern in a pattern-match. For example, + +```ocaml +type t = A | B of string option + +let f (v : t) = match v with | A -> _ | B _| -> _ +``` + +invoking destruct near the cursor (`|`) in the snippet above, you get + +```ocaml +type t = A | B of string option + +let f (v : t) = match v with | A -> _ | B (None) | B (Some _) -> _ +``` + +Importantly, note the undescores in place of expressions in each branch of the +pattern match above. The underscores that occur in place of expressions are +called "typed holes" - a concept explained below. + +Tip (formatting): generated code may not be greatly formatted. If your project +uses a formatter such as OCamlFormat, you can run formatting and get a +well-formatted document (OCamlFormat supports typed holes formatting). + +Tip (for VS Code OCaml Platform users): You can destruct a value using a keybinding +Alt+D or on MacOS Option+D + +#### Typed holes + +OCaml-LSP has a concept of a "typed hole" syntactically represented as `_` +(underscore). A typed hole represents a well-typed "substitute" for an +expression. OCaml-LSP considers these underscores that occur in place of +expressions as a valid well-typed OCaml program: `let foo : int = _` (the typed +hole has type `int` here) or `let bar = _ 10` (the hole has type `int -> 'a`). +One can use such holes during development as temporary substitutes for +expressions and "plug" the holes later with appropriate expressions. + +Note, files that incorporate typed holes are *not* considered valid OCaml by the +OCaml compiler and, hence, cannot be compiled. + +Also, an underscore occurring in place of a pattern (for example `let _ = 10`) +should not be confused with a typed hole that occurs in place of an expression, +e.g., `let a = _`. + +#### Constructing values by type (experimental) + +OCaml-LSP can "construct" expressions based on the type required and offer them +during auto-completion. For example, typing `_` (typed hole) in the snippet +below will trigger auto-completion (`|` is your cursor): + +```ocaml +(* file foo.ml *) +type t = A | B of string option + +(* file bar.ml *) +let v : Foo.t = _| +``` + +The auto-completion offers completions `Foo.A` and `Foo.B _`. You can further +construct values by placing the cursor as such: `Foo.B _|` and triggering code +action "Construct an expression" which offers completions `None` and `Some _`. +Trigger the same code action in `Some _|` will offer `""` - one of the possible +expressions to replace the typed hole with. + +Constructing a value is thus triggered either by typing `_` in place of an +expression or trigger the code action "Construct an Expression". Also, the type +of the value needs to be non-polymorphic to construct a meaningful value. + +Tip (for VS Code OCaml Platform users): You can construct a value using a keybinding +Alt+C or on MacOS Option+C + ## Integration with other tools ### Source file formatting: OCamlFormat & Refmt @@ -104,7 +233,7 @@ formatting support. Note, however, that OCaml-LSP requires presence of OCamlFormat configuration file, called `.ocamlformat`, in the project root to be able to format source files in your project. -### Formatting code on hover +### Formatting code on hover When you hover the cursor over OCaml code, the extension shows you the type of the symbol. To get nicely formatted types, install @@ -174,8 +303,9 @@ the lsp protocol covers a wider scope than merlin. ## Comparison to other LSP Servers for OCaml -Note that the comparisons below makes no claims of being objective and may be -entirely out of date: +Note that the comparisons below make no claims of being objective and may be +entirely out of +date. Also, both servers seem deprecated. - [reason-language-server](https://github.com/jaredly/reason-language-server) This server supports diff --git a/ocaml-lsp-server/docs/ocamllsp/inferIntf-spec.md b/ocaml-lsp-server/docs/ocamllsp/inferIntf-spec.md index ae88f2415..1da302e65 100644 --- a/ocaml-lsp-server/docs/ocamllsp/inferIntf-spec.md +++ b/ocaml-lsp-server/docs/ocamllsp/inferIntf-spec.md @@ -1,4 +1,4 @@ -#### Infer Interface Request +# Infer Interface Request Infer Interface Request is sent from the client to the server to get the infered interface for a given module implementation. @@ -10,21 +10,21 @@ If the file cannot be found in the document store, an error will be returned. Warning: this custom request is meant to be consumed by `ocaml-vscode-platform` exclusively, it can be removed any time and should not be relied on. -##### Client capability +## Client capability nothing that should be noted -##### Server capability +## Server capability property name: `handleInferIntf` property type: `boolean` -##### Request +## Request - method: `ocamllsp/inferIntf` - params: `DocumentUri` (see [`DocumentUri`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#uri) in LSP specification) -##### Response +## Response - result: String - error: code and message set in case an exception happens during the processing of the request. diff --git a/ocaml-lsp-server/docs/ocamllsp/switchImplIntf-spec.md b/ocaml-lsp-server/docs/ocamllsp/switchImplIntf-spec.md index 819b885ac..9eef06f95 100644 --- a/ocaml-lsp-server/docs/ocamllsp/switchImplIntf-spec.md +++ b/ocaml-lsp-server/docs/ocamllsp/switchImplIntf-spec.md @@ -1,4 +1,4 @@ -#### Switch Implementation/Interface Request +# Switch Implementation/Interface Request Switch Implementation/Interface Request is sent from client to server to get URI(s) of the file(s) that the current file can switch to, e.g., if the user @@ -12,22 +12,22 @@ for creation is returned, e.g., if a user wants to switch from "foo.ml", but no files already exist in the project that could be returned, a URI for "foo.mli" is returned. -##### Client capability +## Client capability nothing that should be noted -##### Server capability +## Server capability property name: `handleSwitchImplIntf` property type: `boolean` -##### Request +## Request - method: `ocamllsp/switchImplIntf` - params: `DocumentUri` (see [`DocumentUri`](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#uri) in LSP specification) -##### Response +## Response - result: DocumentUri[] (non-empty) - error: code and message set in case an exception happens during the `ocamllsp/switchImplIntf` request. diff --git a/ocaml-lsp-server/docs/ocamllsp/wrappingAstNode-spec.md b/ocaml-lsp-server/docs/ocamllsp/wrappingAstNode-spec.md index cbb562ed1..3a3525d7c 100644 --- a/ocaml-lsp-server/docs/ocamllsp/wrappingAstNode-spec.md +++ b/ocaml-lsp-server/docs/ocamllsp/wrappingAstNode-spec.md @@ -1,4 +1,6 @@ -#### Wrapping AST Node +# Wrapping AST Node + +## Description (Could also be named `Enclosing AST Node`) @@ -30,16 +32,16 @@ The document URI in the request has to be open before sending a the request. If Note: stability of this custom request is not guaranteed. Talk to the maintainers if you want to depend on it. -##### Client capability +## Client capability nothing that should be noted -##### Server capability +## Server capability property name: `handleWrappingAstNode` property type: `boolean` -##### Request +## Request - method: `ocamllsp/wrappingAstNode` - params: @@ -51,7 +53,7 @@ property type: `boolean` } ``` -##### Response +## Response - result: `Range | null` - error: code and message set in case an exception happens during the processing of the request.