7

Extremely related to this except the answer there doesn't work

I get the following error when entering command-line editing mode q: or Ctrl-F (when already in command mode)

Error detected while processing CursorHold Auto commands for "*":
E11: Invalid in command-line window; <CR> executes, CTRL-C quits:  checktime | endif

The relevant section of my .vimrc is

"automatically reload file when changes detected
set autoread "this doesn't work on it's own!

"https://unix.stackexchange.com/questions/149209/refresh-changed-content-of-file-opened-in-vim/383044#383044
"on these events, any filename... and not in command mode then check files for changes
autocmd FocusGained,BufEnter,CursorHold,CursorHoldI * if mode() != 'c' | checktime | endif

" Notification after file change
autocmd FileChangedShellPost *
  \ echohl WarningMsg | echo "File changed on disk. Buffer reloaded." | echohl None

So my question is how do I detect that I'm in the command-line window and stop that command from running there?

After a bit of reading :h command-line I tried replacing the condition with

if mode() != 'c' && getcmdwintype() == ''

but I'm still seeing the same issue.

4
  • 1
    I can't reproduce your issue. Could you try to put only the relevant section of your vimrc in a separate file (e.g. ~/test.vimrc), start vim with vim -u ~/test.vimrc and confirm that you still get the error. If you don't get the error maybe the problem comes from another autocmd.
    – statox
    Nov 23, 2017 at 12:23
  • @statox I'm running vim 8 VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Oct 20 2017 11:15:05) Included patches: 1-1207 Modified by [email protected] Compiled by [email protected] it seems a little surprising that the other answer clearly worked for someone else but isn't for me - could be a version thing maybe
    – JonnyRaa
    Nov 23, 2017 at 13:23
  • I don't think this is a version problem. Are you sure you're not using another autocmd with the CursorHold event which would cause a problem?
    – statox
    Nov 23, 2017 at 14:20
  • 2
    @statox I've resolved now, see my answer. it turns out that Ale has something in there aswell, I don't think it's relevant though
    – JonnyRaa
    Nov 23, 2017 at 14:43

4 Answers 4

7

Based on Luc's help I ended up going with this:

autocmd FocusGained,BufEnter,CursorHold,CursorHoldI * if !bufexists("[Command Line]") | checktime | endif

The reason this works is that the Command Line window is fairly modal so you can't have one accidentally open in the background - you will only get that buffer if you are actively editing in the command-line-window

The only caveat here is that if you save a buffer with that name, which I did accidentally at some point when messing around with this stuff - in which case the Command line window complains when it gets opened and instead gets named "[Scratch]" or something.

It's also worth noting that you should probably have something like this at the very top of your .vimrc as autocmds are just added to a list and if you are developing them you can end up with your old ones kicking around.

"clear out previous autocmds to stop them being duplicated when resourcing
"this file
autocmd!

I also learned you can list all autocmds by doing :autocmd and list for a specific event like:

:autocmd CursorHold
--- Auto-Commands ---
ALECursorGroup  CursorHold
    *         call ale#cursor#EchoCursorWarningWithDelay()
CursorHold
    *         if !bufexists("[Command Line]") | checktime | endif
Press ENTER or type command to continue
6
  • 3
    Regarding au!, indeed this is a good practice, but don't forget to put your autocommands in a group in order to clear only the auto-commands from this precise group. Nov 23, 2017 at 15:20
  • I second @LucHermitte. Without specifically defining a group (in the command or via :augroup), your autocmd! will delete all the autocommands in the default group, which, depending on your config, could be a lot!
    – Rich
    Nov 23, 2017 at 16:13
  • @Rich is that to cover the case that there is more than one vimrc (eg a system one) introducing autocmds?
    – JonnyRaa
    Nov 23, 2017 at 17:10
  • 1
    Nope. I tried it in my config and it deleted quite a few hat had been added by plugins.
    – Rich
    Nov 23, 2017 at 23:09
  • 1
    The main issue doesn't occur on first run, but if you source your vimrc in an existing Vim instance (so the way you load your plugins doesn't affect things). If you want to see which autocommands it would delete, you can run the following commands in a fresh instance of Vim: 1. :redir > before.txt 2. :autocmd 3: :redir > after.txt 4. :autocmd! 5. :autocmd 6. redir END. And then quit Vim and run vimdiff before.txt after.txt
    – Rich
    Nov 24, 2017 at 15:19
3

bufname('%') returns "[Command Line]" in my case. I don't know if there is another information elsewhere.

You could also listen for CmdwinEnter and CmdwinLeave events and maintain an internal state that'll tell you in which mode you are.

EDIT: Here is what I would do. Note, this is completely untested. This may not work.

" ==== file: autoload/cmdlinewindow.vim
" Initialize to 0, keep the current state if the script is reloaded
let s:is_opened = get(s:, 'is_opened', 0)

function! cmdlinewindow#_enter() abort
    call lh#assert#false(s:is_opened)
    let s:is_opened = 1
endfunction

function! cmdlinewindow#_leave() abort
    call lh#assert#true(s:is_opened)
    let s:is_opened = 0
endfunction

function! cmdlinewindow#is_opened()
    return s:is_opened
endfunction

" ==== file: plugin/cmdlinewindow.vim
aug WatchCmdLineWindow
    au!
    au CmdwinEnter * call cmdlinewindow#_enter()
    au CmdwinLeave * call cmdlinewindow#_leave()
aug END

Then, from elsewhere, you'd just have to check cmdlinewindow#is_opened() result.

NB: lh#assert#...() comes from my vim script library. They are not needed, yet they state in which state I expect to be when calling these functions.

4
  • Nice one with bufname, I get the same result, however if I add that to the autocmd like && bufname('%') != "[Command Line]" I still see the same error after saving and resourcing my .vimrc
    – JonnyRaa
    Nov 23, 2017 at 13:28
  • In that case, it's possible you're not using the right buf-expression. Try with bufname('<abuf>') instead. I can never remember which autocommands require us to use <abuf> instead of %. Nov 23, 2017 at 13:33
  • If this still doesn't work, you can listen for the Enter/Leave events Nov 23, 2017 at 13:35
  • I couldn't get either of those working, with the events probably because of my limited understanding of vim's variables... ended up going with !bufexists("[Command Line]"). Thanks for your help
    – JonnyRaa
    Nov 23, 2017 at 14:28
2

I am having the same issue as you. There are some discussions here and here. It seems that we can use getcmdwintype() to check if we are in command line window. Here is my working setting:

augroup auto_read
    autocmd!
    autocmd FocusGained,BufEnter,CursorHold,CursorHoldI *
                \ if mode() == 'n' && getcmdwintype() == '' | checktime | endif
augroup END
1

For posterity: Turns out, additionally to the mentioned approaches (which would qualify as hacks in my book) you can simply use getcmdwintype(). Credits to user micbou from the Youcompleteme maintainers. Docs:

getcmdwintype()
        Return the current |command-line-window| type. Possible return
        values are the same as |getcmdtype()|. Returns an empty string
        when not in the command-line window.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.