[BUG] M-d / Alt+D (delete-word-forward) consumes trailing whitespace, diverging from expected behavior for readline / MacOS / Emacs

Resolved 💬 1 comment Opened May 14, 2026 by mkosma Closed Jun 12, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

In the chat input, M-d or M-DEL (or any terminal binding that sends ESC d, e.g. iTerm2's default cmd+D mapping) deletes the next word PLUS the whitespace following it.

What Should Happen?

GNU readline and Emacs kill-word both stop at the end of the word and leave trailing whitespace intact. The current Claude Code behavior matches vi's dw, not the readline/Emacs convention that the rest of the input bindings follow.

Verified against:

  • GNU readline (bash prompt): preserves the trailing space.
  • Emacs kill-word (M-d): preserves the trailing space.
  • zsh ZLE kill-word: preserves the trailing space.

Documentation indicates use of GNU-readline semantics (see shortcut table at https://code.claude.com/docs/en/interactive-mode). In addition, issues such as #49317 (closed) apply fixes to conform to GNU readline standards.

(Current behavior resembles vi dw - suggesting that someone could conceivably prefer the current behavior.)

Error Messages/Logs

n/a

Steps to Reproduce

  1. In the Claude Code prompt, type: fooBar baz
  2. Move cursor to the 'B' in fooBar
  3. Press M-d (or cmd+D in iTerm2 with the default "Send Escape Sequence: d" mapping).

Expected: foo baz — single space preserved between foo and baz.
Actual: foobaz — no space.

Claude Model

None

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.140

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Root cause

Claude Code's input layer uses Node.js readline. The Node implementation of readlof _deleteWordRight in lib/internal/readline/interface.js uses this regex:

const match = trailing.match(/^(?:\s+|\W+|\w+)\s*/);

The trailing \s* greedily consumes whitespace after the killed token. Confirmed by extracting strings from the bundled CC binary (2.1.140):

[kDeleteWordRight]() {
  if (this.cursor < this.line.length) {
    this[kBeforeEdit](this.line, this.cursor
    var trailing = StringPrototypeSlice.call(this.line, this.cursor),
        match = RegExpPrototypeExec.call(/^(;
    this.line = StringPrototypeSlice.call(this.line, 0, this.cursor) +
                StringPrototypeSlice.call(tr
    this[kRefreshLine]();
  }
}

This appears to be a long-standing Node divergence from GNU readline — unlikely to be fixed upstream because it would break
compatibility for everyone relying on the cu to live in Claude Code.

Proposed fix

Override _deleteWordRight (or the equivalent with the trailing \s* removed:

const match = trailing.match(/^(?:\s+|\W+|\w

Optional enhancement: expose this as a confit.wordDeleteStyle: "emacs" | "vi", default"emacs") so vi-style users can opt back in. Could also be exposed as a bindable chat:deleteWordForward action in keybindings.json, matching the pattern requeeToLineStart.

Impact

Hits any user re-editing text mid-sentence in a Claude chat input.

Related

  • #27561 — Modern text input (broader rework
  • #51694 — Request to expose chat:deleteToLineStart as a bindable action; same shape of fix
  • #49317 — Prior precedent of fixing readlin bindings

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗