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

add support for refactor-open (qualify and unqualify) code action #399

Merged
merged 2 commits into from
Jul 26, 2021

Conversation

ulugbekna
Copy link
Collaborator

@ulugbekna ulugbekna commented Apr 3, 2021

Reservations I have:

  • I'm not sure code action names are easily understandable / friendly to newcomers

Blockers:

  • Code actions are shown only if the cursor is on open statement, but they can be shown even if the code action won't do anything, e.g.,
open Unix (* both qualify and unqualify code actions will be shown *)
let u = () 
  • (this is merged into ocaml/merlin#master, we need to rebase vendored merlin) refactor-open qualify qualifies with full paths, e.g., for open Import, it does Dune__exe.Import.foo....

To-do

  • add tests
  • add an entry to the README, so that users know about these code actions

@rgrinberg
Copy link
Member

I don't mind the names. This is one of those things that's easy enough to learn by example.

Code actions are shown only if the cursor is on open statement, but they can be shown even if the code action won't do anything, e.g.,

If the code action won't do anything, the edit it computes should be empty. Can we filter it out then?

@ulugbekna
Copy link
Collaborator Author

ulugbekna commented Apr 6, 2021

If the code action won't do anything, the edit it computes should be empty. Can we filter it out then?

Unfortunately, merlin always returns edits, even if those edits when applied do not change the document at all.

(I could check whether edits do anything by applying them before returning the code action, but that seems expensive)


Other notes:

  1. The code action is quite useful for stdlib and in-file modules refactor-open qualify, as is seen in the tests. However, merlin doesn't use short paths when qualifying modules. Example:
open Import
module Bin = Stdune.Bin

let _PATH =
  lazy
    (Bin.parse_path
       (Dune__exe.Import.Option.value ~default:"" (Dune__exe.Import.Unix_env.get Dune__exe.Import.Unix_env.initial "PATH")))

Meanwhile, do you happen to know if that's also the case with refactor-open in merlin's emacs mode?

I will try to fix this anyway.

  1. Do you happen to know what's a good way to do several sequenced queries to merlin (vs ocamlmerlin single)? I need merlin to take into account ".merlin" and all source files (while single query only can take one)?

@rgrinberg
Copy link
Member

Meanwhile, do you happen to know if that's also the case with refactor-open in merlin's emacs mode?

No idea. I don't use the emacs mode.

Do you happen to know what's a good way to do several sequenced queries to merlin (vs ocamlmerlin single)? I need merlin to take into account ".merlin" and all source files (while single query only can take one)?

Is this for tests or something? We don't have .merlin files anymore.

Let's see if @voodoos can help us out.

@ulugbekna
Copy link
Collaborator Author

A due update:

  1. I created PRs to the merlin repo for short-paths and useless edits problems (refactor-open qualify uses short-paths merlin#1313 and refactor-open: don't return useless edits merlin#1314).

I would appreciate your take on whether we should merge this PR as is and wait for upstream merlin to merge fix-PRs, or merge those in ocaml-lsp merlin. Both are fine with me.

Do you happen to know what's a good way to do several sequenced queries to merlin (vs ocamlmerlin single)? I need merlin to take into account ".merlin" and all source files (while single query only can take one)?
Is this for tests or something? We don't have .merlin files anymore.

Yes, I needed to write some tests for merlin, but I figured this out.

@rgrinberg
Copy link
Member

I would appreciate your take on whether we should merge this PR as is and wait for upstream merlin to merge fix-PRs, or merge those in ocaml-lsp merlin. Both are fine with me.

Do you think this feature is useful to users in its current form?

@ulugbekna
Copy link
Collaborator Author

Let's aim to merge this for the release after the next one. I hope by then we'll get a feel whether ocaml/merlin is willing to merge.

@ulugbekna ulugbekna marked this pull request as ready for review July 23, 2021 13:40
@ulugbekna
Copy link
Collaborator Author

ulugbekna commented Jul 23, 2021

@rgrinberg I think that this feature has improved quite a bit in merlin and should be useful to ocaml-lsp users as well :-)

I think this PR is ready as soon as we switch to using the latest merlin master (I think you'd prefer to do that yourself? otherwise, I can make a PR).

I included b975615 in this PR as well:

  • what it does? when we update to the latest merlin, we automatically get the fix for Wrong documentation on hover #344, so I included the changes entry about it and updated the according test
  • why here? we anyway usually rebase and merge, so including this here should be innocuous; let me know if you'd prefer it in a separate PR

I can squash all but b975615 for cleaner history; lmk if you'd like that.

Other feedback/proposals are also welcome.

@ulugbekna ulugbekna linked an issue Jul 23, 2021 that may be closed by this pull request
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.

The PR looks good but we can't rely on the following special libraries in the tests: unix, str, dynlink.

@@ -48,6 +48,12 @@

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

- Bug fix: do not show "random" documentation on hover
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this already in the merlin change list? We usually do not replicate merlin's change list here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is already in the merlin changes list, but since this bug has been reported several times in both ocaml-lsp & vscode-ocaml-platform, I thought it is useful for users to see it fixed.

I think that merlin is ocaml-lsp's backend, but the end user shouldn't be lurking in merlin Changes to see what's new in ocaml-lsp -- maybe we could at least add a link to their Changes inside the ocaml-lsp-vendored merlin source.

Copy link
Collaborator Author

@ulugbekna ulugbekna Jul 25, 2021

Choose a reason for hiding this comment

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

Also, the change entry in merlin is "locate: reset global state from all entry points (#1364)", which is cryptic, isn't it?

Copy link
Member

Choose a reason for hiding this comment

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

It is cryptic. But that can be mended on merlin's side. I'd prefer to see the links to the corresponding change list entries where the fix was done.

I think that merlin is ocaml-lsp's backend, but the end user shouldn't be lurking in merlin Changes to see what's new in ocaml-lsp -- maybe we could at least add a link to their Changes inside the ocaml-lsp-vendored merlin source.

We could have a policy of replicating only the relevant merlin changes in our repo. The problem is that I often lack context as to what is relevant to lsp, and it is extra work. We can bring it up with the rest of the team to see what they think.

@ulugbekna ulugbekna merged commit 07df575 into ocaml:master Jul 26, 2021
@ulugbekna ulugbekna deleted the refactor-open branch July 26, 2021 06:30
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.

Wrong documentation on hover
2 participants