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

Better ocamlformatrpc integration #549

Closed

Conversation

panglesd
Copy link
Collaborator

This PR addresses issue #495.

  • In case of generated code via destruct or "inferred interface", ocaml-lsp now tries to format them using ocamlformat-rpc. If this fails, the non-formatted text is used. (When there are "merlin holes" no formatting is possible untill the merged Handle merlin typed holes ocaml-ppx/ocamlformat#1698 is released).
  • In case of user querying formatting the whole file, ocaml-lsp first tries ocamlformat-rpc and fallback to regular ocamlformat if it fails.

@ulugbekna ulugbekna self-requested a review November 15, 2021 15:19
@panglesd panglesd mentioned this pull request Nov 15, 2021
4 tasks
@rgrinberg
Copy link
Member

The way this works is by sending formatting snippets, but the end result isn't necessarily formatted. I'm curious if you tested this out, does it seem to work well in practice?

let+ formattedText =
Ocamlformat_rpc.(format_type state.ocamlformat_rpc ~typ:newText)
in
match formattedText with
Copy link
Member

Choose a reason for hiding this comment

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

formatted_text

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll update my variable names. Should newText also be renamed to new_text, or has this variable a reason to be formatted in camelCase?

Copy link
Collaborator

@ulugbekna ulugbekna Nov 18, 2021

Choose a reason for hiding this comment

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

camelCase naming is fine if used later for punning, I believe

| Ok res -> Some (code_action_of_case_analysis doc uri res)
| Ok (loc, newText) -> (
let+ formattedText =
Ocamlformat_rpc.(format_type state.ocamlformat_rpc ~typ:newText)
Copy link
Member

Choose a reason for hiding this comment

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

Why do you need the module open? I think Ocamlformat_rpc.format_type should be enough.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You are right, it is enough. I don't remember why I opened it.

Some (code_action_of_intf doc intf params.range)
| Intf -> (
let* intf = Inference.infer_intf ~force_open_impl:true state doc in
let+ formattedIntf =
Copy link
Member

Choose a reason for hiding this comment

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

formatted_intf

@panglesd
Copy link
Collaborator Author

The way this works is by sending formatting snippets, but the end result isn't necessarily formatted. I'm curious if you tested this out, does it seem to work well in practice?

It works, I would say, better than without formatting, even though a subsequent call to ocamlformat for the whole file is needed to have the right formatting. However, I don't think automatically formatting the whole file is good for user experience, as it modifies the file at position far from the cursor without telling the user.

Peek 2021-11-17 11-39

As a comparison, emacs does the same (formatting the generated code only), but is better just in the fact that it indent well the generated lines (but I think this is thanks to tuareg-mode and not merlin-related).

@ulugbekna
Copy link
Collaborator

Just to be sure, it seems that when using ocamlformat rpc the version put in .ocamlformat is not respected, eg see the video below where I have ocamlformat master pinned, and formatting works with .ocamlformat version=0.19.0 (but sometimes it doesn't -- I don't quite understand; it would be nice to make sure the rpc respects the .ocamlformat options, for example, as a test)

Screen.Recording.2021-11-18.at.14.22.33.mov

@rgrinberg
Copy link
Member

Merged after a few tweaks.

@rgrinberg rgrinberg closed this Nov 22, 2021
@ulugbekna
Copy link
Collaborator

AFAIU, Ocamlformat_rpc.configure fn, which is called in Ocamlformat_rpc.(create : unit -> t), specifies formatting config tailored to suit "vscode popups", which isn't what we want when we format source files (we want to get the config from the .ocamlformat file). Shall we revert and let @panglesd continue working on the PR or have a follow up PR?

@rgrinberg
Copy link
Member

rgrinberg commented Nov 22, 2021 via email

@ulugbekna
Copy link
Collaborator

I think you're missing that this PR formats source files as well, and the current master is pretty much unusable since any source file reformatted incorrectly on save (if they have formatting on save on). @panglesd do you have time to fix that?

@panglesd
Copy link
Collaborator Author

Sure, I'll try to fix this soon (I hope by tomorrow evening)

@rgrinberg
Copy link
Member

We'll give you the week :)

@panglesd
Copy link
Collaborator Author

I am not anymore sure that we should format the entire file with ocamlformat_rpc.

As ocamlformat_rpc acts completely independently from the .ocamlformat file, we need to find and parse this file, to send to the ocamlformat_rpc server all the options of .ocamlformat.
The problem is that ocamlformat_rpc does not have a counterpart to the "version" value in the .ocamlformat file: To fail on wrong versions, we would also need to parse the file to find the required version, call ocamlformat-rpc --version to know the installed version, compare the two and fail if they differ.

I start to think that there are more disadvantages in using ocamlformat_rpc instead of calling ocamlformat directly, as we need to reinvent the wheel for two reasons: sending .ocamlformat options, and compare .ocamlformat version with installed version. Thats' a lot!

What do you think? Should I revert back to ocamlformat for formatting whole file? Or should continue the ocamlformat_rpc way? (I have something working except for the version comparison)

@rgrinberg
Copy link
Member

rgrinberg commented Nov 23, 2021 via email

@ulugbekna
Copy link
Collaborator

ulugbekna commented Nov 23, 2021

That indeed seems limitation on the ocamlformat-rpc side, which should be fixed.

I don't know how much we would like to handle .ocamlformat files ourselves, but

  1. parsing ocamlformat files is easy
  2. we anyway would like to add support for auto-completion in ocamlformat files, which should involve parsing those files anyway
  3. we could add various features based on handling ocamlformat files, e.g., on ocamlformat file change propose to reformat all files (preferably with debouncing however)

@rgrinberg
Copy link
Member

rgrinberg commented Nov 23, 2021

I don't mind adding these features but I want all the heavy lifting to be on the ocamlformat side through rpc. It's their format and its interpretationshould be a black box to us as much as possible.

on ocamlformat file change propose to reformat all files (preferably with debouncing however)

That's something that should be done through dune.

@panglesd
Copy link
Collaborator Author

parsing ocamlformat files is easy
Sure, but I agree with Rudi that its their format so parsing should be done on their side.

I will make a PR reverting file formatting to using ocamlformat, and file an issue to the ocamlformat repo about using .ocamlformat for the rpc server.

@rgrinberg
Copy link
Member

Instead of reverting you can also add a flag to disable it. Might save the effort of having to reintroduce the patch after the issue is fixed upstream.

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.

3 participants