Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ let g:claude_code_map_zoom = '<C-w>z'
| Normal | `<Leader>cV` | Toggle with `--verbose` |
| Terminal | `<C-\>` | Hide Claude Code terminal |
| Terminal | `<C-w>z` | **Zoom Toggle**: Maximize or restore terminal |
| Terminal | `<C-v>` | **Paste**: Paste system clipboard content |
| Terminal | `<C-h/j/k/l>` | Navigate to adjacent window |

### Extended keymaps (`g:claude_code_map_extended_prefix` + key)
Expand Down Expand Up @@ -307,6 +308,7 @@ let g:claude_code_float_border = 'double'
| `g:claude_code_map_extended_keys` | `1` | Register `<Leader>c*` keymaps |
| `g:claude_code_map_toggle` | `'<C-\>'` | Toggle key |
| `g:claude_code_map_zoom` | `'<C-w>z'` | Zoom key |
| `g:claude_code_map_paste` | `'<C-v>'` | Paste key |
| `g:claude_code_map_continue` | `'<Leader>cC'` | Continue key |
| `g:claude_code_map_verbose` | `'<Leader>cV'` | Verbose key |
| `g:claude_code_map_extended_prefix` | `'<Leader>c'` | Prefix for all extended keymaps |
Expand All @@ -319,6 +321,7 @@ let g:claude_code_float_border = 'double'
| `g:claude_code_model` | `''` | Claude model override |
| `g:claude_code_debug` | `0` | Enable debug logging to message area |
| `g:claude_code_diff_preview` | `0` | Auto-start diff preview polling on Vim startup |
| `g:claude_code_bracketed_paste` | `1` | Enable bracketed paste mode support |
| `g:claude_code_terminal_start_delay` | `300` | Delay (ms) before attaching to Claude terminal |

Buffer-local `b:claude_code_*` overrides take precedence over `g:` variables.
Expand Down
2 changes: 2 additions & 0 deletions autoload/claude_code/config.vim
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ let s:defaults = {
\ 'map_continue': '<Leader>cC',
\ 'map_verbose': '<Leader>cV',
\ 'map_zoom': '<C-w>z',
\ 'map_paste': '<C-v>',
\ 'bracketed_paste': 1,
\ 'debug': 0,
\ 'terminal_start_delay': 300,
\ 'scroll_keys': 1,
Expand Down
10 changes: 4 additions & 6 deletions autoload/claude_code/git.vim
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,16 @@ function! claude_code#git#root() abort
return s:git_root_cache[l:cwd]
endif

let s:output_redirect = ' 2>/dev/null'
if has("win32")
let s:output_redirect = ' 2>nul'
endif
let l:null = has('win32') ? 'nul' : '/dev/null'
let l:redirect = ' 2>' . l:null

let l:inside = system('git -C ' . shellescape(l:cwd) . ' rev-parse --is-inside-work-tree' . s:output_redirect)
let l:inside = system('git -C ' . shellescape(l:cwd) . ' rev-parse --is-inside-work-tree' . l:redirect)
if v:shell_error || trim(l:inside) !=# 'true'
let s:git_root_cache[l:cwd] = ''
return ''
endif

let l:root = trim(system('git -C ' . shellescape(l:cwd) . ' rev-parse --show-toplevel' . s:output_redirect))
let l:root = trim(system('git -C ' . shellescape(l:cwd) . ' rev-parse --show-toplevel' . l:redirect))
if v:shell_error
let s:git_root_cache[l:cwd] = ''
return ''
Expand Down
13 changes: 13 additions & 0 deletions autoload/claude_code/keymaps.vim
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ function! claude_code#keymaps#setup_terminal(bufnr) abort
execute 'tnoremap <buffer> <silent> <C-l> <C-\><C-n><C-w>l'
execute 'tnoremap <buffer> <silent> ' . claude_code#config#get('map_zoom') . ' <C-\><C-n>:Claude zoom<CR>'

" Paste from system clipboard
let l:paste_key = claude_code#config#get('map_paste')
if !empty(l:paste_key)
execute 'tnoremap <buffer> <silent> ' . l:paste_key . ' <C-\><C-n>:call claude_code#terminal#paste()<CR>'
endif

" Bracketed paste support
if claude_code#config#get('bracketed_paste')
" This allows Vim to handle the escape sequence sent by terminal emulators
" during a paste. We bridge it to our mapping-free paste function.
execute 'tnoremap <buffer> <silent> <Esc>[200~ <C-\><C-n>:call claude_code#terminal#paste()<CR>'
endif

" Mouse/touchpad scroll in terminal mode: escape to Normal, scroll, stay in
" Normal so the user can keep reading. Vim passes raw ScrollWheel events
" through to the running program when in terminal mode, so we must intercept
Expand Down
3 changes: 2 additions & 1 deletion autoload/claude_code/meta_commands.vim
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ function! claude_code#meta_commands#version() abort
\ ]

if executable('claude')
let l:cli_ver = trim(system('claude --version 2>/dev/null'))
let l:null = has('win32') ? 'nul' : '/dev/null'
let l:cli_ver = trim(system('claude --version 2>' . l:null))
if v:shell_error || empty(l:cli_ver)
let l:cli_ver = '(could not determine)'
endif
Expand Down
26 changes: 23 additions & 3 deletions autoload/claude_code/terminal.vim
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,38 @@ function! s:instance_cwd(instance_id) abort
return ''
endif
" Normalise both sides to forward slashes for a reliable comparison.
let l:inst = substitute(a:instance_id, '\\', '/', 'g')
let l:cwd = substitute(getcwd(), '\\', '/', 'g')
let l:inst = tr(a:instance_id, '\', '/')
let l:cwd = tr(getcwd(), '\', '/')
if l:inst ==# l:cwd
return ''
endif
" Return an OS-native path so term_start's cwd option works on all platforms.
if has('win32')
return substitute(a:instance_id, '/', '\\', 'g')
return tr(a:instance_id, '/', '\')
endif
return a:instance_id
endfunction

" Paste from system clipboard into the terminal buffer.
" Bypasses terminal mappings using term_sendkeys().
function! claude_code#terminal#paste() abort
let l:bnr = bufnr('%')
if getbufvar(l:bnr, '&buftype') !=# 'terminal'
return
endif

" Use + register (system clipboard) if available, fallback to * or default.
let l:reg = has('clipboard') ? '+' : '"'
let l:text = getreg(l:reg)
if empty(l:text) && l:reg == '+'
let l:text = getreg('*')
endif

if !empty(l:text)
call term_sendkeys(l:bnr, l:text)
endif
endfunction

" Create a brand-new Claude Code terminal.
function! s:create_new(instance_id) abort
call claude_code#util#debug('terminal: creating new instance for ' . a:instance_id)
Expand Down
11 changes: 11 additions & 0 deletions doc/claude_code.txt
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ Default terminal keymaps (when |g:claude_code_map_keys| is 1):
Terminal mode (inside the Claude window): ~
<C-\> Hide Claude Code terminal
<C-w>z Zoom Toggle: Maximize or restore terminal
<C-v> Paste: Paste system clipboard content
<C-h/j/k/l> Navigate to adjacent window

Extended keymaps (when g:claude_code_map_extended_keys is 1):
Expand Down Expand Up @@ -423,6 +424,11 @@ g:claude_code_map_toggle Default: '<C-\>'
*g:claude_code_map_zoom*
g:claude_code_map_zoom Default: '<C-w>z'
Key to toggle the zoomed (maximized) state.

*g:claude_code_map_paste*
g:claude_code_map_paste Default: '<C-v>'
Key to paste text from the system clipboard into the terminal.
Bypasses terminal mappings using |term_sendkeys()|.

*g:claude_code_map_continue*
g:claude_code_map_continue Default: '<Leader>cC'
Expand Down Expand Up @@ -477,6 +483,11 @@ g:claude_code_diff_preview Default: 0
register the hooks. >
let g:claude_code_diff_preview = 1
<
*g:claude_code_bracketed_paste*
g:claude_code_bracketed_paste Default: 1
Enable bracketed paste mode support. When enabled, terminal emulator
pastes (e.g. Ctrl-Shift-V) are captured and sent via |term_sendkeys()|
to avoid triggering Vim mappings.

*g:claude_code_terminal_start_delay*
g:claude_code_terminal_start_delay Default: 300
Expand Down
Loading