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). diff --git a/examples/example-project/src/ZZ.res b/examples/example-project/src/ZZ.res index 6fd66fcb..6a3c9ddc 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,19 @@ 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) + +let abc = "abc" + +let arr = [1, 2, 3] + +let some7 = Some(7) + + diff --git a/src/NewCompletions.ml b/src/NewCompletions.ml index 81b60e65..b1bda7d9 100644 --- a/src/NewCompletions.ml +++ b/src/NewCompletions.ml @@ -514,7 +514,11 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens -> mkItem ~name ~kind:(kindToInt item) ~deprecated ~detail:(detail name item) ~docstring ~uri ~pos_lnum) - | Cpipe s -> ( + | 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 = let rec loop (path : Path.t) = match path with @@ -522,10 +526,15 @@ 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 = "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 | [] -> []) 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 @@ -537,12 +546,10 @@ let processCompletable ~findItems ~full ~package ~pos ~rawOpens | _ -> 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 + 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 16a219a2..12144800 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 | PipeArray | 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 = @@ -132,24 +134,35 @@ 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 off = skipWhite text off in + let rec loop i = + match i < 0 with + | true -> Some (PipeId (String.sub text 0 (i - 1))) + | false -> ( + 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 + | 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 +171,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