Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Construct as completion suggestions #472

Merged
merged 27 commits into from
Jul 15, 2021

Conversation

ulugbekna
Copy link
Collaborator

@ulugbekna ulugbekna commented Jul 7, 2021

Implements support for merlin Construct.

The main reservation that I have so far is that we're not flexible enough about the depth parameter for Construct. How can we fix this?

From our discussion with voodoos: Local param for Construct isn't ready yet, and we should specify depth param later, when it's more efficient.

To discuss: Maybe it makes more sense to replace _s with snippets, eg calling construct in _ arg1 arg2 will result in (fun _ _ -> _) arg1 arg2 and the cursor will jump to the third underscore (typed hole), while the user likely wants to change the function arguments first.

Otherwise, I used the implementation myself. It seems quite good to me. Demo (the demo used Construct with param set to `Local to use local values, which we turned off now)

Screen.Recording.2021-07-06.at.23.13.40.mov

Copy link
Member

@rgrinberg rgrinberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your efforts. I did an initial review and the PR should be good to go after some minor fixes.

ocaml-lsp-server/src/code_actions/action_construct.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/compl.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/compl.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/code_actions/action_construct.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/ocaml_lsp_server.ml Show resolved Hide resolved
ocaml-lsp-server/src/code_actions/action_construct.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/compl.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/compl.ml Outdated Show resolved Hide resolved
@rgrinberg
Copy link
Member

Maybe it makes more sense to replace _s with snippets, eg calling construct in _ arg1 arg2 will result in (fun _ _ -> _) arg1 arg2 and the cursor will jump to the third underscore (typed hole), while the user likely wants to change the function arguments first.

I would wait until it is possible to insert snippets with code actions before exploring this. It would be very confusing UI if the editor only offers snippets only via completions.

ulugbekna added 19 commits July 13, 2021 18:09
* we don't need to pair completion entries with a fixed range
* use more self-explanatory names for variables
* add comments to where it's not obvious why we're doing this
* make newlines more consistent
(AFAIU, await in an async function is useless if we don't await that function itself)
…aram of request)

does not have `data` field. We return the completion item itself if the `data` field
is missing.

We need this for the "merlin construct as completions" feature
* add comments to explain the code action
syntactically or in AST form
especially vscode-specific commands
* do not put two separate task in merlin thread; do requests in one
@ulugbekna ulugbekna force-pushed the construct-as-completion branch from 036c29e to fcd625b Compare July 13, 2021 13:15
@ulugbekna
Copy link
Collaborator Author

I hope that trying to make two merlin dispatches at once (fcd625b) is worth the complexity. But I tried to make the code modular, readable, and maintainable.

Copy link
Member

@rgrinberg rgrinberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope that trying to make two merlin dispatches at once (fcd625b) is worth the complexity. But I tried to make the code modular, readable, and maintainable.

It's definitely worth it.

The new code looks much better. Some more minor tweaks and it should be good to go.

ocaml-lsp-server/src/client.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/client.ml Show resolved Hide resolved
ocaml-lsp-server/src/compl.ml Outdated Show resolved Hide resolved
ocaml-lsp-server/src/ocaml_lsp_server.ml Show resolved Hide resolved
Copy link
Member

@rgrinberg rgrinberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed a few tweaks.

Looks good to go.

@rgrinberg rgrinberg force-pushed the construct-as-completion branch from 600e4ec to 6f9a240 Compare July 14, 2021 18:07
@ulugbekna ulugbekna merged commit a12fae4 into ocaml:master Jul 15, 2021
@ulugbekna ulugbekna deleted the construct-as-completion branch July 15, 2021 06:47
rgrinberg added a commit to rgrinberg/opam-repository that referenced this pull request Aug 19, 2021
CHANGES:

## Features

- Add a new code action `Add missing rec keyword`, which is available when
  adding a `rec` keyword can fix `Unbound value ...` error, e.g.,

  ```ocaml
  let fact n = if n = 0 then 1 else n * fact (n - 1)
                                     (* ^^^^ Unbound value fact *)
  ```

  Adding `rec` to the definition of `fact` will fix the problem. The new code
  action offers adding `rec`.

- Jump to the first hole on calling `Destruct` code action (only with client
  VSCode OCaml Platform) (ocaml/ocaml-lsp#468)

  Example: when a user invokes `Destruct` code action on `Some 1`, this code is
  replaced by `match Some 1 with None -> _ | Some _ -> _`, where the 1st and
  3rd underscores are "typed holes", a concept created by Merlin to be able to
  put "holes" in OCaml code.

  With this change, now for VSCode OCaml Platform users, on such invocation of
  `Destruct`, the cursor will jump to the first typed hole and select it, so
  that user can start editing right away.

- Use ocamlformat to properly format type snippets. This feature requires the
  `ocamlformat-rpc` opam package to be installed. (ocaml/ocaml-lsp#386)

- Add completion support for polymorphic variants, when it is possible to pin
  down the precise type. Examples (`<|>` stands for the cursor) when completion
  will work (ocaml/ocaml-lsp#473)

  Function application:

  ```
  let foo (a: [`Alpha | `Beta]) = ()

  foo `A<|>
  ```

  Type explicitly shown:

  ```
  let a : [`Alpha | `Beta] = `B<|>
  ```

  Note: this is actually a bug fix, since we were ignoring the backtick when
  constructing the prefix for completion.

- Parse merlin errors (best effort) into a more structured form. This allows
  reporting all locations as "related information" (ocaml/ocaml-lsp#475)

- Add support for Merlin `Construct` command as completion suggestions, i.e.,
  show complex expressions that could complete the typed hole. (ocaml/ocaml-lsp#472)

- Add a code action `Construct an expression` that is shown when the cursor is
  at the end of the typed hole, i.e., `_|`, where `|` is the cursor. The code
  action simply triggers the client (currently only VS Code is supported) to
  show completion suggestions. (ocaml/ocaml-lsp#472)

- Change the formatting-on-save error notification to a warning notification
  (ocaml/ocaml-lsp#472)

- Code action to qualify ("put module name in identifiers") and unqualify
  ("remove module name from identifiers") module names in identifiers (ocaml/ocaml-lsp#399)

  Starting from:

  ```ocaml
  open Unix

  let times = Unix.times ()
  let f x = x.Unix.tms_stime, x.Unix.tms_utime
  ```

  Calling "remove module name from identifiers" with the cursor on the open
  statement will produce:

  ```ocaml
  open Unix

  let times = times ()
  let f x = x.tms_stime, x.tms_utime
  ```

  Calling "put module name in identifiers" will restore:

  ```ocaml
  open Unix

  let times = Unix.times ()
  let f x = x.Unix.tms_stime, x.Unix.tms_utime
  ```

## Fixes

- Do not show "random" documentation on hover

  - fixed by [merlin#1364](ocaml/merlin#1364)
  - fixes duplicate:
    - [ocaml-lsp#344](ocaml/ocaml-lsp#344)
    - [vscode-ocaml-platform#111](ocamllabs/vscode-ocaml-platform#111)

- Correctly rename a variable used as a named/optional argument (ocaml/ocaml-lsp#478)

- When reporting an error at the beginning of the file, use the first line not
  the second (ocaml/ocaml-lsp#489)
rgrinberg added a commit to rgrinberg/opam-repository that referenced this pull request Aug 25, 2021
CHANGES:

## Features

- Add a new code action `Add missing rec keyword`, which is available when
  adding a `rec` keyword can fix `Unbound value ...` error, e.g.,

  ```ocaml
  let fact n = if n = 0 then 1 else n * fact (n - 1)
                                     (* ^^^^ Unbound value fact *)
  ```

  Adding `rec` to the definition of `fact` will fix the problem. The new code
  action offers adding `rec`.

- Use ocamlformat to properly format type snippets. This feature requires the
  `ocamlformat-rpc` opam package to be installed. (ocaml/ocaml-lsp#386)

- Add completion support for polymorphic variants, when it is possible to pin
  down the precise type. Examples (`<|>` stands for the cursor) when completion
  will work (ocaml/ocaml-lsp#473)

  Function application:

  ```
  let foo (a: [`Alpha | `Beta]) = ()

  foo `A<|>
  ```

  Type explicitly shown:

  ```
  let a : [`Alpha | `Beta] = `B<|>
  ```

  Note: this is actually a bug fix, since we were ignoring the backtick when
  constructing the prefix for completion.

- Parse merlin errors (best effort) into a more structured form. This allows
  reporting all locations as "related information" (ocaml/ocaml-lsp#475)

- Add support for Merlin `Construct` command as completion suggestions, i.e.,
  show complex expressions that could complete the typed hole. (ocaml/ocaml-lsp#472)

- Add a code action `Construct an expression` that is shown when the cursor is
  at the end of the typed hole, i.e., `_|`, where `|` is the cursor. The code
  action simply triggers the client (currently only VS Code is supported) to
  show completion suggestions. (ocaml/ocaml-lsp#472)

- Change the formatting-on-save error notification to a warning notification
  (ocaml/ocaml-lsp#472)

- Code action to qualify ("put module name in identifiers") and unqualify
  ("remove module name from identifiers") module names in identifiers (ocaml/ocaml-lsp#399)

  Starting from:

  ```ocaml
  open Unix

  let times = Unix.times ()
  let f x = x.Unix.tms_stime, x.Unix.tms_utime
  ```

  Calling "remove module name from identifiers" with the cursor on the open
  statement will produce:

  ```ocaml
  open Unix

  let times = times ()
  let f x = x.tms_stime, x.tms_utime
  ```

  Calling "put module name in identifiers" will restore:

  ```ocaml
  open Unix

  let times = Unix.times ()
  let f x = x.Unix.tms_stime, x.Unix.tms_utime
  ```

## Fixes

- Do not show "random" documentation on hover

  - fixed by [merlin#1364](ocaml/merlin#1364)
  - fixes duplicate:
    - [ocaml-lsp#344](ocaml/ocaml-lsp#344)
    - [vscode-ocaml-platform#111](ocamllabs/vscode-ocaml-platform#111)

- Correctly rename a variable used as a named/optional argument (ocaml/ocaml-lsp#478)

- When reporting an error at the beginning of the file, use the first line not
  the second (ocaml/ocaml-lsp#489)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants