How to swap files between windows in VIM? [closed] - vim

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
When I work with VIM, I always have multiple windows visible. Sometimes I would like to have an easy way, to swap those windows in places. Is there any Plugin, Macro, etc to make this more easy? BTW, I use MiniBufExplorer.

There are a few useful commands built in which give you a certain amount of control, but it's not comprehensive. The main ones are:
Ctrl-W, r (i.e. hold CTRL, press W, release CTRL, press r) - which rotates the windows (The first window becomes the second one, the second one becomes the third one, etc.)
Ctrl-W, x - swap the current window with the next one
Ctrl-W, Shift-H - move this window to the far left
Ctrl-W, Shift-K - move this window to the top
(and similarly for Ctrl-W, Shift-J and Ctrl-W, Shift-L). See:
:help window-moving
for more information.

I wrote and have been using the following code snippet in my vimrc for
copy-pasting my Vim windows.
This defines for example the following shortcuts:
<c-w>y: "Yanks the window", i.e. stores the number of the buffer in the
current window in a global variable.
<c-w>pp: "Puts the window in Place of the current window", i.e. it reads the
buffer number stored previously and opens that buffer in the current window.
It also stores the number of the buffer that used to be in the current
window.
If by "swapping those windows in places", you mean "opening the buffer in
window A in window B, and vice versa, without changing the position of the
windows", you can use the following keyboard sequence to swap the windows:
Select window A (either with mouse or with keyboard commands)
Press <c-w>y (yanking the buffer number)
Select window B
Press <c-w>pp (pasting the buffer)
Select window A
Press <c-w>pp (pasting the buffer again)
It works only in Vim >= 7.0.
if version >= 700
function! HOpen(dir,what_to_open)
let [type,name] = a:what_to_open
if a:dir=='left' || a:dir=='right'
vsplit
elseif a:dir=='up' || a:dir=='down'
split
end
if a:dir=='down' || a:dir=='right'
exec "normal! \<c-w>\<c-w>"
end
if type=='buffer'
exec 'buffer '.name
else
exec 'edit '.name
end
endfunction
function! HYankWindow()
let g:window = winnr()
let g:buffer = bufnr('%')
let g:bufhidden = &bufhidden
endfunction
function! HDeleteWindow()
call HYankWindow()
set bufhidden=hide
close
endfunction
function! HPasteWindow(direction)
let old_buffer = bufnr('%')
call HOpen(a:direction,['buffer',g:buffer])
let g:buffer = old_buffer
let &bufhidden = g:bufhidden
endfunction
noremap <c-w>d :call HDeleteWindow()<cr>
noremap <c-w>y :call HYankWindow()<cr>
noremap <c-w>p<up> :call HPasteWindow('up')<cr>
noremap <c-w>p<down> :call HPasteWindow('down')<cr>
noremap <c-w>p<left> :call HPasteWindow('left')<cr>
noremap <c-w>p<right> :call HPasteWindow('right')<cr>
noremap <c-w>pk :call HPasteWindow('up')<cr>
noremap <c-w>pj :call HPasteWindow('down')<cr>
noremap <c-w>ph :call HPasteWindow('left')<cr>
noremap <c-w>pl :call HPasteWindow('right')<cr>
noremap <c-w>pp :call HPasteWindow('here')<cr>
noremap <c-w>P :call HPasteWindow('here')<cr>
endif

In my opinion, http://vimcasts.org/episodes/working-with-windows/ has the perfect answer for this question. In brief:
ctrl-w w cycle between the open windows
ctrl-w h focus the window to the left
ctrl-w j focus the window to the down
ctrl-w k focus the window to the up
ctrl-w l focus the window to the right
ctrl-w r rotate all windows
ctrl-w x exchange current window with its neighbour
ctrl-w H move current window to far left
ctrl-w J move current window to bottom
ctrl-w K move current window to top
ctrl-w L move current window to far right

I asked a similar question around the same time: I wanted a way to swap windows specifically without altering an arbitrarily complicated layout. I ended up making a vim plugin out of one of the solutions that was suggested. It's called WindowSwap.vim; install it with your preferred vim plugin manager and give it a whirl.
With WindowSwap.vim, you'd simply
<Leader>yw to yank a window.
Move your cursor to another window.
<Leader>pw to paste that window, swapping it with the position of
the first one.
The key combinations are of course configurable to your preferences.

As <c-w>r or <c-w>x has a restriction that you can't rotate or exchange windows When vertical and horizontal window splits are mixed. And <c-w>H may make the window layout change beyond your expectation especially when you have many windows.
So you may do some work to satisfy your particular needs of window/buffer switching. Here is am example to switching the current window with the top left window(typically I make it vertically maximized):
function! SwitchMainWindow()
let l:current_buf = winbufnr(0)
exe "buffer" . winbufnr(1)
1wincmd w
exe "buffer" . l:current_buf
endfunction
nnoremap <c-w><c-e> :call SwitchMainWindow()<cr>

Related

vim - show one file in several files consistently

I.e. is it possible in vim to edit large file in several simultaneously opened tabs in the following way: first part of text (that fill all vertical space), second - in the second pane, and so on.
if it is not possible in vim, maybe it's feature is implemented in other editors?
Synchronizes two vim panes
Lets say your window is 20 rows, then
:vsplit // splits window into left and right panes
^w^w // focuses right pane
20^e // scrolls right pane down 20 rows
:windo set scrollbind // syncronizes both panes
^w means press and hold CTRL and then press w. Likewise for ^e
:windo means :set scrollbind in all open panes
Implement it in a function
Wraps the above commands in a function and binds it to [
function! SyncScroll()
vsplit
execute "normal! \<c-w>\<c-w>" . winheight(0) . "\<c-e>"
windo set scrollbind
endfunction
nnoremap [ :call SyncScroll()<cr>
You can add the above function and mapping to your vimrc with :e $MYVIMRC and reload it with :source $MYVIMRC
ref:
vim
docs - scrollbinding
wiki - scrollbinding
I think you're looking for the MPage plugin. You probably want to install the latest version from DrChip's page.

How can I switch in and out of NERDtree?

Is there a way to switch in and out of NERDtree -- mouse disabled? I know I can press 'q' to quit NERDtree and go back to text editor, but when I go back to NERDtree it doesn't keep track of which directories I had pressed open before, and I would like to keep the list of directories open. I referenced NERDtree help, but I couldn't find what I was looking for. Perhaps I missed something?
Thanks in advance.
NERDTree opens as a sidebar next to the existing open windows. You can therefore use all Vim window movement commands to jump back and forth.
For example, <C-W>p (that's Ctrl + W followed by P) goes back to the previous window, and 1<C-W><C-W> goes to the first window (which usually is the leftmost split NERDTree). You'll find the whole list at :help window-move-cursor; for effective window handling, it's important you know these very well.
As a potential best practice , I map F2 key to toggle NERDTree.
map <F2> :NERDTreeToggle<CR>
let NERDTreeWinSize=32
let NERDTreeWinPos="left"
let NERDTreeShowHidden=1
let NERDTreeAutoDeleteBuffer=1
let NERDTreeAutoDeleteBuffer=1
And also, I map Ctrl+j/k/hl to quickly move between opened vim windows.
"Smart way to move between windows
map <C-j> <C-W>j
map <C-k> <C-W>k
map <C-h> <C-W>h
map <C-l> <C-W>l
To switch between the NERDtree "window" and the text "window" with
Ctrl+w and then right arrow
and then to go back I use
Ctrl+w and then left arrow
For more info on "vim windows"
http://vimdoc.sourceforge.net/htmldoc/windows.html

How to make a shortcut for moving between Vim windows?

Let’s say I have single Vim tab displaying 9 buffers (equally separated, like a 3×3 table).
Currently, to get from the top left window to the bottom right one, I have to press 3, Ctrl+W, J, and then 3, Ctrl+W, L. This is cumbersome, and I would like to just be able to press Ctrl+9 to go to the 9th window, and Ctrl+3 to go to the 3rd window, etc.
Is there any easy way I can map something like this in Vim?
There's a much simpler solution than using the mouse or hard-set movement mappings; they will break if the window numberings are different from what you have in mind for a 3x3 matrix, or if you decide to work with less than 9 windows. Here's how:
Include the following in your .vimrc:
let i = 1
while i <= 9
execute 'nnoremap <Leader>' . i . ' :' . i . 'wincmd w<CR>'
let i = i + 1
endwhile
Now you can just press <Leader><number> and be taken to the window number you want. I wouldn't recommend going beyond 9, because IMO, the utility of having multiple viewports follows a Rayleigh distribution and quickly becomes useless with too many viewports in one window.
It will be helpful if you have the window number displayed in your statusline to aid you in quickly figuring out which window you're on and which window you want to go to. To do that, use this little function and add it accordingly in your statusline.
function! WindowNumber()
let str=tabpagewinnr(tabpagenr())
return str
endfunction
See it in action in your statusline:
set laststatus=2
set statusline=win:%{WindowNumber()}
Note that the above line will replace your statusline. It was just meant for illustration purposes, to show how to call the function. You should place it where ever you think is appropriate in your statusline. Here's what mine looks like:
Update
romainl asked for my status line in the comments, so here it is:
"statusline
hi StatusLine term=bold cterm=bold ctermfg=White ctermbg=235
hi StatusHostname term=bold cterm=bold ctermfg=107 ctermbg=235 guifg=#799d6a
hi StatusGitBranch term=bold cterm=bold ctermfg=215 ctermbg=235 guifg=#ffb964
function! MyGitBranchStyle()
let branch = GitBranch()
if branch == ''
let branchStyle = ''
else
let branchStyle = 'git:' . branch
end
return branchStyle
endfunction
function! WindowNumber()
let str=tabpagewinnr(tabpagenr())
return str
endfunction
set laststatus=2
set statusline=%#StatusLine#%F%h%m%r\ %h%w%y\ col:%c\ lin:%l\,%L\ buf:%n\ win:%{WindowNumber()}\ reg:%{v:register}\ %#StatusGitBranch#%{MyGitBranchStyle()}\ \%=%#StatusLine#%{strftime(\"%d/%m/%Y-%H:%M\")}\ %#StatusHostname#%{hostname()}
The last line should be a single line (be careful if your setup automatically breaks it into multiple lines). I know there are ways to keep it organized with incremental string joins in each step, but I'm too lazy to change it. :) The GitBranch() function (with other git capabilities) is provided by the git.vim plugin. There's a bug in it as noted here and I use the fork with the bug fix. However, I'm leaving both links and the blog here to give credit to all.
Also, note that I use a dark background, so you might have to change the colours around a bit if you are using a light scheme (and also to suit your tastes).
Better, more general answer:
Use countCtrl+wCtrl+w to jump to the count window below/right of the current one.
For example, if you're in the top left of a 3x3 grid and want to jump to the bottom left you'd use 7Ctrl+wCtrl+w.
Specific 3x3 grid answer:
If you're always using a 3x3 layout you could try these mappings for the numpad, which always jump to the top left and then move the appropriate amount from there, with the key's position on the keypad jumping to the window's with 'equivalent' position on the screen:
noremap <k7> 1<c-w><c-w>
noremap <k8> 2<c-w><c-w>
noremap <k9> 3<c-w><c-w>
noremap <k4> 4<c-w><c-w>
noremap <k5> 5<c-w><c-w>
noremap <k6> 6<c-w><c-w>
noremap <k1> 7<c-w><c-w>
noremap <k2> 8<c-w><c-w>
noremap <k3> <c-w>b
Edited: turns out c-w c-w goes to the top left at the start automatically. The explicit 1 is required in the first mapping, as c-w c-w without a count toggles between the current and the previously selected window.
(The Ctrl-W t mapping always goes to the top-left most window, the Ctrl-W b mapping always goes to the bottom-rightmost).
Alternatively you could map each number to jump to the Nth window, so k6 would be 6 c-w c-w, rather than trying to lay out the keys as on screen.
I prefer use standard vim keys(jkhl).
noremap <C-J> <C-W>w
noremap <C-K> <C-W>W
noremap <C-L> <C-W>l
noremap <C-H> <C-W>h
There is a trick if you notice that the first two maps can jump clock wise or the reverse, rather than just jumping up or down.
And you can also switch to any window directly with <Number><C-J>, for example, 2<C-J> will go to the 2nd window.
Not exactly what you're looking for, but if you're using a terminal that supports it, you can set the following options:
:set mouse+=a
:set ttymouse=xterm2
and click on a buffer to switch to it. Yes, with the mouse.
A bunch of other mouse behavior works too - you can click to move the insertion point, drag to select text or resize splits, and use the scroll wheel.
Ermmm... I'm pretty sure that this will not keep window layout as it is, but I use
:buf sys
to go to system.h,
:buf Sing
to go to MyLargeNamedClassSingleton.cpp
buf will do autocomplete (possibly menucompletion if so configured) so you can do
:buf part<Tab>
to list what files could match the part you typed. Beats the crap out of navigating buffers all around.
But I understand, this doesn't answer your specific question of course :)
I like to move around with the arrow keys.
I map ctr+direction to move to the next window partition in that direction.
map <C-UP> <C-W><C-UP>
map <C-DOWN> <C-W><C-DOWN>
map <C-LEFT> <C-W><C-LEFT>
map <C-RIGHT> <C-W><C-RIGHT>
You cant jump directly from one window to another but I find that it makes it very easy to move between windows

How to flip windows in vim? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
To switch from vertical split to horizontal split fast in Vim
If I have 2 horizontally split windows, how to rotate them to get 2 vertically split windows?
And how to switch buffers?
If you have them split vertically C-wJ to move one to the bottom
If you have them split horizontally C-wL to move one to the right
To rotate in a 'column' or 'row' of split windows, C-wC-r
The following commands can be used to change the window layout. For example,
when there are two vertically split windows, CTRL-W K will change that in
horizontally split windows. CTRL-W H does it the other way around.
Ctrl-w H or type :wincmd H to go from horizontal to vertical layout.
Ctrl-w J or type :wincmd J to go from vertical to horizontal layout.
Ctrl-w r or type :wincmd r to swap the two buffers but keep the window layout the same.
Ctrl-w w or type :wincmd w to move the cursor between the two windows/buffers.
You may wish to bind one or more of these sequences to make it faster to type. I put this in my .vimrc so that ,l moves the cursor to the next buffer in the current tab:
let mapleader = ","
nmap <Leader>l <C-w>w
CTRL-W SHIFT-H will rotate the orientation, CTRL-W H moves to the left window, CTRL-W L moves to the right. See
:help split
and
:help ^w
for more information.
The current answers all work great if you only have two windows open. If you have more than that, the logic for moving windows around can get hairy.
I have this in my .vimrc to allow me to 'yank' and 'delete' a buffer and then paste it into a window over the current buffer or as a [v]split.
fu! PasteWindow(direction) "{{{
if exists("g:yanked_buffer")
if a:direction == 'edit'
let temp_buffer = bufnr('%')
endif
exec a:direction . " +buffer" . g:yanked_buffer
if a:direction == 'edit'
let g:yanked_buffer = temp_buffer
endif
endif
endf "}}}
"yank/paste buffers
:nmap <silent> <leader>wy :let g:yanked_buffer=bufnr('%')<cr>
:nmap <silent> <leader>wd :let g:yanked_buffer=bufnr('%')<cr>:q<cr>
:nmap <silent> <leader>wp :call PasteWindow('edit')<cr>
:nmap <silent> <leader>ws :call PasteWindow('split')<cr>
:nmap <silent> <leader>wv :call PasteWindow('vsplit')<cr>
:nmap <silent> <leader>wt :call PasteWindow('tabnew')<cr>

What is the best way to do smooth scrolling in Vim?

The main scrolling commands in Vim are:
Ctrl-B and Ctrl-F, as well as PageUp and PageDown scroll by full page
Ctrl-U and Ctrl-D scroll half a page by default
Ctrl-Y and Ctrl-E scroll one line
I lose visual context every time for the former two, so I have developed the bad habit of hitting the latter (Ctrl-Y and Ctrl-E) repetitively.
Since there is currently no first party support for smooth scrolling, what are the least objectionable workarounds/plugins?
I use both Vim and GVim depending on the task, and am happy to customize them separately if there is no one really good hack that works for both. The mouse scroll wheel works nicely in GVim, but I'm looking for keyboard based solutions.
Update: I have now pushed this code, refactored somewhat according to the guidelines at :help write-plugin, to a Github repo.
Using the Keyboard
Here is what I have in my .vimrc:
function SmoothScroll(up)
if a:up
let scrollaction="^Y"
else
let scrollaction="^E"
endif
exec "normal " . scrollaction
redraw
let counter=1
while counter<&scroll
let counter+=1
sleep 10m
redraw
exec "normal " . scrollaction
endwhile
endfunction
nnoremap <C-U> :call SmoothScroll(1)<Enter>
nnoremap <C-D> :call SmoothScroll(0)<Enter>
inoremap <C-U> <Esc>:call SmoothScroll(1)<Enter>i
inoremap <C-D> <Esc>:call SmoothScroll(0)<Enter>i
Features:
Scroll on the base of the Vim scroll option.
Customizable scrolling speed (adjust time argument of the sleep command; I use ten milliseconds). Note: just like slowing down the frame rate on a video, if you slow down the smooth scroll too much it will be jerky scroll, not smooth scroll. But whatever works best for you.
Works in normal or insert mode.
Note: all you copy-and-pasters, remember that the ^ character indicates a control character; copy-paste will produce invalid results and these must be entered manually!
^Y – CTRL-V then CTRL-Y
^E – CTRL-V then CTRL-E
However, the <C-U> and <Enter> style syntaxes are literally typed as those characters; the map command intelligently converts them to control characters.
Using the Mouse
The question mentions that scrolling with the mouse works well in GVim, but a keyboard solution is desired. This implies to me that the asker may be interested in a mouse solution if it works in regular terminal Vim.
For me, turning mouse support on allows smooth scrolling through the mouse wheel. Also, for me, smooth scrolling is most important when I am looking around (i.e. in normal mode), not when I am editing (in insert mode), and if I am not actively editing, the need for my hands to stay on the keyboard at all times is removed, so this works well.
On the basis of this question, though, it would seem that some people have to do some more manual setup beyond simply turning the mouse on (I just use set mouse=n):
My .vimrc has the following lines
set mouse=a
map <ScrollWheelUp> <C-Y>
map <ScrollWheelDown> <C-E>
There is a simple remap hack in vim's tips.txt:
Smooth scrolling *scroll-smooth*
If you like the scrolling to go a bit smoother, you can use these mappings:
:map <C-U> <C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y><C-Y>
:map <C-D> <C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E><C-E>
Shameless plug, but I created a plugin here that you can use to easily adjust the distance, speed, and duration of the scrolling animation: https://github.com/terryma/vim-smooth-scroll
A Recent Plugin
I have posted something similar here, but basically there is a great plugin that we can use now for scrolling, called terryma/vim-smooth-scroll. It provides a very nice and smooth scrolling.
The install is quite easy:
1 I use Vundle so I simply appended this in .vimrc.bundles :
Bundle terryma/vim-smooth-scroll
In the latest version of Vundle available today, 29th April of 2016, you can put this in your .vimrc:
Plugin 'terryma/vim-smooth-scroll'
2 As stated in the doc, you can set up 3 arguments: distance, duration and speed.
I am using this in my .vimrc file:
noremap <silent> <c-b> :call smooth_scroll#up(&scroll*2, 10, 4)<CR>
noremap <silent> <c-f> :call smooth_scroll#down(&scroll*2, 10, 4)<CR>
What I do is I set the keyboard repeat to very fast, about 120 chars / second, and the delay small.
Then I map to 4j and to 4k
I navigate up and down source code using j and k which moves the cursor up and down nice and quick, pretty smooth.
But here's the good part, and this works on Linux, not Windows.
For a number of years now, X11's keyboard input works in such a way that when you press and hold j it obviously starts putting out j characters. But when you then keep holding down j and then also press the ctrl key, X11 starts putting out c-j characters without you having to re-press the j key. Then when you let go of the ctrl key and still keep on pressing j, X11 continues to put j's again.
So j makes the cursor start moving nice and smooth downwards, and you can periodically hit ctrl without letting go of j to give it a boost, a jolt.
Also, I do what Devin does, and I set scrolloffset to 5.
Lastly, I swap ctrl and cap lock. The default position of the ctrl key is completely retarded (no offense intended). It makes you have to rotate your left hand. I almost never use caps lock, so I swap them. Then my left pink finger can reach the ctrl key without any yoga moves.
These things have worked for me for years. I only use vim, never gvim.
This isn't exactly smooth scrolling, but it's how I handle not losing context when jumping pages.
set so=7
'scrolloff' 'so' number (default 0)
global
{not in Vi}
Minimal number of screen lines to keep above and below the cursor.
This will make some context visible around where you are working. If
you set it to a very large value (999) the cursor line will always be
in the middle of the window (except at the start or end of the file or
when long lines wrap).
For scrolling horizontally see 'sidescrolloff'.
NOTE: This option is set to 0 when 'compatible' is set.
The Plugin cskeeters/vim-smooth-scroll supports smooth scrolling and requires no configuration. It supports to support smooth scrolling with zt, zz, and zb. It's a fork of terryma's plugin. Some of the open pull requests have been applied.
This combines many of these answers, and this is what I use.
noremap <expr> <C-u> repeat("\<C-y> :sleep 10m<CR>", winheight('%')/2)
noremap <expr> <C-d> repeat("\<C-e> :sleep 10m<CR>", winheight('%')/2)
N <CR-E>
N <CR-Y>
...where 'N' is the number of single lines you want to scroll.
Not smooth in literal sense, but you keep the keyboard.
This may be controversial for hardcore users, but... the best way to smooth scroll in Vim is... mouse wheel.
I just found this plugin called "accelerated-smooth-scroll" ("Vim plugin for accelerated smooth scroll (mapping to <C-D>/<C-U>, <C-F>/<C-B>)") which can be for example used through Vundle by putting this line in your .vimrc:
Plugin 'yonchu/accelerated-smooth-scroll'
Then by restarting Vim and running the :PluginInstall command, then again restart Vim and use the <C-D> (Ctrl+D) and <C-O> (Ctrl+O) commands normally.
Sadly, this plugin also moves the cursor instead of what I wanted: to just scroll the screen like the <C-E> and <C-Y> commands.
I slightly modified #Keith Pinson's code so that ctrl-f and ctrl-b can be mapped too:
function SmoothScroll(scroll_direction, n_scroll)
let n_scroll = a:n_scroll
if a:scroll_direction == 1
let scrollaction=""
else
let scrollaction=""
endif
exec "normal " . scrollaction
redraw
let counter=1
while counter<&scroll*n_scroll
let counter+=1
sleep 10m " ms per line
redraw
exec "normal " . scrollaction
endwhile
endfunction
" smoothly scroll the screen for some scrolling operations
nnoremap <C-U> :call SmoothScroll(1,1)<cr>
nnoremap <C-D> :call SmoothScroll(2,1)<cr>
nnoremap <C-B> :call SmoothScroll(1,2)<cr>
nnoremap <C-F> :call SmoothScroll(2,2)<cr>

Resources