feat(output): Add --show-file-offsets option to annotate directory tree with line ranges#1464
feat(output): Add --show-file-offsets option to annotate directory tree with line ranges#1464nuthalapativarun wants to merge 6 commits intoyamadashy:mainfrom
Conversation
Add a new `--show-file-offsets` CLI flag and `output.showFileOffsets` config option (default: false) that annotates each file entry in the directory structure section with its line range in the output file (e.g., [lines 42–78]). This enables AI agents and users to navigate directly to a specific file's content in the packed output without scanning the entire file. Implementation uses a two-pass render: first render discovers file block positions, then the tree is re-rendered with offset annotations. Since the tree section maintains the same line count between passes, offsets remain stable. Supports XML, Markdown, and plain text output styles. JSON output is structured and does not require tree annotations. Closes yamadashy#1367
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdded a new Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as CLI Engine
participant Config as Config/Output
participant Gen as Output Generator
participant Tree as Tree Generator
participant Offsets as Offset Computer
User->>CLI: Run with --show-file-offsets
CLI->>Config: Build config with showFileOffsets=true
Config-->>Gen: Pass config
Gen->>Gen: First Pass: Render output<br/>(tree without offsets)
Gen->>Offsets: computeFileLineOffsets(output)
Offsets-->>Gen: Record{filePath→{start,end}}
Gen->>Tree: generateTreeString...<br/>WithFileOffsets(offsets)
Tree->>Tree: Format each file entry<br/>with [lines X–Y]
Tree-->>Gen: Annotated tree string
Gen->>Gen: Second Pass:<br/>Re-render full output<br/>with annotated tree
Gen-->>User: Output with file offsets<br/>in directory structure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ent tree inputs Two correctness fixes for --show-file-offsets: 1. Restrict computeFileLineOffsets scanning to the actual files section of the output (after <files> for XML, after # Files for Markdown, after the Files long-separator block for plain). Previously the scanner could produce false offset entries if file content earlier in the output happened to contain marker strings matching our patterns (e.g., a file documenting XML format, or Markdown headings before the files section). 2. Store filePathsForTree, directoryPathsForTree, and filePathsByRootForTree on OutputGeneratorContext so the second-pass tree annotation uses the exact same file/directory sets that buildOutputGeneratorContext computed. Previously the second pass used allFilePaths / emptyDirPaths arguments directly, which could differ from the actual tree inputs when includeFullDirectoryStructure adds extra files to the tree. Adds tests asserting that markers outside the files section are not captured.
- Move --show-file-offsets to Repomix Output Options group (was under Token Count Options) - Use RepomixOutputStyle type instead of string for style parameter - Tighten XML file tag regex to use [^"]+ and allow optional whitespace - Use line.trim() for </file> and </files> tag matching - Trim extracted paths in Markdown and plain formats - Add comment documenting plain separator length constant Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sets.ts fileTreeGenerate.ts exceeded the 250-line limit after adding the three offset-annotation functions. Move treeToStringWithFileOffsets, generateTreeStringWithFileOffsets, and generateTreeStringWithRootsAndFileOffsets into a new src/core/file/fileTreeOffsets.ts. Export generateMultiRootSections and sortTreeNodes from fileTreeGenerate.ts to support the new module. Also add --show-file-offsets and output.showFileOffsets to README.md per CONTRIBUTING.md documentation requirements. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace output.split('\n') with an indexOf-based line iterator (iterLines)
so lines are processed one at a time without duplicating the entire output
string as an array of strings, reducing memory overhead for large repos.
Also release the first-pass output string immediately after offsets are
extracted so GC can reclaim it before the second render begins, avoiding
holding two full output strings in memory simultaneously.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown: record sectionEndLine when breaking on the next top-level heading so the last file's range doesn't bleed into subsequent sections (git diff, "End of Codebase" footer, etc.). Plain: detect the long separator (64 '=') after the first file entry and set sectionEndLine there, mirroring the XML </files> boundary logic. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| '================================================================================', | ||
| 'Directory Structure', | ||
| '================================================================================', | ||
| 'src/', | ||
| ' foo.ts', | ||
| '', | ||
| '================================================================================', | ||
| 'Files', | ||
| '================================================================================', |
There was a problem hiding this comment.
🟡 Plain-text test uses 80-char separator instead of 64-char, defeating section-isolation testing
The plain-text offset test constructs its mock output with 80-character long separators ('='.repeat(80)) at lines 76, 78, 82, and 84, but the production code uses 64-character separators (PLAIN_LONG_SEPARATOR = '='.repeat(64) at src/core/output/outputStyles/plainStyle.ts:1 and LONG_SEPARATOR = '='.repeat(64) at src/core/output/fileOffsets.ts:46,123). Because findFilesSectionStartLine compares prevLine === LONG_SEPARATOR (64 chars) against the test's 80-char string, the match fails and the function falls back to returning 1 (scan entire output). Similarly, the end-of-section detection (line === LONG_SEPARATOR) also never triggers, falling back to the last line. The test still passes because the file markers are found regardless, but it completely fails to validate the section-isolation logic that prevents false matches from file content containing marker strings.
| '================================================================================', | |
| 'Directory Structure', | |
| '================================================================================', | |
| 'src/', | |
| ' foo.ts', | |
| '', | |
| '================================================================================', | |
| 'Files', | |
| '================================================================================', | |
| '================================================================', | |
| 'Directory Structure', | |
| '================================================================', | |
| 'src/', | |
| ' foo.ts', | |
| '', | |
| '================================================================', | |
| 'Files', | |
| '================================================================', |
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Adds a
--show-file-offsetsCLI flag andoutput.showFileOffsetsconfig option that annotates each file entry in the directory structure section with its line range in the output file:This allows AI agents and users to jump directly to a specific file's content in the packed output without scanning the entire file, which is especially valuable for large repositories.
Closes #1367
Changes
output.showFileOffsets: booleanconfig option (default:false) to config schema--show-file-offsetsCLI flagsrc/core/output/fileOffsets.ts— scans rendered output for file block positions (supports XML, Markdown, and plain styles)generateTreeStringWithFileOffsets/generateTreeStringWithRootsAndFileOffsetstofileTreeGenerate.tsgenerateOutput(): first pass discovers file line positions, second pass renders with annotationsImplementation Notes
Two-pass rendering: The directory tree is built before the output content is rendered, so file line positions are not available at tree-build time. The solution:
Because the tree section has the same number of lines in both passes (annotations extend line content but add no new lines), all file block positions remain stable between passes.
JSON output: Not annotated since JSON is structured and does not use a directory tree section.
Test Plan
npm run lintpassesnpm run testpasses (1125 tests)computeFileLineOffsetsfor XML, Markdown, plain, and JSON stylesgenerateTreeStringWithFileOffsetswith and without multi-root