|
1 | 1 | import { getSystemProcessEnv } from '../env' |
| 2 | +import { isUtf8 } from 'buffer' |
2 | 3 | import { spawn } from 'child_process' |
3 | 4 | import * as fs from 'fs' |
4 | 5 | import * as path from 'path' |
@@ -236,10 +237,14 @@ export function codeSearch({ |
236 | 237 | let jsonRemainder = '' |
237 | 238 | const stdoutDecoder = new StringDecoder('utf8') |
238 | 239 | // -l overrides --json; adapt each NUL-delimited path to the match pipeline. |
239 | | - const parseOutputRecord = (record: string) => |
240 | | - filenamesOnly |
241 | | - ? { type: 'match', data: { path: { text: record } } } |
242 | | - : JSON.parse(record) |
| 240 | + const parseOutputRecord = (record: string) => { |
| 241 | + if (!filenamesOnly) return JSON.parse(record) |
| 242 | + const bytes = Buffer.from(record, 'latin1') |
| 243 | + const filePath = isUtf8(bytes) |
| 244 | + ? { text: bytes.toString('utf8') } |
| 245 | + : { bytes: bytes.toString('base64') } |
| 246 | + return { type: 'match', data: { path: filePath } } |
| 247 | + } |
243 | 248 | let stderrBuf = '' |
244 | 249 | // Track matches by file for grouping and limiting |
245 | 250 | const fileGroups = new Map<string, string[]>() |
@@ -342,8 +347,12 @@ export function codeSearch({ |
342 | 347 | // Parse ripgrep output for early stopping. |
343 | 348 | childProcess.stdout.on('data', (chunk: Buffer | string) => { |
344 | 349 | if (isResolved) return |
345 | | - const chunkStr = |
346 | | - typeof chunk === 'string' ? chunk : stdoutDecoder.write(chunk) |
| 350 | + // Preserve filename bytes until a complete NUL-delimited record is available. |
| 351 | + const chunkStr = filenamesOnly |
| 352 | + ? (typeof chunk === 'string' ? Buffer.from(chunk) : chunk).toString('latin1') |
| 353 | + : typeof chunk === 'string' |
| 354 | + ? chunk |
| 355 | + : stdoutDecoder.write(chunk) |
347 | 356 | jsonRemainder += chunkStr |
348 | 357 |
|
349 | 358 | // The last JSON line or filename may be split across chunks. |
|
0 commit comments