24

Is there a way to rebind :q in vim to a more complex command to prevent accidentally exiting vim?

11
  • 11
    :q isn't complex enough? I never hit that accidentally myself... Commented Sep 23, 2012 at 21:11
  • 6
    But the point is still well made. If you're accidentally hitting a three key combination, you're gonna have a hell of a time in vim, in which most things are done with one letter combination (two, if you're counting <esc>) Commented Sep 23, 2012 at 21:45
  • 5
    I've hit many things trying to type :q, but never the reverse. Commented Sep 23, 2012 at 22:13
  • 7
    For me, it is that I have a 20+ year habit in vi/vim - edit file, :q do something at command line. So, :q is reflexive. I want to break that habit. When I've opened 15 buffers, :q is painful to recover from. Commented Nov 1, 2015 at 17:28
  • 4
    I have a habit of typing in the extra q when I just want to save with :w, so it ends up :wq. This is from years of using vim as a cmd only config file editor instead of a full blown editor. Commented Sep 19, 2017 at 13:06

7 Answers 7

15

What you want is :close. It acts like :q but won't let you close the last window:

http://vimdoc.sourceforge.net/htmldoc/windows.html#:close

You can set an alias for the q command to map to close:

cabbrev q <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'close' : 'q')<CR>

Thanks @Paradoxial for this :cabbrev trick.

Sign up to request clarification or add additional context in comments.

2 Comments

Added this, then closed vimrc with a quick :wq. Whoops.
There seems to be a bug in nvim 0.6 whereby it closes unsaved buffers on :q. I found this question because I have a 20-year habit of autonomously hitting :w while I work. After losing my left pinkie during a night of blow and loose women, the little stump now often hits q instead of w. Tragic corner-case...but funny.
13

I know, I know, it is a very old question, but I had the same question today and I found this post first. I developed a short script to put in .vimrc

function! ConfirmQuit(writeFile)
    if (a:writeFile)
        if (expand('%:t')=="")
            echo "Can't save a file with no name."
            return
        endif
        :write
    endif

    if (winnr('$')==1 && tabpagenr('$')==1)
        if (confirm("Do you really want to quit?", "&Yes\n&No", 2)==1)
            :quit
        endif
    else
        :quit
    endif
endfu

cnoremap <silent> q<CR>  :call ConfirmQuit(0)<CR>
cnoremap <silent> x<CR>  :call ConfirmQuit(1)<CR>

I hope this helps someone.

3 Comments

Could you please explain why not to use :cabbrev or :alias? What is the advantage of :cnoremap in this case?
@raacer I think that is the same
@raacer @vialrogo :cabbrev would require a <Space> press to trigger, which imo defeats the purpose
6

You can use something like this to remove the :q command:

:cabbrev q <c-r>=(getcmdtype()==':' && getcmdpos()==1 ? 'echo' : 'q')<CR>

This abbreviates q to echo in command mode, but doesn't allow the abbreviation to trigger if the q isn't in the first column. This way, edit q won't abbreviate to edit echo.

1 Comment

Wonderful solution! Forces me to write ":quit" in that particular vim I intend to keep around for months. For short lived vim sessions (like those for git commit messages) in another shell, ":q" still works as intended.
5

What are you afraid of? Vim won't let you quit (without a ! command modifier, anyway) when you still have unsaved changes, so the only thing you'll potentially lose is the window position, size, and maybe taskbar position of GVIM.

Anyway, to override built-in commands like :q, you can use the cmdalias plugin, like this:

:Alias q if\ winnr('$')>1||tabpagenr('$')>1||confirm('Really\ quit?',\ "&OK\\n&Cancel")==1|quit|endif

This checks for the last window (:q does not necessarily exit Vim), and inserts a confirmation.

3 Comments

The problem is that q is awfully close to !.
@Qix: But you usually need Shift to get the !; neither :q1 nor :Q! to any harm. If you're afflicted by fat-fingering, you won't have much fun in Vim, anyway.
I was being partially facetious. This was the first instance I've ever fat fingered q! in the few years I've been using Vim, lol.
3

ConfirmQuit.vim : Provides a confirm dialog when you try to quit vim

http://www.vim.org/scripts/script.php?script_id=1072

I adapted this by using

autocmd bufenter c:/intranet/notes.txt cnoremap <silent> wq<cr> call ConfirmQuit(1)<cr>

As I only wanted this on this for a particular file

1 Comment

Thank you! However, anyone using plain vim that uses ConfirmQuit.vim will want to remove the "if has("gui_running")"
0

Using the coot/cmdalias_vim plugin, I effectively disabled the short, impulsive quit commands :q, :q!, and :wq. Hopefully this will slow me down and make me think about whether I really want to use :quit or, say, :bdelete. Here's a condensed version of the "autocmd section" of my .vimrc file:

if has("autocmd")
    augroup VIMRC_aliases
        au!
        au VimEnter * CmdAlias wqu\%[it] write|quit
        au VimEnter * CmdAlias q         echo\ "Use\ :qu[it]\ instead\ of\ :q"
        au VimEnter * CmdAlias q!        echo\ "Use\ :qu[it]!\ instead\ of\ :q!"
        au VimEnter * CmdAlias wq        echo\ "Use\ :wqu[it]\ instead\ of\ :wq"
    augroup END
endif

Comments

0

My problem was that I find it difficult to hit the w key with my pinky finger, and I often missed, typing q or wq instead. At the same time, I also actively use commands that I occasionally type by mistake. This requires working on finger placement, but currently, I was losing all my open buffers, which was painful because I had to reopen all the files scattered across directories.

I simply want Vim to prompt for confirmation when I type q or wq. All the solutions mentioned here either didn't work as I needed by disabling these commands, or they worked poorly by not functioning correctly when background buffers were present or when the typed text was not the target command, but simply contained the letters of the target command. So I combined them into my own solution that does exactly what I need.

Here is my solution:

" Prompt for confirmation before exit."
function! ConfirmQuit()
    " Verify the entire command line."
    let l:quit = index(['q', 'wq'], getcmdline()) >= 0
    " Check that the current window is neither a help nor a command-line window."
    let l:my_window =  (&buftype != 'help' && &buftype != 'nofile')
    if l:quit && l:my_window  &&
    \ confirm("Do you really want to quit?", "&Yes\n&No", 2) == 2
        return "\<C-U>"  " Clear the command line."
    endif
    return ''  " Leave the command line unchanged."
endfunction
" Remap the newline character."
cnoremap <expr> <CR> ConfirmQuit() . '<CR>'

" Enable confirmation prompts for unsaved changes before quitting."
set confirm
  • cnoremap - Maps a key sequence (map) in the command mode (c) and avoids recursion (nore).
  • <expr> - Indicates that the second argument should be an expression returning a key sequence rather than plain text.
  • . '<CR>' - Appends the newline character to execute the resulting command, which will either be the original command or an empty command.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.