@@ -52,13 +52,18 @@ type RecordContext =
52
52
53
53
[<RequireQualifiedAccess>]
54
54
type PatternContext =
55
- /// Completing union case field in a pattern (e.g. fun (Some v|) -> )
56
- /// fieldIndex None signifies that the case identifier is followed by a single field, outside of parentheses
57
- | PositionalUnionCaseField of fieldIndex : int option * caseIdRange : range
55
+ /// <summary>Completing union case field pattern (e.g. fun (Some v| ) -> ) or fun (Some (v| )) -> ). In theory, this could also be parameterized active pattern usage.</summary>
56
+ /// <param name="fieldIndex">Position in the tuple. <see cref="None">None</see> if there is no tuple, with only one field outside of parentheses - `Some v|`</param>
57
+ /// <param name="isTheOnlyField">True when completing the first field in the tuple and no other field is bound - `Case (a|)` but not `Case (a|, b)`</param>
58
+ /// <param name="caseIdRange">Range of the case identifier</param>
59
+ | PositionalUnionCaseField of fieldIndex : int option * isTheOnlyField : bool * caseIdRange : range
58
60
59
- /// Completing union case field in a pattern (e.g. fun (Some (Value = v|) -> )
61
+ /// Completing union case field pattern (e.g. fun (Some (Value = v| ) ) -> )
60
62
| NamedUnionCaseField of fieldName : string * caseIdRange : range
61
63
64
+ /// Completing union case field identifier in a pattern (e.g. fun (Case (field1 = a; fie| )) -> )
65
+ | UnionCaseFieldIdentifier of referencedFields : string list * caseIdRange : range
66
+
62
67
/// Any other position in a pattern that does not need special handling
63
68
| Other
64
69
@@ -1261,28 +1266,46 @@ module ParsedInput =
1261
1266
let rec TryGetCompletionContextInPattern suppressIdentifierCompletions ( pat : SynPat ) previousContext pos =
1262
1267
match pat with
1263
1268
| SynPat.LongIdent ( longDotId = id) when rangeContainsPos id.Range pos -> Some( CompletionContext.Pattern PatternContext.Other)
1264
- | SynPat.LongIdent ( argPats = SynArgPats.NamePatPairs ( pats = pats); longDotId = id) ->
1269
+ | SynPat.LongIdent ( argPats = SynArgPats.NamePatPairs ( pats = pats; range = mPairs); longDotId = caseId; range = m) when
1270
+ rangeContainsPos m pos
1271
+ ->
1265
1272
pats
1266
- |> List.tryPick ( fun ( patId , _ , pat ) ->
1267
- if rangeContainsPos patId.idRange pos then
1268
- Some CompletionContext.Invalid
1273
+ |> List.tryPick ( fun ( fieldId , _ , pat ) ->
1274
+ if rangeContainsPos fieldId.idRange pos then
1275
+ let referencedFields = pats |> List.map ( fun ( id , _ , _ ) -> id.idText)
1276
+ Some( CompletionContext.Pattern( PatternContext.UnionCaseFieldIdentifier( referencedFields, caseId.Range)))
1269
1277
else
1270
- let context = Some( PatternContext.NamedUnionCaseField( patId .idText, id .Range))
1278
+ let context = Some( PatternContext.NamedUnionCaseField( fieldId .idText, caseId .Range))
1271
1279
TryGetCompletionContextInPattern suppressIdentifierCompletions pat context pos)
1280
+ |> Option.orElseWith ( fun () ->
1281
+ // Last resort - check for fun (Case (item1 = a; | )) ->
1282
+ // That is, pos is after the last pair and still within parentheses
1283
+ if rangeBeforePos mPairs pos then
1284
+ let referencedFields = pats |> List.map ( fun ( id , _ , _ ) -> id.idText)
1285
+ Some( CompletionContext.Pattern( PatternContext.UnionCaseFieldIdentifier( referencedFields, caseId.Range)))
1286
+ else
1287
+ None)
1272
1288
| SynPat.LongIdent ( argPats = SynArgPats.Pats pats; longDotId = id; range = m) when rangeContainsPos m pos ->
1273
1289
match pats with
1274
1290
1275
1291
// fun (Some v| ) ->
1276
- | [ SynPat.Named _ ] -> Some( CompletionContext.Pattern( PatternContext.PositionalUnionCaseField( None, id.Range)))
1292
+ | [ SynPat.Named _ ] -> Some( CompletionContext.Pattern( PatternContext.PositionalUnionCaseField( None, true , id.Range)))
1277
1293
1278
1294
// fun (Case (| )) ->
1279
1295
| [ SynPat.Paren ( SynPat.Const ( SynConst.Unit, _), m) ] when rangeContainsPos m pos ->
1280
- Some( CompletionContext.Pattern( PatternContext.PositionalUnionCaseField( Some 0 , id.Range)))
1296
+ Some( CompletionContext.Pattern( PatternContext.PositionalUnionCaseField( Some 0 , true , id.Range)))
1297
+
1298
+ // fun (Case (a| )) ->
1299
+ // This could either be the first positional field pattern or the user might want to use named pairs
1300
+ | [ SynPat.Paren ( SynPat.Named _, _) ] ->
1301
+ Some( CompletionContext.Pattern( PatternContext.PositionalUnionCaseField( Some 0 , true , id.Range)))
1281
1302
1282
1303
// fun (Case (a| , b)) ->
1283
- | [ SynPat.Paren ( SynPat.Tuple _ | SynPat.Named _ as pat, _) ] ->
1284
- TryGetCompletionContextInPattern false pat ( Some( PatternContext.PositionalUnionCaseField( Some 0 , id.Range))) pos
1285
- |> Option.orElseWith ( fun () -> Some CompletionContext.Invalid)
1304
+ | [ SynPat.Paren ( SynPat.Tuple ( elementPats = pats) as pat, _) ] ->
1305
+ let context =
1306
+ Some( PatternContext.PositionalUnionCaseField( Some 0 , pats.Length = 1 , id.Range))
1307
+
1308
+ TryGetCompletionContextInPattern false pat context pos
1286
1309
1287
1310
| _ ->
1288
1311
pats
@@ -1297,21 +1320,25 @@ module ParsedInput =
1297
1320
|> List.tryPick ( fun ( i , pat ) ->
1298
1321
let context =
1299
1322
match previousContext with
1300
- | Some ( PatternContext.PositionalUnionCaseField (_, caseIdRange)) ->
1301
- Some( PatternContext.PositionalUnionCaseField( Some i, caseIdRange))
1323
+ | Some ( PatternContext.PositionalUnionCaseField (_, isTheOnlyField , caseIdRange)) ->
1324
+ Some( PatternContext.PositionalUnionCaseField( Some i, isTheOnlyField , caseIdRange))
1302
1325
| _ ->
1303
1326
// No preceding LongIdent => this is a tuple deconstruction
1304
1327
None
1305
1328
1306
1329
TryGetCompletionContextInPattern suppressIdentifierCompletions pat context pos)
1307
1330
|> Option.orElseWith ( fun () ->
1308
- // Last resort - check for fun (Case (a, | )) ->
1331
+ // Last resort - check for fun (Case (item1 = a, | )) ->
1309
1332
// That is, pos is after the last comma and before the end of the tuple
1310
1333
match previousContext, List.tryLast commas with
1311
- | Some ( PatternContext.PositionalUnionCaseField (_, caseIdRange)), Some mComma when
1334
+ | Some ( PatternContext.PositionalUnionCaseField (_, isTheOnlyField , caseIdRange)), Some mComma when
1312
1335
rangeBeforePos mComma pos && rangeContainsPos m pos
1313
1336
->
1314
- Some( CompletionContext.Pattern( PatternContext.PositionalUnionCaseField( Some( pats.Length - 1 ), caseIdRange)))
1337
+ Some(
1338
+ CompletionContext.Pattern(
1339
+ PatternContext.PositionalUnionCaseField( Some( pats.Length - 1 ), isTheOnlyField, caseIdRange)
1340
+ )
1341
+ )
1315
1342
| _ -> None)
1316
1343
| SynPat.Named ( range = m) when rangeContainsPos m pos ->
1317
1344
if suppressIdentifierCompletions then
0 commit comments