Skip to content

Commit c92c269

Browse files
committed
wip complete pipeable functions from dot completion on record when record is type t of module
1 parent 8849a58 commit c92c269

12 files changed

+187
-16
lines changed

analysis/src/CompletionBackEnd.ml

Lines changed: 89 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -970,30 +970,103 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
970970
with
971971
| Some (TypeExpr typ, env) -> (
972972
match typ |> TypeUtils.extractRecordType ~env ~package with
973-
| Some (env, fields, typDecl) ->
973+
| Some (env, fields, typDecl, path) ->
974974
Some
975975
( env,
976976
fields,
977-
typDecl.item.decl |> Shared.declToString typDecl.name.txt )
977+
typDecl.item.decl |> Shared.declToString typDecl.name.txt,
978+
Some path )
978979
| None -> None)
979980
| Some (ExtractedType typ, env) -> (
980981
match typ with
981-
| Trecord {fields} ->
982-
Some (env, fields, typ |> TypeUtils.extractedTypeToString)
982+
| Trecord {fields; path} ->
983+
Some (env, fields, typ |> TypeUtils.extractedTypeToString, path)
983984
| _ -> None)
984985
| None -> None
985986
in
986987
match extracted with
987988
| None -> []
988-
| Some (env, fields, recordAsString) ->
989-
fields
990-
|> Utils.filterMap (fun field ->
991-
if Utils.checkName field.fname.txt ~prefix:fieldName ~exact then
992-
Some
993-
(Completion.create field.fname.txt ~env
994-
?deprecated:field.deprecated ~docstring:field.docstring
995-
~kind:(Completion.Field (field, recordAsString)))
996-
else None))
989+
| Some (env, fields, recordAsString, path) ->
990+
let pipeCompletionsForModule =
991+
match path with
992+
| Some path ->
993+
let completionPath =
994+
(* Remove the last part of the path since we're only after the parent module *)
995+
match
996+
path |> SharedTypes.pathIdentToString |> String.split_on_char '.'
997+
|> List.rev
998+
with
999+
| _ :: rest -> rest
1000+
| [] -> []
1001+
in
1002+
(* Most of this is copied from the pipe completion code. Should probably be unified. *)
1003+
let completions =
1004+
completionPath @ [fieldName]
1005+
|> getCompletionsForPath ~debug ~completionContext:Value
1006+
~exact:false ~opens ~full ~pos ~env ~scope
1007+
in
1008+
let completionPathMinusOpens =
1009+
TypeUtils.removeOpensFromCompletionPath ~rawOpens ~package
1010+
completionPath
1011+
|> String.concat "."
1012+
in
1013+
let completionName name =
1014+
if completionPathMinusOpens = "" then name
1015+
else completionPathMinusOpens ^ "." ^ name
1016+
in
1017+
(* Find all functions in the module that takes type t *)
1018+
let rec fnTakesTypeT t =
1019+
match t.Types.desc with
1020+
| Tlink t1
1021+
| Tsubst t1
1022+
| Tpoly (t1, [])
1023+
| Tconstr (Pident {name = "function$"}, [t1; _], _) ->
1024+
fnTakesTypeT t1
1025+
| Tarrow _ -> (
1026+
match
1027+
TypeUtils.extractFunctionType ~env ~package:full.package t
1028+
with
1029+
| ( (Nolabel, {desc = Tconstr (Path.Pident {name = "t"}, _, _)})
1030+
:: _,
1031+
_ ) ->
1032+
true
1033+
| _ -> false)
1034+
| _ -> false
1035+
in
1036+
completions
1037+
|> List.filter_map (fun (completion : Completion.t) ->
1038+
match completion.kind with
1039+
| Value t when fnTakesTypeT t ->
1040+
let name = completionName completion.name in
1041+
let nameWithPipe = "->" ^ name in
1042+
(* TODO: We need to add support for setting the text insertion location explicitly,
1043+
so we can account for the dot that triggered the completion, but that we want
1044+
removed when inserting the pipe. This means we also need to track the loc of
1045+
the dot + the identifier that we're filtering with (fieldName here).
1046+
That should be easy to do by extending CPField. *)
1047+
Some
1048+
{
1049+
completion with
1050+
name = nameWithPipe;
1051+
sortText =
1052+
Some
1053+
(name |> String.split_on_char '.' |> List.rev
1054+
|> List.hd);
1055+
insertText = Some nameWithPipe;
1056+
env;
1057+
}
1058+
| _ -> None)
1059+
| None -> []
1060+
in
1061+
pipeCompletionsForModule
1062+
@ (fields
1063+
|> Utils.filterMap (fun field ->
1064+
if Utils.checkName field.fname.txt ~prefix:fieldName ~exact then
1065+
Some
1066+
(Completion.create field.fname.txt ~env
1067+
?deprecated:field.deprecated ~docstring:field.docstring
1068+
~kind:(Completion.Field (field, recordAsString)))
1069+
else None)))
9971070
| CPObj (cp, label) -> (
9981071
(* TODO: Also needs to support ExtractedType *)
9991072
if Debug.verbose () then print_endline "[ctx_path]--> CPObj";
@@ -1936,6 +2009,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
19362009
{
19372010
env;
19382011
definition = `NameOnly "jsxConfig";
2012+
path = None;
19392013
fields =
19402014
[
19412015
mkField ~name:"version" ~primitive:"int";
@@ -1965,6 +2039,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
19652039
Trecord
19662040
{
19672041
env;
2042+
path = None;
19682043
definition = `NameOnly "importAttributesConfig";
19692044
fields = [mkField ~name:"type_" ~primitive:"string"];
19702045
}
@@ -1973,6 +2048,7 @@ let rec processCompletable ~debug ~full ~scope ~env ~pos ~forHover completable =
19732048
Trecord
19742049
{
19752050
env;
2051+
path = None;
19762052
definition = `NameOnly "moduleConfig";
19772053
fields =
19782054
[

analysis/src/SharedTypes.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ and completionType =
354354
| Trecord of {
355355
env: QueryEnv.t;
356356
fields: field list;
357+
path: Path.t option;
357358
definition:
358359
[ `NameOnly of string
359360
(** When we only have the name, like when pulling the record from a declared type. *)

analysis/src/TypeUtils.ml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ let rec extractRecordType ~env ~package (t : Types.type_expr) =
213213
in
214214
{field with typ = fieldTyp})
215215
in
216-
Some (env, fields, typ)
216+
Some (env, fields, typ, path)
217217
| Some
218218
( env,
219219
{item = {decl = {type_manifest = Some t1; type_params = typeParams}}}
@@ -390,7 +390,13 @@ let rec extractType ?(printOpeningDebug = true)
390390
maybeSetTypeArgCtx ~typeParams:decl.type_params ~typeArgs env
391391
in
392392
Some
393-
( Trecord {env = envFromDeclaration; fields; definition = `TypeExpr t},
393+
( Trecord
394+
{
395+
env = envFromDeclaration;
396+
path = Some path;
397+
fields;
398+
definition = `TypeExpr t;
399+
},
394400
typeArgContext )
395401
| Some (envFromDeclaration, {item = {name = "t"; decl = {type_params}}}) ->
396402
let typeArgContext =
@@ -571,7 +577,7 @@ let extractTypeFromResolvedType (typ : Type.t) ~env ~full =
571577
match typ.kind with
572578
| Tuple items -> Some (Tuple (env, items, Ctype.newty (Ttuple items)))
573579
| Record fields ->
574-
Some (Trecord {env; fields; definition = `NameOnly typ.name})
580+
Some (Trecord {env; fields; path = None; definition = `NameOnly typ.name})
575581
| Variant constructors ->
576582
Some
577583
(Tvariant
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module SomeModule = {
2+
type t = {name: string}
3+
4+
@get external getName: t => string = "name"
5+
6+
let thisShouldNotBeCompletedFor = () => "hi"
7+
}
8+
9+
let n = {SomeModule.name: "hello"}
10+
11+
// ^dv+
12+
// n.
13+
// ^com
14+
// ^dv-

analysis/tests/src/expected/Completion.res.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ Resolved opens 1 pervasives
728728
ContextPath Value[r].""
729729
ContextPath Value[r]
730730
Path r
731+
Path
731732
[{
732733
"label": "x",
733734
"kind": 5,
@@ -751,6 +752,7 @@ Resolved opens 1 pervasives
751752
ContextPath Value[Objects, Rec, recordVal].""
752753
ContextPath Value[Objects, Rec, recordVal]
753754
Path Objects.Rec.recordVal
755+
Path
754756
[{
755757
"label": "xx",
756758
"kind": 5,
@@ -833,6 +835,8 @@ ContextPath Value[q].aa.""
833835
ContextPath Value[q].aa
834836
ContextPath Value[q]
835837
Path q
838+
Path aa
839+
Path
836840
[{
837841
"label": "x",
838842
"kind": 5,
@@ -857,6 +861,8 @@ ContextPath Value[q].aa.n
857861
ContextPath Value[q].aa
858862
ContextPath Value[q]
859863
Path q
864+
Path aa
865+
Path n
860866
[{
861867
"label": "name",
862868
"kind": 5,
@@ -1081,6 +1087,7 @@ ContextPath Value[FAO, forAutoObject]["forAutoLabel"].""
10811087
ContextPath Value[FAO, forAutoObject]["forAutoLabel"]
10821088
ContextPath Value[FAO, forAutoObject]
10831089
Path FAO.forAutoObject
1090+
Path FAR.
10841091
[{
10851092
"label": "forAuto",
10861093
"kind": 5,
@@ -1106,6 +1113,7 @@ ContextPath Value[FAO, forAutoObject]["forAutoLabel"].forAuto
11061113
ContextPath Value[FAO, forAutoObject]["forAutoLabel"]
11071114
ContextPath Value[FAO, forAutoObject]
11081115
Path FAO.forAutoObject
1116+
Path FAR.forAuto
11091117
CPPipe env:Completion envFromCompletionItem:Completion.FAR
11101118
CPPipe type path:ForAuto.t
11111119
CPPipe pathFromEnv:ForAuto found:false
@@ -1189,6 +1197,7 @@ Resolved opens 3 pervasives Completion.res Completion.res
11891197
ContextPath Value[_z].""
11901198
ContextPath Value[_z]
11911199
Path _z
1200+
Path
11921201
[{
11931202
"label": "x",
11941203
"kind": 5,
@@ -1347,6 +1356,7 @@ Resolved opens 3 pervasives Completion.res Completion.res
13471356
ContextPath Value[funRecord].someFun
13481357
ContextPath Value[funRecord]
13491358
Path funRecord
1359+
Path someFun
13501360
Found type for function (~name: string) => unit
13511361
[{
13521362
"label": "name",
@@ -1367,6 +1377,7 @@ ContextPath Value[retAA](Nolabel).""
13671377
ContextPath Value[retAA](Nolabel)
13681378
ContextPath Value[retAA]
13691379
Path retAA
1380+
Path
13701381
[{
13711382
"label": "x",
13721383
"kind": 5,
@@ -1897,6 +1908,7 @@ Resolved opens 3 pervasives Completion.res Completion.res
18971908
ContextPath Value[funRecord].""
18981909
ContextPath Value[funRecord]
18991910
Path funRecord
1911+
Path
19001912
[{
19011913
"label": "someFun",
19021914
"kind": 5,
@@ -2153,6 +2165,7 @@ Resolved opens 3 pervasives Completion.res Completion.res
21532165
ContextPath Value[rWithDepr].so
21542166
ContextPath Value[rWithDepr]
21552167
Path rWithDepr
2168+
Path so
21562169
[{
21572170
"label": "someInt",
21582171
"kind": 5,

analysis/tests/src/expected/CompletionExpressions.res.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ Resolved opens 1 pervasives
946946
ContextPath Value[fff].someOpt
947947
ContextPath Value[fff]
948948
Path fff
949+
Path someOpt
949950
[{
950951
"label": "someOptField",
951952
"kind": 5,
@@ -1415,6 +1416,7 @@ Resolved opens 2 pervasives CompletionSupport.res
14151416
ContextPath Value[someTyp].""
14161417
ContextPath Value[someTyp]
14171418
Path someTyp
1419+
Path
14181420
[{
14191421
"label": "test",
14201422
"kind": 5,
@@ -1470,6 +1472,7 @@ Resolved opens 2 pervasives CompletionSupport.res
14701472
ContextPath Value[someTyp].""
14711473
ContextPath Value[someTyp]
14721474
Path someTyp
1475+
Path
14731476
[{
14741477
"label": "test",
14751478
"kind": 5,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Complete src/CompletionFromModule.res 11:5
3+
posCursor:[11:5] posNoWhite:[11:4] Found expr:[11:3->11:5]
4+
Pexp_field [11:3->11:4] _:[15:0->11:5]
5+
[set_result] set new result to Cpath Value[n].""
6+
Completable: Cpath Value[n].""
7+
Package opens Pervasives.JsxModules.place holder
8+
Resolved opens 1 pervasives
9+
ContextPath Value[n].""
10+
[ctx_path]--> CPField
11+
ContextPath Value[n]
12+
[ctx_path]--> CPId
13+
Path n
14+
Path SomeModule.
15+
[{
16+
"label": "->SomeModule.getName",
17+
"kind": 12,
18+
"tags": [],
19+
"detail": "t => string",
20+
"documentation": null,
21+
"sortText": "getName",
22+
"insertText": "->SomeModule.getName"
23+
}, {
24+
"label": "name",
25+
"kind": 5,
26+
"tags": [],
27+
"detail": "string",
28+
"documentation": {"kind": "markdown", "value": "```rescript\nname: string\n```\n\n```rescript\ntype t = {name: string}\n```"}
29+
}]
30+
31+

0 commit comments

Comments
 (0)