@@ -1341,8 +1341,13 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
13411341 {
13421342 jsx_container_element_tag_name_start = compName;
13431343 jsx_container_element_props = props;
1344- } ) ->
1344+ } ) -> (
13451345 inJsxContext := true ;
1346+ let is_valid_tag_for_props =
1347+ match compName.txt with
1348+ | Parsetree. JsxTagInvalid _ -> false
1349+ | _ -> true
1350+ in
13461351 let children =
13471352 match expr.pexp_desc with
13481353 | Pexp_jsx_element
@@ -1351,43 +1356,81 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
13511356 children
13521357 | _ -> JSXChildrenItems []
13531358 in
1354- let jsxProps =
1355- CompletionJsx. extractJsxProps ~comp Name ~props ~children
1359+ let compName_loc = compName.loc in
1360+ let compName_lid =
1361+ Ast_helper.Jsx. longident_of_jsx_tag_name compName.txt
13561362 in
1357- let compNamePath = flattenLidCheckDot ~jsx: true compName in
1358- if debug then
1359- Printf. printf " JSX <%s:%s %s> _children:%s\n "
1360- (compNamePath |> String. concat " ." )
1361- (Loc. toString compName.loc)
1362- (jsxProps.props
1363- |> List. map
1364- (fun ({name; posStart; posEnd; exp} : CompletionJsx.prop ) ->
1365- Printf. sprintf " %s[%s->%s]=...%s" name
1366- (Pos. toString posStart) (Pos. toString posEnd)
1367- (Loc. toString exp.pexp_loc))
1368- |> String. concat " " )
1369- (match jsxProps.childrenStart with
1370- | None -> " None"
1371- | Some childrenPosStart -> Pos. toString childrenPosStart);
1363+ let jsxPropsOpt =
1364+ if is_valid_tag_for_props then
1365+ Some
1366+ (CompletionJsx. extractJsxProps
1367+ ~comp Name:(Location. mkloc compName_lid compName_loc)
1368+ ~props ~children )
1369+ else None
1370+ in
1371+ let compNamePath =
1372+ flattenLidCheckDot ~jsx: true
1373+ {txt = compName_lid; loc = compName_loc}
1374+ in
1375+ (if debug then
1376+ match jsxPropsOpt with
1377+ | Some jsxProps ->
1378+ Printf. printf " JSX <%s:%s %s> _children:%s\n "
1379+ (compNamePath |> String. concat " ." )
1380+ (Loc. toString compName_loc)
1381+ (jsxProps.props
1382+ |> List. map
1383+ (fun
1384+ ({name; posStart; posEnd; exp} : CompletionJsx.prop ) ->
1385+ Printf. sprintf " %s[%s->%s]=...%s" name
1386+ (Pos. toString posStart) (Pos. toString posEnd)
1387+ (Loc. toString exp.pexp_loc))
1388+ |> String. concat " " )
1389+ (match jsxProps.childrenStart with
1390+ | None -> " None"
1391+ | Some childrenPosStart -> Pos. toString childrenPosStart)
1392+ | None ->
1393+ Printf. printf " JSX <%s:%s > _children:None\n "
1394+ (compNamePath |> String. concat " ." )
1395+ (Loc. toString compName_loc));
1396+ (* If the tag name is an uppercase path and the cursor is right after a dot (e.g., <O.|),
1397+ prefer module member completion over JSX prop suggestions. *)
1398+ (match compName.txt with
1399+ | Parsetree. JsxUpperTag _ when blankAfterCursor = Some '.' ->
1400+ setResult
1401+ (Cpath
1402+ (CPId
1403+ {
1404+ loc = compName_loc;
1405+ path = compNamePath;
1406+ completionContext = Module ;
1407+ }))
1408+ | _ -> () );
13721409 let jsxCompletable =
1373- match expr.pexp_desc with
1374- | Pexp_jsx_element
1375- ( Jsx_container_element
1376- {
1377- jsx_container_element_closing_tag = None ;
1378- jsx_container_element_children =
1379- JSXChildrenSpreading _ | JSXChildrenItems (_ :: _);
1380- }) ->
1381- (* This is a weird edge case where there is no closing tag but there are children *)
1410+ match (jsxPropsOpt, expr.pexp_desc) with
1411+ | ( Some _,
1412+ Pexp_jsx_element
1413+ ( Jsx_container_element
1414+ {
1415+ jsx_container_element_closing_tag = None ;
1416+ jsx_container_element_children =
1417+ JSXChildrenSpreading _ | JSXChildrenItems (_ :: _);
1418+ }) ) ->
13821419 None
1383- | _ ->
1420+ | Some jsxProps , _ ->
13841421 CompletionJsx. findJsxPropsCompletable ~jsx Props
13851422 ~end Pos:(Loc. end_ expr.pexp_loc) ~pos BeforeCursor
1386- ~pos AfterCompName:(Loc. end_ compName.loc )
1423+ ~pos AfterCompName:(Loc. end_ compName_loc )
13871424 ~first CharBeforeCursorNoWhite ~char AtCursor
1425+ | None , _ -> None
13881426 in
1389- if jsxCompletable <> None then setResultOpt jsxCompletable
1390- else if compName.loc |> Loc. hasPos ~pos: posBeforeCursor then
1427+ (match jsxCompletable with
1428+ | Some _ as res -> setResultOpt res
1429+ | None -> () );
1430+ if
1431+ jsxCompletable = None
1432+ && compName_loc |> Loc. hasPos ~pos: posBeforeCursor
1433+ then
13911434 setResult
13921435 (match compNamePath with
13931436 | [prefix] when Char. lowercase_ascii prefix.[0 ] = prefix.[0 ] ->
@@ -1396,11 +1439,14 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
13961439 Cpath
13971440 (CPId
13981441 {
1399- loc = compName.loc ;
1442+ loc = compName_loc ;
14001443 path = compNamePath;
14011444 completionContext = Module ;
14021445 }))
1403- else iterateJsxProps ~iterator jsxProps
1446+ else
1447+ match jsxPropsOpt with
1448+ | Some jsxProps -> iterateJsxProps ~iterator jsxProps
1449+ | None -> () )
14041450 | Pexp_apply
14051451 {
14061452 funct = {pexp_desc = Pexp_ident {txt = Lident " ->" }};
0 commit comments