Skip to content

Commit 80986d3

Browse files
authored
Enhance variant constructor payload completion (rescript-lang#946)
* enhance variant constructor payload completion * changelog * fix * fix * fix tests
1 parent 56a5f0c commit 80986d3

20 files changed

+212
-42
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ analysis/tests/.bsb.lock
99
analysis/tests-generic-jsx-transform/lib
1010
analysis/tests-generic-jsx-transform/.bsb.lock
1111

12+
analysis/tests-incremental-typechecking/lib
13+
analysis/tests-incremental-typechecking/.bsb.lock
14+
1215
tools/node_modules
1316
tools/lib
1417
tools/**/*.res.js

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
- Extend signature help to work on constructor payloads as well. Can be turned off if wanted through settings. https://github.com/rescript-lang/rescript-vscode/pull/947
1818

19+
#### :nail_care: Polish
20+
21+
- Enhance variant constructor payload completion. https://github.com/rescript-lang/rescript-vscode/pull/946
22+
1923
## 1.48.0
2024

2125
#### :bug: Bug Fix

analysis/Makefile

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@ build-tests:
66
build-tests-generic-jsx-transform:
77
make -C tests-generic-jsx-transform build
88

9+
build-tests-incremental-typechecking:
10+
make -C tests-incremental-typechecking build
11+
912
build-reanalyze:
1013
make -C reanalyze build
1114

12-
build: build-reanalyze build-tests build-tests-generic-jsx-transform
15+
build: build-reanalyze build-tests build-tests-generic-jsx-transform build-tests-incremental-typechecking
1316

1417
dce: build-analysis-binary
1518
opam exec reanalyze.exe -- -dce-cmt _build -suppress vendor
1619

1720
test-analysis-binary:
1821
make -C tests test
1922
make -C tests-generic-jsx-transform test
23+
make -C tests-incremental-typechecking test
2024

2125
test-reanalyze:
2226
make -C reanalyze test
@@ -25,6 +29,8 @@ test: test-analysis-binary test-reanalyze
2529

2630
clean:
2731
make -C tests clean
32+
make -C tests-generic-jsx-transform clean
33+
make -C tests-incremental-typechecking clean
2834
make -C reanalyze clean
2935

3036
.PHONY: build-reanalyze build-tests dce clean test

analysis/src/CompletionExpressions.ml

+34
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,37 @@ let prettyPrintFnTemplateArgName ?currentIndex ~env ~full
255255
(someName |> Utils.lowercaseFirstChar) ^ suffix
256256
| _ -> defaultVarName)
257257
| _ -> defaultVarName)
258+
259+
let completeConstructorPayload ~posBeforeCursor ~firstCharBeforeCursorNoWhite
260+
(constructorLid : Longident.t Location.loc) expr =
261+
match
262+
traverseExpr expr ~exprPath:[] ~pos:posBeforeCursor
263+
~firstCharBeforeCursorNoWhite
264+
with
265+
| None -> None
266+
| Some (prefix, nested) ->
267+
(* The nested path must start with the constructor name found, plus
268+
the target argument number for the constructor. We translate to
269+
that here, because we need to account for multi arg constructors
270+
being represented as tuples. *)
271+
let nested =
272+
match List.rev nested with
273+
| Completable.NTupleItem {itemNum} :: rest ->
274+
[
275+
Completable.NVariantPayload
276+
{constructorName = Longident.last constructorLid.txt; itemNum};
277+
]
278+
@ rest
279+
| nested ->
280+
[
281+
Completable.NVariantPayload
282+
{constructorName = Longident.last constructorLid.txt; itemNum = 0};
283+
]
284+
@ nested
285+
in
286+
let variantCtxPath =
287+
Completable.CTypeAtPos
288+
{constructorLid.loc with loc_start = constructorLid.loc.loc_end}
289+
in
290+
Some
291+
(Completable.Cexpression {contextPath = variantCtxPath; prefix; nested})

analysis/src/CompletionFrontEnd.ml

+16-1
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,9 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
10581058
&& expr |> Res_parsetree_viewer.isBracedExpr
10591059
then ValueOrField
10601060
else Value )))
1061-
| Pexp_construct (lid, eOpt) ->
1061+
| Pexp_construct ({txt = Lident ("::" | "()")}, _) ->
1062+
(* Ignore list expressions, used in JSX, unit, and more *) ()
1063+
| Pexp_construct (lid, eOpt) -> (
10621064
let lidPath = flattenLidCheckDot lid in
10631065
if debug && lid.txt <> Lident "Function$" then
10641066
Printf.printf "Pexp_construct %s:%s %s\n"
@@ -1071,6 +1073,19 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
10711073
eOpt = None && (not lid.loc.loc_ghost)
10721074
&& lid.loc |> Loc.hasPos ~pos:posBeforeCursor
10731075
then setResult (Cpath (CPId (lidPath, Value)))
1076+
else
1077+
match eOpt with
1078+
| Some e when locHasCursor e.pexp_loc -> (
1079+
match
1080+
CompletionExpressions.completeConstructorPayload
1081+
~posBeforeCursor ~firstCharBeforeCursorNoWhite lid e
1082+
with
1083+
| Some result ->
1084+
(* Check if anything else more important completes before setting this completion. *)
1085+
Ast_iterator.default_iterator.expr iterator e;
1086+
setResult result
1087+
| None -> ())
1088+
| _ -> ())
10741089
| Pexp_field (e, fieldName) -> (
10751090
if debug then
10761091
Printf.printf "Pexp_field %s %s:%s\n" (Loc.toString e.pexp_loc)
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
// <div
1+
// <div
22
// ^com
33

4-
// <div testing={}
4+
// <div testing={}
55
// ^com
66

77
module SomeComponent = {
88
@jsx.component
99
let make = (~someProp) => {
10-
let someString = ""
10+
let someString = ""
1111
let someInt = 12
1212
let someArr = [GenericJsx.null]
1313
ignore(someInt)
1414
ignore(someArr)
1515
// someString->st
1616
// ^com
17-
open GenericJsx
17+
open GenericJsx
1818
<div>
19-
{GenericJsx.string(someProp)}
19+
{GenericJsx.string(someProp ++ someString)}
2020
<div> {GenericJsx.null} </div>
2121
// {someString->st}
2222
// ^com
2323
</div>
2424
}
25-
}
25+
}

analysis/tests-generic-jsx-transform/src/expected/GenericJsxCompletion.res.txt

+3-6
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Path GenericJsx.Elements.props
5050
Complete src/GenericJsxCompletion.res 14:21
5151
posCursor:[14:21] posNoWhite:[14:20] Found expr:[8:13->23:3]
5252
posCursor:[14:21] posNoWhite:[14:20] Found expr:[8:14->23:3]
53-
posCursor:[14:21] posNoWhite:[14:20] Found expr:[9:1->22:10]
53+
posCursor:[14:21] posNoWhite:[14:20] Found expr:[9:4->22:10]
5454
posCursor:[14:21] posNoWhite:[14:20] Found expr:[10:4->22:10]
5555
posCursor:[14:21] posNoWhite:[14:20] Found expr:[11:4->22:10]
5656
posCursor:[14:21] posNoWhite:[14:20] Found expr:[12:4->22:10]
@@ -90,22 +90,19 @@ Path Js.String2.st
9090
Complete src/GenericJsxCompletion.res 20:24
9191
posCursor:[20:24] posNoWhite:[20:23] Found expr:[8:13->23:3]
9292
posCursor:[20:24] posNoWhite:[20:23] Found expr:[8:14->23:3]
93-
posCursor:[20:24] posNoWhite:[20:23] Found expr:[9:1->22:10]
93+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[9:4->22:10]
9494
posCursor:[20:24] posNoWhite:[20:23] Found expr:[10:4->22:10]
9595
posCursor:[20:24] posNoWhite:[20:23] Found expr:[11:4->22:10]
9696
posCursor:[20:24] posNoWhite:[20:23] Found expr:[12:4->22:10]
9797
posCursor:[20:24] posNoWhite:[20:23] Found expr:[13:4->22:10]
98-
posCursor:[20:24] posNoWhite:[20:23] Found expr:[16:1->22:10]
98+
posCursor:[20:24] posNoWhite:[20:23] Found expr:[16:4->22:10]
9999
posCursor:[20:24] posNoWhite:[20:23] Found expr:[17:5->22:10]
100100
JSX <div:[17:5->17:8] > _children:17:8
101101
posCursor:[20:24] posNoWhite:[20:23] Found expr:[17:8->22:4]
102-
Pexp_construct :::[18:7->22:4] [18:7->22:4]
103102
posCursor:[20:24] posNoWhite:[20:23] Found expr:[18:7->22:4]
104103
posCursor:[20:24] posNoWhite:[20:23] Found expr:[19:7->22:4]
105-
Pexp_construct :::[19:7->22:4] [19:7->22:4]
106104
posCursor:[20:24] posNoWhite:[20:23] Found expr:[19:7->22:4]
107105
posCursor:[20:24] posNoWhite:[20:23] Found expr:[20:10->22:4]
108-
Pexp_construct :::[20:10->22:4] [20:10->22:4]
109106
posCursor:[20:24] posNoWhite:[20:23] Found expr:[20:10->22:4]
110107
posCursor:[20:24] posNoWhite:[20:23] Found expr:[20:10->20:24]
111108
Completable: Cpath Value[someString]->st <<jsx>>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
SHELL = /bin/bash
2+
3+
node_modules/.bin/rescript:
4+
npm install
5+
6+
build: node_modules/.bin/rescript
7+
node_modules/.bin/rescript > /dev/null || true
8+
9+
test: build
10+
./test.sh
11+
12+
clean:
13+
rm -r node_modules lib
14+
15+
.DEFAULT_GOAL := test
16+
17+
.PHONY: clean test

analysis/tests-incremental-typechecking/package-lock.json

+33
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"scripts": {
3+
"build": "rescript",
4+
"clean": "rescript clean -with-deps"
5+
},
6+
"private": true,
7+
"dependencies": {
8+
"rescript": "11.1.0-rc.2"
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "test-generic-jsx-transform",
3+
"sources": [
4+
{
5+
"dir": "src",
6+
"subdirs": true
7+
}
8+
],
9+
"bsc-flags": ["-w -33-44-8"],
10+
"jsx": { "module": "GenericJsx" }
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let x = Js.Json.Array()
2+
// ^com
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module WithVariant = {
2+
type t = One({miss: bool}) | Two(bool)
3+
}
4+
5+
let x = WithVariant.One()
6+
// ^com
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Complete src/ConstructorCompletion__Json.res 0:22
2+
posCursor:[0:22] posNoWhite:[0:21] Found expr:[0:8->0:23]
3+
Pexp_construct Js
4+
Json
5+
Array:[0:8->0:21] [0:21->0:23]
6+
Completable: Cexpression CTypeAtPos()->variantPayload::Array($0)
7+
Package opens Pervasives.JsxModules.place holder
8+
Resolved opens 1 pervasives
9+
ContextPath CTypeAtPos()
10+
[{
11+
"label": "[]",
12+
"kind": 12,
13+
"tags": [],
14+
"detail": "t",
15+
"documentation": null,
16+
"sortText": "A",
17+
"insertText": "[$0]",
18+
"insertTextFormat": 2
19+
}]
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Complete src/ConstructorCompletion__Own.res 4:24
2+
posCursor:[4:24] posNoWhite:[4:23] Found expr:[4:8->4:25]
3+
Pexp_construct WithVariant
4+
One:[4:8->4:23] [4:23->4:25]
5+
Completable: Cexpression CTypeAtPos()->variantPayload::One($0)
6+
Package opens Pervasives.JsxModules.place holder
7+
Resolved opens 1 pervasives
8+
ContextPath CTypeAtPos()
9+
[{
10+
"label": "{}",
11+
"kind": 4,
12+
"tags": [],
13+
"detail": "Inline record",
14+
"documentation": null,
15+
"sortText": "A",
16+
"insertText": "{$0}",
17+
"insertTextFormat": 2
18+
}]
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
for file in src/*.res; do
2+
output="$(dirname $file)/expected/$(basename $file).txt"
3+
../../rescript-editor-analysis.exe test $file &> $output
4+
# CI. We use LF, and the CI OCaml fork prints CRLF. Convert.
5+
if [ "$RUNNER_OS" == "Windows" ]; then
6+
perl -pi -e 's/\r\n/\n/g' -- $output
7+
fi
8+
done
9+
10+
warningYellow='\033[0;33m'
11+
successGreen='\033[0;32m'
12+
reset='\033[0m'
13+
14+
diff=$(git ls-files --modified src/expected)
15+
if [[ $diff = "" ]]; then
16+
printf "${successGreen}✅ No unstaged tests difference.${reset}\n"
17+
else
18+
printf "${warningYellow}⚠️ There are unstaged differences in tests/! Did you break a test?\n${diff}\n${reset}"
19+
git --no-pager diff src/expected
20+
exit 1
21+
fi

0 commit comments

Comments
 (0)