diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b3b59b0e..17cbe447a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ - Improve precision in signature help. You now do not need to type anything into the argument for it to highlight. https://github.com/rescript-lang/rescript-vscode/pull/675 - Remove redundant function name in signature help, to clean up what's shown to the user some. https://github.com/rescript-lang/rescript-vscode/pull/678 - Show docstrings in hover for record fields and variant constructors. https://github.com/rescript-lang/rescript-vscode/pull/694 +- The necessary leading `?` is now automatically inserted for optional fields when destructuring records. https://github.com/rescript-lang/rescript-vscode/pull/715 #### :bug: Bug Fix diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 75b25c138..be1f71b66 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -1047,10 +1047,10 @@ let printConstructorArgs argsLen ~asSnippet = if List.length !args > 0 then "(" ^ (!args |> String.concat ", ") ^ ")" else "" -type completionMode = Pattern | Expression +type completionMode = Pattern of Completable.patternMode | Expression -let rec completeTypedValue (t : SharedTypes.completionType) ~full ~prefix - ~completionContext ~mode = +let rec completeTypedValue ~full ~prefix ~completionContext ~mode + (t : SharedTypes.completionType) = match t with | Tbool env -> [ @@ -1142,10 +1142,23 @@ let rec completeTypedValue (t : SharedTypes.completionType) ~full ~prefix |> List.filter (fun (field : field) -> List.mem field.fname.txt seenFields = false) |> List.map (fun (field : field) -> - Completion.create field.fname.txt - ~kind: - (Field (field, TypeUtils.extractedTypeToString extractedType)) - ~env) + match (field.optional, mode) with + | true, Pattern Destructuring -> + Completion.create ("?" ^ field.fname.txt) + ~docstring: + [ + field.fname.txt + ^ " is an optional field, and needs to be destructured \ + using '?'."; + ] + ~kind: + (Field (field, TypeUtils.extractedTypeToString extractedType)) + ~env + | _ -> + Completion.create field.fname.txt + ~kind: + (Field (field, TypeUtils.extractedTypeToString extractedType)) + ~env) |> filterItems ~prefix | None -> if prefix = "" then @@ -1157,7 +1170,7 @@ let rec completeTypedValue (t : SharedTypes.completionType) ~full ~prefix (ExtractedType ( extractedType, match mode with - | Pattern -> `Type + | Pattern _ -> `Type | Expression -> `Value )) ~env (); ] @@ -1190,7 +1203,7 @@ let rec completeTypedValue (t : SharedTypes.completionType) ~full ~prefix (ExtractedType ( typ, match mode with - | Pattern -> `Type + | Pattern _ -> `Type | Expression -> `Value )) ~env (); ] @@ -1360,7 +1373,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover Utils.startsWith name prefix && (forHover || not (List.mem name identsSeen))) |> List.map mkLabel - | Cpattern {contextPath; prefix; nested; fallback} -> ( + | Cpattern {contextPath; prefix; nested; fallback; patternMode} -> ( let fallbackOrEmpty ?items () = match (fallback, items) with | Some fallback, (None | Some []) -> @@ -1385,7 +1398,8 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover | Some (typ, _env, completionContext) -> let items = typ - |> completeTypedValue ~mode:Pattern ~full ~prefix ~completionContext + |> completeTypedValue ~mode:(Pattern patternMode) ~full ~prefix + ~completionContext in fallbackOrEmpty ~items ()) | None -> fallbackOrEmpty ()) diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index 9fe9c5369..c917fa91c 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -317,6 +317,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = prefix; nested = List.rev nestedPattern; fallback = None; + patternMode = Default; }) | _ -> () in @@ -391,6 +392,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = nested = []; prefix = ""; fallback = None; + patternMode = Default; })) | Pexp_match (exp, cases) -> ( (* If there's more than one case, or the case isn't a pattern hole, figure out if we're completing another @@ -423,6 +425,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = nested = []; prefix = ""; fallback = None; + patternMode = Default; }) | false, false -> ())) | _ -> unsetLookingForPat () @@ -524,6 +527,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = prefix; nested = List.rev nested; fallback = None; + patternMode = Destructuring; }) | _ -> ()) | _ -> ()); diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index b8f811fad..d0d893609 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -631,6 +631,8 @@ module Completable = struct ^ ")" | NArray -> "array" + type patternMode = Default | Destructuring + type t = | Cdecorator of string (** e.g. @module *) | CnamedArg of contextPath * string * string list @@ -648,6 +650,7 @@ module Completable = struct contextPath: contextPath; nested: nestedPath list; prefix: string; + patternMode: patternMode; fallback: t option; } | CexhaustiveSwitch of {contextPath: contextPath; exprLoc: Location.t} diff --git a/analysis/tests/src/Destructuring.res b/analysis/tests/src/Destructuring.res index 2a9c59359..0ef61122e 100644 --- a/analysis/tests/src/Destructuring.res +++ b/analysis/tests/src/Destructuring.res @@ -19,3 +19,15 @@ let f2 = (x: x) => { // ^com ignore(x) } + +type recordWithOptField = { + someField: int, + someOptField?: bool +} + +let x: recordWithOptField = { + someField: 123 +} + +// let {} = x +// ^com \ No newline at end of file diff --git a/analysis/tests/src/expected/Destructuring.res.txt b/analysis/tests/src/expected/Destructuring.res.txt index dbb31578d..867586806 100644 --- a/analysis/tests/src/expected/Destructuring.res.txt +++ b/analysis/tests/src/expected/Destructuring.res.txt @@ -58,3 +58,20 @@ Completable: Cpattern Value[x]->recordBody "documentation": null }] +Complete src/Destructuring.res 31:8 +posCursor:[31:8] posNoWhite:[31:7] Found pattern:[31:7->31:9] +Completable: Cpattern Value[x]->recordBody +[{ + "label": "someField", + "kind": 5, + "tags": [], + "detail": "someField: int\n\nrecordWithOptField", + "documentation": null + }, { + "label": "?someOptField", + "kind": 5, + "tags": [], + "detail": "?someOptField: option\n\nrecordWithOptField", + "documentation": {"kind": "markdown", "value": "someOptField is an optional field, and needs to be destructured using '?'."} + }] +