Giter Club home page Giter Club logo

ocaml-lsp's Introduction

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 with 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 and you must have the dot-merlin-reader package installed.

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

Syntax Documentation

since OCaml-LSP 1.18.0

OCaml-LSP can display documentation about the node under the cursor when the user hovers over some OCaml code. For example, hovering over the code snippet below will display some information about what the syntax is:

type point = {x: int; y: int}

Hovering over the above will display:

ocaml type point = { x : int; y : int } 
syntax Record type:
Allows you to define variants with a fixed set of fields, and all of the
constructors for a record variant type must have the same fields. See
Manual

The documentation is gotten from the Merlin engine which receives the nodes under the cursor and infers what the syntax may be about, and displays the required information along with links to the manual for further reading.

Syntax Documentation is an optional feature and can be activated by using the LSP config system with the key called syntaxDocumentation and can be enabled via setting it to { enable: true }.

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.

ocaml-lsp's People

Contributors

3rafal avatar actionshrimp avatar andreypopp avatar awilliambauer avatar c-cube avatar cannorin avatar dependabot[bot] avatar edwintorok avatar fsouza avatar giltho avatar jboillot avatar jchavarri avatar jfeser avatar jorisgio avatar khady avatar manasjayanth avatar mnxn avatar nojb avatar nymphium avatar panglesd avatar pinotree avatar piziedust avatar rgrinberg avatar rusty-key avatar smorimoto avatar tatchi avatar tmattio avatar ulugbekna avatar voodoos avatar xvw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ocaml-lsp's Issues

Autocomplete list does not seem to be narrowed on type

(unsure whether this is the right repo to post this issue on)

When I ask for autocompletion, I get a list of items that seem unrelated/invalid for the thing I'm currently autocompleting. Here's an example:

image

I only expect to see myThing here since y is of type x and that's the only thing available on x.

This becomes a bit more problematic when multiple language servers (for multiple languages) are active in the same document. Here's an example of that:

image
Here's a GraphQL operation defined inside of a string. There's a separate GraphQL language server running and providing autocomplete for that snippet, but its items are pushed to the very bottom of the list by all of the other unrelated/invalid items. Since it's inside of a string I was expecting to get no completion at all from ocamllsp/merlin. What I was expecting to see was this:
image
....which comes from the GraphQL LS, and is indeed available in the list, but at the very bottom.

So, I guess my question is, is there a way to get rid of the unrelated items and only get a list of things I can actually use in the place where I'm autocompleting?

support refmt for Reason files

Reason support was added recently, it works quite well included, what's missing now is to support refmt instead of ocamlformat for Reason files.

If it's not too complicated, I can try my luck on it, any pointer will be appreciated :)

Doesn't compile with 4.07

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
[ERROR] The compilation of ocaml-lsp-server failed at "/home/kakadu/.opam/4.07.1+fp+flambda/bin/dune build -j 7 --root . --ignore-promoted-rules --no-config
        --profile release ocaml-lsp-server.install".

#=== ERROR while compiling ocaml-lsp-server.~dev ==============================#
# context     2.0.5 | linux/x86_64 | ocaml-variants.4.07.1+fp+flambda | pinned(git+file:///home/kakadu/asp/ocaml-lsp#master#b1168b8d)
# path        ~/.opam/4.07.1+fp+flambda/.opam-switch/build/ocaml-lsp-server.~dev
# command     ~/.opam/4.07.1+fp+flambda/bin/dune build -j 7 --root . --ignore-promoted-rules --no-config --profile release ocaml-lsp-server.install
# exit-code   1
# env-file    ~/.opam/log/ocaml-lsp-server-19335-ebe0e0.env
# output-file ~/.opam/log/ocaml-lsp-server-19335-ebe0e0.out
### output ###
# File "vendor/merlin/src/ocaml/preprocess/parser_raw.ml", line 5, characters 2-42:
# Error: Unbound value MenhirLib.StaticVersion.require_20190924
# File "_none_", line 1:
# Warning 58: no cmx file was found in path for module Easy_format, and its interface was not compiled with -opaque
# File "_none_", line 1:
# Warning 58: no cmx file was found in path for module Bi_outbuf, and its interface was not compiled with -opaque
# File "_none_", line 1:
# Warning 58: no cmx file was found in path for module Bi_share, and its interface was not compiled with -opaque



<><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
+- The following actions failed
| - build ocaml-lsp-server ~dev
+- 
- No changes have been performed
[NOTE] Pinning command successful, but your installed packages may be out of sync.

➜  ocaml-lsp git:(master) ✗ opam list|grep menhir                                                                                           4.07.1+fp+flambda
55:menhir                  20190924          An LR(1) parser generator

Field name mismatch for Initialize.TextDocumentSyncOptions

The last field of the Intialize.TextDocumentSyncOptions is named didSave in the current code, but it seems to be named simply save in the specification if I'm not mistaken (cf https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/ ).

A bit of context: I'm not sure it is a problem, but I'm trying to find out why my lsp server does not seems to receive didSave notifications, and this would seem to be a likely candidate (since according to the spec, if the save field is omitted (o in this case misnamed), such notifications will not be sent).

I'm sorry about all these issues and if you prefer, I can stop posting them until #87 is merged, ^^

cannot find executable after installation

Hi, I have follow the instruction for opam and installed it for MacOS.

However, I cannot find the executable and it cannot be detected by emacs lsp-mode as well. Do I need to take extra step to link the executable?

It gives a wrong type for optional arguments

For demonstration, with the following code,

let x ?(a=1) b: bool = a + b > 0
let y = x ~a:3 5

ocaml-lsp gives me bool, i.e., the result type of x when I put a cursor on ~a: part, but I think it is bit misleading and it would be better to give int, i.e., the type of the a argument.

[Emacs] Completion takes long time in lsp-mode

I use this server with lsp-mode as a client.
When I choose a completed word in a completion list, ocaml-lsp spend a few seconds (or sometime, dozens of seconds) before it really completes the word.
It used to not spend such a long time, and other lsp servers like haskell-ide-engine and metals don't.

I don't know what version I used before completion became slow, but now I use OCaml 4.09.0 with 8e03749 and OCaml 4.07.1 with 0fedbda

Could you please inspect this issue?

Drop findlib in our version of merlin

We don't actually need findlib for anything as we only support dune generated .merlin files and those don't use the PKG field.

Let's stick to dependencies that can be built with dune in this project.

Not all modules seem to be recognized

I'm trying out ocaml-lsp with https://github.com/ocamllabs/vscode-ocaml-platform, and I can't get completion for modules defined in the same file, hovering also does not work, but when trying completion for Base., it works well and shows me everything. Hovering over Random also gives the signature. Is there some additional configuration required? dune 2.2.0, OCaml 4.06.1, .merlin files are in place.

Support for remote LSP client/server

Emacs' lsp-mode support remote LSP servers via TRAMP. Unfortunately, ocaml-lsp comes with :remote? nil by default.

I tried adding a new configuration with remote? t

(lsp-register-client
 (make-lsp-client
  :new-connection
  (lsp-tramp-connection "ocamllsp")
  :major-modes '(caml-mode tuareg-mode)
  :remote? t
  :priority 0
  :server-id 'ocaml-lsp-server-remote))

And lsp-mode actually managed to start ocamllsp on remote machine, but kind of not completely as the lsp server didn't advertise any capabilities to the client:

 `-[-] ocaml-lsp-server-remote:88874 status:starting
    |-[-] Buffers
    |  `-[+] Tenv.ml
    `-[+] Capabilities

So, I was wondering if this is something you already looked into? Or is it even the right repo to ask this question?

Type error message

Current type mismatch message is hard to parse, e.g., on VS Code

Screen Shot 2020-02-29 at 3 04 24 PM

and, especially, with larger types.

What do people think about a shorter (and formatted with markdown) message? For example, Intellij IDEA for Scala:

Screen Shot 2020-02-29 at 3 02 22 PM

and

Screen Shot 2020-02-29 at 3 03 01 PM

(might not be the best place to fix an error message, but this project seems more flexible to changes)

I could work on this if people like the idea.

TextDocument.apply_content_change should take a list

the spec doesn't seem to say anything about the order of patches in DocumentEdit, so it seems safer to sort them by increasing position (stable sort, to handle the ones with same start pos) and apply them in a fold_right?

this function seems really useful for building any kind of LSP so I think it's good to provide good defaults :)

current master fails to build on linux

I have the same error locally (archlinux with esy) as on Travis: https://travis-ci.com/ocaml/ocaml-lsp/jobs/280940293

error: build failed with exit code: 1
  build log:
    # esy-build-package: building: @opam/ocaml-lsp-server@github:ocaml/ocaml-lsp:ocaml-lsp-server.opam#85f8c566a87fde2ce962e81432705bfaec9d581c
    # esy-build-package: pwd: /home/thomas/.esy/3/b/opam__s__ocaml_lsp_server-3a154f8b
    # esy-build-package: running: 'dune' 'build' '-j' '4' '--root' '.' '--ignore-promoted-rules' '--no-config' '--profile' 'release' 'ocaml-lsp-server.install'
    File "vendor/merlin/src/ocaml/preprocess/parser_raw.ml", line 5, characters 2-42:
    5 |   MenhirLib.StaticVersion.require_20190924
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    Error: Unbound value MenhirLib.StaticVersion.require_20190924
    error: command failed: 'dune' 'build' '-j' '4' '--root' '.' '--ignore-promoted-rules' '--no-config' '--profile' 'release' 'ocaml-lsp-server.install' (exited with 1)
    esy-build-package: exiting with errors above...
    
  building @opam/ocaml-lsp-server@github:ocaml/ocaml-lsp:ocaml-lsp-server.opam#85f8c566a87fde2ce962e81432705bfaec9d581c

I'm building with OCaml 4.08

Batching document change notifications

The emacs lsp-mode package sends a lot of very granular text change notifications (emacs-lsp/lsp-mode#362). Other lsp servers apparently batch these notifications and send diagnostics asynchronously (emacs-lsp/lsp-mode#362 (comment)). ocaml-lsp should probably do the same.

Right now it looks like the type checker runs for every change?

I've looked at implementing this, but I'm not sure how to fit it in with the existing code.

Strings that contain typable names get wrongly typed

When hovering over a word in a string that is a correct name of a typable entity (variable name, function name or constructor), the pop up gives the type of the entity, even if completely unrelated.
Several examples :

image

image

image

Initialization from QtCreator has become broken recently

In last issue #36 @rgrinberg fixed initialization of the server from QtCreator side but after that something has become broken

If QtCreator sends

Content-Length: 679

{"id":"{a081f281-8313-4003-9dde-54476f6304d8}","jsonrpc":"2.0","method":"initialize","params":{"capabilities":{"textDocument":{"codeAction":{"codeActionLiteralSupport":{"codeActionKind":{"valueSet":["*"]}}},"completion":{"completionItem":{},"completionItemKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]},"dynamicRegistration":true},"documentSymbol":{"symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}},"synchronization":{"didSave":true,"dynamicRegistration":true,"willSave":true,"willSaveWaitUntil":false}},"workspace":{"workspaceFolders":true}},"processId":28419,"rootUri":null,"trace":"off"}}

I get in the log error string_of_yojson: string needed. I don't know yet where does it happen. Full merlin log below.

# 0.01 lsp - debug
recv: {
  "id": "{a081f281-8313-4003-9dde-54476f6304d8}",
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "capabilities": {
      "textDocument": {
        "codeAction": {
          "codeActionLiteralSupport": {
            "codeActionKind": { "valueSet": [ "*" ] }
          }
        },
        "completion": {
          "completionItem": {},
          "completionItemKind": {
            "valueSet": [
              1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
              19, 20, 21, 22, 23, 24, 25
            ]
          },
          "dynamicRegistration": true
        },
        "documentSymbol": {
          "symbolKind": {
            "valueSet": [
              1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
              19, 20, 21, 22, 23, 24, 25, 26
            ]
          }
        },
        "synchronization": {
          "didSave": true,
          "dynamicRegistration": true,
          "willSave": true,
          "willSaveWaitUntil": false
        }
      },
      "workspace": { "workspaceFolders": true }
    },
    "processId": 28419,
    "rootUri": null,
    "trace": "off"
  }
}
# 0.01 lsp - debug
time elapsed processing message: 0.000121s
# 0.01 lsp - error
string_of_yojson: string needed

LSP: Incorrectly assuming some optional properties as always given

Background: I tried to use ocaml-lsp from autozimu/LanguageClient-neovim but it failed to initialize with the following error:

lsp/src/initialize.ml.SignatureHelpClientCapabilities.signatureInformation_of_yojson:
  the following record elements were undefined: documentationFormat

The problem was caused at the deserialization step.
According to the spec, the property documentationFormat is optional, and the said client actually omits that property. But ocaml-lsp requires that to be given, which is against the spec.

Above is the case I encountered, but I can see many other properties which are optional in the spec but treated as required (e.g. parameterInformation). In my case fixing documentationFormat was enough to get it working, but this may cause similar problems when used from other clients.

Json de-serialising error

I happened upon the following error (again, using nvim and vim-lsp), but I don't know if it is expected:

# 0.00 lsp - debug
recv: {
  "method": "textDocument/didChange",
  "jsonrpc": "2.0",
  "params": {
    "contentChanges": null,
    "textDocument": {
      "uri": "file:///home/guigui/build/dolmen/tests/smtlib/test-002.smt2",
      "version": 2
    }
  }
}
# 0.00 lsp - debug
time elapsed processing message: 0.005331s
# 0.00 lsp - error
list_of_yojson: list needed

The server still runs after the error, but the handler for the notification does not seem to run.

I suppose it might be another instance of the spec moving too fast and it might be fixed by #87 ?

Can't get project to build

Hi All!
I have been using this lsp frontend quite a bit recently, and had been installing it with opam pin --yes add merlin-lsp.dev https://github.com/ocaml/merlin.git.
Now that it moved here, I've been trying to get opam pin --yes add ocaml-lsp-server.dev https://github.com/ocaml/ocaml-lsp.git to work in the same way, but have been running into several issues.

  1. Opam complains about lack of maintainers and synopsis. I was able to silence that by forking and adding them (mrkmndz@891d861)
  2. Dune complains about lack of project name. fixed with (mrkmndz@94b18b8)
  3. Dune build fails due to "Library "merlin.specific" not found." Adding merlin as a dependency didn't seem to work, and the only thing that seemed to make it build was to switch to dune 2.0.0 (mrkmndz@78ad214). However, this did not feel like the right way to fix it, and causes other problems with my set up.

Furthermore, I can't seem to get it to run once installed in the same way that I used to, namely the form opam exec -- ocaml-lsp-server.

How have you all been running this in development?

Implement textDocument/selectionRange

The most recent version of the specification (3.15) introduced a textDocument/selectionRange request. This request is supposed to suggest available selections to the server.

This very closely corresponds to the Shape command in merlin (cf query_protocol.ml). There is just a bit of a mismatch because merlin returns a tree of shapes (every shape can have many sub shapes), so we'll need to do some intelligent flattening. This last bit we can tweak experimentally after trying out an initial implementation.

Feature: Create interface file

This is a commonly required request in the OCaml tooling world. It has been asked several time for dune in the past (ocaml/dune#150) for example, and the conclusion has been reached that it should be done in the editor tooling.

What do you think about it ? Should it be done at the merlin level (ocaml/merlin#538), at the ocaml-lsp level, or at the editor interface level (e.g. vscode-merlin).

In theory, I think it should be as factorised as possible, so not in the editor interface. This could be probably be done with a workspace/executeCommand request ?

This could be done in addition to @rgrinberg's proposition to propose custom completion in mli files

LSIF support

LSIF (Language Server Index Format) - a standard format for language servers or other programming tools to dump their knowledge about a workspace. This dump can later be used to answer language server LSP requests for the same workspace without running the language server itself.

ocamlformat is not listed as a dependency

It seems that ocamlformat is needed :

[Error - 15:51:16] Request textDocument/formatting failed.
  Message: Unable to find ocamlformat binary
  Code: -32600 
[Error - 15:51:16] [lsp] Unable to find ocamlformat binary

(VSCode)

This was resolved when I installed it. I think it should be added as a dependency

Switch CLI to cmdliner

The way arg parses things is substandard. We should vendor cmdliner and use it instead.

Code actions failures

#113 Has introduced a lot of error responses from the server that seem to be happening on codeAction requests (see note from @rgrinberg in the discussion).

Compilation error with 4.10

$ opam install --solver=mccs ocaml-lsp-server

<><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><>
[ocaml-lsp-server.~dev] no changes from git+https://github.com/ocaml/ocaml-lsp.git

The following actions will be performed:
  ∗ install ocaml-lsp-server ~dev*

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
[ERROR] The compilation of ocaml-lsp-server failed at "/home/user/.opam/opam-init/hooks/sandbox.sh build dune build -j 7 --root . --ignore-promoted-rules --no-config --profile release ocaml-lsp-server.install".

#=== ERROR while compiling ocaml-lsp-server.~dev ==============================#
# context     2.0.3 | linux/x86_64 |  | pinned(git+https://github.com/ocaml/ocaml-lsp.git#5782d1da)
# path        ~/.opam/4.10.0/.opam-switch/build/ocaml-lsp-server.~dev
# command     ~/.opam/opam-init/hooks/sandbox.sh build dune build -j 7 --root . --ignore-promoted-rules --no-config --profile release ocaml-lsp-server.install
# exit-code   1
# env-file    ~/.opam/log/ocaml-lsp-server-22042-c743ac.env
# output-file ~/.opam/log/ocaml-lsp-server-22042-c743ac.out
### output ###
# File "_build/.dune/default/vendor/merlin/src/ocaml/utils/dune", line 2, characters 13-25:
# 2 | (copy_files# 410/*.ml{,i})
#                  ^^^^^^^^^^^^
# Error: Cannot find directory: vendor/merlin/src/ocaml/utils/410



<><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
┌─ The following actions failed
│ λ build ocaml-lsp-server ~dev
└─ 
╶─ No changes have been performed

Module aliases do not get completion

module ZZZ = Base;
ZZZ.<tab>

Nothing is being shown.

Base.<tab> works as expected. Not sure if it's related to vscode extension or ocaml-lsp itself.

Default capabilities for text document synchronization

It appears the when the client omits the synchronization capabilities (aka the Initialize.Synchronization.t value in a TextDocumentClientCapabilities.t), the default value is to assume that all capabilities are present, see

let empty = { willSave = true; willSaveWaitUntil = true; didSave = true }

However, after reading the specification (see quote afterwards), it seems that if omitted, the default capabilities should be assumed to be (at least) the ones present strictly before version 3.x (but not necessarily more I suppose).

Client capabilities got introduced with version 3.0 of the protocol. They therefore only describe capabilities that got introduced in 3.x or later. Capabilities that existed in the 2.x version of the protocol are still mandatory for clients. Clients cannot opt out of providing them. So even if a client omits the ClientCapabilities.textDocument.synchronization it is still required that the client provides text document synchronization (e.g. open, changed and close notifications).

It seems that the willSave, and willSaveWaitUntil capabilities were introduced in 3.0, so I'd guess that the empty, or default, synchronization capabilities should rather be:

let empty = { willSave = false; willSaveWaitUntil = false; didSave = true }

LSP: completion of infix operators in incorrect

open Angstrom

let f = word >>CURSOR

With cursor on CURSOR, ask for completion. Then select >>| in the answer. The final result is

open Angstrom

let f = word >>>>|

It looks like the prefix is ignored when completing an operator.

Connect ocaml-lsp to Monaco Editor

I want to make a web page that contains an editor of code in OCaml. I prefer to use Monaco Editor. Does anyone know how to connect the Monaco Editor to this ocaml-lsp?

Thank you.

Error: Version 2.0 of dune is not supported.

I want to try ocaml-lsp, however, it gave me an Error: Version 2.0 of dune is not supported.

$ git clone --recurse-submodules http://github.com/ocaml/ocaml-lsp.git
... ...
$ cd ocaml-lsp
$ make build
dune build
File "dune-project", line 1, characters 11-14:
1 | (lang dune 2.0)
               ^^^
Error: Version 2.0 of dune is not supported.
Supported versions:
- 0.0
- 1.0 to 1.11
make: *** [build] Error 1

My dune --version is 1.11.4 and opam --version is 2.0.2. Does anyone know how to fix this?

OCaml version mismatch or malformed input

I've got this error when trying current master (pinned today), along with https://github.com/ocamllabs/vscode-ocaml-platform on a reason project:

Fatal error: exception (Failure "Ast_mapper: OCaml version mismatch or malformed input")
Raised at file "stdlib.ml", line 29, characters 17-33
Called from file "src/driver.ml", line 1290, characters 6-39
Re-raised at file "parsing/location.ml", line 904, characters 14-25
Called from file "src/driver.ml", line 1295, characters 4-59
Called from file ".ppx/4a0d78cf09beeeae6a944eea36bafb81/_ppx.ml", line 1, characters 9-36

My opam switch is currently running 4.06 OCaml compiler, is that version unsupported? I've configured ocaml.lsp.path in vscode settings to point to ocamllsp binary inside my switch.

Uri.to_path un-escaping incomplete

I remarked that some special characters escape sequences are not replaced in the Uri.to_path function, for instance:

  • %2B which maps to +
  • %3D which maps to =
  • %5E which maps to ^

There is almost certainly other character escape sequences not currently handled (I just happened upon these in my expérimentations), and it might benefit from the automatic translation of #87 ?
In any case, this is not blocking for me, so on this one I can wait for a generic solution, :)

vendored lib imposes Dune ≥ 2.0

I don't know if this is expected but

#=== ERROR while compiling ocaml-lsp-server.~dev ==============================#
# context              2.0.5 | linux/x86_64 | ocaml-base-compiler.4.07.1 | pinned(git+https://github.com/ocaml/ocaml-lsp.git#3e208720)
# path                 ~/zzz/dev/tezos/_opam/.opam-switch/build/ocaml-lsp-server.~dev
# command              ~/.opam/opam-init/hooks/sandbox.sh build dune build -j 3 --root . --ignore-promoted-rules --no-config --profile release ocaml-lsp-server.install
# exit-code            1
# env-file             ~/.opam/log/ocaml-lsp-server-1538-de96f2.env
# output-file          ~/.opam/log/ocaml-lsp-server-1538-de96f2.out
### output ###
# File "vendor/ocaml-syntax-shims/dune-project", line 1, characters 11-14:
# 1 | (lang dune 2.0)
#                ^^^
# Error: Version 2.0 of dune is not supported.
# Supported versions:
# - 0.0
# - 1.0 to 1.11

Here:
https://github.com/ocaml/ocaml-lsp/blob/master/ocaml-lsp-server.opam#L45
the comment says:

# so we do this manually to be compat with dune 1.0 and dune 2.0

disagreement with spec about request object ID

Spec says that it can be string but LSP expects only integers
https://www.jsonrpc.org/specification#request_object As consequence I can't use LSP server with QtCreator frontend

Part of the log:

# 0.00 lsp - debug
recv: {
  "id": "{8ae72110-d34a-486d-ae5f-d4ee9ca406b7}",
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {
    "capabilities": {
      "textDocument": {
        "codeAction": {
          "codeActionLiteralSupport": {
            "codeActionKind": { "valueSet": [ "*" ] }
          }
        },
        "completion": {
          "completionItem": {},
          "completionItemKind": {
            "valueSet": [
              1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
              19, 20, 21, 22, 23, 24, 25
            ]
          },
          "dynamicRegistration": true
        },
        "documentSymbol": {
          "symbolKind": {
            "valueSet": [
              1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
              19, 20, 21, 22, 23, 24, 25, 26
            ]
          }
        },
        "synchronization": {
          "didSave": true,
          "dynamicRegistration": true,
          "willSave": true,
          "willSaveWaitUntil": false
        }
      },
      "workspace": { "workspaceFolders": true }
    },
    "processId": 23567,
    "rootUri": null,
    "trace": "off"
  }
}
# 0.00 lsp - debug
time elapsed processing message: 0.000103s
# 0.00 lsp - error
Unexpected packet: Of_yojson_error with exc = Failure("int_of_yojson: integer needed"). 
`String ("{8ae72110-d34a-486d-ae5f-d4ee9ca406b7}")

Can't get it to work with emacs lsp-mode

I was able to build ocaml-lsp find and all of the tests passed. However, the emacs lsp-mode doesn't detect any capabilities, and inspecting the io-log reveals that ocamllsp never responds.

This is the emacs configuration:

(defcustom lsp-ocaml-lsp-server-command
  '("ocamllsp")
  "Command to start ocaml-language-server."
  :group 'lsp-ocaml
  :type '(choice
          (string :tag "Single string value")
          (repeat :tag "List of string values"
                  string)))

(lsp-register-client
 (make-lsp-client
  :new-connection
  (lsp-stdio-connection (lambda () lsp-ocaml-lsp-server-command))
  :major-modes '(caml-mode tuareg-mode)
  :priority 0
  :server-id 'ocaml-lsp-server))

and the io log:

[Trace - 11:58:11 AM] Sending request 'initialize - (3)'.
Params: {
  "processId": 335871,
  "rootPath": "/home/samthomas/Cornell/school/cs3110/spring/RML-2.0",
  "clientInfo": {
    "name": "vscode",
    "version": "1.41.1"
  },
  "rootUri": "file:///home/samthomas/Cornell/school/cs3110/spring/RML-2.0",
  "capabilities": {
    "workspace": {
      "workspaceEdit": {
        "documentChanges": true,
        "resourceOperations": [
          "create",
          "rename",
          "delete"
        ]
      },
      "applyEdit": true,
      "symbol": {
        "symbolKind": {
          "valueSet": [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            15,
            16,
            17,
            18,
            19,
            20,
            21,
            22,
            23,
            24,
            25,
            26
          ]
        }
      },
      "executeCommand": {
        "dynamicRegistration": false
      },
      "didChangeWatchedFiles": {
        "dynamicRegistration": true
      },
      "workspaceFolders": true,
      "configuration": true
    },
    "textDocument": {
      "declaration": {
        "linkSupport": true
      },
      "definition": {
        "linkSupport": true
      },
      "implementation": {
        "linkSupport": true
      },
      "typeDefinition": {
        "linkSupport": true
      },
      "synchronization": {
        "willSave": true,
        "didSave": true,
        "willSaveWaitUntil": true
      },
      "documentSymbol": {
        "symbolKind": {
          "valueSet": [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            15,
            16,
            17,
            18,
            19,
            20,
            21,
            22,
            23,
            24,
            25,
            26
          ]
        },
        "hierarchicalDocumentSymbolSupport": true
      },
      "formatting": {
        "dynamicRegistration": true
      },
      "rangeFormatting": {
        "dynamicRegistration": true
      },
      "rename": {
        "dynamicRegistration": true,
        "prepareSupport": true
      },
      "semanticHighlightingCapabilities": {
        "semanticHighlighting": false
      },
      "codeAction": {
        "dynamicRegistration": true,
        "isPreferredSupport": true,
        "codeActionLiteralSupport": {
          "codeActionKind": {
            "valueSet": [
              "",
              "quickfix",
              "refactor",
              "refactor.extract",
              "refactor.inline",
              "refactor.rewrite",
              "source",
              "source.organizeImports"
            ]
          }
        }
      },
      "completion": {
        "completionItem": {
          "snippetSupport": true,
          "documentationFormat": [
            "markdown"
          ]
        },
        "contextSupport": true
      },
      "signatureHelp": {
        "signatureInformation": {
          "parameterInformation": {
            "labelOffsetSupport": true
          }
        }
      },
      "documentLink": {
        "dynamicRegistration": true,
        "tooltipSupport": true
      },
      "hover": {
        "contentFormat": [
          "markdown",
          "plaintext"
        ]
      },
      "foldingRange": {
        "dynamicRegistration": true,
        "rangeLimit": null,
        "lineFoldingOnly": false
      },
      "callHierarchy": {
        "dynamicRegistration": false
      }
    },
    "window": {
      "workDoneProgress": true
    }
  },
  "initializationOptions": null,
  "workDoneToken": "1"
}


Memory leak

ocaml-lsp's memory use grows when I modify a file that it's watching. I've seen it use up to 20Gb of memory. After bisecting, it seems that the bug was introduced by 8a27349. Unfortunately, it's a huge commit so I don't see an obvious culprit.

This is on macos 10.15.3, ocaml 4.08.1.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.