Skip to content

Commit

Permalink
Merge branch 'master' into louis/hover-verbosity
Browse files Browse the repository at this point in the history
* master:
  fix(go-to-def): report error in response (ocaml#899)
  Update readme (ocaml#895)
  chore(nix): update flakes and dune-release (ocaml#894)
  chore: remove ocamlformat-rpc (ocaml#892)
  chore(nix): pass opam-repository and nixpkgs (ocaml#893)
  chore: unvendor ocamlc-loc (ocaml#869)
  fix: merlin document safety (ocaml#890)
  chore: more precise CHANGES (ocaml#889)
  fix: diagnostics on non dune files (ocaml#887)
  refactor: remove Document.is_merlin (ocaml#888)
  fix: symbols in non merlin docs (ocaml#886)
  refactor: style tweaks in document_symbol (ocaml#885)
  fix: handle incorrect document types (ocaml#884)
  Ignore unknown config tags (ocaml#883)
  Make sure nodejs packages required are installed
  chore: prepare 1.14.0
  Don't let opam ask when not needed
  Allow copy-and-paste of contributing instructions
  Add code action for inlining (ocaml#847)
  Add note about protocol extensions to the readme
  • Loading branch information
Khady committed Nov 4, 2022
2 parents 427370b + 2d140c8 commit 1813ecd
Show file tree
Hide file tree
Showing 47 changed files with 2,104 additions and 804 deletions.
5 changes: 0 additions & 5 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
[submodule "submodules/dune"]
path = submodules/dune
url = https://github.com/rgrinberg/jbuilder
branch=lsp
ignore=dirty
14 changes: 13 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
# Unreleased
# 1.14.1

## Fixes

- Fix various server crashes when opening non OCaml/Reason files. Files such as
dune, cram, etc. would cause the server to crash. (#884, fixes #871)

- Ignore unknown tags in merlin configuration to improve forward compatibility
with Dune. (#883)

# 1.14.0

## Features

- Code action for inlining let bindings within a module or expression. (#847)

- Tag "unused code" and "deprecated" warnings, allowing clients to better
display them. (#848)

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ all:
# results in a conflict
.PHONY: install-test-deps
install-test-deps:
opam install 'menhir>20211230' cinaps 'ppx_expect>=v0.15.0' \
opam install --yes 'menhir>20211230' cinaps 'ppx_expect>=v0.15.0' \
ocamlformat.$$(awk -F = '$$1 == "version" {print $$2}' .ocamlformat) ocamlformat-rpc

.PHONY: dev
Expand Down Expand Up @@ -48,7 +48,7 @@ check:
dune build @check

.PHONY: test-e2e
test-e2e:
test-e2e: yarn-install
dune build @install && dune exec -- ocaml-lsp-server/test/run_test_e2e.exe

.PHONY: promote-e2e
Expand Down
148 changes: 144 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

<!-- TODO:
this is quite a large list (which becomes even larger since it's missing some requests), which is not necessarily of big interest to users.
We should consider:
1. Moving it to the bottom
2. Converting it into a table
| Description | Method | OCaml | Reason | Dune | Menhir | .ocamlformat | ...
| Auto-completion | textDocument/completion | x | x | o | o | o | ...
3. (not sure how) Generate the table automatically because, otherwise, it's outdated frequently.
-->

The server supports the following LSP requests:

- [x] `textDocument/completion`
Expand All @@ -85,6 +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:
- [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
<kbd>Alt</kbd>+<kbd>D</kbd> or on MacOS <kbd>Option</kbd>+<kbd>D</kbd>

#### 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
<kbd>Alt</kbd>+<kbd>C</kbd> or on MacOS <kbd>Option</kbd>+<kbd>C</kbd>

## Integration with other tools

### Source file formatting: OCamlFormat & Refmt
Expand All @@ -96,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 <!-- TODO: specify until which olsp version this applies (since ofmt-rpc is inside ofmt now) -->

When you hover the cursor over OCaml code, the extension shows you the type of
the symbol. To get nicely formatted types, install
Expand All @@ -118,11 +255,13 @@ for errors such as logged exceptions.
# clone repo with submodules
git clone --recursive git@github.com:ocaml/ocaml-lsp.git

cd ocaml-lsp

# if you already cloned, pull submodules
git submodule update --init --recursive

# create local switch (or use global one)
opam switch create . ocaml-base-compiler.4.14.0
opam switch --yes create . ocaml-base-compiler.4.14.0

# don't forget to set your environment to use the local switch
eval $(opam env)
Expand Down Expand Up @@ -164,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
Expand Down
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ possible and does not make any assumptions about IO.
ordering
dune-build-info
spawn
(ocamlc-loc (>= 3.5.0))
(omd (and (>= 1.3.2) (< 2.0.0~alpha1)))
(octavius (>= 1.2.2))
(uutf (>= 1.0.2))
Expand Down
46 changes: 23 additions & 23 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.follows = "opam-nix/nixpkgs";
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
opam-nix = {
url = "github:tweag/opam-nix";
inputs.opam-repository.follows = "opam-repository";
Expand All @@ -17,7 +17,7 @@
};
};

outputs = { self, flake-utils, opam-nix, nixpkgs, ... }@inputs:
outputs = { self, flake-utils, opam-nix, opam-repository, nixpkgs, ... }@inputs:
let package = "ocaml-lsp-server";
in flake-utils.lib.eachDefaultSystem (system:
let
Expand All @@ -33,7 +33,6 @@
ppx_yojson_conv = "*";
cinaps = "*";
ppx_expect = "*";
ocamlformat-rpc = "*";
ocamlfind = "1.9.2";
};
packagesFromNames = set:
Expand All @@ -44,7 +43,13 @@
(
let
scope =
on.buildOpamProject { resolveArgs = { with-test = true; }; } package
on.buildOpamProject
{
repos = [ opam-repository ];
inherit pkgs;
resolveArgs = { with-test = true; };
}
package
./.
(allPackages);
overlay = final: prev: {
Expand Down Expand Up @@ -73,6 +78,7 @@
git-subrepo
ocamlformat_0_21_0
yarn
dune-release
]) ++ packagesFromNames devPackages;
inputsFrom = [ self.packages.${system}.default ]
++ packagesFromNames localPackages;
Expand Down
Loading

0 comments on commit 1813ecd

Please sign in to comment.