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

Initial pattern completion #670

Merged
merged 31 commits into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9a63a84
basic setup of some sort of structure, and complete tuple patterns
zth Dec 30, 2022
112ee62
nested tuple
zth Dec 30, 2022
c18e7bf
start integrating completion for records
zth Dec 30, 2022
352872f
complete record bodies/fields in patterns
zth Jan 1, 2023
01516a6
handle completing for new record fields, and filtering already seen f…
zth Jan 1, 2023
5f4d7e0
add test for patterns under other patterns, and handle unsetting what…
zth Jan 1, 2023
3c7562c
identify and handle completing destructuring patterns
zth Jan 1, 2023
cc8412f
comments and cleanup
zth Jan 1, 2023
4df242f
add nested destructure test
zth Jan 1, 2023
26b0e68
fix
zth Jan 1, 2023
779e1be
descend through variant payloads
zth Jan 1, 2023
d349f43
handle polyvariants
zth Jan 1, 2023
72039e2
complete arrays in patterns
zth Jan 1, 2023
57ba325
handle multiple payloads in variants/polyvariants via regular tuple h…
zth Jan 2, 2023
3eb59e2
move from ast iterator to traversal function for finding completables…
zth Jan 3, 2023
8e3baf5
ignore unused var
zth Jan 3, 2023
dda7fd4
handle options
zth Jan 3, 2023
3ea5168
handle completing new items in constructor/variant payloads with mult…
zth Jan 3, 2023
124509e
handle completing new items in tuples
zth Jan 3, 2023
68e22db
add broken parser case
zth Jan 3, 2023
23b7833
remove unused
zth Jan 3, 2023
5976234
refactor and unify how pat tuple items are traversed
zth Jan 3, 2023
c601823
simplify setting completion pattern
zth Jan 3, 2023
a828e79
handle completing root switch case when theres more than one case
zth Jan 3, 2023
11cb6ae
refactor
zth Jan 3, 2023
9429664
handle ppat_or
zth Jan 3, 2023
a61f06b
handle or patterns (including broken patterns) in variant/polyvariant…
zth Jan 4, 2023
3659013
changelog
zth Jan 4, 2023
bb63093
add way to use fallbacks when completing patterns, restoring old beha…
zth Jan 5, 2023
bba5805
refactor nested pattern completion handling in backend
zth Jan 5, 2023
391d8d4
remove unecessary log
zth Jan 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Add autocomplete for JSX prop values. https://github.com/rescript-lang/rescript-vscode/pull/667
- Add snippet support in completion items. https://github.com/rescript-lang/rescript-vscode/pull/668
- Add support from completing polyvariants as values. https://github.com/rescript-lang/rescript-vscode/pull/669
- Add support for completion in patterns. https://github.com/rescript-lang/rescript-vscode/pull/670

#### :nail_care: Polish

Expand Down
118 changes: 112 additions & 6 deletions analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,8 @@ let rec extractType ~env ~package (t : Types.type_expr) =
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractType ~env ~package t1
| Tconstr (Path.Pident {name = "option"}, [payloadTypeExpr], _) ->
Some (Completable.Toption (env, payloadTypeExpr))
| Tconstr (Path.Pident {name = "array"}, [payloadTypeExpr], _) ->
Some (Tarray (env, payloadTypeExpr))
| Tconstr (Path.Pident {name = "bool"}, [], _) -> Some (Tbool env)
| Tconstr (path, _, _) -> (
match References.digConstructor ~env ~package path with
Expand All @@ -1528,6 +1530,8 @@ let rec extractType ~env ~package (t : Types.type_expr) =
Some
(Tvariant
{env; constructors; variantName = name.txt; variantDecl = decl})
| Some (env, {item = {kind = Record fields}}) ->
Some (Trecord {env; fields; typeExpr = t})
| _ -> None)
| Ttuple expressions -> Some (Tuple (env, expressions, t))
| Tvariant {row_fields} ->
Expand Down Expand Up @@ -1566,7 +1570,7 @@ let printConstructorArgs argsLen ~asSnippet =
else ""

let completeTypedValue ~env ~envWhereCompletionStarted ~full ~prefix
~expandOption =
~expandOption ~includeLocalValues ~completionContext =
zth marked this conversation as resolved.
Show resolved Hide resolved
let namesUsed = Hashtbl.create 10 in
let rec completeTypedValueInner t ~env ~full ~prefix ~expandOption =
let items =
Expand Down Expand Up @@ -1641,10 +1645,36 @@ let completeTypedValue ~env ~envWhereCompletionStarted ~full ~prefix
~insertText:(printConstructorArgs numExprs ~asSnippet:true)
~kind:(Value typ) ~env ();
]
| Some (Trecord {env; fields; typeExpr}) -> (
(* As we're completing for a record, we'll need a hint (completionContext)
here to figure out whether we should complete for a record field, or
the record body itself. *)
match completionContext with
| Some (Completable.RecordField {seenFields}) ->
fields
|> List.filter (fun (field : field) ->
List.mem field.fname.txt seenFields = false)
|> List.map (fun (field : field) ->
Completion.create ~name:field.fname.txt
~kind:(Field (field, typeExpr |> Shared.typeToString))
~env)
|> filterItems ~prefix
| None ->
[
Completion.createWithSnippet ~name:"{}"
~insertText:(if !Cfg.supportsSnippets then "{$0}" else "{}")
~sortText:"a" ~kind:(Value typeExpr) ~env ();
])
| Some (Tarray (env, typeExpr)) ->
[
Completion.createWithSnippet ~name:"[]"
~insertText:(if !Cfg.supportsSnippets then "[$0]" else "[]")
~sortText:"a" ~kind:(Value typeExpr) ~env ();
]
| _ -> []
in
(* Include all values and modules in completion if there's a prefix, not otherwise *)
if prefix = "" then items
if prefix = "" || includeLocalValues = false then items
else
items
@ completionForExportedValues ~env:envWhereCompletionStarted ~prefix
Expand Down Expand Up @@ -1729,7 +1759,57 @@ let getJsxLabels ~componentPath ~findTypeOfValue ~package =
typ |> getLabels
| None -> []

let processCompletable ~debug ~full ~scope ~env ~pos ~forHover
(** This moves through a pattern via a set of instructions, trying to resolve the type at the end of the pattern. *)
let rec resolveNestedPattern typ ~env ~package ~nested =
match nested with
| [] -> Some (typ, env, None)
| patternPath :: nested -> (
match (patternPath, typ |> extractType ~env ~package) with
| Completable.PTupleItem {itemNum}, Some (Tuple (env, tupleItems, _)) -> (
match List.nth_opt tupleItems itemNum with
| None -> None
| Some typ -> typ |> resolveNestedPattern ~env ~package ~nested)
| PFollowRecordField {fieldName}, Some (Trecord {env; fields}) -> (
match
fields
|> List.find_opt (fun (field : field) -> field.fname.txt = fieldName)
with
| None -> None
| Some {typ} -> typ |> resolveNestedPattern ~env ~package ~nested)
| PRecordBody {seenFields}, Some (Trecord {env; typeExpr}) ->
Some (typeExpr, env, Some (Completable.RecordField {seenFields}))
| ( PVariantPayload {constructorName = "Some"; itemNum = 0},
Some (Toption (env, typ)) ) ->
typ |> resolveNestedPattern ~env ~package ~nested
| ( PVariantPayload {constructorName; itemNum},
Some (Tvariant {env; constructors}) ) -> (
match
constructors
|> List.find_opt (fun (c : Constructor.t) ->
c.cname.txt = constructorName)
with
| None -> None
| Some constructor -> (
match List.nth_opt constructor.args itemNum with
| None -> None
| Some (typ, _) -> typ |> resolveNestedPattern ~env ~package ~nested))
| ( PPolyvariantPayload {constructorName; itemNum},
Some (Tpolyvariant {env; constructors}) ) -> (
match
constructors
|> List.find_opt (fun (c : polyVariantConstructor) ->
c.name = constructorName)
with
| None -> None
| Some constructor -> (
match List.nth_opt constructor.args itemNum with
| None -> None
| Some typ -> typ |> resolveNestedPattern ~env ~package ~nested))
| PArray, Some (Tarray (env, typ)) ->
typ |> resolveNestedPattern ~env ~package ~nested
| _ -> None)

let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover
(completable : Completable.t) =
let package = full.package in
let rawOpens = Scope.getRawOpens scope in
Expand Down Expand Up @@ -1792,7 +1872,7 @@ let processCompletable ~debug ~full ~scope ~env ~pos ~forHover
| Some (_, typ, env) ->
typ
|> completeTypedValue ~env ~envWhereCompletionStarted ~full ~prefix
~expandOption:true)
~expandOption:true ~includeLocalValues:true ~completionContext:None)
| Cdecorator prefix ->
let mkDecorator (name, docstring) =
{(Completion.create ~name ~kind:(Label "") ~env) with docstring}
Expand Down Expand Up @@ -2057,11 +2137,11 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i
| Some (Optional _, typ) ->
typ
|> completeTypedValue ~env ~envWhereCompletionStarted ~full ~prefix
~expandOption:true
~expandOption:true ~includeLocalValues:true ~completionContext:None
| Some ((Unlabelled _ | Labelled _), typ) ->
typ
|> completeTypedValue ~env ~envWhereCompletionStarted ~full ~prefix
~expandOption:false)
~expandOption:false ~includeLocalValues:true ~completionContext:None)
| CnamedArg (cp, prefix, identsSeen) ->
let labels =
match
Expand Down Expand Up @@ -2091,3 +2171,29 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i
Utils.startsWith name prefix
&& (forHover || not (List.mem name identsSeen)))
|> List.map mkLabel
| Cpattern {typ; prefix; nested; fallback} -> (
let fallbackOrEmpty ?items () =
match (fallback, items) with
| Some fallback, (None | Some []) ->
fallback |> processCompletable ~debug ~full ~scope ~env ~pos ~forHover
| _, Some items -> items
| None, None -> []
in
let envWhereCompletionStarted = env in
match
typ
|> getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
~exact:true ~scope
|> completionsGetTypeEnv
with
| Some (typ, env) -> (
match typ |> resolveNestedPattern ~env ~package:full.package ~nested with
| None -> fallbackOrEmpty ()
| Some (typ, env, completionContext) ->
let items =
typ
|> completeTypedValue ~env ~envWhereCompletionStarted ~full ~prefix
~expandOption:false ~includeLocalValues:false ~completionContext
in
fallbackOrEmpty ~items ())
| None -> fallbackOrEmpty ())
Loading