@@ -23,8 +23,9 @@ export function formatCodeSearchOutput(
2323 return 'Found 0 matches'
2424 }
2525 const lines = stdout . split ( '\n' )
26+ const knownFilePaths = collectMatchFilePaths ( lines )
2627 const formatted : string [ ] = [
27- `Found ${ options . matchCount ?? countFormattedMatches ( lines ) } matches` ,
28+ `Found ${ options . matchCount ?? knownFilePaths . matchCount } matches` ,
2829 ]
2930 let currentFile : string | null = null
3031
@@ -43,9 +44,9 @@ export function formatCodeSearchOutput(
4344 // - Match lines: filename:line_number:content
4445 // - Context lines (with -A/-B/-C flags): filename-line_number-content
4546
46- // Use regex to find the pattern: separator + digits + separator
47- // This handles filenames with hyphens/colons by matching the line number pattern
48- const parsedLine = parseRipgrepLine ( line )
47+ // Use known match file paths to disambiguate context lines, which use
48+ // hyphens as separators and can otherwise conflict with hyphenated paths.
49+ const parsedLine = parseRipgrepLine ( line , knownFilePaths . filePaths )
4950
5051 if ( ! parsedLine ) {
5152 formatted . push ( line )
@@ -76,13 +77,34 @@ export function formatCodeSearchOutput(
7677 return formatted . join ( '\n' )
7778}
7879
79- function parseRipgrepLine ( line : string ) : {
80+ function parseRipgrepLine (
81+ line : string ,
82+ knownFilePaths : string [ ] = [ ] ,
83+ ) : {
8084 filePath : string
8185 lineNumber : string
8286 content : string
8387 isContext : boolean
8488} | null {
85- // Try match line pattern: filename:digits:content
89+ const matchLine = parseRipgrepMatchLine ( line )
90+ if ( matchLine ) {
91+ return matchLine
92+ }
93+
94+ const contextLine = parseRipgrepContextLine ( line , knownFilePaths )
95+ if ( contextLine ) {
96+ return contextLine
97+ }
98+
99+ return null
100+ }
101+
102+ function parseRipgrepMatchLine ( line : string ) : {
103+ filePath : string
104+ lineNumber : string
105+ content : string
106+ isContext : false
107+ } | null {
86108 const matchLineMatch = line . match ( / ( .* ?) : ( \d + ) : ( .* ) $ / )
87109 if ( matchLineMatch ) {
88110 return {
@@ -93,23 +115,61 @@ function parseRipgrepLine(line: string): {
93115 }
94116 }
95117
96- // Try context line pattern: filename-digits-content
97- const contextLineMatch = line . match ( / ( .* ?) - ( \d + ) - ( .* ) $ / )
98- if ( contextLineMatch ) {
118+ return null
119+ }
120+
121+ function parseRipgrepContextLine (
122+ line : string ,
123+ knownFilePaths : string [ ] ,
124+ ) : {
125+ filePath : string
126+ lineNumber : string
127+ content : string
128+ isContext : true
129+ } | null {
130+ for ( const filePath of knownFilePaths ) {
131+ if ( ! line . startsWith ( filePath + '-' ) ) {
132+ continue
133+ }
134+ const rest = line . slice ( filePath . length + 1 )
135+ const lineNumberMatch = rest . match ( / ^ ( \d + ) - ( .* ) $ / )
136+ if ( ! lineNumberMatch ) {
137+ continue
138+ }
99139 return {
100- filePath : contextLineMatch [ 1 ] ,
101- lineNumber : contextLineMatch [ 2 ] ,
102- content : contextLineMatch [ 3 ] ,
140+ filePath,
141+ lineNumber : lineNumberMatch [ 1 ] ,
142+ content : lineNumberMatch [ 2 ] ,
103143 isContext : true ,
104144 }
105145 }
106146
107- return null
147+ const contextLineMatch = line . match ( / ( .* ) - ( \d + ) - ( .* ) $ / )
148+ return contextLineMatch
149+ ? {
150+ filePath : contextLineMatch [ 1 ] ,
151+ lineNumber : contextLineMatch [ 2 ] ,
152+ content : contextLineMatch [ 3 ] ,
153+ isContext : true ,
154+ }
155+ : null
108156}
109157
110- function countFormattedMatches ( lines : string [ ] ) : number {
111- return lines . filter ( ( line ) => {
112- const parsedLine = parseRipgrepLine ( line )
113- return parsedLine && ! parsedLine . isContext
114- } ) . length
158+ function collectMatchFilePaths ( lines : string [ ] ) : {
159+ filePaths : string [ ]
160+ matchCount : number
161+ } {
162+ const filePaths = new Set < string > ( )
163+ let matchCount = 0
164+ for ( const line of lines ) {
165+ const parsedLine = parseRipgrepMatchLine ( line )
166+ if ( parsedLine ) {
167+ filePaths . add ( parsedLine . filePath )
168+ matchCount += 1
169+ }
170+ }
171+ return {
172+ filePaths : [ ...filePaths ] . sort ( ( a , b ) => b . length - a . length ) ,
173+ matchCount,
174+ }
115175}
0 commit comments