@@ -181,6 +181,9 @@ export async function regexSearchFiles(
181181 return formatResults ( filteredResults , cwd )
182182}
183183
184+ const MAX_RIPGREP_MB = 0.25
185+ const MAX_BYTE_SIZE = MAX_RIPGREP_MB * 1024 * 1024 // 0./25MB in bytes
186+
184187function formatResults ( results : SearchResult [ ] , cwd : string ) : string {
185188 const groupedResults : { [ key : string ] : SearchResult [ ] } = { }
186189
@@ -200,21 +203,102 @@ function formatResults(results: SearchResult[], cwd: string): string {
200203 groupedResults [ relativeFilePath ] . push ( result )
201204 } )
202205
206+ // Track byte size
207+ let byteSize = Buffer . byteLength ( output , "utf8" )
208+ let wasLimitReached = false
209+
203210 for ( const [ filePath , fileResults ] of Object . entries ( groupedResults ) ) {
204- output += `${ filePath . toPosix ( ) } \n│----\n`
211+ // Check if adding this file's path would exceed the byte limit
212+ const filePathString = `${ filePath . toPosix ( ) } \n│----\n`
213+ const filePathBytes = Buffer . byteLength ( filePathString , "utf8" )
214+
215+ if ( byteSize + filePathBytes >= MAX_BYTE_SIZE ) {
216+ wasLimitReached = true
217+ break
218+ }
205219
206- fileResults . forEach ( ( result , index ) => {
220+ output += filePathString
221+ byteSize += filePathBytes
222+
223+ for ( let resultIndex = 0 ; resultIndex < fileResults . length ; resultIndex ++ ) {
224+ const result = fileResults [ resultIndex ]
207225 const allLines = [ ...result . beforeContext , result . match , ...result . afterContext ]
208- allLines . forEach ( ( line ) => {
209- output += `│${ line ?. trimEnd ( ) ?? "" } \n`
226+
227+ // Calculate bytes in all lines for this result
228+ let resultBytes = 0
229+ const resultLines : string [ ] = [ ]
230+
231+ for ( const line of allLines ) {
232+ const trimmedLine = line ?. trimEnd ( ) ?? ""
233+ const lineString = `│${ trimmedLine } \n`
234+ const lineBytes = Buffer . byteLength ( lineString , "utf8" )
235+
236+ // Check if adding this line would exceed the byte limit
237+ if ( byteSize + resultBytes + lineBytes >= MAX_BYTE_SIZE ) {
238+ wasLimitReached = true
239+ break
240+ }
241+
242+ resultLines . push ( lineString )
243+ resultBytes += lineBytes
244+ }
245+
246+ // If we hit the limit in the middle of processing lines, break out of the result loop
247+ if ( wasLimitReached ) {
248+ break
249+ }
250+
251+ // Add all lines for this result to the output
252+ resultLines . forEach ( ( line ) => {
253+ output += line
210254 } )
255+ byteSize += resultBytes
256+
257+ // Add separator between results if needed
258+ if ( resultIndex < fileResults . length - 1 ) {
259+ const separatorString = "│----\n"
260+ const separatorBytes = Buffer . byteLength ( separatorString , "utf8" )
211261
212- if ( index < fileResults . length - 1 ) {
213- output += "│----\n"
262+ if ( byteSize + separatorBytes >= MAX_BYTE_SIZE ) {
263+ wasLimitReached = true
264+ break
265+ }
266+
267+ output += separatorString
268+ byteSize += separatorBytes
214269 }
215- } )
216270
217- output += "│----\n\n"
271+ // Check if we've hit the byte limit
272+ if ( byteSize >= MAX_BYTE_SIZE ) {
273+ wasLimitReached = true
274+ break
275+ }
276+ }
277+
278+ // If we hit the limit, break out of the file loop
279+ if ( wasLimitReached ) {
280+ break
281+ }
282+
283+ const closingString = "│----\n\n"
284+ const closingBytes = Buffer . byteLength ( closingString , "utf8" )
285+
286+ if ( byteSize + closingBytes >= MAX_BYTE_SIZE ) {
287+ wasLimitReached = true
288+ break
289+ }
290+
291+ output += closingString
292+ byteSize += closingBytes
293+ }
294+
295+ // Add a message if we hit the byte limit
296+ if ( wasLimitReached ) {
297+ const truncationMessage = `\n[Results truncated due to exceeding the ${ MAX_RIPGREP_MB } MB size limit. Please use a more specific search pattern.]`
298+ // Only add the message if it fits within the limit
299+ if ( byteSize + Buffer . byteLength ( truncationMessage , "utf8" ) < MAX_BYTE_SIZE ) {
300+ output += truncationMessage
301+ }
218302 }
219303
220304 return output . trim ( )
0 commit comments