Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NoMatchParen might cause E201: *ReadPre autocommands must not change current buffer #345

Open
GoogleCodeExporter opened this issue Aug 21, 2015 · 1 comment

Comments

@GoogleCodeExporter
Copy link

When using "NoMatchParen" (from the matchparen plugin in the runtime) via
a *ReadPre autocommand this might cause a E201, because it uses "windo"
 and then the "(curbuf != old_curbuf)" check in Vim's readfile function fails.

What steps will reproduce the problem?
1. vim -u NONE -N -p file1 file2
2. runtime plugin/matchparen.vim
3. au BufReadPre * NoMatchParen
4. !echo foo >> file2
5. Vim will ask to reload the file, pressing "l" will cause the error:

E201: *ReadPre autocommands must not change current buffer
E321: Could not reload "file2"

The following patch fixes it.  Given how necessary such an Windo function
usually is, which restores the previous window, I think it would be useful to
have it provided by Vim itself somehow.  The same applies to "bufdo".

    diff --git i/runtime/plugin/matchparen.vim w/runtime/plugin/matchparen.vim
    index 3804ab9..396ff32 100644
    --- i/runtime/plugin/matchparen.vim
    +++ w/runtime/plugin/matchparen.vim
    @@ -181,9 +181,16 @@ function! s:Highlight_Matching_Pair()
     endfunction

     " Define commands that will disable and enable the plugin.
    -command! NoMatchParen windo silent! call matchdelete(3) | unlet! g:loaded_matchparen |
    +function! s:Windo(command)
    +    let curaltwin = winnr('#') ? winnr('#') : 1
    +    let currwin = winnr()
    +    execute 'windo ' . a:command
    +    execute curaltwin . 'wincmd w'
    +    execute currwin . 'wincmd w'
    +endfunction
    +command! NoMatchParen call s:Windo('silent! call matchdelete(3)') | unlet! g:loaded_matchparen |
              \ au! matchparen
    -command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved
    +command! DoMatchParen runtime plugin/matchparen.vim | call s:Windo('doau CursorMoved')


The following patch fixes it in LargeFile itself:

    diff --git i/plugin/LargeFile.vim w/plugin/LargeFile.vim
    index 41a90d3..8b21c0c 100644
    --- i/plugin/LargeFile.vim
    +++ w/plugin/LargeFile.vim
    @@ -73,7 +73,7 @@ fun! s:LargeFile(force,fname)
          au BufLeave       <buffer>        call s:LargeFileLeave()
            endif
            au WinEnter             *                       call s:LargeFileWinEnter()
    -    au BufUnload       <buffer>        augroup LargeFileAU|au! <buffer>|augroup END
    +    au BufUnload       <buffer>        augroup LargeFileAU|exec 'au! * <buffer>'|augroup END
        augroup END
        let b:LargeFile_mode = 1
     "   call Decho("turning  b:LargeFile_mode to ".b:LargeFile_mode)
    @@ -105,7 +105,14 @@ fun! s:ParenMatchOff()
        redir END
        if matchparen_enabled =~ 'g:loaded_matchparen'
            let b:LF_nmpkeep= 1
    +    " Disable matchparen. (Re)store current window numbers, it uses "windo",
    +    " and this might cause 'E201: *ReadPre autocommands must not change
    +    " current buffer'.
    +    let curaltwin = winnr('#') ? winnr('#') : 1
    +    let currwin = winnr()
            NoMatchParen
    +    execute curaltwin . 'wincmd w'
    +    execute currwin . 'wincmd w'
        endif
     "  call Dret("s:ParenMatchOff")
     endfun

Original issue reported on code.google.com by dhahler@gmail.com on 20 Mar 2015 at 6:52

@GoogleCodeExporter
Copy link
Author

I fully agree that such :windo extension as provided by your s:Windo() function 
is necessary for most plugin uses. My ArgsAndMore plugin 
(http://www.vim.org/scripts/script.php?script_id=4152) provides such extended 
:Windo command (and :Bufdo, :Argdo, :Tabdo, etc.) also for interactive use.

Besides saving and restoring the original and previous windows, the window 
layout may also be affected by :windo; namely, windows with a height / width of 
0 (frequently used in "Rolodex mode") will increase to size 1 by entering. This 
can be undone by wrapping the :windo with this:

    let l:originalWindowLayout = winrestcmd()
    windo ...
    silent! execute l:originalWindowLayout

Full implementation:

    +function! s:Windo(command)
    +    let l:originalWindowLayout = winrestcmd()
    +    let curaltwin = winnr('#') ? winnr('#') : 1
    +    let currwin = winnr()
    +    execute 'windo ' . a:command
    +    execute curaltwin . 'wincmd w'
    +    execute currwin . 'wincmd w'
    +    silent! execute l:originalWindowLayout
    +endfunction

Original comment by sw...@ingo-karkat.de on 20 Mar 2015 at 7:12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant