Setting netrw like NERDTree - vim

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
" ---------------------------------------------------------------

Related

Keep netrw view after closed just like nerdtree in VIM

Here's my netrw settings, I toggle netrw with <F2>.
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 = 20
set autochdir
" Toggle Vexplore with <F2>
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 <F2> :call ToggleVExplorer()<CR>
This is the first view I open netrw:
Then I do some operations in netrw just like this.
But when toggle happened, the operations I did disappear.
Can anyone who knows about netrw help me solve this problem? I have been confused for two months. SOS!
I hope when I open netrw again, I can see the view when I leave netrw. I know that if I don't close netrw it will not clean my operation when switch to other buffers, but sometimes I have to close it temporarily due to valuable screen space.

set name to window and reference to it with command

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

Vim - show diff on commit in mercurial;

In my .hgrc I can provide an editor or a command to launch an editor with options on commit.
I want to write a method or alias that launches $ hg ci, it would not only open up message in Vim, but also would split window and there print out $ hg diff.
I know that I can give parameters to vim by using +{command} option. So launching $ vim "+vsplit" does the split but any other options goes to first opened window. So I assume i need a specific function, yet I have no experience in writing my own Vim scripts.
The script should:
Open new vertical split with empty buffer (with vnew possibly)
In empty buffer launch :.!hg diff
Set empty buffer file type as diff :set ft=diff
I've written such function:
function! HgCiDiff()
vnew
:.!hg diff
set ft=diff
endfunction
And in .hgrc I've added option: editor = vim "+HgCiDiff()"
It kind of works, but I would like that splited window would be in right side (now it opens up in left) and mercurial message would be focused window. Also :wq could be setted as temporary shortcut to :wq<CR>:q! (having an assumption that mercurial message is is focused).
Any suggestions to make this a bit more useful and less chunky?
UPDATE: I found vim split guide so changing vnew with rightbelow vnew opens up diff on the right side.
So I expanded my own code:
function! HgCiDiff()
"In .hgrc editor option I call vim "+HgCiDiff()"
"It opens new split with diff inside
rightbelow vnew
:.!hg diff
set ft=diff
saveas! /tmp/hgdiff.txt
execute "normal \<c-w>w"
endfunction
Yet It missed :wq mapping as :wqa, yet using :wqa is not that hard.
Sources of my vimrc is located here: http://hg.jackleo.info/vim-configs/src/08df5cb9d143/vimrc
Sources of my hgrc is located here: http://hg.jackleo.info/home-configs/src/22f5fb47a7d2/.hgrc
Update: as suggested by Randy Morris I updated my code and now it works just as I wanted. Thanks! Also added few extra features as the time went by.
function! HgCiDiff()
"In .hgrc editor option I call vim "+HgCiDiff()"
"It opens new split with diff inside
rightbelow vnew
setlocal buftype=nofile
:.!hg diff
setlocal ft=diff
wincmd p
setlocal spell spelllang=en_us
cnoremap wq wqa
cnoremap q qa
start
endfunction
Edit
Hmm I think this might not be what you are after on second reading. I understand you want a multi-file (unified) diff. I'd really use a hg-aware UI tool and a separate vim editor for the commit message. Sorry about that.
I'll leave the 'original' response stand in case you didn't know VCSCommand + Hg + Vim yet:
My weapon of choice is to abstract it all away with
vcscommand.vim : CVS/SVN/SVK/git/hg/bzr integration plugin
You would
:VCSVimDiff
to diffsplit against the repo version (also with Leadercv)
:VCSVimDiff <revid>
to compare against a specific revision.
My solution consists of three vim files. It doesn't require hg configuration changes, and only shows the diff for the files you're committing, if you've used hg commit file1 file2:
~/.vim/ftdetect/hg.vim
au BufRead,BufNewFile /tmp/hg-editor-*.txt set filetype=hg
~/.vim/syntax/hg.vim
" Vim syntax file
" Language: hg commit file
" Maintainer: Marius Gedminas <marius#gedmin.as>
" Filenames: /tmp/hg-editor-*.txt
" Last Change: 2012 July 8
" Based on gitcommit.vim by Tim Pope
if exists("b:current_syntax")
finish
endif
syn case match
syn sync minlines=50
if has("spell")
syn spell toplevel
endif
syn match hgComment "^HG: .*"
hi def link hgComment Comment
let b:current_syntax = "hg"
~/.vim/ftplugin/hg.vim
" Show diff while editing a Mercurial commit message
" Inspired by http://stackoverflow.com/questions/8009333/vim-show-diff-on-commit-in-mercurial
" and Michael Scherer' svn.vim
function! HgCiDiff()
let i = 0
let list_of_files = ''
while i <= line('$') && getline(i) != 'HG: --'
let i = i + 1
endwhile
while i <= line('$')
let line = getline(i)
if line =~ '^HG: \(added\|changed\)'
let file = substitute(line, '^HG: \(added\|changed\) ', '', '')
let file = "'".substitute(file, "'", "'\''", '')."'"
let list_of_files = list_of_files . ' '.file
endif
let i = i + 1
endwhile
if list_of_files == ""
return
endif
pclose
new
setlocal ft=diff previewwindow bufhidden=delete nobackup noswf nobuflisted nowrap buftype=nofile
silent exec ':0r!hg diff ' . list_of_files
setlocal nomodifiable
goto 1
redraw!
" nooo idea why I have to do this
syn enable
endfunction
call HgCiDiff()
Here's my variation based on Marius Gedminas and JackLeo's versions:
function! HgCiDiff()
" find files that were changed (not interested in added or deleted)
let changed_files = []
let pattern = '\vHG: changed \zs(.+)\ze'
while search("HG: changed", "W") > 0
let line_text = getline(line("."))
call add(changed_files, matchstr(line_text, pattern))
endwhile
let diff_cmd = "hg diff " . join(changed_files, " ")
" Reset cursor to beginning of the buffer
call cursor(1, 1)
rightbelow vnew
setlocal buftype=nofile
let diff_output = system(diff_cmd)
call append(0, split(diff_output, "\n"))
" Reset cursor to beginning of the buffer
call cursor(1, 1)
setlocal ft=diff
wincmd p
setlocal spell spelllang=en_us
cnoremap wq wqa
cnoremap q qa!
startinsert
endfunction

How to open or close NERDTree and Tagbar with <leader>\?

I want <leader>\ to open or close NERDTree and Tagbar, under the following conditions:
Only close both if NERDTree and Tagbar are both opened
Open both if NERDTree and Tagbar are closed OR if one is already opened
So far, in VIMRC, I have:
nmap <leader>\ :NERDTreeToggle<CR> :TagbarToggle<CR>
Which doesn't exactly work, since if one is opened, and the other closed. It would open the one that was closed and close the one that was opened.
How can this be achieved?
You need to use a function that checks whether the plugin windows are open or not and then acts accordingly. This should work and will also jump back to the window that you started in:
function! ToggleNERDTreeAndTagbar()
let w:jumpbacktohere = 1
" Detect which plugins are open
if exists('t:NERDTreeBufName')
let nerdtree_open = bufwinnr(t:NERDTreeBufName) != -1
else
let nerdtree_open = 0
endif
let tagbar_open = bufwinnr('__Tagbar__') != -1
" Perform the appropriate action
if nerdtree_open && tagbar_open
NERDTreeClose
TagbarClose
elseif nerdtree_open
TagbarOpen
elseif tagbar_open
NERDTree
else
NERDTree
TagbarOpen
endif
" Jump back to the original window
for window in range(1, winnr('$'))
execute window . 'wincmd w'
if exists('w:jumpbacktohere')
unlet w:jumpbacktohere
break
endif
endfor
endfunction
nnoremap <leader>\ :call ToggleNERDTreeAndTagbar()<CR>
hmm... this works for me in vimrc
The toggle option checks if the window already exists, so no custom function needed (#JanLarres or one of the contributors) must have added it to TagBar :D
" NERDTree
map <leader>n :NERDTreeToggle<CR>
" TagBar
map <leader>t :TagbarToggle<CR>

Switch to last-active tab in VIM

In Vim, is there a way to quickly toggle between the current tab and the last-active tab? Sort of the way '' toggles between the current line and the last-active line. Plugins / keyboard mappings / voodoo all acceptable.
Put this in your .vimrc:
if !exists('g:lasttab')
let g:lasttab = 1
endif
nmap <Leader>tl :exe "tabn ".g:lasttab<CR>
au TabLeave * let g:lasttab = tabpagenr()
Then, in normal mode, type \tl to swap to the tab you viewed last.
Fix the potential issue when a tab is closed:
" Switch to last-active tab
if !exists('g:Lasttab')
let g:Lasttab = 1
let g:Lasttab_backup = 1
endif
autocmd! TabLeave * let g:Lasttab_backup = g:Lasttab | let g:Lasttab = tabpagenr()
autocmd! TabClosed * let g:Lasttab = g:Lasttab_backup
nmap <silent> <Leader>` :exe "tabn " . g:Lasttab<cr>
I use buffers and not tabs, but I am able to switch between the current and latest used buffer using :b#
Basics of using buffers are:
:e filename to open file in new buffer
:bn to go to next buffer
:bp to go to previous buffer
:bd to close current buffer
here's a solution in lua for folks that uses neovim also make sure to change <A-S-b> to your favorite keybinding.
-- switching to last active tab
vim.api.nvim_create_autocmd("TabLeave", {
pattern = "*",
callback = function()
vim.api.nvim_set_keymap('n', '<A-S-b>', '<cmd>tabn ' .. vim.api.nvim_tabpage_get_number(0) .. '<CR>', { noremap = true, silent = true })
end
})

Resources