Last active
May 18, 2023 08:31
-
-
Save jaandrle/d0ce92e67d03dd8da4b7b932b379b879 to your computer and use it in GitHub Desktop.
Just “Explorer” part
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# For inspiration | |
augroup netrw_mapping | |
autocmd! | |
autocmd filetype netrw call <sid>OnNetrwEnter() | |
augroup END | |
function s:OnNetrwEnter() | |
nmap <buffer> <leader>e :bd\|Vifm<cr> | |
endfunction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*vifm-plugin.txt* For Vifm version 0.12 Last change: 2021 Oct 04 | |
Email for bugs and suggestions: <andrle.jan@centrum.cz> (original plugin <xaizek@posteo.net>) | |
Using the vifm.vim plugin~ | |
vifm-plugin for using vifm in Vim as a file selector. | |
Commands: | |
*vifm-:VifmToEdit* | |
:EditVifm select a file or files to open in the current buffer. | |
*vifm-:Vifm* | |
:Vifm alias for :VifmToEdit. | |
*vifm-:VifmToSplit* | |
:SplitVifm split buffer and select a file or files to open. | |
*vifm-:VifmToVsplit* | |
:VsplitVifm vertically split buffer and select a file or files to open. | |
*vifm-:DiffVifm* | |
:DiffVifm select a file or files to compare to the current file with | |
:vert diffsplit. | |
*vifm-:VifmToTab* | |
:TabVifm select a file or files to open in tabs. | |
Each command accepts up to two arguments: left pane directory and right pane | |
directory. After arguments are checked, vifm process is spawned in a special | |
"file-picker" mode. To pick files just open them either by pressing l, i or | |
Enter keys, or by running :edit command. If no files are selected, file | |
under the cursor is opened, otherwise whole selection is passed to the plugin | |
and opened in Vim. | |
Once vifm is opened additional commands that correspond to commands listed | |
above become available: | |
:VimToEdit | |
:VimToVsplit | |
:VimToSplit | |
:VimToDiff | |
:VimToTab | |
Their meaning is the same as the meaning of Vifm*, but these commands overrule | |
their Vifm* command used to start vifm. *Vifm basically provide default, | |
which can be overwritten right on file open. | |
Installing and disabling~ | |
To use the plugin copy the vifm.vim file to either the system wide vim/plugin | |
directory or into ~/.vim/plugin. | |
If you would prefer not to use the plugin and it is in the system wide plugin | |
directory add > | |
let loaded_vifm=1 | |
to your ~/.vimrc file. | |
Configuration variables~ | |
*g:vifm_exec* | |
A string variable. Equals "vifm" by default and specifies path to vifm's | |
executable. | |
*g:vifm_exec_args* | |
A string variable that specifies arguments for vifm. Empty by default. | |
*g:vifm_term* | |
A string variable that specifies command to run GUI terminal. | |
By default it's equal to 'xterm -e'. | |
*g:vifm_embed_term* | |
A boolean variable. When evaluates to true and it's possible to create a | |
terminal buffer, it will be used. Enabled by default inside GUI version. | |
Effectively always enabled in neovim. | |
*g:vifm_embed_split* | |
A boolean variable. When evaluates to true and Vifm is embedded in a | |
terminal, it will be run inside a new split. This allows commands to support | |
Vim's |<mod>| and a |<count>| for controlling the orientation and size of the | |
split, making it possible to run a command inside of Vim such as: | |
- `:vertical Vifm` | |
- `:leftabove vertical 60Vifm` | |
See `:help :command-modifiers` for Vim's command modifiers documentation. | |
False by default. | |
*g:vifm_embed_cwd* | |
{not on MS-Windows} | |
A boolean variable. When evaluates to true and Vifm is embedded in a | |
terminal, vifm will change the active directory in vim while navigating. | |
False by default. | |
*g:vifm_replace_netrw* | |
A boolean variable. When enabling this, don't forget to disable the |netrw| | |
plugin (see `:h netrw-noload`), otherwise it can interfere with this plugin | |
opening directories using vifm. Defaults to false. | |
*g:vifm_replace_netrw_cmd* | |
A string variable. The command to use to open folders when | |
g:vifm_replace_netrw is enabled. Defaults to "Vifm". |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" Use Vifm as Explore inside Vim | |
" From https://gist.github.com/jaandrle/d0ce92e67d03dd8da4b7b932b379b879 | |
" Originally see https://github.com/vifm/vifm.vim (vifm syntax, config, rename, cmd-line support and so on) | |
if exists('loaded_vifm') | |
finish | |
endif | |
let loaded_vifm = 1 | |
" Remember path to the script to know where to look for vifm documentation. | |
let s:script_path = expand('<sfile>') | |
" Setup commands to run vifm. | |
" :VifmToEdit - open file or files in current buffer. | |
" :VifmToPedit - open file in preview window. | |
" :VifmToSplit - split buffer and open file or files. | |
" :VifmToVsplit - vertically split buffer and open file or files. | |
" :VifmToDiff - load file for :vert diffsplit. | |
" :VifmToTab - load file or files in tabs. | |
" Check whether :drop command is available. Do not use exist(':drop'), it's | |
" deceptive. | |
let s:has_drop = 0 | |
try | |
drop | |
catch /E471:/ " argument required | |
let s:has_drop = 1 | |
catch /E319:/ " command is not available | |
catch /E492:/ " not an editor command | |
endtry | |
let s:tab_drop_cmd = (s:has_drop ? 'tablast | tab drop' : 'tabedit') | |
command! -bar -nargs=* -count -complete=dir Vifm | |
\ :call s:StartVifm('<mods>', <count>, 'edit', <f-args>) | |
command! -bar -nargs=* -count -complete=dir VifmToEdit | |
\ :call s:StartVifm('<mods>', <count>, 'edit', <f-args>) | |
command! -bar -nargs=* -count -complete=dir VifmToPedit | |
\ :call s:StartVifm('<mods>', <count>, 'pedit', <f-args>) | |
command! -bar -nargs=* -count -complete=dir VifmToVsplit | |
\ :call s:StartVifm('<mods>', <count>, 'vsplit', <f-args>) | |
command! -bar -nargs=* -count -complete=dir VifmToSplit | |
\ :call s:StartVifm('<mods>', <count>, 'split', <f-args>) | |
command! -bar -nargs=* -count -complete=dir VifmToDiff | |
\ :call s:StartVifm('<mods>', <count>, 'vert diffsplit', <f-args>) | |
command! -bar -nargs=* -count -complete=dir VifmToTab | |
\ :call s:StartVifm('<mods>', <count>, s:tab_drop_cmd, <f-args>) | |
function! s:StartVifm(mods, count, editcmd, ...) abort | |
echoerr 'vifm executable wasn''t found' | |
endfunction | |
if !exists('g:vifm_term') | |
if has('win32') | |
if filereadable('C:\Windows\system32\cmd.exe') | |
let g:vifm_term = 'C:\Windows\system32\cmd.exe /C' | |
else | |
" If don't find use the integrate shell it work too | |
let g:vifm_term = '' | |
endif | |
else | |
let g:vifm_term = 'xterm -e' | |
endif | |
endif | |
if !exists('g:vifm_embed_term') | |
let g:vifm_embed_term = has('gui_running') | |
endif | |
if !exists('g:vifm_exec') | |
let g:vifm_exec = 'vifm' | |
endif | |
if !exists('g:vifm_exec_args') | |
let g:vifm_exec_args = '' | |
endif | |
if !has('nvim') && exists('*term_start') | |
function! VifmExitCb(data, job, code) abort | |
let data = a:data | |
if (bufnr('%') == bufnr('#') || !bufexists(0)) && !data.split | |
enew | |
else | |
silent! buffer # | |
endif | |
silent! bdelete! # | |
if data.split | |
silent! close | |
endif | |
if has('job') && type(data.cwdjob) == v:t_job | |
call job_stop(data.cwdjob) | |
endif | |
call s:HandleRunResults(a:code, data.listf, data.typef, data.editcmd) | |
endfunction | |
endif | |
function s:DetermineTermEnv() abort | |
if !has('gui_running') | |
return (&term =~ 256 ? 'xterm-256color' : &term) | |
endif | |
if empty($TERM) || $TERM == 'dumb' | |
return 'xterm-256color' | |
endif | |
return $TERM | |
endfunction | |
function! s:StartVifm(mods, count, editcmd, ...) abort | |
if a:0 > 2 | |
echoerr 'Too many arguments' | |
return | |
endif | |
let embed = has('nvim') || exists('*term_start') && g:vifm_embed_term | |
let ldir = (a:0 > 0) ? a:1 : expand('%:p:h') | |
let ldir = s:PreparePath(ldir) | |
let rdir = (a:0 > 1) ? a:2 : '' | |
let rdir = s:PreparePath(rdir) | |
let listf = tempname() | |
let typef = tempname() | |
" XXX: this is horrible, but had to do this to work around selection | |
" clearing after each command-line command (:let in this case) | |
let edit = ' | execute ''cnoremap j <cr>'' | normal gs:editj' | |
let pickargs = [ | |
\ '--choose-files', listf, | |
\ '--on-choose', | |
\ has('win32') | |
\ ? 'echo \"%%VIFM_OPEN_TYPE%%\">' . typef : 'echo $VIFM_OPEN_TYPE >' . typef, | |
\ '+command VimToEdit :let $VIFM_OPEN_TYPE=''edit''' . edit, | |
\ '+command VimToVsplit :let $VIFM_OPEN_TYPE=''vsplit''' . edit, | |
\ '+command VimToSplit :let $VIFM_OPEN_TYPE=''split''' . edit, | |
\ '+command VimToDiff :let $VIFM_OPEN_TYPE=''vert diffsplit''' . edit, | |
\ '+command VimToPedit :let $VIFM_OPEN_TYPE=''pedit''' . edit, | |
\ '+command VimToTab :let $VIFM_OPEN_TYPE='''.s:tab_drop_cmd."'" . edit] | |
call map(pickargs, embed ? 'shellescape(v:val)' : 'shellescape(v:val, 1)') | |
let pickargsstr = join(pickargs, ' ') | |
" Use embedded terminal if available. | |
if embed | |
let [cwdf, cwdjob] = s:StartCwdJob() | |
if cwdf != '' | |
let cwdargs = '-c "autocmd DirEnter * !pwd >> ' . shellescape(cwdf) . '"' | |
else | |
let cwdargs = '' | |
endif | |
let data = { 'listf' : listf, 'typef' : typef, 'editcmd' : a:editcmd, | |
\ 'cwdjob' : cwdjob, 'split': get(g:, 'vifm_embed_split', 0) } | |
if !has('nvim') | |
let env = { 'TERM' : s:DetermineTermEnv() } | |
let options = { 'term_name' : 'vifm: '.a:editcmd, 'curwin' : 1, | |
\ 'exit_cb': funcref('VifmExitCb', [data]), 'env' : env } | |
else | |
function! data.on_exit(id, code, event) abort | |
if (bufnr('%') == bufnr('#') || !bufexists(0)) && !self.split | |
enew | |
else | |
silent! buffer # | |
endif | |
silent! bdelete! # | |
if self.split | |
silent! close | |
endif | |
if self.cwdjob != 0 | |
call jobstop(self.cwdjob) | |
endif | |
call s:HandleRunResults(a:code, self.listf, self.typef, self.editcmd) | |
endfunction | |
endif | |
if data.split | |
exec a:mods . ' ' . (a:count ? a:count : '') . 'new' | |
else | |
enew | |
endif | |
let termcmd = g:vifm_exec.' '.g:vifm_exec_args.' '.cwdargs.' '.ldir.' ' | |
\ .rdir.' '.pickargsstr | |
if !has('nvim') | |
if has('win32') | |
keepalt let buf = term_start(termcmd, options) | |
else | |
keepalt let buf = term_start(['/bin/sh', '-c', termcmd], options) | |
endif | |
else | |
call termopen(termcmd, data) | |
let oldbuf = bufname('%') | |
execute 'keepalt file' escape('vifm: '.a:editcmd, ' |') | |
" This is for Neovim, which uses these options even in terminal mode | |
setlocal nonumber norelativenumber nospell | |
execute bufnr(oldbuf).'bwipeout' | |
" Use execute to not break highlighting. | |
execute 'startinsert' | |
endif | |
return | |
else | |
" Gvim cannot handle ncurses so run vifm in a terminal. | |
if has('gui_running') | |
execute 'silent noautocmd !' | |
\ g:vifm_term g:vifm_exec g:vifm_exec_args ldir rdir pickargsstr | |
else | |
execute 'silent noautocmd !' | |
\ g:vifm_exec g:vifm_exec_args ldir rdir pickargsstr | |
endif | |
" Execution of external command might have left Vim's window cleared, force | |
" redraw before doing anything else. | |
redraw! | |
call s:HandleRunResults(v:shell_error, listf, typef, a:editcmd) | |
endif | |
endfunction | |
function! s:StartCwdJob() abort | |
if get(g:, 'vifm_embed_cwd', 0) && (has('job') || has('nvim')) | |
let cwdf = tempname() | |
silent! exec '!mkfifo '. cwdf | |
let cwdcmd = ['/bin/sh', '-c', | |
\ 'while true; do cat ' . shellescape(cwdf) . '; done'] | |
if !has('nvim') | |
let cwdopts = { 'out_cb': 'VifmCwdCb' } | |
function! VifmCwdCb(channel, data) abort | |
call s:HandleCwdOut(a:data) | |
endfunction | |
let cwdjob = job_start(cwdcmd, cwdopts) | |
else | |
let cwdopts = {} | |
function! cwdopts.on_stdout(id, data, event) abort | |
if a:data[0] ==# '' | |
return | |
endif | |
call s:HandleCwdOut(a:data[0]) | |
endfunction | |
let cwdjob = jobstart(cwdcmd, cwdopts) | |
endif | |
return [cwdf, cwdjob] | |
endif | |
return ['', 0] | |
endfunction | |
function! s:HandleCwdOut(data) abort | |
exec 'cd ' . fnameescape(a:data) | |
endfunction | |
function! s:HandleRunResults(exitcode, listf, typef, editcmd) abort | |
if a:exitcode != 0 | |
echoerr 'Got non-zero code from vifm: ' . a:exitcode | |
call delete(a:listf) | |
call delete(a:typef) | |
return | |
endif | |
" The selected files are written and read from a file instead of using | |
" vim's clientserver so that it will work in the console without a X server | |
" running. | |
if !file_readable(a:listf) | |
echoerr 'Failed to read list of files' | |
call delete(a:listf) | |
call delete(a:typef) | |
return | |
endif | |
let flist = readfile(a:listf) | |
call delete(a:listf) | |
let opentype = file_readable(a:typef) ? readfile(a:typef) : [] | |
call delete(a:typef) | |
" User exits vifm without selecting a file. | |
if empty(flist) | |
echohl WarningMsg | echo 'No file selected' | echohl None | |
return | |
endif | |
let unescaped_firstfile = flist[0] | |
call map(flist, 'fnameescape(v:val)') | |
let firstfile = flist[0] | |
if !empty(opentype) && !empty(opentype[0]) && | |
\ opentype[0] != '"%VIFM_OPEN_TYPE%"' | |
let editcmd = has('win32') ? opentype[0][1:-2] : opentype[0] | |
else | |
let editcmd = a:editcmd | |
endif | |
" Don't split if current window is empty | |
if empty(expand('%')) && editcmd =~ '^v\?split$' | |
execute 'edit' fnamemodify(flist[0], ':.') | |
let flist = flist[1:-1] | |
if len(flist) == 0 | |
return | |
endif | |
endif | |
" We emulate :args to not leave unnamed buffer around after we open our | |
" buffers. | |
if editcmd == 'edit' && len(flist) > 1 | |
silent! %argdelete | |
endif | |
" Doesn't make sense to run :pedit multiple times in a row. | |
if editcmd == 'pedit' && len(flist) > 1 | |
let flist = [ flist[0] ] | |
endif | |
for file in flist | |
execute editcmd fnamemodify(file, ':.') | |
if editcmd == 'edit' && len(flist) > 1 | |
execute 'argadd' fnamemodify(file, ':.') | |
endif | |
endfor | |
" When we open a single file, there is no need to navigate to its window, | |
" because we're already there | |
if len(flist) == 1 | |
return | |
endif | |
" Go to the first file working around possibility that :drop command is not | |
" evailable, if possible | |
if editcmd == 'edit' || !s:has_drop | |
" Linked folders must be resolved to successfully call 'buffer' | |
let firstfile = unescaped_firstfile | |
let firstfile = resolve(fnamemodify(firstfile, ':h')) | |
\ .'/'.fnamemodify(firstfile, ':t') | |
let firstfile = fnameescape(firstfile) | |
execute 'buffer' fnamemodify(firstfile, ':.') | |
elseif s:has_drop | |
" Mind that drop replaces arglist, so don't use it with :edit. | |
execute 'drop' firstfile | |
endif | |
endfunction | |
function! s:PreparePath(path) abort | |
let path = substitute(a:path, '\', '/', 'g') | |
if !isdirectory(path) | |
" For example, we were' in a terminal buffer whose name isn't a path | |
let path = '' | |
endif | |
if has('win32') | |
if len(path) != 0 | |
let path = '"'.path.'"' | |
endif | |
else | |
let path = escape(fnameescape(path), '()') | |
endif | |
return path | |
endfunction | |
if get(g:, 'vifm_replace_netrw') | |
function! s:HandleBufEnter(fname) abort | |
if a:fname !=# '' && isdirectory(a:fname) | |
if bufexists(0) | |
buffer # | |
else | |
enew | |
endif | |
silent! bdelete! # | |
let embed_split = get(g:, 'vifm_embed_split', 0) | |
let g:vifm_embed_split = 0 | |
exec get(g:, 'vifm_replace_netrw_cmd', 'Vifm') . ' ' . a:fname | |
let g:vifm_embed_split = embed_split | |
endif | |
endfunction | |
augroup neovimvifm | |
au BufEnter * silent call s:HandleBufEnter(expand('<amatch>')) | |
augroup END | |
endif | |
" vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab : |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment