I have 8 square (equal) windows in my vim screen spanning over 2 large monitors and I want to refer each of them with shortcuts < A-1 >, < A-2 > ... . There is a command in vim N-wincmd-wincmd that allows to to reference to the window by its number, but it is useless for me because other plugins sometimes create windows (like syntastic for syntax checking) and referring by number doesn't exactly matches the correct window. I thought maybe I could reference windows by names, so the question is, how do I set a name to some window, and then make a short cut so the cursor goes to the window with that name when pressing < A - n > where n is the window number?
The following lets you save a static extra window number for each visible window, and then jump to it quickly.
Just call :MarkWins when your layout is clean, and then the mappings <A-1>, <A-2>... will jump to the good window, even if new windows were created after that.
" Mark all visible windows from 1 :
command! MarkWins call s:mark_windows()
" Go to a previously marked window :
command! -nargs=1 GoToMarkedWin call s:go_to_marked_win(<f-args>)
" Mappings (Alt-1, Alt-2...) :
for s:n in range(1,8)
exe printf('noremap <silent> <a-%d> :GoToMarkedWin %d<cr>', s:n, s:n)
endfor
function! s:mark_windows()
let l:old_winnr = winnr()
windo let w:win_mark = winnr()
exe printf('%d wincmd w', l:old_winnr)
endf
function! s:go_to_marked_win(n)
let l:old_winnr = winnr()
while 1
if exists('w:win_mark') && w:win_mark == a:n
return
endif
wincmd w
if winnr() == l:old_winnr | return | endif
endw
endf
Related
I want do something like this:
check if a split named __Potion_Bytecode__ exists
if exists, switch to the split with name
if not, new a split named __Potion_Bytecode__
Here is code I am now doing:
function! PotionShowBytecode()
" Here I need to check if split exists
" open a new split and set it up
vsplit __Potion_Bytecode__
normal! ggdG
endfunction
In lh-vim-lib, I have lh#buffer#jump() that does exactly that. It relies on another function to find a window where the buffer could be.
" Function: lh#buffer#find({filename}) {{{3
" If {filename} is opened in a window, jump to this window, otherwise return -1
function! lh#buffer#find(filename)
let b = bufwinnr(a:filename) " find the window where the buffer is opened
if b == -1 | return b | endif
exe b.'wincmd w' " jump to the window found
return b
endfunction
function! lh#buffer#jump(filename, cmd)
let b = lh#buffer#find(a:filename)
if b != -1 | return b | endif
call lh#window#create_window_with(a:cmd . ' ' . a:filename)
return winnr()
endfunction
Which uses another function to work around the extremely annoying E36:
" Function: lh#window#create_window_with(cmd) {{{3
" Since a few versions, vim throws a lot of E36 errors around:
" everytime we try to split from a windows where its height equals &winheight
" (the minimum height)
function! lh#window#create_window_with(cmd) abort
try
exe a:cmd
catch /E36:/
" Try again after an increase of the current window height
resize +1
exe a:cmd
endtry
endfunction
If you want to work with tabs, you'll have to use tab* functions instead.
I have this code taken from another StackOverflow user Conner, from this question Automatically quit Vim if NERDTree and TagList are the last and only buffers
(There wasn't an option for me to comment on that question, so my only option was to ask a new one).
The question is: How do I close Vim editor (in Linux Mint) if only NERDTree and TagList are the only two buffers left?
The answer provided was:
" If only 2 windows left, NERDTree and Tag_List, close vim or current tab
fun! NoExcitingBuffersLeft()
if winnr("$") == 3
let w1 = bufname(winbufnr(1))
let w2 = bufname(winbufnr(2))
let w3 = bufname(winbufnr(3))
if (exists(":NERDTree")) && (w1 == "__Tag_List__" || w2 == "__Tag_List__" || w3 == "__Tag_List__")
if tabpagenr("$") == 1
exec 'qa'
else
exec 'tabclose'
endif
endif
endif
endfun
autocmd BufWinLeave * call NoExcitingBuffersLeft()
But that does not work properly. Is closes whenever I close the last "exciting" buffer (one that is non-NERDTree or non-TagList), but it also closes whenever I try to open a new file from NERDTree (by double clicking on a filename in the "explorer").
Honestly, I do not understand this code too well. I have tried to mess around with it but I couldn't get the results I would like.
How do I alter this code to not close when I open a new file from NERDTree explorer?
Thank you, Conner, and the rest of the community!
From the Taglist manual, put on your .vimrc file
let Tlist_Exit_OnlyWindow=1
I don't use NERDTree, but you may succeed with the following
autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif
Basically, my .vimrc starts TagList and NERDTree when Vim is launched, as splits on the left and on the right of the normal file buffer.
I want to close Vim when, closing the last buffer/tab, TagList and NERDTree splits are the only remained. I'm already using vim-nerdtree-tabs and it works great when NERDTree is the only and last buffer open.
I'm aware that such topic has been discussed here on StackOverflow but I cannot find anything related to both NERDTree and TagList.
Thanks
let Tlist_Exit_OnlyWindow = 1
will close Tag_list window if it's the last window, look at http://vim-taglist.sourceforge.net/manual.html for more infomation about Tlist_Exit_OnlyWindow, I'm not sure if you are looking for this, if not, please delete my answer.
Something like... (untested)
fun! NoExcitingBuffersLeft()
if tabpagenr("$") == 1 && winnr("$") == 2
let window1 = bufname(winbufnr(1))
let window2 = bufname(winbufnr(2))
if (window1 == t:NERDTreeBufName || window1 == "__Tag_List__") &&
(window2 == t:NERDTreeBufName || window2 == "__Tag_List__")
quit
endif
endif
endfun
then tie that function to an autocommand...
au WinEnter * call NoExcitingBuffersLeft()<cr>
I don't use either of those plugins, so you may need to adjust the t:NERDTreeBufName and __Tag_List__.
Improving on Conner's idea, I've made a functional solution here.
" If only 2 windows left, NERDTree and Tag_List, close vim or current tab
fun! NoExcitingBuffersLeft()
if winnr("$") == 3
let w1 = bufname(winbufnr(1))
let w2 = bufname(winbufnr(2))
let w3 = bufname(winbufnr(3))
if (exists(":NERDTree")) && (w1 == "__Tag_List__" || w2 == "__Tag_List__" || w3 == "__Tag_List__")
if tabpagenr("$") == 1
exec 'qa'
else
exec 'tabclose'
endif
endif
endif
endfun
autocmd BufWinLeave * call NoExcitingBuffersLeft()
Need vim 7.0+ for the BufWinLeave event.
Closes the tab if more than one tab is open, otherwise quits vim.
This way, the auto-command is tied to when you close the last window that's not NERDTree or Tag_List, rather than upon entering one of the two windows.
This is nice extendable solution. To validate against other plugins/window types just add them to the regex check.
function! s:CloseAddons()
for w in range(1, winnr('$'))
if bufname(winbufnr(w)) !~# '__Tagbar\|NERD_tree_\|coc-explorer'
\ && getbufvar(winbufnr(w), "&buftype") !=? "quickfix"
return
endif
endfor
if tabpagenr('$') ==? 1
execute 'quitall'
else
execute 'tabclose'
endif
endfunction
I want vim to open up the :Explorer when no file is opened or created. Eg. when I call vim without any options.
calling vim newfile.txt should still behave the normal way though.
How would I go about doing this? I can't seem to find the correct autocmd for it.
If you want to do this for vim invocation only, the best way is to use argc():
autocmd VimEnter * :if argc() is 0 | Explore | endif
argc() function returns a number of filenames specified on command-line when vim was invoked unless something modified arguments list, more information at :h argc().
Found the answer myself:
"open to Explorer when no file is opened
function! TabIsEmpty()
" Remember which window we're in at the moment
let initial_win_num = winnr()
let win_count = 0
" Add the length of the file name on to count:
" this will be 0 if there is no file name
windo let win_count += len(expand('%'))
" Go back to the initial window
exe initial_win_num . "wincmd w"
" Check count
if win_count == 0
" Tab page is empty
return 1
else
return 0
endif
endfunction
" Test it like this:
" echo TabIsEmpty()
function! OpenExplorer()
if (TabIsEmpty())
:Explore
end
endfunction
The greatest part of this code was taken from this question.
I used nmap <silent> <f2> :NERDTreeToggle<cr> to toggle nerdtree window. How can I do the same with netrw?
nerdtree window is not shown in the buffer list(:ls). netrw is listed in the buffer list. How can I make it not listed?
:bn command works but :bp command does not work in the netrw window. Is this a bug?
The 'Vexplore' command opens a vertical directory browser. You can build on this by adding the following code to your .vimrc file to toggle the vertical browser with Ctrl-E (for example):
" Toggle Vexplore with Ctrl-E
function! ToggleVExplorer()
if exists("t:expl_buf_num")
let expl_win_num = bufwinnr(t:expl_buf_num)
if expl_win_num != -1
let cur_win_nr = winnr()
exec expl_win_num . 'wincmd w'
close
exec cur_win_nr . 'wincmd w'
unlet t:expl_buf_num
else
unlet t:expl_buf_num
endif
else
exec '1wincmd w'
Vexplore
let t:expl_buf_num = bufnr("%")
endif
endfunction
map <silent> <C-E> :call ToggleVExplorer()<CR>
The code above tries to open the Explorer window on the left hand side of the screen at all times; I use it with multiple split vertical windows open.
[OPTIONAL] You might like to add the following lines to your .vimrc to improve the browsing experience:
" Hit enter in the file browser to open the selected
" file with :vsplit to the right of the browser.
let g:netrw_browse_split = 4
let g:netrw_altv = 1
" Change directory to the current buffer when opening files.
set autochdir
Starting with netrw v150, there's :Lexplore, which will toggle a netrw window on the left-hand side.
I just did some improvements on Nick's solution which fixes:
opens 100% high window (independent from window splits)
:Lexplore opens it on left side, :Lexplore! on the right
listing the directory of the current file (even on remote directories)
Put these lines to the end of your .vimrc:
com! -nargs=* -bar -bang -complete=dir Lexplore call netrw#Lexplore(<q-args>, <bang>0)
fun! Lexplore(dir, right)
if exists("t:netrw_lexbufnr")
" close down netrw explorer window
let lexwinnr = bufwinnr(t:netrw_lexbufnr)
if lexwinnr != -1
let curwin = winnr()
exe lexwinnr."wincmd w"
close
exe curwin."wincmd w"
endif
unlet t:netrw_lexbufnr
else
" open netrw explorer window in the dir of current file
" (even on remote files)
let path = substitute(exists("b:netrw_curdir")? b:netrw_curdir : expand("%:p"), '^\(.*[/\\]\)[^/\\]*$','\1','e')
exe (a:right? "botright" : "topleft")." vertical ".((g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize) . " new"
if a:dir != ""
exe "Explore ".a:dir
else
exe "Explore ".path
endif
setlocal winfixwidth
let t:netrw_lexbufnr = bufnr("%")
endif
endfun
Suggested options to behave like NERDTree:
" absolute width of netrw window
let g:netrw_winsize = -28
" do not display info on the top of window
let g:netrw_banner = 0
" tree-view
let g:netrw_liststyle = 3
" sort is affecting only: directories on the top, files below
let g:netrw_sort_sequence = '[\/]$,*'
" use the previous window to open file
let g:netrw_browse_split = 4
Toggle function
Here is my version of toggle function, based on Nick's answer. Now you can use hotkey from any pane, not only from netrw's pane. In Nick's version it causes an error, also I did some code cleanup and remap it to Ctrl-O, because Ctrl-E is used by default to scroll down by one line.
" Toggle Vexplore with Ctrl-O
function! ToggleVExplorer()
if exists("t:expl_buf_num")
let expl_win_num = bufwinnr(t:expl_buf_num)
let cur_win_num = winnr()
if expl_win_num != -1
while expl_win_num != cur_win_num
exec "wincmd w"
let cur_win_num = winnr()
endwhile
close
endif
unlet t:expl_buf_num
else
Vexplore
let t:expl_buf_num = bufnr("%")
endif
endfunction
map <silent> <C-O> :call ToggleVExplorer()<CR>
Variable "t:expl_buf_num" is global for current tab, so you can have one Explorer per tab. You can change it to "w:expl_buf_num" if you want to be able to open Explorer in every window.
Keep focus in Explorer
Also I like to have this at my .vimrc:
" Open file, but keep focus in Explorer
autocmd filetype netrw nmap <c-a> <cr>:wincmd W<cr>
Actually,
let g:netrw_browse_split = 4
let g:netrw_altv = 1
works best for me.
*g:netrw_browse_split* when browsing, <cr> will open the file by:
=0: re-using the same window
=1: horizontally splitting the window first
=2: vertically splitting the window first
=3: open file in new tab
=4: act like "P" (ie. open previous window)
Note that |g:netrw_preview| may be used
to get vertical splitting instead of
horizontal splitting.
I think the best behavior is described by option 4. By pressing enter, file is opened on the other split, avoiding an overpopulation of splits.
" Toggle Vexplore with Ctrl-E
function! ToggleVExplorer()
Lexplore
vertical resize 30
endfunction
map <silent> <C-E> :call ToggleVExplorer()<CR>
Simplify
As a similar and simpler aprroach to Nick's, you could make it toggleable (and very NERDTree-like) with F9 with this in your .vimrc:
" ---------------------------------------------------------------
" File Explorer start
let g:netrw_banner = 0
let g:netrw_liststyle = 3
let g:netrw_browse_split = 4
let g:netrw_altv = 1
let g:netrw_winsize = 15
" Toggle Vexplore with F9
map <silent> <F9> :Lexplore<CR>
" File Explorer end
" ---------------------------------------------------------------