claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

[BUG] Vi edit mode ESC timeout too long, requires double-ESC or delay to enter normal mode

Open chrismerck opened this issue 1 month ago • 0 comments

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?

tl;dr: please implement John Hawthorn's suggestion and reduce ttimeoutlen to 10ms -- https://www.johnhawthorn.com/2012/09/vi-escape-delays/


When using vi edit mode, pressing ESC to exit insert mode requires either pressing ESC twice or waiting ~500ms before pressing the next key. We suspect this is due to the escape sequence timeout being too long for comfortable vim-style editing.

I note that I use vi line editing in bash on iTerm2 and I do not have this issue. Perhaps the terminal configuration from bash (and ofc from vi editor) tightens this escape sequence timeout?

To repro, enter vi INSERT mode in claude code, then press ESC and note that it takes ~500 ms for -- INSERT -- to disappear.

What Should Happen?

Single ESC immediately exits insert mode; subsequent b moves cursor back one word (vim normal mode behavior).

Error Messages/Logs


Steps to Reproduce

Try pressing ESC and then in ~100ms press b. Note that ESC-b is interpreted as Alt+b (emacs backward-word). Cursor moves back one word, but remains in insert mode. Pressing b again inserts the character "b", rather than again going back as expected. It remains in insert mode.

Claude Model

None

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

2.1.1

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Related Issues

  • #7391 (ESC key multi-purpose conflicts)
  • #10926 (Vi edit mode ESC handling conflicts)

FWIW, here's Claude Code's analysis of how to fix this in React Ink:

Node.js readline has an escapeCodeTimeout option: "The duration readline will wait for a character when reading an ambiguous key sequence... Default: 500 milliseconds"

This is the culprit. Ink uses readline under the hood, inheriting the 500ms default.

The Fix

When creating the readline interface (or equivalent stdin handler), pass a shorter timeout:

  import * as readline from 'readline';

  const rl = readline.createInterface({
    input: process.stdin,
    escapeCodeTimeout: 10  // 10ms instead of 500ms
  });

  readline.emitKeypressEvents(process.stdin, rl);

chrismerck avatar Jan 07 '26 23:01 chrismerck