From becbca2d0ca2a94d88cc107397b7cb28581681bc Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 12:22:24 +0200 Subject: [PATCH 1/8] Improve code for pipe autocomplete. Use a dedicate code path that takes care of pipe and is separate from normal identifiers. --- examples/example-project/src/ZZ.res | 32 +++++++++++--------- src/NewCompletions.ml | 11 ++----- src/PartialParser.ml | 47 +++++++++++++++++------------ 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/examples/example-project/src/ZZ.res b/examples/example-project/src/ZZ.res index 6fd66fcb..6c1c4adc 100644 --- a/examples/example-project/src/ZZ.res +++ b/examples/example-project/src/ZZ.res @@ -79,25 +79,25 @@ let testRecordFields = (gr: gr) => { } @ocaml.doc("vr docstring") -type vr = | V1 | V2 +type vr = V1 | V2 let v1 = V1 module DoubleNested = ModuleWithDocComment.Nested.NestedAgain -let uncurried = (. x) => x+1; +let uncurried = (. x) => x + 1 module Inner = { - type tInner = int; + type tInner = int let vInner = 34 } -type typeInner = Inner.tInner; +type typeInner = Inner.tInner -let valueInner = Inner.vInner; +let valueInner = Inner.vInner @ocaml.doc("Doc comment for functionWithTypeAnnotation") -let functionWithTypeAnnotation : unit => int = () => 1 +let functionWithTypeAnnotation: unit => int = () => 1 module HoverInsideModuleWithComponent = { let x = 2 // check that hover on x works @@ -111,14 +111,12 @@ module Lib = { let next = (~number=0, ~year) => number + year } -@ocaml.doc("This module is commented") -@deprecated("This module is deprecated") -module Dep : { - @ocaml.doc("Some doc comment") - @deprecated("Use customDouble instead") - let customDouble : int => int +@ocaml.doc("This module is commented") @deprecated("This module is deprecated") +module Dep: { + @ocaml.doc("Some doc comment") @deprecated("Use customDouble instead") + let customDouble: int => int - let customDouble2 : int => int + let customDouble2: int => int } = { let customDouble = foo => foo * 2 let customDouble2 = foo => foo * 2 @@ -129,8 +127,12 @@ let cc = Dep.customDouble(11) module O = { module Comp = { @react.component - let make = (~first="", ~kas=11, ~foo=3, ~second, ~v) => React.string(first ++ second ++ string_of_int(foo)) + let make = (~first="", ~kas=11, ~foo=3, ~second, ~v) => + React.string(first ++ second ++ string_of_int(foo)) } } -let comp = \ No newline at end of file +let comp = + +let lll = List.make(3, 4) + diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index 81b60e65..e191808c 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -514,7 +514,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens -> mkItem ~name ~kind:(kindToInt item) ~deprecated ~detail:(detail name item) ~docstring ~uri ~pos_lnum) - | Cpipe s -> ( + | Cpipe (lhs, partialName) -> ( let getModulePath path = let rec loop (path : Path.t) = match path with @@ -536,14 +536,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens Some (modulePath, partialName) | _ -> None in - let lhsPath = - match Str.split (Str.regexp_string "->") s with - | [lhs] -> getLhsPath ~lhs ~partialName:"" - | [lhs; partialName] -> getLhsPath ~lhs ~partialName - | _ -> - (* Only allow one -> *) - None - in + let lhsPath = getLhsPath ~lhs ~partialName in let removePackageOpens modulePath = match modulePath with | toplevel :: rest when package.TopTypes.opens |> List.mem toplevel -> diff --git a/src/PartialParser.ml b/src/PartialParser.ml index 16a219a2..e6fbec15 100644 --- a/src/PartialParser.ml +++ b/src/PartialParser.ml @@ -116,7 +116,7 @@ type completable = | Cpath of string list (** e.g. ["M", "foo"] for M.foo *) | Cjsx of string list * string (** E.g. (["M", "Comp"], "id") for foo" *) + | Cpipe of string * string (** E.g. ("x", "foo") for "x->foo" *) let isLowercaseIdent id = let rec loop i = @@ -132,24 +132,32 @@ let isLowercaseIdent id = let findCompletable text offset = let mkPath s = let len = String.length s in - let pipeParts = Str.split (Str.regexp_string "->") s in - if - (len > 1 && s.[len - 2] = '-' && s.[len - 1] = '>') - || List.length pipeParts > 1 - then Cpipe s - else - let parts = Str.split (Str.regexp_string ".") s in - let parts = - match s.[len - 1] = '.' with true -> parts @ [""] | false -> parts - in - match parts with - | [id] when String.lowercase_ascii id = id -> ( - match findJsxContext text (offset - len - 1) with - | None -> Cpath parts - | Some componentName -> - Cjsx (Str.split (Str.regexp_string ".") componentName, id)) - | _ -> Cpath parts + let parts = Str.split (Str.regexp_string ".") s in + let parts = + match s.[len - 1] = '.' with true -> parts @ [""] | false -> parts + in + match parts with + | [id] when String.lowercase_ascii id = id -> ( + match findJsxContext text (offset - len - 1) with + | None -> Cpath parts + | Some componentName -> + Cjsx (Str.split (Str.regexp_string ".") componentName, id)) + | _ -> Cpath parts in + let mkPipe off partialName = + let rec loop i = + match i < 0 with + | true -> Some (String.sub text 0 (i - 1)) + | false -> ( + match text.[i] with + | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' -> loop (i - 1) + | _ -> Some (String.sub text (i + 1) (off - i))) + in + match loop off with + | None -> None + | Some lhs -> Some (Cpipe (lhs, partialName)) + in + let suffix i = String.sub text (i + 1) (offset - (i + 1)) in let rec loop i = match i < 0 with @@ -158,7 +166,8 @@ let findCompletable text offset = match text.[i] with | '>' when i > 0 && text.[i - 1] = '-' -> let rest = suffix i in - if isLowercaseIdent rest then loop (i - 2) else Some (mkPath rest) + if isLowercaseIdent rest then mkPipe (i - 2) rest + else Some (mkPath rest) | '~' -> let labelPrefix = suffix i in let funPath = findCallFromArgument text (i - 1) in From dfa225eb213a1e350fbfee2fb1acbb9f597c1d42 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 12:29:55 +0200 Subject: [PATCH 2/8] Allow white space before pipe: `foo ->` --- src/PartialParser.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PartialParser.ml b/src/PartialParser.ml index e6fbec15..431e2889 100644 --- a/src/PartialParser.ml +++ b/src/PartialParser.ml @@ -145,6 +145,7 @@ let findCompletable text offset = | _ -> Cpath parts in let mkPipe off partialName = + let off = skipWhite text off in let rec loop i = match i < 0 with | true -> Some (String.sub text 0 (i - 1)) From 1f93745e7d265564d3306dea80200f44eb43744e Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 12:42:19 +0200 Subject: [PATCH 3/8] Pipe autocomplete for string literals. --- src/NewCompletions.ml | 12 ++++++++---- src/PartialParser.ml | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index e191808c..ab34ad79 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -514,7 +514,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens -> mkItem ~name ~kind:(kindToInt item) ~deprecated ~detail:(detail name item) ~docstring ~uri ~pos_lnum) - | Cpipe (lhs, partialName) -> ( + | Cpipe (pipe, partialName) -> ( let getModulePath path = let rec loop (path : Path.t) = match path with @@ -524,8 +524,8 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens in match loop path with _ :: rest -> List.rev rest | [] -> [] in - let getLhsPath ~lhs ~partialName = - match [lhs] |> findItems ~exact:true with + let getLhsPath ~pipeId ~partialName = + match [pipeId] |> findItems ~exact:true with | (_uri, {SharedTypes.item = Value t}) :: _ -> let modulePath = match t.desc with @@ -536,7 +536,11 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens Some (modulePath, partialName) | _ -> None in - let lhsPath = getLhsPath ~lhs ~partialName in + let lhsPath = + match pipe with + | PipeId pipeId -> getLhsPath ~pipeId ~partialName + | PipeString -> Some (["Js"; "String2"], partialName) + in let removePackageOpens modulePath = match modulePath with | toplevel :: rest when package.TopTypes.opens |> List.mem toplevel -> diff --git a/src/PartialParser.ml b/src/PartialParser.ml index 431e2889..8f930bdf 100644 --- a/src/PartialParser.ml +++ b/src/PartialParser.ml @@ -109,6 +109,8 @@ let findJsxContext text offset = in loop offset +type pipe = PipeId of string | PipeString + type completable = | Cdecorator of string (** e.g. @module *) | Clabel of string list * string @@ -116,7 +118,7 @@ type completable = | Cpath of string list (** e.g. ["M", "foo"] for M.foo *) | Cjsx of string list * string (** E.g. (["M", "Comp"], "id") for foo" *) + | Cpipe of pipe * string (** E.g. ("x", "foo") for "x->foo" *) let isLowercaseIdent id = let rec loop i = @@ -148,11 +150,12 @@ let findCompletable text offset = let off = skipWhite text off in let rec loop i = match i < 0 with - | true -> Some (String.sub text 0 (i - 1)) + | true -> Some (PipeId (String.sub text 0 (i - 1))) | false -> ( match text.[i] with | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' -> loop (i - 1) - | _ -> Some (String.sub text (i + 1) (off - i))) + | '"' when i == off -> Some PipeString + | _ -> Some (PipeId (String.sub text (i + 1) (off - i)))) in match loop off with | None -> None From 06e27dbf95d7e8bbe05f2f4a3bf439b310e97256 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 13:01:42 +0200 Subject: [PATCH 4/8] Autocomplete for id of string type. --- examples/example-project/src/ZZ.res | 2 ++ src/NewCompletions.ml | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/example-project/src/ZZ.res b/examples/example-project/src/ZZ.res index 6c1c4adc..1e016f9b 100644 --- a/examples/example-project/src/ZZ.res +++ b/examples/example-project/src/ZZ.res @@ -136,3 +136,5 @@ let comp = let lll = List.make(3, 4) +let abc = "abc" + diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index ab34ad79..890643b5 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -515,6 +515,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens mkItem ~name ~kind:(kindToInt item) ~deprecated ~detail:(detail name item) ~docstring ~uri ~pos_lnum) | Cpipe (pipe, partialName) -> ( + let stringModulePath = ["Js"; "String2"] in let getModulePath path = let rec loop (path : Path.t) = match path with @@ -522,7 +523,9 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens | Pdot (p, s, _) -> s :: loop p | Papply _ -> [] in - match loop path with _ :: rest -> List.rev rest | [] -> [] + match path with + | Path.Pident id when Ident.name id = "string" -> stringModulePath + | _ -> ( match loop path with _ :: rest -> List.rev rest | [] -> []) in let getLhsPath ~pipeId ~partialName = match [pipeId] |> findItems ~exact:true with @@ -539,7 +542,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens let lhsPath = match pipe with | PipeId pipeId -> getLhsPath ~pipeId ~partialName - | PipeString -> Some (["Js"; "String2"], partialName) + | PipeString -> Some (stringModulePath, partialName) in let removePackageOpens modulePath = match modulePath with From fd5eddb42d8f5becfe620547779489541f6afb04 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 13:06:39 +0200 Subject: [PATCH 5/8] Pipe autocomplete for array literals and types. --- examples/example-project/src/ZZ.res | 2 ++ src/NewCompletions.ml | 3 +++ src/PartialParser.ml | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/example-project/src/ZZ.res b/examples/example-project/src/ZZ.res index 1e016f9b..c11b093a 100644 --- a/examples/example-project/src/ZZ.res +++ b/examples/example-project/src/ZZ.res @@ -138,3 +138,5 @@ let lll = List.make(3, 4) let abc = "abc" +let arr = [1, 2, 3] + diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index 890643b5..e10e3983 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -515,6 +515,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens mkItem ~name ~kind:(kindToInt item) ~deprecated ~detail:(detail name item) ~docstring ~uri ~pos_lnum) | Cpipe (pipe, partialName) -> ( + let arrayModulePath = ["Js"; "Array2"] in let stringModulePath = ["Js"; "String2"] in let getModulePath path = let rec loop (path : Path.t) = @@ -525,6 +526,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens in match path with | Path.Pident id when Ident.name id = "string" -> stringModulePath + | Path.Pident id when Ident.name id = "array" -> arrayModulePath | _ -> ( match loop path with _ :: rest -> List.rev rest | [] -> []) in let getLhsPath ~pipeId ~partialName = @@ -543,6 +545,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens match pipe with | PipeId pipeId -> getLhsPath ~pipeId ~partialName | PipeString -> Some (stringModulePath, partialName) + | PipeArray -> Some (arrayModulePath, partialName) in let removePackageOpens modulePath = match modulePath with diff --git a/src/PartialParser.ml b/src/PartialParser.ml index 8f930bdf..12144800 100644 --- a/src/PartialParser.ml +++ b/src/PartialParser.ml @@ -109,7 +109,7 @@ let findJsxContext text offset = in loop offset -type pipe = PipeId of string | PipeString +type pipe = PipeId of string | PipeArray | PipeString type completable = | Cdecorator of string (** e.g. @module *) @@ -155,6 +155,7 @@ let findCompletable text offset = match text.[i] with | 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' -> loop (i - 1) | '"' when i == off -> Some PipeString + | ']' when i == off -> Some PipeArray | _ -> Some (PipeId (String.sub text (i + 1) (off - i)))) in match loop off with From 2da6d9f46ea6c4f49c223adbf450821c7fa4adb2 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 14:07:04 +0200 Subject: [PATCH 6/8] Autocomplete for builtin option type. --- examples/example-project/src/ZZ.res | 3 +++ src/NewCompletions.ml | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/example-project/src/ZZ.res b/examples/example-project/src/ZZ.res index c11b093a..6a3c9ddc 100644 --- a/examples/example-project/src/ZZ.res +++ b/examples/example-project/src/ZZ.res @@ -140,3 +140,6 @@ let abc = "abc" let arr = [1, 2, 3] +let some7 = Some(7) + + diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index e10e3983..56b2f0ad 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -516,6 +516,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens ~detail:(detail name item) ~docstring ~uri ~pos_lnum) | Cpipe (pipe, partialName) -> ( let arrayModulePath = ["Js"; "Array2"] in + let optionModulePath = ["Belt"; "Option"] in let stringModulePath = ["Js"; "String2"] in let getModulePath path = let rec loop (path : Path.t) = @@ -525,8 +526,9 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens | Papply _ -> [] in match path with - | Path.Pident id when Ident.name id = "string" -> stringModulePath | Path.Pident id when Ident.name id = "array" -> arrayModulePath + | Path.Pident id when Ident.name id = "option" -> optionModulePath + | Path.Pident id when Ident.name id = "string" -> stringModulePath | _ -> ( match loop path with _ :: rest -> List.rev rest | [] -> []) in let getLhsPath ~pipeId ~partialName = From 892ea55a513a28cade50d2e221961ec6ebc83b38 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 14:10:31 +0200 Subject: [PATCH 7/8] Pipe autocomplete for builtin list type. Fixes https://github.com/rescript-lang/rescript-editor-support/issues/98 --- src/NewCompletions.ml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index 56b2f0ad..b1bda7d9 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -516,6 +516,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens ~detail:(detail name item) ~docstring ~uri ~pos_lnum) | Cpipe (pipe, partialName) -> ( let arrayModulePath = ["Js"; "Array2"] in + let listModulePath = ["Belt"; "List"] in let optionModulePath = ["Belt"; "Option"] in let stringModulePath = ["Js"; "String2"] in let getModulePath path = @@ -527,6 +528,7 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens in match path with | Path.Pident id when Ident.name id = "array" -> arrayModulePath + | Path.Pident id when Ident.name id = "list" -> listModulePath | Path.Pident id when Ident.name id = "option" -> optionModulePath | Path.Pident id when Ident.name id = "string" -> stringModulePath | _ -> ( match loop path with _ :: rest -> List.rev rest | [] -> []) From 1a8f7e2479728401983a927d88cafefcdf24572e Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Fri, 9 Apr 2021 14:12:08 +0200 Subject: [PATCH 8/8] Update Changes.md --- Changes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changes.md b/Changes.md index fc18cbe2..2fc89758 100644 --- a/Changes.md +++ b/Changes.md @@ -3,6 +3,7 @@ - Don't show file path on hover. - Add autocomplete for props in JSX components. - Autocomplete: fix issue where `->` autocomplete was overruling `.`. See https://github.com/rescript-lang/rescript-editor-support/issues/99. +- Add pipe autocomplete for builtin list, array, string, option types. And for string and array literals. ## Release 1.0.6 of rescript-vscode This [commit](https://github.com/rescript-lang/rescript-editor-support/commit/03ee0d97b250474028d4fb08eac81ddb21ccb082) is vendored in [rescript-vscode 1.0.6](https://github.com/rescript-lang/rescript-vscode/releases/tag/1.0.6).