@@ -48,6 +48,7 @@ let completionWithParser ~currentFile ~debug ~offset ~path ~posCursor text =
48
48
49
49
let found = ref false in
50
50
let result = ref None in
51
+ let currentTypeLoc = ref None in
51
52
let scope = ref (Scope. create () ) in
52
53
let setResultOpt x =
53
54
if ! result = None then
@@ -403,6 +404,18 @@ let completionWithParser ~currentFile ~debug ~offset ~path ~posCursor text =
403
404
if expr.pexp_loc |> Loc. hasPos ~pos: posNoWhite && ! result = None then (
404
405
setFound () ;
405
406
match expr.pexp_desc with
407
+ | Pexp_match (switchExpr, [{pc_lhs = lhsPat}])
408
+ when CompletionPatterns. isPatternHole lhsPat
409
+ && locHasCursor switchExpr.pexp_loc = false ->
410
+ setResult (Cpattern {kind = Empty ; typeLoc = switchExpr.pexp_loc})
411
+ | Pexp_match (switchExpr , cases ) ->
412
+ let oldTypeLoc = ! currentTypeLoc in
413
+ currentTypeLoc := Some switchExpr.pexp_loc;
414
+ cases
415
+ |> List. iter (fun case ->
416
+ Ast_iterator. default_iterator.case iterator case);
417
+ currentTypeLoc := oldTypeLoc;
418
+ processed := true
406
419
| Pexp_extension ({txt = "obj" } , PStr [str_item ]) ->
407
420
Ast_iterator. default_iterator.structure_item iterator str_item
408
421
| Pexp_extension ({txt} , _ ) -> setResult (CextensionNode txt)
@@ -614,6 +627,58 @@ let completionWithParser ~currentFile ~debug ~offset ~path ~posCursor text =
614
627
(Pos. toString posCursor) (Pos. toString posNoWhite)
615
628
(Loc. toString pat.ppat_loc);
616
629
(match pat.ppat_desc with
630
+ | Ppat_record ([] , _ ) ->
631
+ (* No fields means empty record body.*)
632
+ setResult
633
+ (Cpattern
634
+ {kind = Field {hint = " " ; seenFields = [] }; typeLoc = pat.ppat_loc})
635
+ | Ppat_record (fields , _ ) -> (
636
+ let fieldWithCursor = ref None in
637
+ let fieldWithPatHole = ref None in
638
+ fields
639
+ |> List. iter (fun (fname , f , _ ) ->
640
+ match
641
+ ( fname.Location. txt,
642
+ f.Parsetree. ppat_loc
643
+ |> CursorPosition. classifyLoc ~pos: posBeforeCursor )
644
+ with
645
+ | Longident. Lident fname , HasCursor ->
646
+ fieldWithCursor := Some (fname, f)
647
+ | Lident fname , _ when CompletionPatterns. isPatternHole f ->
648
+ fieldWithPatHole := Some (fname, f)
649
+ | _ -> () );
650
+ let seenFields =
651
+ fields
652
+ |> List. filter_map (fun (fieldName , _f , _ ) ->
653
+ match fieldName with
654
+ | {Location. txt = Longident. Lident fieldName } -> Some fieldName
655
+ | _ -> None )
656
+ in
657
+ match (! fieldWithCursor, ! fieldWithPatHole) with
658
+ | Some (fname , f ), _ | None , Some (fname , f ) -> (
659
+ match f.ppat_desc with
660
+ | Ppat_extension ({txt = "rescript.patternhole" } , _ ) ->
661
+ (* A pattern hole means for example `{someField: <com>}`. We want to complete for the type of `someField`. *)
662
+ setResult
663
+ (Cpattern
664
+ {kind = FieldValue {fieldName = fname}; typeLoc = pat.ppat_loc})
665
+ | Ppat_var {txt} ->
666
+ (* A var means `{s}` or similar. Complete for fields. *)
667
+ setResult
668
+ (Cpattern
669
+ {kind = Field {hint = txt; seenFields}; typeLoc = pat.ppat_loc})
670
+ | _ -> () )
671
+ | None , None -> (
672
+ (* Figure out if we're completing for a new field.
673
+ If the cursor is inside of the record body, but no field has the cursor,
674
+ and there's no pattern hole. Check the first char to the left of the cursor,
675
+ ignoring white space. If that's a comma, we assume you're completing for a new field. *)
676
+ match firstCharBeforeCursorNoWhite with
677
+ | Some ',' ->
678
+ setResult
679
+ (Cpattern
680
+ {kind = Field {hint = " " ; seenFields}; typeLoc = pat.ppat_loc})
681
+ | _ -> () ))
617
682
| Ppat_construct (lid , _ ) ->
618
683
let lidPath = flattenLidCheckDot lid in
619
684
if debug then
0 commit comments