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

Complete tagged template application #7278

Merged
merged 15 commits into from
Feb 6, 2025
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- Fix async context checking for module await. https://github.com/rescript-lang/rescript/pull/7271
- Fix `%external` extension. https://github.com/rescript-lang/rescript/pull/7272
- Fix issue with type environment for unified ops. https://github.com/rescript-lang/rescript/pull/7277
- Fix completion for application with tagged template. https://github.com/rescript-lang/rescript/pull/7278

# 12.0.0-alpha.8

Expand Down
59 changes: 59 additions & 0 deletions analysis/src/CompletionFrontEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,65 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
(* Case foo-> when the parser adds a ghost expression to the rhs
so the apply expression does not include the cursor *)
if setPipeResult ~lhs ~id:"" then setFound ()
(*
A dot completion for a tagged templated application with an expr hole.
Example:
sh`echo "meh"`.
*)
| Pexp_apply
{
funct = {pexp_desc = Pexp_ident {txt = Lident "."; loc = _}};
args =
[
(* sh`echo "meh"` *)
(_, ({pexp_desc = Pexp_apply _} as innerExpr));
(* recovery inserted node *)
(_, {pexp_desc = Pexp_extension ({txt = "rescript.exprhole"}, _)});
];
}
when Res_parsetree_viewer.is_tagged_template_literal innerExpr ->
exprToContextPath innerExpr
|> Option.iter (fun cpath ->
setResult
(Cpath
(CPField
{
contextPath = cpath;
fieldName = "";
posOfDot;
exprLoc = expr.pexp_loc;
}));
setFound ())
(*
A dot completion for a tagged templated application with an ident.
Example:
sh`echo "meh"`.foo
*)
| Pexp_apply
{
funct = {pexp_desc = Pexp_ident {txt = Lident "."; loc = _}};
args =
[
(* sh`echo "meh"` *)
(_, ({pexp_desc = Pexp_apply _} as innerExpr));
(* foo *)
(_, {pexp_desc = Pexp_ident {txt = Lident fieldName}});
];
}
when Res_parsetree_viewer.is_tagged_template_literal innerExpr
&& expr.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor ->
exprToContextPath innerExpr
|> Option.iter (fun cpath ->
setResult
(Cpath
(CPField
{
contextPath = cpath;
fieldName;
posOfDot;
exprLoc = expr.pexp_loc;
}));
setFound ())
| _ -> (
if expr.pexp_loc |> Loc.hasPos ~pos:posNoWhite && !result = None then (
setFound ();
Expand Down
16 changes: 16 additions & 0 deletions tests/analysis_tests/tests/src/CompletionTaggedTemplate.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module M = {
type t

let a = (_t:t) => 4
let b = (_:t) => "c"
let xyz = (_:t, p:int) => p + 1
}

@module("meh") @taggedTemplate
external meh: (array<string>, array<string>) => M.t = "default"

// let x = meh`foo`.
// ^com

// let y = meh`bar`.x
// ^com
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
Complete src/CompletionTaggedTemplate.res 11:20
posCursor:[11:20] posNoWhite:[11:19] Found expr:[11:11->0:-1]
Completable: Cpath Value[meh](Nolabel, Nolabel).""
Package opens Pervasives.JsxModules.place holder
ContextPath Value[meh](Nolabel, Nolabel).""
ContextPath Value[meh](Nolabel, Nolabel)
ContextPath Value[meh]
Path meh
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)->
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)
ContextPath Value[meh]
Path meh
CPPipe pathFromEnv:M found:true
Path M.
[{
"label": "->M.xyz",
"kind": 12,
"tags": [],
"detail": "(t, int) => int",
"documentation": null,
"sortText": "xyz",
"insertText": "->M.xyz",
"additionalTextEdits": [{
"range": {"start": {"line": 11, "character": 19}, "end": {"line": 11, "character": 20}},
"newText": ""
}]
}, {
"label": "->M.b",
"kind": 12,
"tags": [],
"detail": "t => string",
"documentation": null,
"sortText": "b",
"insertText": "->M.b",
"additionalTextEdits": [{
"range": {"start": {"line": 11, "character": 19}, "end": {"line": 11, "character": 20}},
"newText": ""
}]
}, {
"label": "->M.a",
"kind": 12,
"tags": [],
"detail": "t => int",
"documentation": null,
"sortText": "a",
"insertText": "->M.a",
"additionalTextEdits": [{
"range": {"start": {"line": 11, "character": 19}, "end": {"line": 11, "character": 20}},
"newText": ""
}]
}]

Complete src/CompletionTaggedTemplate.res 14:21
posCursor:[14:21] posNoWhite:[14:20] Found expr:[14:11->14:21]
Completable: Cpath Value[meh](Nolabel, Nolabel).x
Package opens Pervasives.JsxModules.place holder
ContextPath Value[meh](Nolabel, Nolabel).x
ContextPath Value[meh](Nolabel, Nolabel)
ContextPath Value[meh]
Path meh
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)->x
ContextPath Value[meh](Nolabel, Nolabel, Nolabel)
ContextPath Value[meh]
Path meh
CPPipe pathFromEnv:M found:true
Path M.x
[{
"label": "->M.xyz",
"kind": 12,
"tags": [],
"detail": "(t, int) => int",
"documentation": null,
"sortText": "xyz",
"insertText": "->M.xyz",
"additionalTextEdits": [{
"range": {"start": {"line": 14, "character": 19}, "end": {"line": 14, "character": 20}},
"newText": ""
}]
}]