Skip to content

Commit

Permalink
Fix prefix parsing for method call
Browse files Browse the repository at this point in the history
When completing module paths or record fields Merlin expects the
    beginning of the path and the `.` to be part of the prefix. But when
    accessing an object's methods, the prefix should not contain the `#`
    sign. We use a sub-matching group to that effect.

    - Prefix for [my_record.|] is ["my_record."] (handled by [name_or_label])
    - Prefix for [my_object#|] is [""] (handled by [method_call])
  • Loading branch information
voodoos committed Aug 23, 2024
1 parent 43ca593 commit 0fc6a4b
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
18 changes: 15 additions & 3 deletions ocaml-lsp-server/src/prefix_parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ include struct
])
;;

(** When completing module paths or record fields Merlin expects the
beginning of the path and the `.` to be part of the prefix. But when
accessing an object's methods, the prefix should not contain the `#`
sign. We use a sub-matching group to that effect.
- Prefix for [my_record.|] is ["my_record."] (handled by [name_or_label])
- Prefix for [my_object#|] is [""] (handled by [method_call]) *)
let method_call = compile (seq [ char '#'; Re.group (rep name_char); stop ])

(** matches let%lwt and let* style expressions. See
here:https://v2.ocaml.org/manual/bindingops.html *)
let monadic_bind =
Expand All @@ -42,8 +51,11 @@ let parse ~pos ~len text =
(*Attempt to match each of our possible prefix types, the order is important
because there is some overlap between the regexs*)
let matched =
List.find_map [ name_or_label; monadic_bind; infix_operator ] ~f:(fun regex ->
Re.exec_opt ~pos ~len regex text)
List.find_map
[ name_or_label; method_call; monadic_bind; infix_operator ]
~f:(fun regex -> Re.exec_opt ~pos ~len regex text)
in
matched |> Option.map ~f:(fun x -> Re.Group.get x 0)
matched
|> Option.map ~f:(fun x ->
if Re.Group.test x 1 then Re.Group.get x 1 else Re.Group.get x 0)
;;
48 changes: 47 additions & 1 deletion ocaml-lsp-server/test/e2e-new/completion.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1251,5 +1251,51 @@ let%expect_test "completion for object methods" =
print_completions ~limit:3 source position;
[%expect
{|
No completions |}]
Completions:
{
"kind": 14,
"label": "in",
"textEdit": {
"newText": "in",
"range": {
"end": { "character": 34, "line": 0 },
"start": { "character": 34, "line": 0 }
}
}
}
{
"detail": "'a",
"kind": 2,
"label": "a_method",
"sortText": "0000",
"textEdit": {
"newText": "a_method",
"range": {
"end": { "character": 34, "line": 0 },
"start": { "character": 34, "line": 0 }
}
}
} |}]
;;
let%expect_test "completion for object methods" =
let source = {ocaml|let f (x : < a_method : 'a; ab_m : 'b >) = x#ab|ocaml} in
let position = Position.create ~line:0 ~character:49 in
print_completions ~limit:3 source position;
[%expect
{|
Completions:
{
"detail": "'b",
"kind": 2,
"label": "ab_m",
"sortText": "0000",
"textEdit": {
"newText": "ab_m",
"range": {
"end": { "character": 49, "line": 0 },
"start": { "character": 47, "line": 0 }
}
}
} |}]
;;

0 comments on commit 0fc6a4b

Please sign in to comment.