claude-code-shift-enter
ai/claude-code-shift-enter · Updated · Tags: ai
正在用 AI 翻譯成中文,可能需要一分鐘… 以下暫時顯示英文原文。
Shift+Enter in Claude Code — setup, and where /terminal-setup matters
Verified against Claude Code 2.1.220 on macOS (Darwin 24.6.0), 2026-07-28.
Colour key: CC extension panel CC CLI in a standalone terminal CC CLI in an editor's integrated terminal
TL;DR
- Claude Code extension panel (VS Code / Cursor / desktop app): no setup. Shift+Enter inserts a newline out of the box, because the input is a real UI textbox, not a terminal.
- Claude Code CLI in any terminal: setup required. Terminals send the same byte for Enter and Shift+Enter, so the key must be remapped. Run
/terminal-setuponce inside a Claude Code session running in that terminal. - Cursor's integrated terminal counts as a terminal — it needs the same
keybindings.jsonentry as VS Code's. Cursor and VS Code keep separate keybinding files, so setting one up does not set up the other. - On this machine, both VS Code and Cursor already have the binding installed (verified). iTerm2 could not be verified from a sandboxed shell.
- Universal fallbacks that never need setup:
\then Enter, or Ctrl+J.
Comparison: the three ways you run Claude Code
| CC extension panel (VS Code / Cursor / desktop app) | CC CLI in a standalone terminal (iTerm2, Ghostty, Terminal.app…) | CC CLI in Cursor / VS Code integrated terminal | |
|---|---|---|---|
| Input surface | Native UI textbox | TTY | TTY (VS Code's xterm.js) |
| Shift+Enter works by default? | Yes | No | No |
| Setup needed | None | /terminal-setup | /terminal-setup |
| What setup changes | — | The terminal app's own key-mapping config (iTerm2 plist, Ghostty/Alacritty/Kitty/WezTerm/Zed config file) | keybindings.json of that editor |
| Where the config lands | — | e.g. iTerm2 prefs, ~/.config/ghostty/config | ~/Library/Application Support/{Code,Cursor}/User/keybindings.json |
| Shared between VS Code and Cursor? | n/a | n/a | No — separate files, set up each one |
| Terminal.app special case | — | Shift+Enter is not bindable; /terminal-setup enables Option+Enter instead | — |
| Survives an SSH / remote session? | n/a | Binding lives on the local machine, so yes — but you must run /terminal-setup locally, not over SSH | Same |
The extension can be configured to run Claude in a terminal instead of the native panel (claudeCode.useTerminal). If you turn that on, you are in the third column, not the first.
Do I need setup?
Answer the one question: is my prompt box a terminal?
- Typing into the Claude panel in VS Code / Cursor / the desktop app → no setup.
- Typing into a shell where you ran
claude→ setup, regardless of which app hosts that shell.
Where to run /terminal-setup
Run it from a Claude Code session inside the terminal you actually type in, on your local machine.
claude
> /terminal-setup
- In Cursor's integrated terminal → run it there; it edits Cursor's
keybindings.json. - In VS Code's integrated terminal → run it there; it edits VS Code's
keybindings.json. - In iTerm2 / Ghostty / Kitty / WezTerm / Alacritty / Zed → run it in that app; it edits that app's config.
- Over SSH or in a container → the keybinding belongs to the terminal emulator on your laptop, so run
/terminal-setupin a local session of the same app. Running it on the remote box does nothing useful. - After it runs, restart or reload the terminal app (iTerm2 in particular) before the key takes effect.
Terminals /terminal-setup knows how to configure
vscode, cursor, windsurf, zed, iterm2, ghostty, kitty, wezterm, alacritty — plus Terminal.app via the Option+Enter path.
Anything else (Warp, Hyper, Konsole, …): bind Shift+Enter manually to send ESC + CR, or use the fallbacks below.
What it actually installs (editor terminals)
/terminal-setup appends this to your editor's keybindings.json:
{
"key": "shift+enter",
"command": "workbench.action.terminal.sendSequence",
"args": { "text": "\u001b\r" },
"when": "terminalFocus"
}
\u001b\r is ESC followed by carriage return — the "meta+Enter" sequence Claude Code reads as newline, don't submit. The when: terminalFocus clause keeps Shift+Enter unchanged everywhere else in the editor.
If a Shift+Enter terminal binding already exists with different args, Claude Code leaves it alone and tells you so rather than overwriting it.
Current state on this machine (verified)
| Location | Status | Evidence |
|---|---|---|
| VS Code integrated terminal | Configured | ~/Library/Application Support/Code/User/keybindings.json — shift+enter → sendSequence \u001b\r, when: terminalFocus |
| Cursor integrated terminal | Configured | ~/Library/Application Support/Cursor/User/keybindings.json — same binding |
| Claude extension panel | N/A — works natively | No config needed |
iTerm2 (installed at /Applications/iTerm.app) | Unverified | iTerm2 preferences are not readable from a sandboxed shell. Run /terminal-setup inside iTerm2 to be sure — it is a no-op if already configured. |
Fallbacks that always work (no setup)
| Keys | Notes |
|---|---|
\ then Enter | Backslash at end of line, then Enter. Works in every terminal. |
| Ctrl+J | Sends a raw linefeed. Works in every terminal. |
| Option+Enter | Works once "Option as Meta" is enabled — the path /terminal-setup uses for Terminal.app. |
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Shift+Enter submits the message | Running the CLI in a terminal without the binding | Run /terminal-setup in that terminal |
| Works in VS Code, not in Cursor (or vice versa) | Separate keybindings.json per editor | Run /terminal-setup in the other one too |
Ran /terminal-setup, still nothing | Terminal not reloaded, or an existing conflicting binding was left in place | Restart the app; check keybindings.json / the terminal's key map for a competing shift+enter entry |
| Ran it over SSH, no effect | Binding must live on the local terminal emulator | Re-run in a local session of the same terminal app |
| Terminal.app: Shift+Enter never works | Terminal.app cannot bind Shift+Enter | Use Option+Enter (after /terminal-setup), or \+Enter / Ctrl+J |
Disclaimer: These documents are personal notes. The information may be incomplete, out of date or wrong, so check it before you rely on it.