Skip to content

repl: strip trailing CR when loading history (Windows CRLF) - #30293

Closed
samuelpatro wants to merge 3 commits into
oven-sh:mainfrom
samuelpatro:claude/fix-windows-issues-4X3tQ
Closed

repl: strip trailing CR when loading history (Windows CRLF)#30293
samuelpatro wants to merge 3 commits into
oven-sh:mainfrom
samuelpatro:claude/fix-windows-issues-4X3tQ

Conversation

@samuelpatro

Copy link
Copy Markdown

History files written with CRLF line endings (e.g. on Windows, or after editing in an editor that converts EOLs) carried the trailing '\r' into each entry. The CR then leaked into recall, .history output, and was re-saved verbatim, compounding the corruption on every session.

Mirror the pattern used in ini.zig: strip '\r' before treating the line as an entry.

I could not run bun bd test in this environment (missing clang-21), but verified with the system bun that the new test fails before the fix and the change is a one-line copy of the established pattern.

What does this PR do?

Fixes a CRLF handling bug in the Bun REPL's history loader.

History.load in src/repl.zig split the history file on '\n' only, so when the file used CRLF line endings (common on Windows, or after editing in a CRLF-defaulting editor), every loaded entry kept a trailing '\r'. The stray CR then leaked into:

arrow-key recall (the cursor jumped to column 0 after the recalled text),
.history output,
the next .save — which wrote the same CRs back, compounding the corruption on every subsequent session.
The fix mirrors the existing pattern in src/ini.zig:60: strip a trailing '\r' before treating the line as an entry.

How did you verify your code works?

Added a regression test in test/js/bun/repl/repl.test.ts ("strips CRLF when loading existing history") that:

Seeds a temp $HOME with a .bun_repl_history containing old_one\r\nold_two\r\n,
Spawns bun repl, evaluates one new line, then .exit (forcing load → modify → save),
Re-reads the saved history and asserts there are no \r bytes and all three entries are present.
Verified the test fails against an unpatched Bun (system bun reproduced old_one\r\nold_two\r\nnew_three\n in the saved file).

Could not run bun bd test to confirm the patched build passes — sandbox is missing clang-21. Please run locally before merging:

bun bd test test/js/bun/repl/repl.test.ts -t "strips CRLF"

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai

coderabbitai Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The REPL history loader now trims trailing \r characters from each history entry when loading the history file, enabling proper handling of Windows-style CRLF line endings. A test suite verifies that existing CRLF-terminated history files are normalized when loaded and saved.

Changes

CRLF Normalization in REPL History

Layer / File(s) Summary
Core Implementation
src/repl.zig
History.load() normalizes each line by trimming a trailing \r before checking length and appending to entries, enabling CRLF history files to load without carriage-return characters.
Test Coverage
test/js/bun/repl/repl.test.ts
New test suite spawns bun repl with a pre-seeded .bun_repl_history file containing CRLF line endings and asserts the saved history is normalized to \n-only line breaks.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: fixing CRLF handling in the REPL history loader by stripping trailing CR characters.
Description check ✅ Passed The description fully addresses both required template sections with detailed explanations of what the PR does and how it was verified.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/js/bun/repl/repl.test.ts`:
- Around line 936-944: Move the process exit assertion so it runs after the
saved-history assertions: keep the existing saved = await Bun.file(...).text()
and the three expect(saved)... checks first (ensuring no "\r" and presence of
"old_one\n", "old_two\n", "new_three\n"), then await proc.exited and assert
expect(exitCode).toBe(0); this changes only the order of checking the exitCode/
proc.exited usage (variable exitCode from proc.exited) so test failures show
saved-history diffs before the process exit assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8c381254-c9c8-4ddc-a262-ca5fc6cda754

📥 Commits

Reviewing files that changed from the base of the PR and between b009453 and 5dc0065.

📒 Files selected for processing (2)
  • src/repl.zig
  • test/js/bun/repl/repl.test.ts

Comment thread test/js/bun/repl/repl.test.ts
claude and others added 2 commits May 17, 2026 19:29
History files written with CRLF line endings (e.g. on Windows, or after
editing in an editor that converts EOLs) carried the trailing '\r' into
each entry. The CR then leaked into recall, .history output, and was
re-saved verbatim, compounding the corruption on every session.

Mirror the pattern used in ini.zig: strip '\r' before treating the line
as an entry.

I could not run `bun bd test` in this environment (missing clang-21),
but verified with the system bun that the new test fails before the fix
and the change is a one-line copy of the established pattern.
Port the prior Zig fix to the new Rust REPL. History files written with
CRLF line endings (Windows, or after editing in a CRLF editor) carried
the trailing '\r' into each entry, leaking into recall, .history output,
and the next save.
@samuelpatro
samuelpatro force-pushed the claude/fix-windows-issues-4X3tQ branch from 5dc0065 to aabc696 Compare May 17, 2026 17:31
@robobun

robobun commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Picked this up in #36510 on top of current main (the repl.zig file is gone now, so only the repl.rs hunk applies). The commit carries your Co-authored-by trailer. Thanks for the fix and the test.

robobun added a commit that referenced this pull request Aug 13, 2026
History.load split the history file on '\n' only, so a file written with
CRLF line endings (Windows, or after editing in a CRLF editor) kept a
trailing '\r' on every loaded entry. The stray CR then leaked into
arrow-key recall, .history output, and the next save, compounding on
every session.

Strip a trailing '\r' from each split line before storing the entry.

Adopts the fix from #30293 for the current Rust REPL (the repl.zig hunk
in that PR no longer applies).

Co-authored-by: Samuel <samuelpatro@users.noreply.github.com>
@robobun

robobun commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Closing this one in favor of #36510, which carries the same change for the current Rust REPL. This branch still patches src/runtime/cli/repl.zig, which no longer exists on main, so it cannot merge as-is. #36510 has just been rebased onto current main and its commit keeps your Co-authored-by trailer, so the credit stays with you. Thanks again for the fix and the test.

@robobun robobun closed this Aug 13, 2026
robobun added a commit that referenced this pull request Aug 13, 2026
The trailing-CR strip in History::load is the fix from #30293 (carried
by #36510 until this PR superseded it). Add that PR's case as its own
test: a history file of ordinary entries with CRLF line endings loads
without a '\r' on any entry and is written back with LF endings.

Co-authored-by: Samuel <samuelpatro@users.noreply.github.com>
@robobun

robobun commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

One more pointer, since #36510 has now been closed too: your CRLF fix is part of #38023 (which stores multi-line history entries on one line and needs the same trailing-CR strip when loading). Its commits keep your Co-authored-by trailer and the CRLF case from this PR is one of its tests, so that is the PR to follow now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants