Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make pipe completion work reliably across submodules. #663

Merged
merged 1 commit into from
Dec 22, 2022
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- Accept both `@ns.doc` and the new `@res.doc` for the internal representation of doc comments. And both `@ns.optional` and `@res.optional` for the optional fields. https://github.com/rescript-lang/rescript-vscode/pull/642
- Make pipe completion work more reliably after function calls. https://github.com/rescript-lang/rescript-vscode/pull/656
- Make pipe completion work in pipe chains, not just on the first pipe. https://github.com/rescript-lang/rescript-vscode/pull/656
- Make pipe completion work reliably when the path resolution needs to traverse submodules https://github.com/rescript-lang/rescript-vscode/pull/663

#### :bug: Bug Fix

Expand Down
22 changes: 11 additions & 11 deletions analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1371,21 +1371,21 @@ let rec getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
| Some path -> Some path
| None -> (
match expandPath typePath with
| _ :: rest when rest <> [] ->
(* Assume a non-empty type path is coming from the compiler and
can be used as-is. *)
Some (List.rev rest)
| _ ->
(* Get the path from the comletion environment *)
let path = envFromCompletionItem.path in
if path = [] then None
| _ :: pathRev ->
(* type path is relative to the completion environment
express it from the root of the file *)
let pathFromEnv_ =
QueryEnv.pathFromEnv envFromCompletionItem (List.rev pathRev)
in
if pathFromEnv_ = [] then None
else
let pathFromEnv =
if env.file.moduleName = envFromCompletionItem.file.moduleName
then path
else envFromCompletionItem.file.moduleName :: path
then pathFromEnv_
else envFromCompletionItem.file.moduleName :: pathFromEnv_
in
Some pathFromEnv))
Some pathFromEnv
| _ -> None))
| None -> None
in
match completionPath with
Expand Down
38 changes: 34 additions & 4 deletions analysis/src/SharedTypes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,45 @@ module File = struct
end

module QueryEnv : sig
type t = private {file: File.t; exported: Exported.t; path: path}
type t = private {
file: File.t;
exported: Exported.t;
pathRev: path;
parent: t option;
}
val fromFile : File.t -> t
val enterStructure : t -> Module.structure -> t

(* Express a path starting from the module represented by the env.
E.g. the env is at A.B.C and the path is D.
The result is A.B.C.D if D is inside C.
Or A.B.D or A.D or D if it's in one of its parents. *)
val pathFromEnv : t -> path -> path
end = struct
type t = {file: File.t; exported: Exported.t; path: path}
type t = {file: File.t; exported: Exported.t; pathRev: path; parent: t option}

let fromFile (file : File.t) =
{file; exported = file.structure.exported; pathRev = []; parent = None}

(* Prune a path and find a parent environment that contains the module name *)
let rec prunePath pathRev env name =
if Exported.find env.exported Module name <> None then pathRev
else
match (pathRev, env.parent) with
| _ :: rest, Some env -> prunePath rest env name
| _ -> []

let pathFromEnv env path =
match path with
| [] -> env.pathRev |> List.rev
| name :: _ ->
let prunedPathRev = prunePath env.pathRev env name in
List.rev_append prunedPathRev path

let fromFile file = {file; exported = file.structure.exported; path = []}
let enterStructure env (structure : Module.structure) =
{env with exported = structure.exported; path = structure.name :: env.path}
let name = structure.name in
let pathRev = name :: prunePath env.pathRev env name in
{env with exported = structure.exported; pathRev; parent = Some env}
end

module Completion = struct
Expand Down
45 changes: 45 additions & 0 deletions analysis/tests/src/CompletionPipeSubmodules.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
module A = {
module B1 = {
type b1 = B1
let xx = B1
}
module B2 = {
let yy = 20
}
type t = {v: B1.b1}
let x = {v: B1.B1}
}

// let _ = A.B1.xx->
// ^com
// b1 seen from B1 is A.B1.b1

// let _ = A.x.v->
// ^com
// B1.b1 seen from A is A.B1.b1

module C = {
type t = C
}

module D = {
module C2 = {
type t2 = C2
}

type d = {v: C.t, v2: C2.t2}
let d = {v: C.C, v2: C2.C2}
}

module E = {
type e = {v: D.d}
let e = {v: D.d}
}

// let _ = E.e.v.v->
// ^com
// C.t seen from D is C.t

// let _ = E.e.v.v2->
// ^com
// C2.t2 seen from D is D.C2.t2
56 changes: 56 additions & 0 deletions analysis/tests/src/expected/CompletionPipeSubmodules.res.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Complete src/CompletionPipeSubmodules.res 12:20
posCursor:[12:20] posNoWhite:[12:19] Found expr:[12:11->20:8]
Completable: Cpath Value[A, B1, xx]->
[{
"label": "A.B1.xx",
"kind": 12,
"tags": [],
"detail": "b1",
"documentation": null
}, {
"label": "A.B1.B1",
"kind": 4,
"tags": [],
"detail": "B1\n\ntype b1 = B1",
"documentation": null
}]

Complete src/CompletionPipeSubmodules.res 16:18
posCursor:[16:18] posNoWhite:[16:17] Found expr:[16:11->20:8]
Completable: Cpath Value[A, x].v->
[{
"label": "A.B1.xx",
"kind": 12,
"tags": [],
"detail": "b1",
"documentation": null
}, {
"label": "A.B1.B1",
"kind": 4,
"tags": [],
"detail": "B1\n\ntype b1 = B1",
"documentation": null
}]

Complete src/CompletionPipeSubmodules.res 38:20
posCursor:[38:20] posNoWhite:[38:19] Found expr:[38:11->0:-1]
Completable: Cpath Value[E, e].v.v->
[{
"label": "C.C",
"kind": 4,
"tags": [],
"detail": "C\n\ntype t = C",
"documentation": null
}]

Complete src/CompletionPipeSubmodules.res 42:21
posCursor:[42:21] posNoWhite:[42:20] Found expr:[42:11->0:-1]
Completable: Cpath Value[E, e].v.v2->
[{
"label": "D.C2.C2",
"kind": 4,
"tags": [],
"detail": "C2\n\ntype t2 = C2",
"documentation": null
}]