Skip to content

Commit edc9547

Browse files
committed
WIP: better completion for applications
1 parent 9da9b19 commit edc9547

File tree

7 files changed

+98
-105
lines changed

7 files changed

+98
-105
lines changed

analysis/src/CompletionBackEnd.ml

+6
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,11 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
965965
| [], [(Nolabel | Labelled _ | Optional _)] ->
966966
(* should not happen, but just ignore extra arguments *) []
967967
in
968+
969+
(* (match typ.desc with
970+
| Tarrow _ -> print_endline "its an arrow"
971+
| Tconstr _ -> print_endline "it's an alias"
972+
| _ -> print_endline "something else"); *)
968973
match TypeUtils.extractFunctionType ~env ~package typ with
969974
| args, tRet when args <> [] ->
970975
let args = processApply args labels in
@@ -1047,6 +1052,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
10471052
| None -> [])
10481053
| None -> [])
10491054
| CPPipe {contextPath = cp; id = prefix; lhsLoc; inJsx; synthetic} -> (
1055+
(* TODO: resolve somewhere in here a potential alias *)
10501056
if Debug.verbose () then print_endline "[ctx_path]--> CPPipe";
10511057
match
10521058
cp

analysis/src/TypeUtils.ml

-10
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,6 @@ let extractFunctionType ~env ~package typ =
248248
match t.desc with
249249
| Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> loop ~env acc t1
250250
| Tarrow (label, tArg, tRet, _, _) -> loop ~env ((label, tArg) :: acc) tRet
251-
| Tconstr (path, typeArgs, _) -> (
252-
match References.digConstructor ~env ~package path with
253-
| Some
254-
( env,
255-
{
256-
item = {decl = {type_manifest = Some t1; type_params = typeParams}};
257-
} ) ->
258-
let t1 = t1 |> instantiateType ~typeParams ~typeArgs in
259-
loop ~env acc t1
260-
| _ -> (List.rev acc, t))
261251
| _ -> (List.rev acc, t)
262252
in
263253
loop ~env [] typ

tests/analysis_tests/tests/src/CompletionTaggedTemplate.res

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module M = {
2-
type t
2+
type t = promise<string>
33

44
let a = (_t:t) => 4
55
let b = (_:t) => "c"
@@ -9,8 +9,11 @@ module M = {
99
@module("meh") @taggedTemplate
1010
external meh: (array<string>, array<string>) => M.t = "default"
1111

12+
let w = meh``
13+
14+
// ^dv+
15+
// let _ = w.
16+
// ^com
17+
1218
// let x = meh`foo`.
1319
// ^com
14-
15-
// let y = meh`bar`.x
16-
// ^com

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -1885,13 +1885,19 @@ Resolved opens 2 Completion Completion
18851885
ContextPath Value[withCallback](~a)
18861886
ContextPath Value[withCallback]
18871887
Path withCallback
1888-
Found type for function (~b: int) => int
1888+
Found type for function (~b: int) => callback
18891889
[{
18901890
"label": "b",
18911891
"kind": 4,
18921892
"tags": [],
18931893
"detail": "int",
18941894
"documentation": null
1895+
}, {
1896+
"label": "a",
1897+
"kind": 4,
1898+
"tags": [],
1899+
"detail": "int",
1900+
"documentation": null
18951901
}]
18961902

18971903
Complete src/Completion.res 332:21
@@ -1904,7 +1910,7 @@ Resolved opens 2 Completion Completion
19041910
ContextPath Value[withCallback](~b)
19051911
ContextPath Value[withCallback]
19061912
Path withCallback
1907-
Found type for function (~a: int) => int
1913+
Found type for function callback
19081914
[{
19091915
"label": "a",
19101916
"kind": 4,

tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt

+3-14
Original file line numberDiff line numberDiff line change
@@ -162,27 +162,16 @@ ContextPath Value[Js, String2, trim](Nolabel)->st <<jsx>>
162162
ContextPath Value[Js, String2, trim](Nolabel)
163163
ContextPath Value[Js, String2, trim]
164164
Path Js.String2.trim
165-
Path Js.String2.st
165+
CPPipe pathFromEnv: found:true
166+
Path Js_string2.st
166167
[{
167168
"label": "React.string",
168169
"kind": 12,
169170
"tags": [],
170-
"detail": "string",
171+
"detail": "t",
171172
"documentation": {"kind": "markdown", "value": "Turns `string` into a JSX element so it can be used inside of JSX."},
172173
"sortText": "A",
173174
"insertTextFormat": 2
174-
}, {
175-
"label": "Js.String2.startsWith",
176-
"kind": 12,
177-
"tags": [],
178-
"detail": "(t, t) => bool",
179-
"documentation": {"kind": "markdown", "value": "\nES2015: `startsWith(str, substr)` returns `true` if the `str` starts with\n`substr`, `false` otherwise.\n\nSee [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.startsWith(\"ReScript\", \"Re\") == true\nJs.String2.startsWith(\"ReScript\", \"\") == true\nJs.String2.startsWith(\"JavaScript\", \"Re\") == false\n```\n"}
180-
}, {
181-
"label": "Js.String2.startsWithFrom",
182-
"kind": 12,
183-
"tags": [],
184-
"detail": "(t, t, int) => bool",
185-
"documentation": {"kind": "markdown", "value": "\nES2015: `startsWithFrom(str, substr, n)` returns `true` if the `str` starts\nwith `substr` starting at position `n`, false otherwise. If `n` is negative,\nthe search starts at the beginning of `str`.\n\nSee [`String.startsWith`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.startsWithFrom(\"ReScript\", \"Scri\", 2) == true\nJs.String2.startsWithFrom(\"ReScript\", \"\", 2) == true\nJs.String2.startsWithFrom(\"JavaScript\", \"Scri\", 2) == false\n```\n"}
186175
}]
187176

188177
Complete src/CompletionJsx.res 24:19

tests/analysis_tests/tests/src/expected/CompletionTaggedTemplate.res.txt

+65-21
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
1-
Complete src/CompletionTaggedTemplate.res 11:20
2-
posCursor:[11:20] posNoWhite:[11:19] Found expr:[11:11->0:-1]
3-
Completable: Cpath Value[meh](Nolabel, Nolabel).""
1+
2+
Complete src/CompletionTaggedTemplate.res 14:13
3+
[decoratorCompletion] Found @module with non-string payload
4+
posCursor:[14:13] posNoWhite:[14:12] Found expr:[14:11->14:13]
5+
Pexp_field [14:11->14:12] _:[20:0->14:13]
6+
[set_result] set new result to Cpath Value[w].""
7+
Completable: Cpath Value[w].""
48
Package opens Pervasives.JsxModules.place holder
5-
ContextPath Value[meh](Nolabel, Nolabel).""
6-
ContextPath Value[meh](Nolabel, Nolabel)
7-
ContextPath Value[meh]
8-
Path meh
9-
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)->
10-
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)
11-
ContextPath Value[meh]
12-
Path meh
9+
ContextPath Value[w].""
10+
[dot_completion]--> Triggered
11+
ContextPath Value[w]
12+
[ctx_path]--> CPId
13+
Path w
14+
[extract_type]--> starting extraction of type: M.t, in env: CompletionTaggedTemplate. Has type arg ctx: false
15+
[extract_type]--> digging for type M.t in CompletionTaggedTemplate
16+
[extract_type]--> found type manifest
17+
[extract_type]--> starting extraction of type: promise<string>, in env: CompletionTaggedTemplate.M. Has type arg ctx: false
18+
ContextPath Value[w]->
19+
[ctx_path]--> CPPipe
20+
ContextPath Value[w]
21+
[ctx_path]--> CPId
22+
Path w
23+
[pipe_completion] mainTypeId: promise
1324
CPPipe pathFromEnv:M found:true
1425
Path M.
1526
[{
@@ -21,7 +32,7 @@ Path M.
2132
"sortText": "xyz",
2233
"insertText": "->M.xyz",
2334
"additionalTextEdits": [{
24-
"range": {"start": {"line": 11, "character": 19}, "end": {"line": 11, "character": 20}},
35+
"range": {"start": {"line": 14, "character": 12}, "end": {"line": 14, "character": 13}},
2536
"newText": ""
2637
}]
2738
}, {
@@ -33,7 +44,7 @@ Path M.
3344
"sortText": "b",
3445
"insertText": "->M.b",
3546
"additionalTextEdits": [{
36-
"range": {"start": {"line": 11, "character": 19}, "end": {"line": 11, "character": 20}},
47+
"range": {"start": {"line": 14, "character": 12}, "end": {"line": 14, "character": 13}},
3748
"newText": ""
3849
}]
3950
}, {
@@ -45,25 +56,34 @@ Path M.
4556
"sortText": "a",
4657
"insertText": "->M.a",
4758
"additionalTextEdits": [{
48-
"range": {"start": {"line": 11, "character": 19}, "end": {"line": 11, "character": 20}},
59+
"range": {"start": {"line": 14, "character": 12}, "end": {"line": 14, "character": 13}},
4960
"newText": ""
5061
}]
5162
}]
5263

53-
Complete src/CompletionTaggedTemplate.res 14:21
54-
posCursor:[14:21] posNoWhite:[14:20] Found expr:[14:11->14:21]
55-
Completable: Cpath Value[meh](Nolabel, Nolabel).x
64+
Complete src/CompletionTaggedTemplate.res 17:20
65+
[decoratorCompletion] Found @module with non-string payload
66+
[set_result] set new result to Cpath Value[meh](Nolabel, Nolabel).""
67+
posCursor:[17:20] posNoWhite:[17:19] Found expr:[17:11->0:-1]
68+
Completable: Cpath Value[meh](Nolabel, Nolabel).""
5669
Package opens Pervasives.JsxModules.place holder
57-
ContextPath Value[meh](Nolabel, Nolabel).x
70+
ContextPath Value[meh](Nolabel, Nolabel).""
71+
[dot_completion]--> Triggered
5872
ContextPath Value[meh](Nolabel, Nolabel)
73+
[ctx_path]--> CPApply
5974
ContextPath Value[meh]
75+
[ctx_path]--> CPId
6076
Path meh
61-
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)->x
77+
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)->
78+
[ctx_path]--> CPPipe
6279
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)
80+
[ctx_path]--> CPApply
6381
ContextPath Value[meh]
82+
[ctx_path]--> CPId
6483
Path meh
84+
[pipe_completion] mainTypeId: promise
6585
CPPipe pathFromEnv:M found:true
66-
Path M.x
86+
Path M.
6787
[{
6888
"label": "->M.xyz",
6989
"kind": 12,
@@ -73,7 +93,31 @@ Path M.x
7393
"sortText": "xyz",
7494
"insertText": "->M.xyz",
7595
"additionalTextEdits": [{
76-
"range": {"start": {"line": 14, "character": 19}, "end": {"line": 14, "character": 20}},
96+
"range": {"start": {"line": 17, "character": 19}, "end": {"line": 17, "character": 20}},
97+
"newText": ""
98+
}]
99+
}, {
100+
"label": "->M.b",
101+
"kind": 12,
102+
"tags": [],
103+
"detail": "t => string",
104+
"documentation": null,
105+
"sortText": "b",
106+
"insertText": "->M.b",
107+
"additionalTextEdits": [{
108+
"range": {"start": {"line": 17, "character": 19}, "end": {"line": 17, "character": 20}},
109+
"newText": ""
110+
}]
111+
}, {
112+
"label": "->M.a",
113+
"kind": 12,
114+
"tags": [],
115+
"detail": "t => int",
116+
"documentation": null,
117+
"sortText": "a",
118+
"insertText": "->M.a",
119+
"additionalTextEdits": [{
120+
"range": {"start": {"line": 17, "character": 19}, "end": {"line": 17, "character": 20}},
77121
"newText": ""
78122
}]
79123
}]

tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt

+9-54
Original file line numberDiff line numberDiff line change
@@ -333,32 +333,9 @@ ContextPath Value[Js, Array2, filter](Nolabel, Nolabel)->filt
333333
ContextPath Value[Js, Array2, filter](Nolabel, Nolabel)
334334
ContextPath Value[Js, Array2, filter]
335335
Path Js.Array2.filter
336-
Path Js.Array2.filt
337-
[{
338-
"label": "->Js.Array2.filter",
339-
"kind": 12,
340-
"tags": [],
341-
"detail": "(t<'a>, 'a => bool) => t<'a>",
342-
"documentation": {"kind": "markdown", "value": "\nApplies the given predicate function (the second argument) to each element in\nthe array; the result is an array of those elements for which the predicate\nfunction returned `true`. See\n[`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)\non MDN.\n\n## Examples\n\n```rescript\nlet nonEmpty = s => s != \"\"\nJs.Array2.filter([\"abc\", \"\", \"\", \"def\", \"ghi\"], nonEmpty) == [\"abc\", \"def\", \"ghi\"]\n```\n"},
343-
"sortText": "filter",
344-
"insertText": "->Js.Array2.filter",
345-
"additionalTextEdits": [{
346-
"range": {"start": {"line": 86, "character": 38}, "end": {"line": 86, "character": 39}},
347-
"newText": ""
348-
}]
349-
}, {
350-
"label": "->Js.Array2.filteri",
351-
"kind": 12,
352-
"tags": [],
353-
"detail": "(t<'a>, ('a, int) => bool) => t<'a>",
354-
"documentation": {"kind": "markdown", "value": "\nEach element of the given array are passed to the predicate function. The\nreturn value is an array of all those elements for which the predicate function\nreturned `true`.\n\nSee\n[`Array.filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)\non MDN.\n\n## Examples\n\n```rescript\n// keep only positive elements at odd indices\nlet positiveOddElement = (item, index) => mod(index, 2) == 1 && item > 0\n\nJs.Array2.filteri([6, 3, 5, 8, 7, -4, 1], positiveOddElement) == [3, 8]\n```\n"},
355-
"sortText": "filteri",
356-
"insertText": "->Js.Array2.filteri",
357-
"additionalTextEdits": [{
358-
"range": {"start": {"line": 86, "character": 38}, "end": {"line": 86, "character": 39}},
359-
"newText": ""
360-
}]
361-
}]
336+
CPPipe pathFromEnv: found:true
337+
Path Js_array2.filt
338+
[]
362339

363340
Complete src/DotPipeCompletionSpec.res 89:70
364341
posCursor:[89:70] posNoWhite:[89:69] Found expr:[89:3->89:70]
@@ -414,20 +391,9 @@ ContextPath Value[Js, String2, toLowerCase](Nolabel)->toUpperCa
414391
ContextPath Value[Js, String2, toLowerCase](Nolabel)
415392
ContextPath Value[Js, String2, toLowerCase]
416393
Path Js.String2.toLowerCase
417-
Path Js.String2.toUpperCa
418-
[{
419-
"label": "->Js.String2.toUpperCase",
420-
"kind": 12,
421-
"tags": [],
422-
"detail": "t => t",
423-
"documentation": {"kind": "markdown", "value": "\n`toUpperCase(str)` converts `str` to upper case using the locale-insensitive\ncase mappings in the Unicode Character Database. Notice that the conversion can\nexpand the number of letters in the result; for example the German ß\ncapitalizes to two Ses in a row.\n\nSee [`String.toUpperCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.toUpperCase(\"abc\") == \"ABC\"\nJs.String2.toUpperCase(`Straße`) == `STRASSE`\nJs.String2.toUpperCase(`πς`) == `ΠΣ`\n```\n"},
424-
"sortText": "toUpperCase",
425-
"insertText": "->Js.String2.toUpperCase",
426-
"additionalTextEdits": [{
427-
"range": {"start": {"line": 94, "character": 30}, "end": {"line": 94, "character": 31}},
428-
"newText": ""
429-
}]
430-
}]
394+
CPPipe pathFromEnv: found:true
395+
Path Js_string2.toUpperCa
396+
[]
431397

432398
Complete src/DotPipeCompletionSpec.res 97:63
433399
posCursor:[97:63] posNoWhite:[97:62] Found expr:[97:3->97:63]
@@ -442,20 +408,9 @@ ContextPath Value[Js, String2, toUpperCase](Nolabel)->toLowerC
442408
ContextPath Value[Js, String2, toUpperCase](Nolabel)
443409
ContextPath Value[Js, String2, toUpperCase]
444410
Path Js.String2.toUpperCase
445-
Path Js.String2.toLowerC
446-
[{
447-
"label": "->Js.String2.toLowerCase",
448-
"kind": 12,
449-
"tags": [],
450-
"detail": "t => t",
451-
"documentation": {"kind": "markdown", "value": "\n`toLowerCase(str)` converts `str` to lower case using the locale-insensitive\ncase mappings in the Unicode Character Database. Notice that the conversion can\ngive different results depending upon context, for example with the Greek\nletter sigma, which has two different lower case forms; one when it is the last\ncharacter in a string and another when it is not.\n\nSee [`String.toLowerCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase)\non MDN.\n\n## Examples\n\n```rescript\nJs.String2.toLowerCase(\"ABC\") == \"abc\"\nJs.String2.toLowerCase(`ΣΠ`) == `σπ`\nJs.String2.toLowerCase(`ΠΣ`) == `πς`\n```\n"},
452-
"sortText": "toLowerCase",
453-
"insertText": "->Js.String2.toLowerCase",
454-
"additionalTextEdits": [{
455-
"range": {"start": {"line": 97, "character": 54}, "end": {"line": 97, "character": 55}},
456-
"newText": ""
457-
}]
458-
}]
411+
CPPipe pathFromEnv: found:true
412+
Path Js_string2.toLowerC
413+
[]
459414

460415
Complete src/DotPipeCompletionSpec.res 101:7
461416
posCursor:[101:7] posNoWhite:[101:6] Found expr:[100:9->104:1]

0 commit comments

Comments
 (0)