From b0b19f30b946fa75ea696663b1f85cb4dba61b13 Mon Sep 17 00:00:00 2001 From: rlavkvmflzk <48257409+rlavkvmflzk@users.noreply.github.com> Date: Sat, 11 Apr 2026 05:24:51 +0900 Subject: [PATCH] fix(grep): handle Windows drive-letter paths and CRLF in parseOutput The grep tool's content and count output modes always returned 'No matches found' on Windows due to two issues: 1. Regex ^(.+?):(\d+):(.*)$ fails on Windows paths like C:\path\file.ts:42:content because lazy .+? matches only 'C', then \d+ fails on '\path\...' 2. ripgrep outputs CRLF line endings on Windows. After split('\n'), trailing \r breaks the $ anchor in the regex, causing every line to fail matching. Fix: update parseOutput and parseCountOutput regexes to handle drive-letter prefixes ([A-Za-z]:[\/]), and strip trailing \r from each line before matching. Note: PR #2976 attempted to fix (1) with --path-separator=/ but this flag gets expanded by MSYS2/Git Bash to a full path, causing a separate rg error. This PR avoids --path-separator entirely. Closes #2962 --- src/tools/grep/cli.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tools/grep/cli.ts b/src/tools/grep/cli.ts index 1a6cd89d0..bcec98aaa 100644 --- a/src/tools/grep/cli.ts +++ b/src/tools/grep/cli.ts @@ -102,7 +102,8 @@ function parseOutput(output: string, filesOnly = false): GrepMatch[] { const matches: GrepMatch[] = [] const lines = output.split("\n") - for (const line of lines) { + for (let line of lines) { + line = line.replace(/\r$/, "") if (!line.trim()) continue if (filesOnly) { @@ -115,7 +116,8 @@ function parseOutput(output: string, filesOnly = false): GrepMatch[] { continue } - const match = line.match(/^(.+?):(\d+):(.*)$/) + // Handle Windows drive-letter paths (e.g. C:\path\file.ts:42:content) + const match = line.match(/^([A-Za-z]:[\\\/].*?|.+?):(\d+):(.*)$/) if (match) { matches.push({ file: match[1], @@ -134,10 +136,11 @@ function parseCountOutput(output: string): CountResult[] { const results: CountResult[] = [] const lines = output.split("\n") - for (const line of lines) { + for (let line of lines) { + line = line.replace(/\r$/, "") if (!line.trim()) continue - const match = line.match(/^(.+?):(\d+)$/) + const match = line.match(/^([A-Za-z]:[\\\/].*?|.+?):(\d+)$/) if (match) { results.push({ file: match[1],