Skip to content

Commit 0d8fbc3

Browse files
authored
Heuristic for JSX completion happening at the very end of a component with children (#875)
* heuristic for JSX completion happening at the very end of a component with children * fix comment
1 parent 95f77e1 commit 0d8fbc3

File tree

4 files changed

+50
-10
lines changed

4 files changed

+50
-10
lines changed

analysis/src/CompletionFrontEnd.ml

+4-4
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,14 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
249249
Some text.[offsetNoWhite]
250250
else None
251251
in
252+
let charAtCursor =
253+
if offset < String.length text then text.[offset] else '\n'
254+
in
252255
let posBeforeCursor = Pos.posBeforeCursor posCursor in
253256
let charBeforeCursor, blankAfterCursor =
254257
match Pos.positionToOffset text posCursor with
255258
| Some offset when offset > 0 -> (
256259
let charBeforeCursor = text.[offset - 1] in
257-
let charAtCursor =
258-
if offset < String.length text then text.[offset] else '\n'
259-
in
260260
match charAtCursor with
261261
| ' ' | '\t' | '\r' | '\n' ->
262262
(Some charBeforeCursor, Some charBeforeCursor)
@@ -918,7 +918,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
918918
CompletionJsx.findJsxPropsCompletable ~jsxProps
919919
~endPos:(Loc.end_ expr.pexp_loc) ~posBeforeCursor
920920
~posAfterCompName:(Loc.end_ compName.loc)
921-
~firstCharBeforeCursorNoWhite
921+
~firstCharBeforeCursorNoWhite ~charAtCursor
922922
in
923923
if jsxCompletable <> None then setResultOpt jsxCompletable
924924
else if compName.loc |> Loc.hasPos ~pos:posBeforeCursor then

analysis/src/CompletionJsx.ml

+24-6
Original file line numberDiff line numberDiff line change
@@ -802,12 +802,17 @@ type jsxProps = {
802802
}
803803

804804
let findJsxPropsCompletable ~jsxProps ~endPos ~posBeforeCursor
805-
~firstCharBeforeCursorNoWhite ~posAfterCompName =
805+
~firstCharBeforeCursorNoWhite ~charAtCursor ~posAfterCompName =
806806
let allLabels =
807807
List.fold_right
808808
(fun prop allLabels -> prop.name :: allLabels)
809809
jsxProps.props []
810810
in
811+
let beforeChildrenStart =
812+
match jsxProps.childrenStart with
813+
| Some childrenPos -> posBeforeCursor < childrenPos
814+
| None -> posBeforeCursor <= endPos
815+
in
811816
let rec loop props =
812817
match props with
813818
| prop :: rest ->
@@ -860,13 +865,26 @@ let findJsxPropsCompletable ~jsxProps ~endPos ~posBeforeCursor
860865
nested = [];
861866
})
862867
else None
868+
else if rest = [] && beforeChildrenStart && charAtCursor = '>' then
869+
(* This is a special case for: <SomeComponent someProp=> (completing directly after the '=').
870+
The completion comes at the end of the component, after the equals sign, but before any
871+
children starts, and '>' marks that it's at the end of the component JSX.
872+
This little heuristic makes sure we pick up this special case. *)
873+
Some
874+
(Cexpression
875+
{
876+
contextPath =
877+
CJsxPropValue
878+
{
879+
pathToComponent =
880+
Utils.flattenLongIdent ~jsx:true jsxProps.compName.txt;
881+
propName = prop.name;
882+
};
883+
prefix = "";
884+
nested = [];
885+
})
863886
else loop rest
864887
| [] ->
865-
let beforeChildrenStart =
866-
match jsxProps.childrenStart with
867-
| Some childrenPos -> posBeforeCursor < childrenPos
868-
| None -> posBeforeCursor <= endPos
869-
in
870888
let afterCompName = posBeforeCursor >= posAfterCompName in
871889
if afterCompName && beforeChildrenStart then
872890
Some

analysis/tests/src/CompletionJsx.res

+3
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,6 @@ module CompWithoutJsxPpx = {
4545

4646
// <CompWithoutJsxPpx n
4747
// ^com
48+
49+
// <SomeComponent someProp=>
50+
// ^com

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

+19
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,22 @@ Path CompWithoutJsxPpx.make
473473
"documentation": null
474474
}]
475475

476+
Complete src/CompletionJsx.res 48:27
477+
posCursor:[48:27] posNoWhite:[48:26] Found expr:[48:4->48:28]
478+
JSX <SomeComponent:[48:4->48:17] someProp[48:18->48:26]=...[48:18->48:26]> _children:None
479+
Completable: Cexpression CJsxPropValue [SomeComponent] someProp
480+
Package opens Pervasives.JsxModules.place holder
481+
Resolved opens 1 pervasives
482+
ContextPath CJsxPropValue [SomeComponent] someProp
483+
Path SomeComponent.make
484+
[{
485+
"label": "\"\"",
486+
"kind": 12,
487+
"tags": [],
488+
"detail": "string",
489+
"documentation": null,
490+
"sortText": "A",
491+
"insertText": "{\"$0\"}",
492+
"insertTextFormat": 2
493+
}]
494+

0 commit comments

Comments
 (0)