Preventing Vim preview window from moving main - vim

Is there an autocmd for when the preview window is opened/closed?
I want to scroll the main window n lines up when it the preview window is opened, then n lines down when it is closed, to counteract the "moving text" effect that occurs natively.
Am I able to do this with the relevant autocmd (and what is it), or is there a better way for me to achieve this?

There is no such autocmd event. But you can use WinEnter and BufDelete associated with previewwindow option to achieve something similar.
Using WinEnter you can check previewwindow; if you are on preview window, you can set a buffer variable to differ this event from subsequent events that can be generated by moving to another window and back to preview window. You can also set au BufDelete <buffer> call MyRestoreMainWindow() to call your function when preview window is closed.

I see this question asked often and always scratch my head wondering what is that window-shifting people talk about that I don't experience.
Well, today it occurred to me that two options that I've added to my ~/.vimrc a long time ago have the pleasant side effect of preventing that dreaded window-shifting:
set splitbelow
set splitright
Give it a try!

I was actually wondering the same thing except with the tab bar -- how to prevent that annoying shift from occuring when the tab bar is shown or hidden. Have you considered a wrapper function? The following seems to work for the ps example (it will still cause a shift if the preview window would obscure the cursor)
se splitbelow splitright
fun! PsWrapper(text)
let view=winsaveview()
exe 'ps' a:text
call winrestview(view)
endfun
While we're here ... the tab bar case seems to require some black magic. Ie, as someone pointed out, the tabbar will cause the text to scroll down if the cursor is above the middle line (??). But this seems to work - to always show a tab bar:
let [view,g:stal]=[winsaveview(),&stal]
let [view.topline,&stal]=[view.topline+!g:stal,2]
call winrestview(view)
and to restore the original tabbar setting
let [view.topline,&stal]=[view.topline-!g:stal,g:stal]
call winrestview(view)

You can't really do this with a simple autocmd - Using the WinEnter/WinLeave/BufEnter/BufLeave auto commands all have minor quirks (stated in the vim documentation) so they won't consistently solve your problem completely.
If this happens to you when opening splits, then you can solve this like #romainl suggested, by defining in your .vimrc :
set splitright
set splitbelow
BUT... This will still happen when opening various 'preview' windows, or using the quickfix or location list windows vim has to offer. I use them a lot, and this problem really annoyed me, so I wrote a plugin to solve this.
You can check it out here: https://github.com/gillyb/stable-windows
It works by maintaining state of the cursor position and top line number of the windows open in your vim layout, and restoring them each time you switch to a different buffer.
It's relatively new (as of writing this answer) so if you find any bugs feel free to open an issue, and I will try to address them quickly.
Hope this helps! :)

Related

Stop vim from dynamically updating folds

Is there any way to stop vim from automatically updating folds on the fly? I really love vim's folding, and I prefer having it in syntax mode so that folds are created as I type. But for instance when I code C++ and I write a bracket { it automatically closes all subsequent folds, and when I then close the bracket again with a }, vim automatically expands all subsequent folds, meaning that I have to refold everything.
Another related problem, if I have the same document open in a different buffer, say I have run ":split", then writing an open bracket { will nest all folds in the buffer under the fold in which I opened the bracket, and closing it will un-nest the folds but also close all of them. If I use either "." or "->" to access a member function/variable, it resets all folds in the buffer to be whatever the current foldlevel is, regardless of which folds I have opened/closed myself.
This is somewhat frustrating when I have the same document open in two buffers so I can read the contents of one function when writing another, as I constantly have to switch buffers and reopen my folds.
In my .vimrc I have
set foldmethod=syntax
and that is about it. For autocompletion I use clang-complete and supertab with:
let g:SuperTabDefaultCompletionType = "<c-x><c-u><c-p>"
I think that is everything which migh affect this.
Edit:
Added some pictures to help illustrate the problem
Both problems can be solved with the following two autocmds:
autocmd InsertLeave,WinEnter * setlocal foldmethod=syntax
autocmd InsertEnter,WinLeave * setlocal foldmethod=manual
This sets the buffer local 'foldmethod' to manual when insert mode is entered or its window (a buffer display) is left, and sets it to syntax when insert mode is left or its window is entered.
This works because setting 'foldmethod' to manual will keep the folds automatically created by syntax as if you set them yourself (manually), and manual folds are not updated based on the syntax of the file.
I've found two bugs with this solution:
When switching windows while in insert mode, the autocmd will set the 'foldmethod' to syntax for the new window, even though it's in insert mode and should be set to manual.
This isn't really a problem for me because I use Vim like a civilized person and operate in normal mode by default.
When
a new buffer is created (e.g. by reading a file)
and 'foldlevel' is 0
and a particular syntax is used (I'm able to duplicate the issue with a C file)
and the o or O command is used to enter insert mode for the first time in that buffer (doing i<esc>o does not duplicate the bug),
then all folds below the cursor will be opened.
I accidentally discovered this when testing the above solution, and now looking back I'm surprised I found it; it's almost not even worth mentioning. I don't intend on trying to write a test file that has the exact syntax necessary to duplicate the bug, so this may go unnoticed for another eon.
I actually discovered this question several months ago and used the solution Ben linked to for a while, before eventually being annoyed enough with the multiple window for one buffer issue (your second problem) to fix it.
So thanks to Ben for his solution, and you for asking this question!
I made a bit of a modification to user4830797's answer which helps deal with situations where the file you're editing doesn't use foldmethod=syntax (for example, a .vimrc file which might use foldmethod=marker):
autocmd InsertLeave,WinEnter * let &l:foldmethod=g:oldfoldmethod
autocmd InsertEnter,WinLeave * let g:oldfoldmethod=&l:foldmethod | setlocal foldmethod=manual
I think you need to check :h 'foldlevel. You should also perhaps use :mkview, probably in autocmd which restores manually open and closed folds.
Other then that you should perhaps set folding method differently on different file types (for instance on C you could set it to manual or marker)
If you temporarily set the foldmethod to manual, then Vim will keep all the folds currently defined by syntax, and keep them in the exact open/closed state you have them in now. This can be done automatically with an InsertEnter autocmd and restored on InsertLeave to protect your fold states in a single window. Unfortunately I have not yet spent time trying to get it working in split windows, but using window-local variables it is easy enough to even account for the user switching windows or something without leaving insert mode. See http://vim.wikia.com/wiki/Keep_folds_closed_while_inserting_text for details and discussion.

Make Syntastic close just the error window

I've got the (Mac)Vim Syntastic plugin installed via Janus. When I open the :Errors window to view the reason for syntax errors, it shrinks the file with the errors to one line and uses the rest of the real estate for the Errors window.
Is there a way to make it hog less room for errors and more importantly, how do I close just the Errors window? The usual :q closes both the Errors window AND the original file, even if the cursor is in the Errors window. (That's not 100% correct -- it gratefully does not close the file if the file hasn't yet been saved).
Syntastic uses the location list (a window-local variant of the quickfix list), so a :lclose will close it, but keep the other buffers.
As per syntastic's help pages, the initial height can be configured:
:let g:syntastic_loc_list_height=5
But I suspect that your intrusive Janus distribution has a hand in that. Vim "distributions" like spf-13 and Janus lure you with a quick install and out of the box settings, but you pay the price with increased complexity (you need to understand both Vim's runtime loading scheme and the arbitrary conventions of the distribution) and inflexibility (the distribution may make some things easier, but other things very difficult). Vim is incredibly customizable, using someone else's customization makes no sense.
The command to close the Syntastic error window is:
:SyntasticReset
Syntastic gets confused when you're juggling multiple buffers on one screen so here's a script that will collect information about the situation, then do the right thing:
function JustCloseSyntasticWindow()
"Check which buffer we are in, and if not, return to the main one:
if &ft == "qf"
normal ZZ
endif
"Since different buffers have different command spaces, check if we've
"escaped the other buffer and then tell syntastic to stop.
if &ft != "qf"
SyntasticReset
" --- or ----
SyntasticToggleMode
endif
endfunction
au FileType buffer1_ft nnoremap :yourcmd<CR>:call JustCloseSyntasticWindow()<cr>
au FileType main_win_ft nnoremap :yourcmd<CR>:call JustCloseSyntasticWindow()<cr>
Don't be shy on the duct tape for this job, it's the only thing holding the unit together.
You can use :lclose to close it.

Is it possible to restore windows status after maximum window?

I always have this problem. When a windows seems too small to view code, i will type :only the maximum this window and hide other windows. But when the editing is finished i quit want to restore the previous status of windows. Exactly the same before i maximum one window. It there any plugin to do this job? Or it's build-in in vim?
EDIT: I found a plugin called ZoomWin can actually do this job. But 0 can't been map to :ZoomWin in my vim. Still don't know why. The help file says i can use 0 to call Zoomvim just after i installing this plugin.
You could probably write a script using mkview and loadview if you wanted to keep this all in one tab, however, this is the exact thing that vim's tabs were made for. I suggest using the following mapping to map \0 to open the current buffer in a new tab. To close the tab just do :q as you would normally do and you'll go back to your previous tab which contains the window layout you want.
:nnoremap <leader>0 :tabedit %<cr>
Note that this mapping uses <leader> so if you've changed your mapleader then the sequence will not be \0.

How can I maximize a split window?

Invoking :help in Vim, I got the help manual page with split window. I want to maximize the help manual window and close the other window.
How can I do this? What is the Vim command to do this?
You can employ Ctrl+WT (that's a capital T) to move any open window to its own tab.
As mentioned by others Ctrl+W_ / Ctrl+W| to maximize within the current tab/window layout (while respecting min height/width settings for various other windows).
(Ctrl+W= resizes all windows to equal size, respecting the minimum height/width settings)
Edit To the comment
start vim (e.g. gvim /tmp/test.cpp)
invoke help :help various-motions - opens a split window
move help into separate tab maximized: C-wT
enjoy reading the fine manual :)
move the help back into the original tab:
mAZZ<C-w>S`A
mA: set global mark A
ZZ: close help buffer/tab
C-wS: split original window
`A: jump to saved mark A
You can avoid using a mark for normal (non-help) buffers. Let me know if you're interested.
With :help [topic] you open up a topic that interests you.
Ctrl-Wo will minimize the other windows (leaving only the help window open/maximized).
(Ctrl-Wo means holding Ctrl press W, and then o)
You can expand a window to its maximum size using Ctrl+W_ (underscore). The final size of the expanded window will be constrained by the value of the winminheight option. When you close the help window, your previous window(s) will be restored to their former sizes.
I prefer to use tabs for that. Use
:tabedit %
to open a file maximized in a new tab, once you are done return to the old setup with all windows using
:tabclose
I find this the ideal solution as this works together with :cw and the Tagbar plugin. Taken from: vim.wikia
I like to use 'M' to maximize and 'm' to minimize.
It won't look great as it'll shrink all the other open windows that are in the same buffer, but I found it to be more useful when dealing with tabs. So for instance, instead of opening a new tab for that file then having to close it after you're done with it or want to minimize it.
nnoremap <C-W>M <C-W>\| <C-W>_
nnoremap <C-W>m <C-W>=
The reason for nnoremap is that I don't care about recursive mapping, but just map should also work.
Install the plugin vim-maximizer, then you can maximize the current window and restore with F3
You can get help window in full size without closing/resizing any other windows by using
tab help {topic}
This will open help window in a new tab, other windows will be left as-is (really resized so that tabline can be shown, but this is only one additional line above). You can close help as usual: at least :bw<CR> and <C-w>c work for me closing new tab as well.
Plugin ZoomWin
by Charles Campbell
This plugin remaps
Ctrl-w o
to do both: maximize and restore previous layout.
This plugin can be downloaded from two locations
https://www.vim.org/scripts/script.php?script_id=508 (v24)
http://www.drchip.org/astronaut/vim/index.html#ZOOMWIN (v25)
To get just the help up, then close the other window, do this: :helpCTRL-WCTRL-W:close. Then you'll have just the help up.
Somehow the ZoomWin plugin did not work at all for me, I now see there are other plugins but I already wrote this and gives me the exact effect I wanted (with a minor quirk detailed below):
function! ToggleZoom(zoom)
if exists("t:restore_zoom") && (a:zoom == v:true || t:restore_zoom.win != winnr())
exec t:restore_zoom.cmd
unlet t:restore_zoom
elseif a:zoom
let t:restore_zoom = { 'win': winnr(), 'cmd': winrestcmd() }
exec "normal \<C-W>\|\<C-W>_"
endif
endfunction
augroup restorezoom
au WinEnter * silent! :call ToggleZoom(v:false)
augroup END
nnoremap <silent> <Leader>+ :call ToggleZoom(v:true)<CR>
Use the mapped key (Leader and + in my case) to toggle between maximized / previous layout. If you change to another split in the same tab, maximization turns off.
If you change tabs, the split stays maximized, although somehow it won't cover the complete full width anymore, with the width minimized windows gaining back some 4 columns or something. Anyway it works acceptably for me even with that minor quirk.
edit: somehow it works fine now, must've messed up in some way before.
in your .vimrc, just place
nmap - :res<CR>:vertical res<CR>$
When you want maximize current window, just press - in command mode. Press = when you want to restore the last status of multiple window

Vertical spilts and folding in gvim

I have problems with automated splits and folding. In my ~/.gvimrc file, at the very end, I have the command vsplit, so that when I'm using gvim as opposed to vim, it opens with two panes. The problem occurs when I open a file that would normally be folded via the command line, as in gvim example.cpp. This opens the example.cpp file in two panes; however, the first pane is folded while the second is not. It's a minor annoyance, but I wondered if anyone had a suggestion to get the second (or all) buffers to be folded when the window first appears.
If it makes a difference, I use set foldmethod=indent in my ~/.vimrc file, and my version is 7.1.
this is very strange, it also happens here, I'm guessing there must be a bug because other settings are valid on the second pane, except for the 'foldmethod' setting.
Anyway, I found an easy workaround. I have this at the end of my .vimrc and what you are looking for now works on my vim:
set foldmethod=indent
set sw=2
set tw=2
vsplit +edit
Now when I open a file, the window is split in two and both are folded correctly.
The workaround is executing the ex command :edit on the second pane so that the missing settings (although it seems that only 'foldmethod' is missing) are reloaded. That's what the +edit after the vsplit does.
Hope this resolves your problem.

Resources