Making two windows with separate files(?) in gvim - vim

I'm a beginner vi user. I don't know the terminology, but I want to split my gvim terminal(screen?) into 2 windows which each have 5 different files(buffers?). I can open the first 5 files in one window, then split to a second window, but I don't know how to open 5 more different files in the second window. I haven't been able to find this information. Normally I switch between files with :n and :prev.
To say it again: I want files 1-5 on a left window and files 6-10 on a right window. Is this possible?

You can indeed have window-local argument lists:
:arglocal
:args file1 file2 file3 file4 file5
:vsplit
:arglocal
:args file6 file7 file8 file9 file10
This way, you can have one argument list (with files 1-5) for the left window, and another (with files 6-10) on a split right window. Commands like :next and :first in the windows are then independent of each other.

Buffers are global. It means that you can't have, say two vertical windows, housing two exclusive sets of buffers. The same applies to tabs, of course.
So, just use two instances: one on the left with files 1-5 and the other on the left with files 6-10.
Because the two instances are separated, you can safely use :n et :prev without "overflowing".

Tabs are viewports for windows, windows are viewports for buffers. You can view any buffer in any window. I would not call it impossible to create some workaround though: e.g. you can create commands :NEXT and :PREV via :command and make them iterate only over buffers that were opened in this window via :EDIT: like in the code below. But I would highly suggest use some plugin that aids in buffer switching like Command-T (I have nnoremap ,b :CommandTBuffer<CR> for buffer switching) and forget about highly inefficient :next/:previous commands.
function s:Edit(args)
let w:winbuflist=get(w:, 'winbuflist', [bufnr('%')])
execute 'edit' a:args
let buf=bufnr('%')
if index(w:winbuflist, buf) == -1
call add(w:winbuflist, bufnr('%'))
endif
endfunction
function s:Switch(direction)
let buf=bufnr('%')
let w:winbuflist=get(w:, 'winbuflist', [buf])
let idx=index(w:winbuflist, buf)
if idx==-1 || w:winbuflist ==# [buf]
if idx == -1
echohl ErrorMsg
echomsg 'Current buffer was not opened using :E or was opened in another window'
echohl None
endif
execute a:direction
return
elseif a:direction is# 'next'
let idx += 1
if idx == len(w:winbuflist)
let idx=0
endif
elseif a:direction is# 'previous'
let idx -= 1
if idx == -1
let idx=len(w:winbuflist)-1
endif
endif
execute 'buffer' w:winbuflist[idx]
endfunction
function s:RemoveBuf(buf)
for tab in range(1, tabpagenr('$'))
for win in range(1, tabpagewinnr(tab, '$'))
call filter(getwinvar(win, 'winbuflist', []), 'v:val isnot '.a:buf)
endfor
endfor
endfunction
augroup BufWinList
autocmd! BufWipeout * :call s:RemoveBuf(+expand('<abuf>'))
augroup END
" \/\/\/\/\/\/\/ Warning: this is not a completion option. It also
" \/\/\/\/\/\/\/ makes command do the expansion of its arguments.
command -complete=file -nargs=? -bar EDIT :call s:Edit(<q-args>)
command -nargs=0 -bar NEXT :call s:Switch('next')
command -nargs=0 -bar PREV :call s:Switch('previous')

It looks that you just need to perform several splits.
Split to 2 vertical windows: Ctrl-w v
In each window: Ctrl-w s (repeat it 4 times, to get 5 buffers)
You can move between windows with Ctrl-w j / Ctrl-w k

The :split command takes a file name, and opens that in a new, horizontally split window. (But you can also first just :split / <C-W>s / <C-W>v, and then :edit / :next another file.) Prepend :vertical (or shorter :vsplit) for vertical splitting. With this, you can create your desired layout.
To focus a different window, there are many mappings that start with Ctrl + W, e.g. <C-w>j to go to the window below. See :help CTRL-W for the full list.

Related

vim: Get last pasted text total line number

Whenever I paste a text, vim always tell me how many lines I pasted on the bottom left. Eg it says "6 more lines".
Is it possible to programmatically access that number?
Or, access total line on given register?
I'm gonna use the number to count how many macro should I execute. Eg. vim says "6 more lines", then I type 6#q.
Calculate the difference between the line of mark '[ and '] (first and last lines of yanked text):
:echo line("']") - line("'[") + 1
Please note the marks are for any change, not only yanks, so use the expression right after yanking.
fun! MacroOverChange(macroname)
let l:how_many = line("']") - line("'[") + 1
execute "normal! ". l:how_many . "#" . a:macroname
endfun
:call MacroOverChange("a")
com -nargs=1 Mover :call MacroOverChange(<f-args>)
nnoremap <leader>m :Mover<space>
The command Mover (Mnemonic for "Macro Over") accepts arguments, for instance, if you want to run Mover macro 'a', just type:
:Mover a
The map allows you to type <leader>m and get the following
:Mover |
Where | is the cursor point
A better function that runs over exactly last changed/yanked block.
The advantage of this function is that it runs exactly over the last yanked/changed block
fun! RunMacroOver(macroname)
execute "'[,']normal #". a:macroname
endfun
com -nargs=1 Rover :call RunMacroOver(<f-args>)
nnoremap <leader>r :Rover<space>
To avoid creating files in your system in order to test these functions copy them in yout browser and run:
:#+
If you paste these line in a vim buffer you can select a paragraph, for example and yank, that will place the copied text into default register #" and you can make those lines active making: :#"
OBS: Just avoid copying lines with :

Merge changes using vimdiff

In my case, I have two files file1 and file2. Using vimdiff, I want to merge the changes as follows:
In first difference, place line from file1 above line from file2. It means difference such as Listing 2 in file2 and List 2 should be List 2 followed by Listing 2 in the merged file.
Reverse case in another change.
Snapshot is shown below.
How can we achieve this using vimdiff?
You can use the following basic commands to merge:
do - Get changes from other window into the current window.
dp - Put the changes from current window into the other window.
]c - Jump to the next change.
[c - Jump to the previous change.
zo - Open folded lines.
zc - Close folded lines.
zr - Unfold both files completely.
zm - Fold both files completely.
Ctrlww - change window.
:only | wq - quit other windows, write and quit.
Quirks to watch for
Both do and dp work if you are on a block of change (or just one line under a single line of change) in Normal mode, but not in Visual mode.
The undo command will only work in the buffer that was changed, so if you use dp and change your mind, you need to switch to the other buffer to undo.
:diffupdate will re-scan the files for changes (Vim can get confused, and show bogus stuff).
Visual mode and finer grained control
When selecting lines of text in Visual mode, you must use the normal commands:
:'<,'>diffget and
:'<,'>diffput.
For example:
Enter Visual mode and mark some text/lines.
Then type :diffput to push the selected lines to the other file or :diffget to get the selected lines from the other file.
To belabor the point: This means that if there is a block of changes consisting of multiple lines, then selecting a subset of lines and issueing :diffput will only apply those changes in the other buffer.
(:diffget and :diffput also accept ranges, see :h copy-diffs for more.)
Compare two buffers inside Vim
If you load up two files in splits (:vs or :sp), you can do :diffthis on each window and achieve a diff of files that were already loaded in buffers.
:diffoff can be used to turn off the diff mode.
This Vimcasts post and video show this in practice.
How to apply all changes between buffers
Make sure that all participating buffers are in diff mode (see :h start-vimdiff)
a. Get changes from a buffer to the current one:
:%diffget <buffer-number>
b. Put all changes from current buffer into another:
:%diffput <buffer-number>
(:% is a range to select the entire file; see :h :%. :ls will show currently opened buffers.)
You can switch back and forth between the two windows with Ctrlww. You can copy from one window do a Ctrlww, and then paste into the other. As you resolve differences, the highlights will change, and disappear.
Take a look at this video.
You can just switch between the windows and copy and paste to resolve the differences, as #David W. suggests in his answer, but Vim also has dedicated :diffput and :diffget commands to simplify this. With these (or the corresponding normal mode do and dp commands), you don't have to switch between windows, and the range defaults to the current change.
If you need to add instead of overwrite with the other buffer's differences (which is a rather unusual case in a classic two-way diff), you still have to yank the original lines and put them after the :diffget.
After you're done in one place, you can use the ]c, [c commands to jump to the next difference.
I am using the following mappings to deal with three-way merges (when conflictstyle=diff3)
nnoremap g1 :<C-U>call MergeKeepLeft()<CR>
nnoremap g2 :<C-U>call MergeKeepBoth()<CR>
nnoremap g3 :<C-U>call MergeKeepRight()<CR>
function! MergeKeepLeft()
let lastsearch = #/
let #/ = '<<<<<<<'
execute "normal! ?\<cr>dd"
let #/ = '|||||||'
execute "normal! /\<cr>V"
let #/ = '>>>>>>>'
execute "normal! /\<cr>d"
let #/ = lastsearch
endfunction
function! MergeKeepBoth()
let lastsearch = #/
let #/ = '<<<<<<<'
execute "normal! ?\<cr>dd"
let #/ = '|||||||'
execute "normal! /\<cr>V"
let #/ = '======='
execute "normal! /\<cr>d"
let #/ = '>>>>>>>'
execute "normal! /\<cr>dd"
let #/ = lastsearch
endfunction
function! MergeKeepRight()
let lastsearch = #/
let #/ = '<<<<<<<'
execute "normal! ?\<cr>V"
let #/ = '======='
execute "normal! /\<cr>d"
let #/ = '>>>>>>>'
execute "normal! /\<cr>dd"
let #/ = lastsearch
endfunction

How can I tell Vim to close only a specific level of folds in a file?

For example, how can I tell Vim to only close all level 2 folds in a file, leaving other levels open?
Edit: Let's say I have 3 levels of folds in my file. 1, 2, and 3. I only want to close level 2 folds, leaving levels 1 and 3 open.
You can also set 'foldlevel' via the [count] on zM: 2zM; this is shorter than #timrau's answer.
Use foldlevel.
:set foldlevel=2
function! FoldToTheLevel(TheLevel)
"set mark "f" at current position
execute "normal! mf"
"close all the folder recursively
execute "normal! ggVGzC"
"open all the folder which have smaller level
let h=0
while h<a:TheLevel
execute "normal! ggVGzo"
let h+=1
endwhile
"open all the folder which have larger level
folddoclosed execute "normal! VzOzc"
"jump back and show in the middle
execute "normal! `fzz"
endfunction
command! -nargs=1 F call FoldToTheLevel(<f-args>)
add this to .vimrc
run
:F num
to close the folder which the level is {num}

Is circular scrolling possible in vim?

Is it possible to configure vim such that a movement command "wraps around" the vertical (or horizontal) buffer?
In other words, assume I'm on line 2 in a buffer, in visual mode. I press 3k. My cursor is now positioned on the last line of the buffer.
Or more simply, my cursor is on the first line of the file -- I press k. Now my cursor flips to the last line of the file.
Apologies if this has been asked before, but I couldn't find any references searching for "circular scrolling" or "wrap-around scrolling".
It's probably possible with some vimscript hackery, but it's much more universal to become efficient with motions like G to go to the bottom of a file and gg or 1G or <C-Home> to go to the top of the file. Likewise, $ for the end of a line and 0 for the beginning of the line or ^ for the first non-blank character.
You can also set :help whichwrap, which specifies which keys will move of to the next line when moving past the end of the line or move to the previous line when moving past the beginning of the line. Other then that I don't think there's built in functionality for what you're asking. You can could do it with some vimscript but it would require remapping h,j,k, and l to functions and handling whether they are at the end/beginning of the line/file. To me that seems overkill and rather messy.
All that being said, if you must...
nnoremap j :call CheckJ()<cr>
nnoremap k :call CheckK()<cr>
nnoremap h :call CheckH()<cr>
nnoremap l :call CheckL()<cr>
fun! CheckJ()
if line('.') == line('$')
norm! gg
else
norm! j
endif
endfun
fun! CheckK()
if line('.') == 1
norm! G
else
norm! k
endif
endfun
fun! CheckH()
if col('.') == 1
norm! $
else
norm! h
endif
endfun
fun! CheckL()
if col('.') == (col('$') - 1)
norm! 0
else
norm! l
endif
endfun
Vim is a text editor, and text has both physical and logical properties of having a beginning and an end, both in columns and lines. Therefore, the feature you're requesting doesn't exist, and probably won't ever be included in Vim.
It can, however, with some effort be emulated in Vimscript, by binding most movement commands to custom implementations. But that would introduce inconsistencies in the usage model, as ranges (e.g. :42,10) still wouldn't wrap around.
Why would you want such a wrap-around? Is this for a particular file type, or are you used to it from another editor?

Vim close buffer but not split window

If I have 2 buffers split horizontally/vertically and want to close one of them, but i don't want to close a window. I want to keep places of split windows are the same as before closing buffer.
If I press :bd , the window in which was closed buffer also became closed.
Like #RusAlex I don't like plug-ins. I also like to know what code I enter actually does.
nmap ,d :b#<bar>bd#<CR>
In short this adds a key mapping to vim's normal mode waiting for key sequence ,d. When executed this switches to a previously open buffer and attempts to delete the buffer you switched away from.
Deleting an off-screen buffer keeps the screen split as it is.
The command consists of three space-separated parts:
nmap - add/change key mapping for mode normal
,d - key sequence to react to; first , (comma), then d
:b#<bar>bd#<CR> - key sequence to execute
The command to be executed consists of five parts:
: - switch vim to mode command-line
b# - switch window to previously open buffer
<bar> - expect a follow-up command; represents | (pipe character); used for chaining commands
bd# - delete previously open buffer, i.e. the buffer just switched away from
<CR> - execute command(s); represents carriage return, basically the keys Return or Enter
The command is in the format it is used in a configuration file like ~/.vimrc. If you want to add the mapping from within vim you prepend : (colon) - the mapping then will be lost when exiting vim:
:nmap ,d :b#<bar>bd#<CR>
When you open vim it is usually in normal mode as opposed to modes insert (indicated on the bottom of the screen by -- INSERT -- after pressing i), visual and so on. The n in nmap specifies the key mapping to be added to normal mode only. Find more on mappings here
Important notes:
b# will switch to the current buffer if it is the only known buffer.
b# may switch to a hidden/closed buffer, e.g. the one you just closed by pressing ,d.
bd# will close the current buffer if it is the only known buffer unsplitting the screen leaving you with an empty buffer.
bd# will fail if the buffer switched away from is a hidden/closed buffer.
bd# will still unsplit if after switching another window shows the buffer to close.
Additional notes:
:windo b# will switch all windows to the previously open buffer. Not sure how to combine with bd.
<CR> can be left out in which case you have to manually press Return or Enter to execute.
:nmap , displays all normal mode mappings starting with ,.
:ls lists open buffers.
It's impossible to have an empty window in vim, but you can just create a new empty file in the current window using :enew.
I'll have to check on my work computer, but I think the script I'm using for this is BufClose.
You want to delete the buffer but keep the split? You need a new buffer then - :new will do that for you, creating a buffer for a new/empty file, but you'll still need to kill the old buffer/window. In vim a window is a viewport on a buffer, so if you want an empty window you need an empty buffer.
Here's a variation on the answer provided #zenbro that keeps all your (split) windows and tabs open even if the buffer you close is the last one.
The function switches all windows pointing to the current buffer (that you are closing) to the next buffer (or a new buffer if the current buffer is the last one).
function! CloseBuffer()
let curBuf = bufnr('%')
let curTab = tabpagenr()
exe 'bnext'
" If in last buffer, create empty buffer
if curBuf == bufnr('%')
exe 'enew'
endif
" Loop through tabs
for i in range(tabpagenr('$'))
" Go to tab (is there a way with inactive tabs?)
exe 'tabnext ' . (i + 1)
" Store active window nr to restore later
let curWin = winnr()
" Loop through windows pointing to buffer
let winnr = bufwinnr(curBuf)
while (winnr >= 0)
" Go to window and switch to next buffer
exe winnr . 'wincmd w | bnext'
" Restore active window
exe curWin . 'wincmd w'
let winnr = bufwinnr(curBuf)
endwhile
endfor
" Close buffer, restore active tab
exe 'bd' . curBuf
exe 'tabnext ' . curTab
endfunction
To map it:
map <silent> <F4> :call CloseBuffer()<cr>
#RusAlex version + activate current buffer in the end need if delete buffer twice.
nmap ,d :b#<bar>bd#<bar>b<CR>
Here is some workaround:
function! CloseSplitOrDeleteBuffer()
let curNr = winnr()
let curBuf = bufnr('%')
wincmd w " try to move on next split
if winnr() == curNr " there is no split"
exe 'bdelete'
elseif curBuf != bufnr('%') " there is split with another buffer
wincmd W " move back"
exe 'bdelete'
else " there is split with same buffer"
wincmd W
wincmd c
endif
endfunction
nnoremap <silent> Q :call CloseSplitOrDeleteBuffer()<CR>

Resources