Skip to content

Commit 0837d20

Browse files
committed
Add functions to extract case names from active patterns and refactor related logic
1 parent 5106d21 commit 0837d20

File tree

1 file changed

+35
-52
lines changed

1 file changed

+35
-52
lines changed

src/FsAutoComplete.Core/Commands.fs

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,21 @@ module Commands =
9292
let fantomasLogger = LogProvider.getLoggerByName "Fantomas"
9393
let commandsLogger = LogProvider.getLoggerByName "Commands"
9494

95+
/// Extracts the case name(s) from an active pattern name string.
96+
/// For partial patterns like "|CaseName|_|" returns "CaseName"
97+
/// For full patterns like "|Even|Odd|" returns the first case name
98+
let extractActivePatternCaseName (name: string) : string =
99+
let parts = name.Split('|') |> Array.filter (fun s -> s <> "" && s <> "_")
100+
if parts.Length > 0 then parts.[0] else name
101+
102+
/// Extracts all case names from an active pattern display name.
103+
/// For "(|ParseInt|_|)" returns ["ParseInt"]
104+
/// For "(|Even|Odd|)" returns ["Even"; "Odd"]
105+
let extractActivePatternCaseNames (displayName: string) : string list =
106+
displayName.TrimStart('|', '(').TrimEnd('|', '_', ')').Split('|')
107+
|> Array.filter (fun s -> not (String.IsNullOrWhiteSpace(s)))
108+
|> Array.toList
109+
95110
/// Find case usages for partial active patterns by walking the AST
96111
/// Returns ranges where the case names appear in pattern matches
97112
let findPartialActivePatternCaseUsages (caseNames: string list) (parseResults: FSharpParseFileResults) : range list =
@@ -140,45 +155,27 @@ module Commands =
140155
}
141156

142157
let rec walkExpr (expr: SynExpr) =
143-
seq {
144-
match expr with
145-
| SynExpr.Match(expr = matchExpr; clauses = clauses) ->
146-
// Walk the discriminator expression
147-
yield! walkExpr matchExpr
148-
158+
let walkMatchClauses clauses =
159+
seq {
149160
for clause in clauses do
150161
match clause with
151162
| SynMatchClause(pat = pat; resultExpr = resultExpr) ->
152163
yield! walkPat pat
153-
// Walk the result expression to find nested matches
154164
yield! walkExpr resultExpr
165+
}
166+
167+
seq {
168+
match expr with
169+
| SynExpr.Match(expr = matchExpr; clauses = clauses) ->
170+
yield! walkExpr matchExpr
171+
yield! walkMatchClauses clauses
155172
| SynExpr.MatchBang(expr = matchExpr; clauses = clauses) ->
156-
// Walk the discriminator expression
157173
yield! walkExpr matchExpr
158-
159-
for clause in clauses do
160-
match clause with
161-
| SynMatchClause(pat = pat; resultExpr = resultExpr) ->
162-
yield! walkPat pat
163-
// Walk the result expression to find nested matches
164-
yield! walkExpr resultExpr
174+
yield! walkMatchClauses clauses
165175
| SynExpr.TryWith(tryExpr = tryExpr; withCases = clauses) ->
166-
// Walk the try expression
167176
yield! walkExpr tryExpr
168-
169-
for clause in clauses do
170-
match clause with
171-
| SynMatchClause(pat = pat; resultExpr = resultExpr) ->
172-
yield! walkPat pat
173-
// Walk the result expression to find nested matches
174-
yield! walkExpr resultExpr
175-
| SynExpr.MatchLambda(matchClauses = clauses) ->
176-
for clause in clauses do
177-
match clause with
178-
| SynMatchClause(pat = pat; resultExpr = resultExpr) ->
179-
yield! walkPat pat
180-
// Walk the result expression to find nested matches
181-
yield! walkExpr resultExpr
177+
yield! walkMatchClauses clauses
178+
| SynExpr.MatchLambda(matchClauses = clauses) -> yield! walkMatchClauses clauses
182179
| SynExpr.Lambda(args = args; body = body) ->
183180
match args with
184181
| SynSimplePats.SimplePats(pats = pats) ->
@@ -937,30 +934,20 @@ module Commands =
937934
let symbolNameCore =
938935
match symbol with
939936
| :? FSharpActivePatternCase as apc ->
940-
// For active pattern cases, use the case name directly
937+
// For active pattern cases, extract just the case name without bars
941938
// apc.Name may include bars like "|LetterOrDigit|_|" for partial patterns
942-
// We need to extract just the case name without bars
943-
let name = apc.Name
944-
945-
if name.StartsWith("|") then
946-
// Partial pattern: "|CaseName|_|" -> extract "CaseName"
947-
let parts = name.Split('|') |> Array.filter (fun s -> s <> "" && s <> "_")
948-
if parts.Length > 0 then parts.[0] else name
939+
if apc.Name.StartsWith("|") then
940+
extractActivePatternCaseName apc.Name
949941
else
950-
name
942+
apc.Name
951943
| :? FSharpMemberOrFunctionOrValue as mfv when mfv.IsActivePattern ->
952-
// For active pattern functions (the function definition), extract just the case name(s)
953-
// DisplayNameCore is like "|LetterOrDigit|_|" for partial patterns
954-
// For multi-case patterns like "(|Even|Odd|)", we should return the full pattern
944+
// For active pattern functions, extract just the case name for partial patterns
945+
// For full patterns like "(|Even|Odd|)", use DisplayNameCore as-is
955946
let displayName = symbol.DisplayNameCore
956947

957948
if displayName.Contains("|_|") then
958-
// Partial active pattern - extract just the case name(s) without the partial marker
959-
// "|CaseName|_|" -> "CaseName"
960-
let parts = displayName.Split('|') |> Array.filter (fun s -> s <> "" && s <> "_")
961-
if parts.Length > 0 then parts.[0] else displayName
949+
extractActivePatternCaseName displayName
962950
else
963-
// Full active pattern - use DisplayNameCore as-is
964951
displayName
965952
| _ -> symbol.DisplayNameCore
966953

@@ -1042,11 +1029,7 @@ module Commands =
10421029
baseFiltered, []
10431030
else
10441031
// For partial patterns, find case usages by walking the AST
1045-
// Extract case names from the pattern (e.g., "|ParseInt|_|" -> ["ParseInt"])
1046-
let caseNames =
1047-
patternDisplayName.TrimStart('|', '(').TrimEnd('|', '_', ')').Split('|')
1048-
|> Array.filter (fun s -> not (String.IsNullOrWhiteSpace(s)))
1049-
|> Array.toList
1032+
let caseNames = extractActivePatternCaseNames patternDisplayName
10501033

10511034
let caseUsageRanges =
10521035
findPartialActivePatternCaseUsages caseNames tyRes.GetParseResults

0 commit comments

Comments
 (0)