Skip to content
This repository was archived by the owner on Apr 24, 2021. It is now read-only.

Improve code for pipe autocomplete. #107

Merged
merged 8 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
39 changes: 24 additions & 15 deletions examples/example-project/src/ZZ.res
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 = <O.Comp key="12" second="abcc" v=12 />
let comp = <O.Comp key="12" second="abcc" v=12 />

let lll = List.make(3, 4)

let abc = "abc"

let arr = [1, 2, 3]

let some7 = Some(7)


27 changes: 17 additions & 10 deletions src/NewCompletions.ml
Original file line number Diff line number Diff line change
Expand Up @@ -514,18 +514,27 @@ 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
| Pident id -> [Ident.name id]
| 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
Expand All @@ -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
Expand Down
52 changes: 33 additions & 19 deletions src/PartialParser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,16 @@ 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
(** e.g. (["M", "foo"], "label") for M.foo(...~label...) *)
| Cpath of string list (** e.g. ["M", "foo"] for M.foo *)
| Cjsx of string list * string
(** E.g. (["M", "Comp"], "id") for <M.Comp ... id *)
| Cpipe of string (** E.g. "x->foo" *)
| Cpipe of pipe * string (** E.g. ("x", "foo") for "x->foo" *)

let isLowercaseIdent id =
let rec loop i =
Expand All @@ -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
Expand All @@ -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
Expand Down