Severity: high · Category: bug
Location: plugin/keymaps.vim — line 8 (nnoremap <leader>x :xall<CR>) interacting with QuitPre autocmd at lines 36-39
What's wrong
The terminal-cleanup logic (s:CloseTerminalsOnExit) is hooked exclusively to the QuitPre autocommand. :xall (the command bound to <leader>x) does NOT fire QuitPre, so the cleanup never executes and the running terminal job blocks the quit. A user who edits a file, opens a terminal with <leader>t, then presses <leader>x to save-and-quit gets E948: Job still running and Vim stays open with the change half-applied. By contrast <leader>q (:confirm qall) and :q DO fire QuitPre and work correctly. This also directly contradicts the design intent stated in the surrounding comment and in CLAUDE.md, which claims terminals auto-close "when Vim exits."
Evidence
Tested with vim 9.0 against the actual file. :xall does not trigger QuitPre:
autocmd QuitPre * let g:qp+=1 ... xall -> result quitpre_fired=0 while Vim still exited (exit=0).
Full repro using the real s:OpenTerminal flow (edit a file, below new + term_start sleep, modify buffer, run :xall): result xall_error=Vim(xall):E948: Job still running, Vim left open with 2 windows.
The cleanup is only registered for QuitPre:
augroup ivim_terminal_cleanup
autocmd QuitPre * call s:CloseTerminalsOnExit()
augroup END
There is no VimLeavePre / ExitPre / other handler covering :xall (or :wqall).
Suggested fix
Either (a) add :call s:CloseTerminals() into the <leader>x mapping path, e.g. nnoremap <leader>x :xall<CR> -> a small function that wipes terminals then runs :xall; or (b) make the cleanup fire on a broader event. Simplest robust fix: change the mapping to call a wrapper, e.g.
function! s:SaveQuitAll() abort
call s:CloseTerminals()
xall
endfunction
nnoremap x :call SaveQuitAll()
Note QuitPre still handles the plain :q/<leader>q cases, so keep that too. (Consider the same wrapper if :wqall is ever added.)
Related documentation
CLAUDE.md — line 170 (Terminal section)
The doc states terminals auto-close "when Vim exits — QuitPre autocommand gated on the last non-terminal window ... and :qall never trips E947." While :qall/:confirm qall are correctly handled, <leader>x (:xall) bypasses QuitPre entirely and fails with E948 (see the keymaps.vim finding). The blanket "when Vim exits" claim is inaccurate for the save-and-quit-all path.
Fix: After fixing the keymaps.vim bug, update this line to reflect that <leader>x/:xall cleans terminals via an explicit wrapper (not via QuitPre), or generalize the statement once the fix covers all quit-all variants.
Filed from an automated multi-agent source review (2026-05-29); finding adversarially verified at high confidence. Line numbers reflect the audit-fixes-2026-05 working tree.
Severity: high · Category: bug
Location:
plugin/keymaps.vim— line 8 (nnoremap <leader>x :xall<CR>) interacting with QuitPre autocmd at lines 36-39What's wrong
The terminal-cleanup logic (s:CloseTerminalsOnExit) is hooked exclusively to the
QuitPreautocommand.:xall(the command bound to<leader>x) does NOT fireQuitPre, so the cleanup never executes and the running terminal job blocks the quit. A user who edits a file, opens a terminal with<leader>t, then presses<leader>xto save-and-quit getsE948: Job still runningand Vim stays open with the change half-applied. By contrast<leader>q(:confirm qall) and:qDO fire QuitPre and work correctly. This also directly contradicts the design intent stated in the surrounding comment and in CLAUDE.md, which claims terminals auto-close "when Vim exits."Evidence
Tested with vim 9.0 against the actual file.
:xalldoes not trigger QuitPre:autocmd QuitPre * let g:qp+=1 ...
xall-> resultquitpre_fired=0while Vim still exited (exit=0).Full repro using the real s:OpenTerminal flow (edit a file,
below new+ term_start sleep, modify buffer, run:xall): resultxall_error=Vim(xall):E948: Job still running, Vim left open with 2 windows.The cleanup is only registered for QuitPre:
augroup ivim_terminal_cleanup
autocmd QuitPre * call s:CloseTerminalsOnExit()
augroup END
There is no VimLeavePre / ExitPre / other handler covering :xall (or :wqall).
Suggested fix
Either (a) add
:call s:CloseTerminals()into the<leader>xmapping path, e.g.nnoremap <leader>x :xall<CR>-> a small function that wipes terminals then runs:xall; or (b) make the cleanup fire on a broader event. Simplest robust fix: change the mapping to call a wrapper, e.g.function! s:SaveQuitAll() abort
call s:CloseTerminals()
xall
endfunction
nnoremap x :call SaveQuitAll()
Note QuitPre still handles the plain
:q/<leader>qcases, so keep that too. (Consider the same wrapper if:wqallis ever added.)Related documentation
CLAUDE.md— line 170 (Terminal section)The doc states terminals auto-close "when Vim exits — QuitPre autocommand gated on the last non-terminal window ... and
:qallnever tripsE947." While:qall/:confirm qallare correctly handled,<leader>x(:xall) bypasses QuitPre entirely and fails with E948 (see the keymaps.vim finding). The blanket "when Vim exits" claim is inaccurate for the save-and-quit-all path.Fix: After fixing the keymaps.vim bug, update this line to reflect that
<leader>x/:xallcleans terminals via an explicit wrapper (not via QuitPre), or generalize the statement once the fix covers all quit-all variants.Filed from an automated multi-agent source review (2026-05-29); finding adversarially verified at high confidence. Line numbers reflect the
audit-fixes-2026-05working tree.