Skip to content

Prefix read_file tool output with line numbers#56779

Merged
MartinYe1234 merged 13 commits into
mainfrom
AI-226/line-numbers-in-read-file
May 22, 2026
Merged

Prefix read_file tool output with line numbers#56779
MartinYe1234 merged 13 commits into
mainfrom
AI-226/line-numbers-in-read-file

Conversation

@MartinYe1234

@MartinYe1234 MartinYe1234 commented May 14, 2026

Copy link
Copy Markdown
Contributor

Format read_file tool output in cat -n style: each line is prefixed with its line number right-aligned in a 6-character field, followed by a single tab, followed by the line's original content (newlines preserved, including CRLF). Numbering reflects the actual file lines, so a ranged read starting at line 42 emits 42 for its first line, not 1.

For large files, content returned by get_buffer_content_or_outline is not prefixed:

  • The symbol outline path already conveys structure via its [L100-150] annotations.
  • The truncated first-1KB fallback (used when a file exceeds AUTO_OUTLINE_SIZE and has no parseable outline) is wrapped in a synthetic # First 1KB of … header, so its lines don't correspond to real file line numbers.

Both cases are reported via BufferContent::is_synthetic (renamed from is_outline).

Also updates the edit_file tool's input doc to describe the prefix format and tell the model to strip it before constructing old_text / new_text, preserving the original indentation that appears after the tab.

Updates how we render read_file tool call outputs in the UI (screenshots included in comments below).
Also fixes an existing bug where read_file tool call outputs would not re-render their content code block when an older thread was restored (the tool's replay hook was missing).

Closes AI-226

Release Notes:

  • Improved how read_file tool output renders in the agent panel, with a line-number gutter, and fixed it not re-rendering on restored threads

Format read_file tool output in cat -n style: each line is prefixed with its line number right-aligned in a 6-character field, followed by a tab, followed by the line's original content. The outline path for large files is left untouched. Documents the prefix format on the edit_file tool so the model knows to strip it before constructing old_text/new_text.
@MartinYe1234 MartinYe1234 self-assigned this May 14, 2026
@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label May 14, 2026
@zed-community-bot zed-community-bot Bot added the staff Pull requests authored by a current member of Zed staff label May 14, 2026
@MartinYe1234

Copy link
Copy Markdown
Contributor Author

Need to fix:
Tool output rendering
Run Evals to ensure no regressions

@MartinYe1234

Copy link
Copy Markdown
Contributor Author

Currently, we do not handle Read File Output properly for file outlines.
image

@MartinYe1234

MartinYe1234 commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

This PR also fixes the issue where the Read File tool output doesn't render properly when opening a tool call ui item on an older message thread:
Before:
image

Now:
image

Follow-up to the cat -n style line-number prefixing in read_file:

- Stop prefixing line numbers on synthetic content returned by get_buffer_content_or_outline. Previously the 1KB-fallback path (used when a file is larger than AUTO_OUTLINE_SIZE and has no parseable symbol outline) would emit a synthetic '# First 1KB of …' header and then have line numbers attached as if it were real file content, misleading the model about where each line actually lives. The fallback is now reported as is_synthetic: true, matching the symbol-outline case.

- Rename BufferContent::is_outline to is_synthetic to reflect its new meaning ('callers must skip real-file line numbers'), since the 1KB fallback is not actually an outline.

- Extract a shared resolve_line_range helper used by both the skill-file and buffer-backed paths, eliminating duplicated default-and-clamp arithmetic that had already drifted between the two.

- Warn (once) when format_with_line_numbers crosses u32::MAX lines, so the silent 'offset as u32' wraparound has a breadcrumb if it ever fires.

- Restore write!(output, …) over push_str(&format!(…)) inside the line-number loop to avoid a per-line allocation.
@MartinYe1234 MartinYe1234 requested a review from benbrandt May 19, 2026 17:24
MartinYe1234 and others added 7 commits May 19, 2026 10:25
Pairs with the read_file tool's cat -n style line-number prefixing: when the conversation view encounters a fenced code block whose lines are prefixed with a right-aligned line number and a tab, it parses the prefix out, renders the file content with its detected language's syntax highlighting, and shows the line numbers in a dedicated gutter rather than letting them appear inline as if they were part of the source.

- markdown: add Markdown::first_code_block_language so the renderer can pick syntax highlighting based on the fence language or path.

- conversation_view: thread the additional gpui (StyledText, TextRun) and language (Language, Rope) imports needed by the new renderer.

- thread_view: add a CatNumberedCodeBlock parser/renderer that detects the line-number prefix on each line of a single fenced code block and lays the content out with a gutter.
The ReadFileTool now prefixes its output with cat -n-style line numbers, but this remote-editing integration test was missed when the unit tests were updated.
@MartinYe1234 MartinYe1234 marked this pull request as ready for review May 19, 2026 18:27

@benbrandt benbrandt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know i said to feature flag it... but given that the models are all passing -n to every tool already, and evals looked good, I'm actually fine just rolling with it since it effects multiple parts of the system. We'll have time to test it out.

Thanks 💪🏻

Comment thread crates/agent/src/tools/read_file_tool.rs
Comment thread crates/agent/src/tools/read_file_tool.rs Outdated
@MartinYe1234 MartinYe1234 force-pushed the AI-226/line-numbers-in-read-file branch from fb8695b to 32fab86 Compare May 22, 2026 14:47
@MartinYe1234 MartinYe1234 added this pull request to the merge queue May 22, 2026
Merged via the queue into main with commit cfd0461 May 22, 2026
62 checks passed
@MartinYe1234 MartinYe1234 deleted the AI-226/line-numbers-in-read-file branch May 22, 2026 15:05
@dandv

dandv commented May 29, 2026

Copy link
Copy Markdown
Contributor

@MartinYe1234 related? #57230

@MartinYe1234

Copy link
Copy Markdown
Contributor Author

@dandv Not related as this only affects how we render output from the read file tool. #57230 seems to be an issue with the terminal tool not persisting output on restart.

TomPlanche pushed a commit to TomPlanche/zed that referenced this pull request Jun 2, 2026
Format `read_file` tool output in `cat -n` style: each line is prefixed
with its line number right-aligned in a 6-character field, followed by a
single tab, followed by the line's original content (newlines preserved,
including CRLF). Numbering reflects the actual file lines, so a ranged
read starting at line 42 emits `42` for its first line, not `1`.

For large files, content returned by `get_buffer_content_or_outline` is
**not** prefixed:

- The symbol outline path already conveys structure via its `[L100-150]`
annotations.
- The truncated first-1KB fallback (used when a file exceeds
`AUTO_OUTLINE_SIZE` and has no parseable outline) is wrapped in a
synthetic `# First 1KB of …` header, so its lines don't correspond to
real file line numbers.

Both cases are reported via `BufferContent::is_synthetic` (renamed from
`is_outline`).

Also updates the `edit_file` tool's input doc to describe the prefix
format and tell the model to strip it before constructing `old_text` /
`new_text`, preserving the original indentation that appears after the
tab.

Updates how we render `read_file` tool call outputs in the UI
(screenshots included in comments below).
Also fixes an existing bug where `read_file` tool call outputs would not
re-render their content code block when an older thread was restored
(the tool's `replay` hook was missing).

Closes AI-226

Release Notes:

- Improved how `read_file` tool output renders in the agent panel, with
a line-number gutter, and fixed it not re-rendering on restored threads

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement staff Pull requests authored by a current member of Zed staff

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants