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

Text_document has bugs when performing updates and getting positions #1207

Closed
faldor20 opened this issue Oct 29, 2023 · 6 comments · Fixed by ocaml/opam-repository#26202
Closed
Milestone

Comments

@faldor20
Copy link
Contributor

The Text_document module has some weird bugs:
These expect tests show the issue:

let%expect_test "replace second line first line is \\n" =
  let range = tuple_range (1, 2) (1, 2) in
  let doc = make_document (Uri.of_path "foo.ml") ~text:"\nfoo\nbar\nbaz\n" in
  let edit = TextEdit.create ~newText:"change" ~range in
  let newDoc = Text_document.apply_text_document_edits doc [ edit ] in
  newDoc |> Text_document.text |> String.escaped |> print_endline;
  [%expect {|
    result: \nfochangeo\nbar\nbaz\n |}]

let%expect_test "get position after change" =
  let range = tuple_range (1, 2) (1, 2) in
  let doc = make_document (Uri.of_path "foo.ml") ~text:"\nfoo\nbar\nbaz\n" in
  let edit = TextDocumentContentChangeEvent.create ~text:"change" ~range () in
  let newDoc = Text_document.apply_content_changes doc [ edit ] in
  let pos = Text_document.absolute_position newDoc range.start in
  newDoc |> Text_document.text |> String.escaped |> print_endline;
  printf "pos: %d\n" pos;
  [%expect {|
    pos: 3 |}]

Test one demonstrates how making the change causes text to become duplicated
Test two demonstrates how after making a change the absolute position comes out messed up.
I noticed that in my testing the end_ position when running absolute_range seemed unaffected, maybe that helps.

I discovered these issues while trying to use the lsp as a library in another project, they were very very confusing to debug 😅

I've noticed that sometimes it seems ocmallsp kind of gets confused and has to be restarted, I suspect this is a contributor to that issue as it could cause the editor and language-service to go out of sync.

I wonder if we could set up a property based test for the text_Document that run's the same edit's on a string using a simpler method than the zipper, then just feed in a huge sample of random positions and change text and see what happens. Just a thought.

@faldor20
Copy link
Contributor Author

Another possibility is to have the lsp check the on disk file, when it gets a file-saved notification to see if the current editor file has diverged from the file on disk, if so it could freak out and also load the on-disk file

@rgrinberg
Copy link
Member

I don't understand the issue with the first test. As far as I see, you're inserting the string change at the 3rd position on the second line and the output demonstrates that's exactly what happens.

@faldor20
Copy link
Contributor Author

faldor20 commented Nov 28, 2023

ahh, sorry, the tests actually fail. The test shows what should happen, if you actually run them you see the output is wrong.
I made an attempt at fixing this a while ago and got some of the way there, from memory there are two issues

  1. The beginning_of_line function within the string_zipper sometimes puts you on the previous line and leaves you there.
    Which was fixed by the below change adding a check to see if you've been put on the wrong line
let beginning_of_line t =
  let line=t.line in
  let t = prev_newline t in
  if is_begin t &&t.line=line  then t else advance_char t
  1. drop_until leaves the abs_pos completely borked( like a position longer than the entire string). This means when you call Text_document.absolute_position which intern calls String_zipper.offset the output is all over the place. I tried a few things to try and fix that, but I ran out of time and couldn't get it quite right.

rgrinberg added a commit that referenced this issue Nov 28, 2023
Signed-off-by: Rudi Grinberg <[email protected]>

<!-- ps-id: 271f1802-b582-4bac-b946-fe86c8e85541 -->
@rgrinberg
Copy link
Member

I attempted to reproduce in #1216. The first test seems to pass. Haven't looked closely at the second one yet.

@faldor20
Copy link
Contributor Author

Oh okay, I'll test it myself again but my results were

\nfochangeo\nfoo\nbar\nbaz\n

You can see foo gets duplicated

@rgrinberg
Copy link
Member

Thanks for the bug report @faldor20 and @emilienlemaire for the fix

voodoos added a commit to voodoos/opam-repository that referenced this issue Jul 5, 2024
CHANGES:

## Features

- Introduce a configuration option to control dune diagnostics. The option is
  called `duneDiganostics` and it may be set to `{ enable: false }` to disable
  diagnostics. (ocaml/ocaml-lsp#1221)

- Support folding of `ifthenelse` expressions (ocaml/ocaml-lsp#1031)

- Improve hover behavior (ocaml/ocaml-lsp#1245)

  Hovers are no longer displaye on useless parsetree nodes such as keywords,
  comments, etc.

  Multiline hovers are now filtered away.

  Display expanded ppx's in the hover window.

- Improve document symbols (ocaml/ocaml-lsp#1247)

  Use the parse tree instead of the typed tree. This means that document
  symbols will work even if the source code doesn't type check.

  Include symbols at arbitrary depth.

  Differentiate functions / types / variants / etc.

  This now includes PPXs like `let%expect_test` or `let%bench` in the outline.

- Introduce a `destruct-line` code action. This is an improved version of the
  old `destruct` code action. (ocaml/ocaml-lsp#1283)

- Improve signature inference to only include types for elements that were
  absent from the signature. Previously, all signature items would always be
  inserted. (ocaml/ocaml-lsp#1289)

- Add an `update-signature` code action to update the types of elements that
  were already present in the signature (ocaml/ocaml-lsp#1289)

- Add custom
  [`ocamllsp/merlinCallCompatible`](https://github.com/ocaml/ocaml-lsp/blob/e165f6a3962c356adc7364b9ca71788e93489dd0/ocaml-lsp-server/docs/ocamllsp/merlinCallCompatible-spec.md)
  request (ocaml/ocaml-lsp#1265)

- Add custom [`ocamllsp/typeEnclosing`](https://github.com/ocaml/ocaml-lsp/blob/109801e56f2060caf4487427bede28b824f4f1fe/ocaml-lsp-server/docs/ocamllsp/typeEnclosing-spec.md) request (ocaml/ocaml-lsp#1304)

## Fixes

- Detect document kind by looking at merlin's `suffixes` config.

  This enables more lsp features for non-.ml/.mli files. Though it still
  depends on merlin's support. (ocaml/ocaml-lsp#1237)

- Correctly accept the `--clientProcessId` flag. (ocaml/ocaml-lsp#1242)

- Disable automatic completion and signature help inside comments (ocaml/ocaml-lsp#1246)

- Includes a new optional/configurable option to toggle syntax documentation. If
  toggled on, allows display of syntax documentation on hover tooltips. Can be
  controlled via environment variables and by GUI for VS code. (ocaml/ocaml-lsp#1218)

- For completions on labels that the LSP gets from merlin, take into account
  whether the prefix being completed starts with `~` or `?`. Change the label
  completions that start with `?` to start with `~` when the prefix being
  completed starts with `~`. (ocaml/ocaml-lsp#1277)

- Fix document syncing (ocaml/ocaml-lsp#1278, ocaml/ocaml-lsp#1280, fixes ocaml/ocaml-lsp#1207)

- Stop generating inlay hints on generated code (ocaml/ocaml-lsp#1290)

- Fix parenthesizing of function types in `SignatureHelp` (ocaml/ocaml-lsp#1296)

- Fix syntax documentation rendering (ocaml/ocaml-lsp#1318)
avsm pushed a commit to avsm/opam-repository that referenced this issue Sep 5, 2024
CHANGES:

## Features

- Introduce a configuration option to control dune diagnostics. The option is
  called `duneDiganostics` and it may be set to `{ enable: false }` to disable
  diagnostics. (ocaml/ocaml-lsp#1221)

- Support folding of `ifthenelse` expressions (ocaml/ocaml-lsp#1031)

- Improve hover behavior (ocaml/ocaml-lsp#1245)

  Hovers are no longer displaye on useless parsetree nodes such as keywords,
  comments, etc.

  Multiline hovers are now filtered away.

  Display expanded ppx's in the hover window.

- Improve document symbols (ocaml/ocaml-lsp#1247)

  Use the parse tree instead of the typed tree. This means that document
  symbols will work even if the source code doesn't type check.

  Include symbols at arbitrary depth.

  Differentiate functions / types / variants / etc.

  This now includes PPXs like `let%expect_test` or `let%bench` in the outline.

- Introduce a `destruct-line` code action. This is an improved version of the
  old `destruct` code action. (ocaml/ocaml-lsp#1283)

- Improve signature inference to only include types for elements that were
  absent from the signature. Previously, all signature items would always be
  inserted. (ocaml/ocaml-lsp#1289)

- Add an `update-signature` code action to update the types of elements that
  were already present in the signature (ocaml/ocaml-lsp#1289)

- Add custom
  [`ocamllsp/merlinCallCompatible`](https://github.com/ocaml/ocaml-lsp/blob/e165f6a3962c356adc7364b9ca71788e93489dd0/ocaml-lsp-server/docs/ocamllsp/merlinCallCompatible-spec.md)
  request (ocaml/ocaml-lsp#1265)

- Add custom [`ocamllsp/typeEnclosing`](https://github.com/ocaml/ocaml-lsp/blob/109801e56f2060caf4487427bede28b824f4f1fe/ocaml-lsp-server/docs/ocamllsp/typeEnclosing-spec.md) request (ocaml/ocaml-lsp#1304)

## Fixes

- Detect document kind by looking at merlin's `suffixes` config.

  This enables more lsp features for non-.ml/.mli files. Though it still
  depends on merlin's support. (ocaml/ocaml-lsp#1237)

- Correctly accept the `--clientProcessId` flag. (ocaml/ocaml-lsp#1242)

- Disable automatic completion and signature help inside comments (ocaml/ocaml-lsp#1246)

- Includes a new optional/configurable option to toggle syntax documentation. If
  toggled on, allows display of syntax documentation on hover tooltips. Can be
  controlled via environment variables and by GUI for VS code. (ocaml/ocaml-lsp#1218)

- For completions on labels that the LSP gets from merlin, take into account
  whether the prefix being completed starts with `~` or `?`. Change the label
  completions that start with `?` to start with `~` when the prefix being
  completed starts with `~`. (ocaml/ocaml-lsp#1277)

- Fix document syncing (ocaml/ocaml-lsp#1278, ocaml/ocaml-lsp#1280, fixes ocaml/ocaml-lsp#1207)

- Stop generating inlay hints on generated code (ocaml/ocaml-lsp#1290)

- Fix parenthesizing of function types in `SignatureHelp` (ocaml/ocaml-lsp#1296)

- Fix syntax documentation rendering (ocaml/ocaml-lsp#1318)
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 a pull request may close this issue.

2 participants