• Stars
    star
    766
  • Rank 59,308 (Top 2 %)
  • Language
    OCaml
  • License
    Other
  • Created almost 5 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

OCaml Language Server Protocol implementation

OCaml-LSP

Build Coverage Status

OCaml-LSP is a language server for OCaml that implements Language Server Protocol (LSP).

If you use Visual Studio Code, see OCaml Platform extension page for detailed instructions on setting up your editor for OCaml development with OCaml-LSP: what packages need to be installed, how to configure your project and get most out of the OCaml editor support, and how to report and debug problems.

Installation

Below we show how to install OCaml-LSP using opam, esy, and from sources. OCaml-LSP comes in a package called ocaml-lsp-server but the installed program (i.e., binary) is called ocamllsp.

Installing with package managers

Opam

To install the language server in the currently used opam switch:

$ opam install ocaml-lsp-server

Note: you will need to install ocaml-lsp-server in every switch where you would like to use it.

Esy

To add the language server to an esy project, run in terminal:

$ esy add @opam/ocaml-lsp-server

Installing from sources

This project uses submodules to handle dependencies. This is done so that users who install ocaml-lsp-server into their sandbox will not share dependency constraints on the same packages that ocaml-lsp-server is using.

$ git clone --recurse-submodules http://github.com/ocaml/ocaml-lsp.git
$ cd ocaml-lsp
$ make install

Additional package installations

  • Install ocamlformat package if you want source file formatting support.

    Note: To have source file formatting support in your project, there needs to be an .ocamlformat file present in your project's root directory.

  • OCaml-LSP also uses a program called ocamlformat-rpc to format code that is either generated or displayed by OCaml-LSP, e.g., when you hover over a module identifier, you can see its typed nicely formatted. This program comes with ocamlformat (version > 0.21.0). Previously, it was a standalone package.

Usage

Usually, your code editor, or some extension/plugin that you install on it, is responsible for launching ocamllsp.

Important: OCaml Language Server has its information about the files from the last time your built your project. We recommend using the Dune build system and running it in "watch" mode to always have correctly functioning OCaml-LSP, e.g., dune build --watch.

Integration with Dune RPC

since OCaml-LSP 1.11.0

OCaml-LSP can communicate wit Dune's RPC system to offer some interesting features. User can launch Dune's RPC system by running Dune in watch mode. OCaml-LSP will not launch Dune's RPC for you. But OCaml-LSP will see if there is an RPC running and will communicate with it automatically.

There are various interesting features and caveats:

  1. Dune's RPC enables new kinds of diagnostics (i.e., warnings and errors) to be shown in the editor, e.g., mismatching interface and implementation files. You need to save the file to refresh such diagnostics because Dune doesn't see unsaved files; otherwise, you may see stale (no longer correct) warnings or errors. OCaml-LSP updates diagnostics after each build is complete in watch mode.

  2. Dune file promotion support. If you, for example, use ppx_expect and have failing tests, you will get a diagnostic when Dune reports that your file can be promoted. You can promote your file using the code action Promote.

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 (inexhaustive list):

  • textDocument/completion
  • completionItem/resolve
  • textdocument/hover
  • textDocument/signatureHelp
  • textDocument/declaration
  • textDocument/definition
  • textDocument/typeDefinition
  • textDocument/implementation
  • textDocument/codeLens
  • textDocument/documentHighlight
  • textDocument/documentSymbol
  • textDocument/references
  • textDocument/documentColor
  • textDocument/colorPresentation
  • textDocument/formatting
  • textDocument/rangeFormatting
  • textDocument/onTypeFormatting
  • textDocument/prepareRename
  • textDocument/foldingRange
  • textDocument/selectionRange
  • workspace/didChangeConfiguration
  • workspace/symbol

Note that degrees of support for each LSP request are varying.

Configuration

Read more about configurations supported by ocamllsp

Semantic highlighting

since OCaml-LSP 1.15.0 (since version 1.15.0-4.14 for OCaml 4, 1.15.0-5.0 for OCaml 5)

Semantic highlighting support is enabled by default.

since OCaml-LSP 1.14.0

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.

{
    "ocaml.server.extraEnv": {
        "OCAMLLSP_SEMANTIC_HIGHLIGHTING": "full"
    },
}

LSP Extensions

The server also supports a number of OCaml specific extensions to the protocol:

Note that editor support for these extensions varies. In general, the OCaml Platform extension for Visual Studio Code will have the best support.

Unusual features

Destructing a value

since OCaml-LSP 1.0.0

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,

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

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

since OCaml-LSP 1.8.0

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)

since OCaml-LSP 1.8.0

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):

(* 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

Debugging

If you use Visual Studio Code, please see OCaml Platform extension page for a detailed guide on how to report and debug problems.

If you use another code editor and use OCaml-LSP, you should be able to set the server trace to verbose using your editor's LSP client and watch the trace for errors such as logged exceptions.

Contributing to project

# clone repo with submodules
git clone --recursive [email protected]: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 --yes create . ocaml-base-compiler.4.14.0

# don't forget to set your environment to use the local switch
eval $(opam env)

# install dependencies
make install-test-deps

# build
make all

# the ocamllsp executable can be found at _build/default/ocaml-lsp-server/bin/main.exe

Changelog

User-visible changes should come with an entry in the changelog under the appropriate part of the unreleased section. PR that doesn't provide an entry will fail CI check. This behavior can be overridden by using the "no changelog" label, which is used for changes that are not user-visible.

Tests

To run tests execute:

$ make test

Note that tests require Node.js and Yarn installed.

Relationship to Other Tools

The lsp server uses merlin under the hood, but users are not required to have merlin installed. We vendor merlin because we currently heavily depend on some implementation details of merlin that make it infeasible to upgrade the lsp server and merlin independently.

History

The implementation of the lsp protocol itself was taken from facebook's hack

Previously, this lsp server was a part of merlin, until it was realized that the lsp protocol covers a wider scope than merlin.

Comparison to other LSP Servers for OCaml

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 This server supports bucklescript & reason. However, this project does not use merlin which means that it supports fewer versions of OCaml and offers less "smart" functionality - especially in the face of sources that do not yet compile.

  • ocaml-language-server This project is extremely similar in the functionality it provides because it also reuses merlin on the backend. The essential difference is that this project is written in typescript, while our server is in OCaml. We feel that it's best to use OCaml to maximize the contributor pool.

More Repositories

1

ocaml

The core OCaml system: compilers, runtime system, base libraries
OCaml
4,732
star
2

dune

A composable build system for OCaml.
OCaml
1,626
star
3

merlin

Context sensitive completion for OCaml in Vim and Emacs
OCaml
1,574
star
4

opam

opam is a source-based package manager. It supports multiple simultaneous compiler installations, flexible package constraints, and a Git-friendly development workflow.
OCaml
1,225
star
5

opam-repository

Main public package repository for opam, the source package manager of OCaml.
516
star
6

tuareg

Emacs OCaml mode
Emacs Lisp
346
star
7

v2.ocaml.org

Implementation of the ocaml.org website.
HTML
323
star
8

odoc

Documentation compiler for OCaml and Reason
OCaml
320
star
9

ocamlunix

Unix system programming in OCaml book
TeX
276
star
10

Zarith

The Zarith library implements arithmetic and logical operations over arbitrary-precision integers and rational numbers. The implementation, based on GMP, is very efficient.
OCaml
223
star
11

ocaml-re

Pure OCaml regular expressions, with support for Perl and POSIX-style strings
OCaml
208
star
12

setup-ocaml

GitHub Action for the OCaml programming language
TypeScript
196
star
13

ocaml.org

The official OCaml website.
HTML
162
star
14

omd

extensible Markdown library and tool in "pure OCaml"
OCaml
152
star
15

RFCs

Design discussions about the OCaml language
150
star
16

oasis

Cabal like system for OCaml
OCaml
124
star
17

ocamlbuild

The legacy OCamlbuild build manager
OCaml
121
star
18

ocaml-ci-scripts

Skeletons for CI scripts
OCaml
101
star
19

flexdll

a dlopen-like API for Windows
OCaml
100
star
20

vim-ocaml

Vim runtime files for OCaml
Vim Script
85
star
21

v3.ocaml.org-rescript

The next implementation of ocaml.org, built on OCaml, ReScript, NextJS, and Tailwind.
ReScript
75
star
22

graphics

The Graphics library from OCaml, in a standalone repository
C
51
star
23

infrastructure

WIki to hold the information about the machine resources available to OCaml.org
HTML
40
star
24

num

The legacy Num library for arbitrary-precision integer and rational arithmetic that used to be part of the OCaml core distribution
OCaml
35
star
25

MPP-language-blender

MPP: a meta preprocessor that blends programming languages
OCaml
33
star
26

obi

OCaml Build Infrastructure
OCaml
30
star
27

oasis2opam

Tool to convert OASIS metadata to OPAM package descriptions
OCaml
27
star
28

ocamlfind

The OCaml findlib library manager
OCaml
26
star
29

ocaml-logo

Official Logo for OCaml
26
star
30

caml-mode

Emacs mode to edit OCaml files
Emacs Lisp
19
star
31

code-of-conduct

Documents related to the Code of Conduct
17
star
32

ocaml-beta-repository

Opam2 remote for beta versions of the OCaml compiler
Shell
16
star
33

ocaml-manual

OBSOLETE, ARCHIVED mirror of the OCaml manual
TeX
15
star
34

opam-file-format

Parser and printer for the opam file syntax
OCaml
15
star
35

ood

OCaml.org v3 data repository
OCaml
14
star
36

camlp-streams

The Stream and Genlex libraries for use with Camlp4 and Camlp5
OCaml
14
star
37

platform-blog

Repository for the Platform blog
13
star
38

oloop

Evaluate code through the OCaml toploop for inclusion in educational material.
OCaml
12
star
39

dbm

The legacy CamlDBM library for accessing NDBM/GDBM database files
OCaml
12
star
40

ocaml-library-standard

Documenting how OCaml libraries are managed
11
star
41

stdlib-shims

Shim to substitute `Pervasives` with `Stdlib` before 4.08.
Standard ML
10
star
42

dune-www

Website for dune.build
SCSS
10
star
43

0install-tools

Tools for distributing OCaml via 0install
8
star
44

platform-dev

Dev versions of the tools used to build the upcoming platform
Shell
8
star
45

opam.ocaml.org

Scripts and documentation for the opam.ocaml.org website
Shell
7
star
46

oasis-db

Hackage like system for OCaml based on OASIS
OCaml
7
star
47

uchar

Uchar compatibility library
OCaml
6
star
48

stdlib-random

Versioned random number library
OCaml
6
star
49

oasis-website

Devel website for OASIS http://oasis.forge.ocamlcore.org
JavaScript
5
star
50

cwn-data

The data repository for the Caml Weekly News
HTML
5
star
51

ocaml-pr-repository

opam switches for all the proposed pull requests against the compiler
5
star
52

oasis2debian

Convert _oasis to debian/ directory.
OCaml
5
star
53

homebrew-ocaml

A Homebrew tap for OCaml and OPAM distribution
Ruby
5
star
54

ocaml.org-media

Media files that we don't want to include in main ocaml.org repo.
HTML
4
star
55

opam-source-archives

mirror of precious opam repository packages whose source websites have disappeared
Shell
4
star
56

subsystem-meetings

sharing documents for specialized developer meetings
4
star
57

ocaml.org-scripts

Scripts for the ocaml.org infrastructure machines
Shell
2
star
58

ocaml.org-infratest

Tests for ocaml.org websites and services.
Shell
2
star
59

release-readiness

Tracking release readiness for OCaml compiler releases
1
star
60

opam-bulk-logs

Logs of daily OPAM bulk package builds
1
star
61

obi-logs

Logs for OCaml Build Infrastructure
1
star