rtk-ai/rtk
View on GitHubBug: `rtk grep` misparses single-file rg output when content contains colons
Open
#1613 opened on Apr 29, 2026
bugeffort-smallfilter-qualitygood first issue
Description
Environment
- RTK: 0.37.2
- ripgrep: 15.1.0
- OS: Windows; rtk and rg are installed via scoop
Description
rtk grep searching a single file produces incorrect filenames and line numbers when matched lines contain colons. The parser mistakenly treats the line number as a filename and the content gets truncated.
Steps to Reproduce
# Create test file
cat > test.ts << 'EOF'
function readEnabledFromBranch(ctx: ExtensionContext, fallback: boolean): boolean {
return true;
}
function simpleNoColon() {
return 42;
}
EOF
# Run
rtk grep "function" test.ts
Actual Output
2 matches in 2F:
[file] 1 (1):
0: ExtensionContext, fallback: boolean): boolean {
[file] test.ts (1):
4: function simpleNoColon() {
- Line with colons: filename=
2(wrong — this is the line number), line_number=0(parse failure) - Line without colons: correct
Expected Output
2 matches in 1F:
[file] test.ts (2):
1: function readEnabledFromBranch(ctx: ExtensionContext, fallback: boolean): boolean {
4: function simpleNoColon() {
Reason
rg Output Format Difference
In grep_cmd.rs, rg is invoked:
rg_cmd.args(["-n", "--no-heading", &rg_pattern, path]);
ripgrep omits the filename prefix when searching a single file. RTK's parser assumes filename is always present.
# Multi-file: filename is ALWAYS included
src/a.ts:2:function foo() { }
src/b.ts:5:function bar() { }
│ │ │
▼ ▼ ▼
file linenum content
# Single-file: filename is OMITTED
2:function readEnabledFromBranch(ctx: ExtensionContext) { }
│ │ │
▼ ▼ ▼
linenum content (contains colons!)
When RTK parses the single-file output with splitn(3, ':'):
Input: 2:function readEnabledFromBranch(ctx: ExtensionContext) { }
↓ splitn(3, ':')
Part: ["2"] ["function readEnabledFromBranch(ctx"] [" ExtensionContext) { }"]
│ │ │
▼ ▼ ▼
treated as treated as treated as
filename linenum content
❌ ❌ (fails) ✓ (truncated)
let parts: Vec<&str> = line.splitn(3, ':').collect();
let (file, line_num, content) = if parts.len() == 3 {
let ln = parts[1].parse().unwrap_or(0);
(parts[0].to_string(), ln, parts[2]) // ← BUG: parts[0] is line number, not filename
} else if parts.len() == 2 {
let ln = parts[0].parse().unwrap_or(0);
(path.to_string(), ln, parts[1]) // ← Never reached: colons in content inflate count to 3
};
Suggested Fix
Add --with-filename to force rg to always include the filename prefix:
-H, --with-filename
This flag instructs ripgrep to print the file path for each matching
line. This is the default when more than one file is searched. If
--heading is enabled (the default when printing to a tty), the file
path will be shown above clusters of matches from each file; otherwise,
the file name will be shown as a prefix for each matched line.
rg_cmd.args(["-n", "--no-heading", "--with-filename", &rg_pattern, path]);
(BUT I'm not sure if it triggers other potential bug)
Or migrate rtk grep parsing to rg --json to avoid delimiter-based parsing bugs.