터미널에서 긴 프롬프트는 힘들다

Claude Code 쓰다 보면 몇 줄 넘는 프롬프트를 치고 싶을 때가 종종 있다. 들여쓰기가 있거나, 코드를 붙이거나, 한글 IME 상태에서 복잡한 편집이 필요한 순간이다. 터미널의 한 줄 편집기는 이런 상황에 약하다.

이럴 때 Claude Code 프롬프트를 외부 에디터로 열어서 쓸 수 있다. 방법 자체는 간단한데, 운용하다 보면 사소한 함정이 하나 있어 같이 정리한다.


기본 방법 — $EDITOR + Ctrl+X Ctrl+E

Claude Code는 프롬프트 입력 중 Ctrl+X 뒤이어 Ctrl+E 를 누르면 $EDITOR 환경변수에 지정된 에디터를 띄운다. 내부적으로는 claude-prompt-<uuid>.md 같은 임시 파일을 만들고 그걸 에디터에 넘긴다. 편집 후 저장하고 닫으면 그 내용이 그대로 프롬프트에 입력된다.

가장 단순한 세팅:

# ~/.zshrc
export EDITOR='nvim'

이러면 Ctrl+X Ctrl+E로 nvim이 뜨고, :wq로 닫으면 내용이 Claude Code 프롬프트로 들어온다. 끝.

참고로 최근 Claude Code 버전은 Ctrl+G도 같은 동작으로 바인딩돼 있다. 둘 다 테스트해보고 손에 맞는 걸 쓰면 된다.


전역 EDITOR는 nvim, Claude만 Cursor로

그런데 EDITOR 환경변수는 git, crontab, less 등 여러 곳에서 참조한다. 나는 이걸 nvim으로 둔 상태가 편해서 바꾸고 싶지 않다. Claude Code 프롬프트만 GUI 에디터(Cursor, VSCode)로 띄우고 싶을 때는 함수로 감싸서 EDITOR를 이 프로세스 범위에서만 오버라이드 하면 된다.

~/.zshrc 에 들어 있는 건 이거다.

cc() {
  # VSCode 쓸 때
  # EDITOR="code -w" command claude "$@"

  # Cursor 쓸 때
  EDITOR="/Applications/Cursor.app/Contents/Resources/app/bin/cursor -w" command claude "$@"
}

핵심 두 가지.

  • command claude — alias나 동명 함수가 걸려 있어도 실제 claude 바이너리를 실행하도록 우회
  • -w 플래그 — Cursor/VSCode는 기본적으로 연 뒤 바로 셸로 제어를 반환한다. -w(또는 --wait)를 붙여야 에디터 창이 닫힐 때까지 대기. 없으면 Claude Code가 빈 파일을 바로 읽어간다

이제 터미널에서 cc만 치면 Claude Code가 뜨고, 프롬프트 편집 시 Cursor로 열린다. 다른 툴들은 EDITOR=nvim을 그대로 본다.


실제 동작

1. 프롬프트에서 Ctrl+X Ctrl+E

Claude Code 프롬프트에서 Ctrl+X Ctrl+E 입력

2. Cursor에 임시 파일이 열린다

Cursor에 claude-prompt 임시 파일이 열린 모습

파일명은 claude-prompt-<uuid>.md 형식. 마크다운이라 코드 블록이나 리스트도 편하게 쓸 수 있다.

3. 저장하고 닫으면 프롬프트로 들어온다

여기서 한 가지 이상한 게 생겼다.

![복귀 후 프롬프트에 ^[[O^[I 이상 문자가 끼어든 상태

프롬프트 앞부분의 기존 텍스트와 Cursor에서 쓴 내용 사이에 ^[[O^[[I^[[O^[[I^[[O 가 박혀 있다. 정체가 뭘까.


^[[O, ^[[I의 정체 — Focus Reporting

터미널에는 포커스 리포팅(Focus Reporting) 이라는 기능이 있다. ANSI/xterm 스펙의 DEC Private Mode 1004. 이게 켜져 있으면 터미널 창의 포커스가 들어오고 나갈 때 아래 두 이스케이프 시퀀스가 터미널에 주입된다.

이벤트시퀀스
포커스 들어옴 (focus-in)ESC [ I (표기상 ^[[I)
포커스 나감 (focus-out)ESC [ O (표기상 ^[[O)

이걸 왜 쓰느냐면, vim/tmux 같은 TUI 앱이 유휴 상태일 때 렌더링을 멈추거나 커서 스타일을 바꾸기 위해 필요하다. 터미널이 보내주는 이 이벤트로 현재 창이 활성인지 아닌지를 알 수 있다.

문제는 이 지점이다.

  1. Claude Code가 Cursor를 띄운다. 이 순간 터미널 포커스가 내 터미널 → Cursor 윈도우로 이동한다. 터미널이 ^[[O (focus-out)을 내보낸다
  2. Cursor에서 저장/종료하면 포커스가 다시 터미널로 돌아온다. ^[[I (focus-in)이 내보내진다
  3. 창 전환을 두세 번 하다 보면 여러 번의 in/out이 생긴다
  4. 이 이스케이프 시퀀스들은 stdin 버퍼에 쌓인다. Claude Code가 에디터 종료 후 다시 입력 읽기를 시작할 때, 앞서 쌓인 것들을 프롬프트 텍스트로 흡수한다

정리하면 Cursor/VSCode 같은 별도 윈도우 GUI 에디터를 띄울 때만 이 현상이 생긴다. 터미널에서 포커스가 실제로 왔다갔다 하기 때문이다.


해결 — TUI 에디터를 쓰거나

1순위: nvim / vim / helix / micro

같은 터미널 세션 안에서 도는 TUI 에디터는 포커스가 창 단위로 움직이지 않는다. 창은 하나, 안에서 그냥 화면이 바뀔 뿐이다. focus-in/out 이벤트 자체가 생기지 않는다.

export EDITOR='nvim'

내 경험상 이게 제일 안정적이다. nvim이 충분히 좋은 마크다운 편집기이기도 하고.

2순위: 그래도 Cursor/VSCode를 쓰고 싶다면

몇 가지 부분 해결책이 있지만 완벽한 건 없다.

  • 복귀 후 섞인 ^[[ 시퀀스를 backspace로 수동 제거한 뒤 Enter
  • 터미널 앱 설정에서 focus reporting 비활성화 (Ghostty, iTerm2 등에 옵션 있음). 단 vim/tmux 쪽 기능도 같이 잃는다
  • Cursor/VSCode를 쓰되 cc 함수 내에서 임시로 focus reporting을 꺼주는 랩퍼를 끼우기 — 번거롭다

깔끔한 길은 첫 번째다. 긴 프롬프트 편집에 IDE급 기능이 꼭 필요한 게 아니라면 TUI 에디터 쪽이 낫다.


요약

  • Claude Code 프롬프트는 Ctrl+X Ctrl+E (또는 Ctrl+G)로 $EDITOR 호출
  • 전역 EDITOR를 건드리지 않고 싶다면 cc() 함수 패턴으로 Claude 한정 오버라이드. -w 플래그를 꼭 붙일 것
  • Cursor/VSCode를 쓰면 포커스 리포팅 시퀀스가 프롬프트에 섞이는 부작용이 있다.
  • 제일 안정적인 조합은 TUI 에디터(nvim 등) + EDITOR=nvim

참고 링크