diff --git a/Changes.md b/Changes.md index 713aa65a..8c02e779 100644 --- a/Changes.md +++ b/Changes.md @@ -5,6 +5,7 @@ - Fix type hint when hovering over labeled arguments of components (See https://github.com/rescript-lang/rescript-editor-support/issues/63). - Fix issue where values declared with type annotation would not show up in autocomplete, and would show no doc comment on hover. (See https://github.com/rescript-lang/rescript-vscode/issues/72). - Fix hover on definitions inside a react component module, or whenever multiple definitins for the same value exist in the module (See https://github.com/rescript-lang/rescript-editor-support/issues/67). +- Add support for autocomplete of labelled arguments `foo(~label... )`. ## Release 1.0.5 of rescript-vscode This [commit](https://github.com/rescript-lang/rescript-editor-support/commit/6bdd10f6af259edc5f9cbe5b9df06836de3ab865) is vendored in [rescript-vscode 1.0.5](https://github.com/rescript-lang/rescript-vscode/releases/tag/1.0.5). diff --git a/examples/example-project/src/ZZ.res b/examples/example-project/src/ZZ.res index 10b92d13..335e57e9 100644 --- a/examples/example-project/src/ZZ.res +++ b/examples/example-project/src/ZZ.res @@ -105,3 +105,9 @@ module HoverInsideModuleWithComponent = { @react.component let make = () => React.null } + +module Lib = { + let foo = (~age, ~name) => name ++ string_of_int(age) + let next = (~number=0, ~year) => number + year +} + diff --git a/src/rescript-editor-support/NewCompletions.re b/src/rescript-editor-support/NewCompletions.re index 673c2062..7451316a 100644 --- a/src/rescript-editor-support/NewCompletions.re +++ b/src/rescript-editor-support/NewCompletions.re @@ -820,9 +820,54 @@ let computeCompletions = (~full, ~maybeText, ~package, ~pos, ~state) => { |> List.filter(decorator => Utils.startsWith(decorator, prefix)) |> List.map(mkDecorator); - | Some((_, _, Some(Clabel(_)))) => - // not supported yet - [] + | Some((text, offset, Some(Clabel(funPath, prefix)))) => + let rawOpens = PartialParser.findOpens(text, offset); + let allModules = + package.TopTypes.localModules @ package.dependencyModules; + + let getItems = parts => + getItems( + ~full, + ~package, + ~rawOpens, + ~getModule=State.fileForModule(state, ~package), + ~allModules, + ~pos, + ~parts, + ); + + let labels = { + switch (getItems(funPath)) { + | [(_uri, {SharedTypes.item: Value(typ)}), ..._] => + let rec getLabels = (t: Types.type_expr) => + switch (t.desc) { + | Tlink(t1) + | Tsubst(t1) => getLabels(t1) + | Tarrow(Labelled(l) | Optional(l), tArg, tRet, _) => [ + (l, tArg), + ...getLabels(tRet), + ] + | Tarrow(Nolabel, _, tRet, _) => getLabels(tRet) + | _ => [] + }; + typ |> getLabels; + | _ => [] + }; + }; + + let mkLabel = ((name, typ)) => + mkItem( + ~name, + ~kind=4, + ~detail=typ |> Shared.typeToString, + ~docstring=None, + ~uri=full.file.uri, + ~pos_lnum=fst(pos), + ); + + labels + |> List.filter(((name, _t)) => Utils.startsWith(name, prefix)) + |> List.map(mkLabel); | Some((_, _, None)) => [] }; diff --git a/src/rescript-editor-support/NotificationHandlers.re b/src/rescript-editor-support/NotificationHandlers.re index 612f5cdf..7599b405 100644 --- a/src/rescript-editor-support/NotificationHandlers.re +++ b/src/rescript-editor-support/NotificationHandlers.re @@ -9,14 +9,6 @@ let getTextDocument = doc => { Some((uri, text)); }; -let reloadAllState = state => { - Log.log("RELOADING ALL STATE"); - { - ...TopTypes.empty(~rootUri=state.rootUri), - documentText: state.documentText, - }; -}; - let notificationHandlers: list((string, (state, Json.t) => result(state, string))) = [ ( diff --git a/src/rescript-editor-support/PartialParser.re b/src/rescript-editor-support/PartialParser.re index d2d5ef2e..6c654b3b 100644 --- a/src/rescript-editor-support/PartialParser.re +++ b/src/rescript-editor-support/PartialParser.re @@ -64,9 +64,32 @@ let rec startOfLident = (text, i) => }; }; +// foo(... ~arg) from ~arg find foo +let findCallFromArgument = (text, offset) => { + let rec loop = (~i, ~nClosed) => + if (i > 0) { + switch (text.[i]) { + | '(' when nClosed > 0 => loop(~i=i - 1, ~nClosed=nClosed - 1) + + | '(' => + let i1 = skipWhite(text, i - 1); + let i0 = startOfLident(text, i1); + let funLident = String.sub(text, i0, i1 - i0 + 1); + Str.split(Str.regexp_string("."), funLident); + + | ')' => loop(~i=i - 1, ~nClosed=nClosed + 1) + + | _ => loop(~i=i - 1, ~nClosed) + }; + } else { + []; + }; + loop(~i=offset, ~nClosed=0); +}; + type completable = | Cdecorator(string) - | Clabel(string) + | Clabel(list(string), string) | Cpath(list(string)) | Cpipe(string); @@ -92,7 +115,10 @@ let findCompletable = (text, offset) => { : ( switch (text.[i]) { | '>' when i > 0 && text.[i - 1] == '-' => loop(i - 2) - | '~' => Some(Clabel(String.sub(text, i + 1, offset - (i + 1)))) + | '~' => + let labelPrefix = String.sub(text, i + 1, offset - (i + 1)); + let funPath = findCallFromArgument(text, i - 1); + Some(Clabel(funPath, labelPrefix)); | '@' => Some(Cdecorator(String.sub(text, i + 1, offset - (i + 1)))) | 'a'..'z' | 'A'..'Z' diff --git a/src/rescript-editor-support/RescriptEditorSupport.re b/src/rescript-editor-support/RescriptEditorSupport.re index fdaf2112..c566864d 100644 --- a/src/rescript-editor-support/RescriptEditorSupport.re +++ b/src/rescript-editor-support/RescriptEditorSupport.re @@ -7,7 +7,12 @@ let capabilities = ("hoverProvider", J.t), ( "completionProvider", - J.o([("triggerCharacters", J.l([J.s("."), J.s(">"), J.s("@")]))]), + J.o([ + ( + "triggerCharacters", + J.l([J.s("."), J.s(">"), J.s("@"), J.s("~")]), + ), + ]), ), ("definitionProvider", J.t), ("typeDefinitionProvider", J.t),