| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585 |
- let s:srcdir = expand('<sfile>:h:h:p')
- let s:sep = exists('+shellslash') && !&shellslash ? '\' : '/'
- let s:noswapfile = (2 == exists(':noswapfile')) ? 'noswapfile' : ''
- let s:noau = 'silent noautocmd keepjumps'
- let s:cb_map = {} " callback map
- let s:rel = get(g:, 'dirvish_relative_paths', 0)
- " Debug:
- " echo '' > dirvish.log ; tail -F dirvish.log
- " nvim +"let g:dirvish_dbg=1" -- b1 b2
- " :bnext
- " -
- if get(g:, 'dirvish_dbg')
- func! s:log(msg, ...) abort
- call writefile([a:msg], expand('~/dirvish.log'), 'as')
- endf
- else
- func! s:log(msg, ...) abort
- endf
- endif
- func! s:msg_error(msg) abort
- redraw | echohl ErrorMsg | echomsg 'dirvish:' a:msg | echohl None
- endf
- func! s:eq(dir1, dir2) abort
- return fnamemodify(a:dir1, ':p') ==# fnamemodify(a:dir2, ':p')
- endf
- " Gets full path, or relative if g:dirvish_relative_paths=1.
- func! s:f(f) abort
- let f = fnamemodify(a:f, s:rel ? ':p:.' : ':p')
- " Special case: ":p:." yields empty for CWD.
- return !empty(f) ? f : fnamemodify(a:f, ':p')
- endf
- func! s:suf() abort
- let m = get(g:, 'dirvish_mode', 1)
- return type(m) == type(0) && m <= 1 ? 1 : 0
- endf
- " Normalizes slashes:
- " - Replace "\" with "/", for safe use of fnameescape(), isdirectory(). Vim bug #541.
- " - Collapse slashes (except UNC-style \\foo\bar).
- " - Always end dir with "/".
- " - Special case: empty string (CWD) => "./".
- func! s:sl(f) abort
- let f = has('win32') ? tr(a:f, '\', '/') : a:f
- " Collapse slashes (except UNC-style \\foo\bar).
- let f = f[0] . substitute(f[1:], '/\+', '/', 'g')
- " End with separator.
- return empty(f) ? './' : (f[-1:] !=# '/' && isdirectory(f) ? f.'/' : f)
- endf
- " Workaround for platform quirks, and shows an error if dir is invalid.
- func! s:fix_dir(dir, silent) abort
- let dir = s:sl(a:dir)
- if !isdirectory(dir)
- " Fallback for cygwin/MSYS paths lacking a drive letter.
- let dir = empty($SYSTEMDRIVE) ? dir : '/'.tolower($SYSTEMDRIVE[0]).(dir)
- if !isdirectory(dir)
- if !a:silent
- call s:msg_error("invalid directory: '".a:dir."'")
- endif
- return ''
- endif
- endif
- return dir
- endf
- func! s:parent_dir(f) abort
- let f_noslash = substitute(a:f, escape(s:sep == '\'?'[/\]':'/','\').'\+$', '', 'g')
- return s:fix_dir(fnamemodify(f_noslash, ':h'), 0)
- endf
- if v:version > 704 || v:version == 704 && has('patch279')
- func! s:globlist(dir_esc, pat) abort
- return globpath(a:dir_esc, a:pat, !s:suf(), 1)
- endf
- else " Older versions cannot handle filenames containing newlines.
- func! s:globlist(dir_esc, pat) abort
- return split(globpath(a:dir_esc, a:pat, !s:suf()), "\n")
- endf
- endif
- func! s:list_dir(dir) abort
- let s:rel = get(g:, 'dirvish_relative_paths', 0)
- " Escape for globpath().
- let dir_esc = escape(substitute(a:dir,'\[','[[]','g'), ',;*?{}^$\')
- let paths = s:globlist(dir_esc, '*')
- "Append dot-prefixed files. globpath() cannot do both in 1 pass.
- let paths = paths + s:globlist(dir_esc, '.[^.]*')
- if s:rel && !s:eq(a:dir, s:parent_dir(s:sl(getcwd()))) " Avoid blank CWD.
- return map(paths, "fnamemodify(v:val, ':p:.')")
- else
- return map(paths, "fnamemodify(v:val, ':p')")
- endif
- endf
- func! s:info(paths, dirsize) abort
- for f in a:paths
- " Slash decides how getftype() classifies directory symlinks. #138
- let noslash = substitute(f, escape(s:sep,'\').'$', '', 'g')
- let fname = len(a:paths) < 2 ? '' : printf('%12.12s ',fnamemodify(substitute(f,'[\\/]\+$','',''),':t'))
- let size = (-1 != getfsize(f) && a:dirsize ? matchstr(system('du -hs '.shellescape(f)),'\S\+') : printf('%.2f',getfsize(f)/1000.0).'K')
- echo (-1 == getfsize(f) ? '?' : (fname.(getftype(noslash)[0]).' '.getfperm(f)
- \.' '.strftime('%Y-%m-%d.%H:%M:%S',getftime(f)).' '.size).('link'!=#getftype(noslash)?'':' -> '.fnamemodify(resolve(f),':~:.')))
- endfor
- endf
- func! s:set_args(args) abort
- if exists('*arglistid') && arglistid() == 0
- arglocal
- endif
- let normalized_argv = map(argv(), 'fnamemodify(v:val, ":p")')
- for f in a:args
- let i = index(normalized_argv, f)
- if -1 == i
- exe '$argadd '.fnameescape(fnamemodify(f, ':p'))
- elseif 1 == len(a:args)
- exe (i+1).'argdelete'
- syntax clear DirvishArg
- endif
- endfor
- echo 'arglist: '.argc().' files'
- " Define (again) DirvishArg syntax group.
- exe 'source '.fnameescape(s:srcdir.'/syntax/dirvish.vim')
- endf
- func! dirvish#shdo(paths, cmd) abort
- " Remove empty/duplicate lines.
- let lines = uniq(sort(filter(copy(a:paths), '-1!=match(v:val,"\\S")')))
- let head = fnamemodify(get(lines, 0, '')[:-2], ':h')
- let jagged = 0 != len(filter(copy(lines), 'head != fnamemodify(v:val[:-2], ":h")'))
- if empty(lines) | call s:msg_error('Shdo: no files') | return | endif
- let dirvish_bufnr = bufnr('%')
- let cmd = a:cmd =~# '\V{}' ? a:cmd : (empty(a:cmd)?'{}':(a:cmd.' {}')) "DWIM
- " Paths from argv() or non-dirvish buffers may be jagged; assume CWD then.
- let dir = jagged ? getcwd() : head
- let tmpfile = tempname().(&sh=~?'cmd.exe'?'.bat':(&sh=~'\(powershell\|pwsh\)'?'.ps1':'.sh'))
- for i in range(0, len(lines)-1)
- let f = substitute(lines[i], escape(s:sep,'\').'$', '', 'g') "trim slash
- if !filereadable(f) && !isdirectory(f)
- let lines[i] = '#invalid path: '.shellescape(f)
- continue
- endif
- let f = !jagged && 2==exists(':lcd') ? fnamemodify(f, ':t') : lines[i]
- let lines[i] = substitute(cmd, '\V{}', escape(shellescape(f),'&\'), 'g')
- endfor
- execute 'silent split' tmpfile '|' (2==exists(':lcd')?('lcd '.dir):'')
- setlocal bufhidden=wipe
- silent keepmarks keepjumps call setline(1, lines)
- silent write
- if executable('chmod')
- call system('chmod u+x '.tmpfile)
- silent edit
- endif
- augroup dirvish_shcmd
- autocmd! * <buffer>
- " Refresh Dirvish after executing a shell command.
- exe 'autocmd ShellCmdPost <buffer> nested if !v:shell_error && bufexists('.dirvish_bufnr.')'
- \.'|setlocal bufhidden=hide|buffer '.dirvish_bufnr.'|silent! Dirvish'
- \.'|buffer '.bufnr('%').'|setlocal bufhidden=wipe|endif'
- augroup END
- nnoremap <buffer><silent> Z! :silent write<Bar>exe '!'.(has('win32')?fnameescape(escape(expand('%:p:gs?\\?/?'), '&\')):join(map(split(&shell), 'shellescape(v:val)')).' %')<Bar>if !v:shell_error<Bar>close<Bar>endif<CR>
- endf
- " Returns true if the buffer was modified by the user.
- func! s:buf_modified() abort
- return b:changedtick > get(b:dirvish, '_c', b:changedtick)
- endf
- func! s:buf_init() abort
- augroup dirvish_buflocal
- autocmd! * <buffer>
- autocmd BufEnter,WinEnter <buffer> call <SID>on_bufenter()
- if exists('##TextChanged')
- autocmd TextChanged,TextChangedI <buffer> if <SID>buf_modified()
- \&& has('conceal')|exe 'setlocal conceallevel=0'|endif
- endif
- " BufUnload is fired for :bwipeout/:bdelete/:bunload, _even_ if
- " 'nobuflisted'. BufDelete is _not_ fired if 'nobuflisted'.
- " NOTE: For 'nohidden' we cannot reliably handle :bdelete like this.
- if &hidden
- autocmd BufUnload <buffer> call s:on_bufunload()
- endif
- augroup END
- setlocal buftype=nofile noswapfile
- endf
- func! s:on_bufenter() abort
- if bufname('%') is '' " Something is very wrong. #136
- return
- elseif !exists('b:dirvish') || (empty(getline(1)) && 1 == line('$'))
- Dirvish
- elseif 3 != &l:conceallevel && !s:buf_modified()
- call s:win_init()
- else
- " Ensure w:dirvish for window splits, `:b <nr>`, etc.
- let w:dirvish = extend(get(w:, 'dirvish', {}), b:dirvish, 'keep')
- endif
- endf
- func! s:save_state(d) abort
- " Remember previous ('original') buffer.
- let p = s:buf_valid(bufnr('%')) || !exists('w:dirvish') ? 0+bufnr('%') : w:dirvish.prevbuf
- if !s:buf_valid(p)
- "If reached via :edit/:buffer/etc. we cannot get the (former) altbuf.
- let p = exists('b:dirvish') && s:buf_valid(b:dirvish.prevbuf) ? b:dirvish.prevbuf : bufnr('#')
- endif
- " Remember alternate buffer.
- let a = (p != bufnr('#') && s:buf_valid(bufnr('#'))) || !exists('w:dirvish') ? 0+bufnr('#') : w:dirvish.altbuf
- if !s:buf_valid(a) || a == p
- let a = exists('b:dirvish') && s:buf_valid(b:dirvish.altbuf) ? b:dirvish.altbuf : -1
- endif
- " Save window-local settings.
- let a:d.altbuf = a
- let a:d.prevbuf = p
- let w:dirvish = extend(get(w:, 'dirvish', {}), a:d, 'force')
- let [w:dirvish._w_wrap, w:dirvish._w_cul] = [&l:wrap, &l:cul]
- if has('conceal') && !exists('b:dirvish')
- let [w:dirvish._w_cocu, w:dirvish._w_cole] = [&l:concealcursor, &l:conceallevel]
- endif
- call s:log(printf('save_state: bufnr=%d altbuf=%d prevbuf=%d', bufnr(''), a:d.altbuf, a:d.prevbuf))
- endf
- func! s:win_init() abort
- let w:dirvish = extend(get(w:, 'dirvish', {}), b:dirvish, 'keep')
- setlocal nowrap cursorline
- if has('conceal')
- setlocal concealcursor=nvc conceallevel=2
- endif
- endf
- func! s:on_bufunload() abort
- call s:restore_winlocal_settings()
- endf
- func! s:buf_close() abort
- let d = get(w:, 'dirvish', {})
- if empty(d)
- return
- endif
- let [altbuf, prevbuf] = [get(d, 'altbuf', 0), get(d, 'prevbuf', 0)]
- call s:log(printf('buf_close: bufnr=%d altbuf=%d prevbuf=%d', bufnr(''), altbuf, prevbuf))
- let found_alt = s:try_visit(altbuf, 0)
- if !s:try_visit(prevbuf, 0) && !found_alt
- \ && (1 == bufnr('%') || (prevbuf != bufnr('%') && altbuf != bufnr('%')))
- bdelete
- endif
- endf
- func! s:restore_winlocal_settings() abort
- if !exists('w:dirvish') " can happen during VimLeave, etc.
- return
- endif
- if has('conceal') && has_key(w:dirvish, '_w_cocu')
- let [&l:cocu, &l:cole] = [w:dirvish._w_cocu, w:dirvish._w_cole]
- endif
- endf
- func! s:open_selected(splitcmd, bg, line1, line2) abort
- let curbuf = bufnr('%')
- let [curtab, curwin, wincount] = [tabpagenr(), winnr(), winnr('$')]
- let p = (a:splitcmd ==# 'p') " Preview-mode
- let paths = getline(a:line1, a:line2)
- for path in paths
- let isdir = path[-1:] == s:sep
- if !isdirectory(path) && !filereadable(path)
- call s:msg_error(printf('invalid (access denied?): %s', path))
- continue
- endif
- " Open files (not dirs) using relative paths.
- let shortname = fnamemodify(path, isdir ? ':p:~' : ':~:.')
- if p " Go to previous window.
- exe (winnr('$') > 1 ? 'wincmd p|if winnr()=='.winnr().'|wincmd w|endif' : 'vsplit')
- endif
- if isdir
- exe (p || a:splitcmd ==# 'edit' ? '' : a:splitcmd.'|') 'Dirvish' fnameescape(shortname)
- else
- exe (p ? 'edit' : a:splitcmd) fnameescape(shortname)
- endif
- " Return to previous window after _each_ split, else we get lost.
- if a:bg && (p || (a:splitcmd =~# 'sp' && winnr('$') > wincount))
- wincmd p
- endif
- endfor
- if a:bg "return to dirvish buffer
- if a:splitcmd ==# 'tabedit'
- exe 'tabnext' curtab '|' curwin.'wincmd w'
- elseif a:splitcmd ==# 'edit'
- execute 'silent keepalt keepjumps buffer' curbuf
- endif
- elseif !exists('b:dirvish') && exists('w:dirvish')
- call s:set_altbuf(w:dirvish.prevbuf)
- endif
- endf
- func! s:set_altbuf(bnr) abort
- if !s:buf_valid(a:bnr) | return | endif
- if has('patch-7.4.605') | let @# = a:bnr | return | endif
- let curbuf = bufnr('%')
- if s:try_visit(a:bnr, 1)
- let noau = bufloaded(curbuf) ? 'noau' : ''
- " Return to the current buffer.
- execute 'silent keepjumps' noau s:noswapfile 'buffer' curbuf
- endif
- endf
- func! s:try_visit(bnr, noau) abort
- if s:buf_valid(a:bnr)
- " If _previous_ buffer is _not_ loaded (because of 'nohidden'), we must
- " allow autocmds (else no syntax highlighting; #13).
- let noau = a:noau && bufloaded(a:bnr) ? 'noau' : ''
- execute 'silent keepjumps' noau s:noswapfile 'buffer' a:bnr
- return 1
- endif
- return 0
- endf
- if exists('*win_execute')
- " Performs `cmd` in all windows showing `bnr`.
- func! s:bufwin_do(cmd, bnr) abort
- call map(filter(getwininfo(), {_,v -> a:bnr ==# v.bufnr}), {_,v -> win_execute(v.winid, s:noau.' '.a:cmd)})
- endf
- else
- func! s:tab_win_do(tnr, cmd, bnr) abort
- exe s:noau 'tabnext' a:tnr
- for wnr in range(1, tabpagewinnr(a:tnr, '$'))
- if a:bnr ==# winbufnr(wnr)
- exe s:noau wnr.'wincmd w'
- exe a:cmd
- endif
- endfor
- endf
- func! s:bufwin_do(cmd, bnr) abort
- let [curtab, curwin, curwinalt, curheight, curwidth, squashcmds] = [tabpagenr(), winnr(), winnr('#'), winheight(0), winwidth(0), filter(split(winrestcmd(), '|'), 'v:val =~# " 0$"')]
- for tnr in range(1, tabpagenr('$'))
- let [origwin, origwinalt] = [tabpagewinnr(tnr), tabpagewinnr(tnr, '#')]
- for bnr in tabpagebuflist(tnr)
- if a:bnr == bnr
- call s:tab_win_do(tnr, a:cmd, a:bnr)
- exe s:noau origwinalt.'wincmd w|' s:noau origwin.'wincmd w'
- break
- endif
- endfor
- endfor
- exe s:noau 'tabnext '.curtab
- exe s:noau curwinalt.'wincmd w|' s:noau curwin.'wincmd w'
- if (&winminheight == 0 && curheight != winheight(0)) || (&winminwidth == 0 && curwidth != winwidth(0))
- for squashcmd in squashcmds
- if squashcmd =~# '^\Cvert ' && winwidth(matchstr('\d\+', squashcmd)) != 0
- \ || squashcmd =~# '^\d' && winheight(matchstr('\d\+', squashcmd)) != 0
- exe s:noau squashcmd
- endif
- endfor
- endif
- endf
- endif
- func! s:buf_render(dir, lastpath) abort
- let bnr = bufnr('%')
- let isnew = empty(getline(1))
- if !isdirectory(a:dir)
- echoerr 'dirvish: not a directory:' a:dir
- return
- endif
- if !isnew
- call s:bufwin_do('let w:dirvish["_view"] = winsaveview()', bnr)
- endif
- if v:version > 704 || v:version == 704 && has("patch73")
- setlocal undolevels=-1
- endif
- silent keepmarks keepjumps %delete _
- silent keepmarks keepjumps call setline(1, s:list_dir(a:dir))
- if type("") == type(get(g:, 'dirvish_mode')) " Apply user's filter.
- execute get(g:, 'dirvish_mode')
- endif
- if v:version > 704 || v:version == 704 && has("patch73")
- setlocal undolevels<
- endif
- if !isnew
- call s:bufwin_do('call winrestview(w:dirvish["_view"])', bnr)
- endif
- if !empty(a:lastpath)
- let pat = tr(s:f(a:lastpath), '/', s:sep) " platform slashes
- call search('\V\^'.escape(pat, '\').'\$', 'cw')
- endif
- " Place cursor on the tail (last path segment).
- call search('\'.s:sep.'\zs[^\'.s:sep.']\+\'.s:sep.'\?$', 'c', line('.'))
- " TRICK: From :help getfperm(): "If the directory cannot be read, empty string is returned."
- " This misses the "--x" case (no "r" access), but it's the best we have.
- if empty(getline(1)) && '' ==# getfperm(a:dir . '/.')
- call s:msg_error(printf('cannot list directory (permissions: %s): %s', getfperm(a:dir), a:dir))
- endif
- endf
- func! s:apply_icons() abort
- if 0 == len(s:cb_map)
- return
- endif
- highlight clear Conceal
- let i = 0
- for f in getline(1, '$')
- let i += 1
- let icon = ''
- for id in sort(keys(s:cb_map))
- let icon = s:cb_map[id](f)
- if -1 != match(icon, '\S')
- break
- endif
- endfor
- if icon != ''
- let isdir = (f[-1:] == s:sep)
- let f = substitute(s:f(f), escape(s:sep,'\').'$', '', 'g') " Full path, trim slash.
- let tail_esc = escape(fnamemodify(f,':t').(isdir?(s:sep):''), '[,*.^$~\')
- exe 'syntax match DirvishColumnHead =\%'.i.'l^.\{-}\ze'.tail_esc.'$= conceal cchar='.icon
- endif
- endfor
- endf
- let s:recursive = ''
- func! s:open_dir(d, reload) abort
- if s:recursive ==# a:d._dir
- return
- endif
- let s:recursive = a:d._dir
- call s:log(printf('open_dir ENTER: %d %s', bufnr('%'), a:d._dir))
- let d = a:d
- let dirname_without_sep = substitute(d._dir, '[\\/]\+$', '', 'g')
- " Vim tends to 'simplify' buffer names. Examples (gvim 7.4.618):
- " ~\foo\, ~\foo, foo\, foo
- " Try to find an existing buffer before creating a new one.
- let bnr = -1
- for pat in ['', ':~:.', ':~']
- let dir = fnamemodify(d._dir, pat)
- if dir == '' | continue | endif
- let bnr = bufnr('^'.dir.'$')
- if -1 != bnr
- break
- endif
- endfor
- " Note: :noautocmd not used here, to allow BufEnter/BufNew. 61282f2453af
- " Thus s:recursive guards against recursion (for performance).
- if -1 == bnr
- execute 'silent' s:noswapfile 'keepalt edit' fnameescape(d._dir)
- else
- execute 'silent' s:noswapfile 'buffer' bnr
- endif
- " Force a normalized directory path.
- " - Starts with "~/" or "/", ie absolute (important for ":h").
- " - Ends with "/".
- " - Avoids ".././..", ".", "./", etc. (breaks %:p, not updated on :cd).
- " - Avoids [Scratch] in some cases (":e ~/" on Windows).
- if bufname('%')[-1:] != '/' || bufname('%')[0:1] !=# d._dir[0:1]
- execute 'silent' s:noswapfile 'file' fnameescape(d._dir)
- endif
- if !isdirectory(bufname('%')) " sanity check
- throw 'invalid directory: '.bufname('%')
- endif
- if &buflisted && bufnr('$') > 1
- setlocal nobuflisted
- endif
- call s:set_altbuf(d.prevbuf) "in case of :bd, :read#, etc.
- let b:dirvish = exists('b:dirvish') ? extend(b:dirvish, d, 'force') : d
- call s:buf_init()
- call s:win_init()
- if a:reload || s:should_reload()
- call s:buf_render(b:dirvish._dir, get(b:dirvish, 'lastpath', ''))
- " Set up Dirvish before any other `FileType dirvish` handler.
- exe 'source '.fnameescape(s:srcdir.'/ftplugin/dirvish.vim')
- let curwin = winnr()
- setlocal filetype=dirvish
- if curwin != winnr() | throw 'FileType autocmd changed the window' | endif
- let b:dirvish._c = b:changedtick
- call s:apply_icons()
- endif
- let s:recursive = ''
- call s:log(printf('open_dir EXIT : %d %s', bufnr('%'), a:d._dir))
- endf
- func! s:should_reload() abort
- return !s:buf_modified() || (empty(getline(1)) && 1 == line('$'))
- endf
- func! s:buf_valid(bnr) abort
- return bufexists(a:bnr) && (empty(bufname(a:bnr)) || !isdirectory(s:sl(bufname(a:bnr))))
- endf
- func! dirvish#open(...) range abort
- if &autochdir
- call s:msg_error("'autochdir' is not supported")
- return
- endif
- if (&bufhidden =~# '\vunload|delete|wipe' || (!&autowriteall && !&hidden && &modified))
- \ && (!exists("*win_findbuf") || len(win_findbuf(winbufnr(0))) == 1)
- call s:msg_error(&modified ? 'E37: No write since last change' : 'E37: Buffer would be deleted: '.bufnr('%'))
- return
- endif
- if a:0 > 1
- " Detect whether a <Cmd> mapping or the legacy fallback is being used
- let l:visual_lines = mode(0) == 'n' ? [a:firstline, a:lastline] : [line('v'), line('.')]
- call s:open_selected(a:1, a:2, min(l:visual_lines), max(l:visual_lines))
- return
- endif
- let d = {}
- let is_uri = -1 != match(a:1, '^\w\+:[\/][\/]')
- let from_path = s:sl(fnamemodify(bufname('%'), ':p'))
- let to_path = s:sl(fnamemodify(!empty(a:1) || empty(@%) ? a:1 : @%, ':p'))
- let d._dir = s:fix_dir(filereadable(to_path) ? fnamemodify(to_path, ':p:h') : to_path, is_uri)
- " Fallback to CWD for URIs. #127
- let d._dir = empty(d._dir) && is_uri ? s:fix_dir(getcwd(), is_uri) : d._dir
- if empty(d._dir) " s:fix_dir() already showed error.
- return
- endif
- let reloading = exists('b:dirvish') && d._dir ==# b:dirvish._dir && s:recursive !=# d._dir
- if reloading
- let d.lastpath = '' " Do not place cursor when reloading.
- elseif !is_uri && s:eq(d._dir, s:parent_dir(from_path))
- let d.lastpath = from_path " Save lastpath when navigating _up_.
- endif
- call s:save_state(d)
- call s:open_dir(d, reloading)
- endf
- func! dirvish#add_icon_fn(fn) abort
- if !exists('v:t_func') || type(a:fn) != v:t_func | throw 'argument must be a Funcref' | endif
- let s:cb_map[string(a:fn)] = a:fn
- return string(a:fn)
- endf
- func! dirvish#remove_icon_fn(fn_id) abort
- if has_key(s:cb_map, a:fn_id)
- call remove(s:cb_map, a:fn_id)
- return 1
- endif
- return 0
- endf
- nnoremap <silent> <Plug>(dirvish_quit) :<C-U>call <SID>buf_close()<CR>
- nnoremap <silent> <Plug>(dirvish_arg) :<C-U>call <SID>set_args([getline('.')])<CR>
- xnoremap <silent> <Plug>(dirvish_arg) :<C-U>call <SID>set_args(getline("'<", "'>"))<CR>
- nnoremap <silent> <Plug>(dirvish_K) :<C-U>call <SID>info([getline('.')],!!v:count)<CR>
- xnoremap <silent> <Plug>(dirvish_K) :<C-U>call <SID>info(getline("'<", "'>"),!!v:count)<CR>
|