diff --git a/CHANGELOG.md b/CHANGELOG.md index ad7114f76..2b6c471de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ ## master +#### :rocket: New Feature + +- Enable completion for `Js.Exn.Error(error)` when pattern matching on `exn`. This is to make the `Js.Exn.Error` API more discoverable. https://github.com/rescript-lang/rescript-vscode/pull/728 + ## 1.12.0 #### :rocket: New Feature diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index dada1028a..7a62de8e6 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -1277,7 +1277,21 @@ let rec completeTypedValue ~full ~prefix ~completionContext ~mode ^ if !Cfg.supportsSnippets then "{$0}" else "{}") ~sortText:"A" ~kind:(Value typ) ~env (); ] - | _ -> [] + | Tfunction _ -> [] + | Texn env -> + [ + Completion.create + (full.package.builtInCompletionModules.exnModulePath @ ["Error(error)"] + |> ident) + ~kind:(Label "Catches errors from JavaScript errors.") + ~docstring: + [ + "Matches on a JavaScript error. Read more in the [documentation on \ + catching JS \ + exceptions](https://rescript-lang.org/docs/manual/latest/exception#catching-js-exceptions)."; + ] + ~env; + ] let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover (completable : Completable.t) = diff --git a/analysis/src/Packages.ml b/analysis/src/Packages.ml index a8d218c88..f00d2d40c 100644 --- a/analysis/src/Packages.ml +++ b/analysis/src/Packages.ml @@ -111,6 +111,7 @@ let newBsPackage ~rootPath = promiseModulePath = ["Promise"]; listModulePath = ["List"]; resultModulePath = ["Result"]; + exnModulePath = ["Exn"]; } else if opens_from_bsc_flags @@ -129,6 +130,7 @@ let newBsPackage ~rootPath = promiseModulePath = ["Js"; "Promise"]; listModulePath = ["List"]; resultModulePath = ["Result"]; + exnModulePath = ["Js"; "Exn"]; } else { @@ -140,6 +142,7 @@ let newBsPackage ~rootPath = promiseModulePath = ["Js"; "Promise"]; listModulePath = ["Belt"; "List"]; resultModulePath = ["Belt"; "Result"]; + exnModulePath = ["Js"; "Exn"]; }); }))) | None -> None) diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index c6e87ad5d..622065cdd 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -298,6 +298,7 @@ type polyVariantConstructor = {name: string; args: Types.type_expr list} type completionType = | Tuple of QueryEnv.t * Types.type_expr list * Types.type_expr | Toption of QueryEnv.t * completionType + | Texn of QueryEnv.t | Tbool of QueryEnv.t | Tarray of QueryEnv.t * completionType | Tstring of QueryEnv.t @@ -519,6 +520,7 @@ type builtInCompletionModules = { promiseModulePath: string list; listModulePath: string list; resultModulePath: string list; + exnModulePath: string list; } type package = { diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index a07490b8c..95de5fb55 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -119,6 +119,7 @@ let rec extractType ~env ~package (t : Types.type_expr) = |> Option.map (fun payloadTyp -> Tarray (env, payloadTyp)) | Tconstr (Path.Pident {name = "bool"}, [], _) -> Some (Tbool env) | Tconstr (Path.Pident {name = "string"}, [], _) -> Some (Tstring env) + | Tconstr (Path.Pident {name = "exn"}, [], _) -> Some (Texn env) | Tconstr (path, _, _) -> ( match References.digConstructor ~env ~package path with | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> @@ -421,6 +422,7 @@ let rec extractedTypeToString ?(inner = false) = function | Trecord {definition = `NameOnly name; fields} -> if inner then name else printRecordFromFields ~name fields | TinlineRecord {fields} -> printRecordFromFields fields + | Texn _ -> "exn" let unwrapCompletionTypeIfOption (t : SharedTypes.completionType) = match t with diff --git a/analysis/tests/src/CompletionPattern.res b/analysis/tests/src/CompletionPattern.res index bf465db05..b2280b88c 100644 --- a/analysis/tests/src/CompletionPattern.res +++ b/analysis/tests/src/CompletionPattern.res @@ -201,3 +201,8 @@ let ff: recordWithFn = {someFn: () => ()} // switch ff { | {someFn: }} // ^com + +let xn: exn = Obj.magic() + +// switch xn { | } +// ^com diff --git a/analysis/tests/src/expected/CompletionPattern.res.txt b/analysis/tests/src/expected/CompletionPattern.res.txt index 3a603eb50..e935e98ca 100644 --- a/analysis/tests/src/expected/CompletionPattern.res.txt +++ b/analysis/tests/src/expected/CompletionPattern.res.txt @@ -905,8 +905,19 @@ Completable: Cpattern Value[s]->tuple($1) }] Complete src/CompletionPattern.res 201:25 -posCursor:[201:25] posNoWhite:[201:24] Found expr:[201:3->201:28] +posCursor:[201:25] posNoWhite:[201:24] Found expr:[201:3->204:25] posCursor:[201:25] posNoWhite:[201:24] Found pattern:[201:17->201:28] Completable: Cpattern Value[ff]->recordField(someFn) [] +Complete src/CompletionPattern.res 206:16 +XXX Not found! +Completable: Cpattern Value[xn] +[{ + "label": "Js.Exn.Error(error)", + "kind": 4, + "tags": [], + "detail": "Catches errors from JavaScript errors.", + "documentation": {"kind": "markdown", "value": "Matches on a JavaScript error. Read more in the [documentation on catching JS exceptions](https://rescript-lang.org/docs/manual/latest/exception#catching-js-exceptions)."} + }] +