1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 09:30:04 +08:00
SpaceVim/bundle/vimfiler.vim/autoload/vimfiler/helper.vim
2020-06-13 14:06:35 +08:00

333 lines
9.2 KiB
VimL
Vendored

"=============================================================================
" FILE: helper.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" License: MIT license
"=============================================================================
function! vimfiler#helper#_get_directory_files(directory, ...) abort
" Save current files.
let is_manualed = get(a:000, 0, 0)
let context = {
\ 'vimfiler__is_dummy' : 0,
\ 'is_redraw' : is_manualed,
\ }
let path = a:directory
if path !~ '^\a\w*:'
let path = b:vimfiler.source . ':' . path
endif
let args = vimfiler#parse_path(path)
let current_files = vimfiler#init#_candidates(
\ unite#get_vimfiler_candidates([args], context),
\ b:vimfiler.source)
for file in current_files
" Initialize.
let file.vimfiler__is_marked = 0
let file.vimfiler__is_opened = 0
let file.vimfiler__nest_level = 0
endfor
return vimfiler#helper#_sort_files(current_files)
endfunction
function! vimfiler#helper#_sort_files(files) abort
let files = a:files
let dirs = filter(copy(a:files), 'v:val.vimfiler__is_directory')
let files = filter(copy(a:files), '!v:val.vimfiler__is_directory')
if g:vimfiler_directory_display_top
let files = s:sort(dirs, b:vimfiler.local_sort_type)
\+ s:sort(files, b:vimfiler.local_sort_type)
else
let files = s:sort(files + dirs, b:vimfiler.local_sort_type)
endif
return files
endfunction
function! vimfiler#helper#_parse_path(path) abort
let path = a:path
let source_name = matchstr(path, '^\h[^:]*\ze:')
if (vimfiler#util#is_windows() && len(source_name) == 1)
\ || source_name == ''
" Default source.
let source_name = 'file'
let source_arg = path
if vimfiler#util#is_win_path(source_arg)
let source_arg = vimfiler#util#substitute_path_separator(
\ fnamemodify(expand(source_arg), ':p'))
endif
else
let source_arg = path[len(source_name)+1 :]
endif
let source_args = source_arg == '' ? [] :
\ map(split(source_arg, '\\\@<!:', 1),
\ 'substitute(v:val, ''\\\(.\)'', "\\1", "g")')
return insert(source_args, source_name)
endfunction
function! vimfiler#helper#_get_cd_path(dir) abort
let dir = vimfiler#util#substitute_path_separator(a:dir)
if dir =~ '^\h\w*:'
" Parse path.
let ret = vimfiler#parse_path(dir)
let b:vimfiler.source = ret[0]
let dir = join(ret[1:], ':')
elseif a:dir !=# b:vimfiler.current_dir
let b:vimfiler.source = 'file'
endif
let current_dir = b:vimfiler.current_dir
if dir == '..'
let chars = split(current_dir, '\zs')
if count(chars, '/') <= 1
if count(chars, ':') < 1
\ || b:vimfiler.source ==# 'file'
" Ignore.
return current_dir
endif
let dir = substitute(current_dir, ':[^:]*$', '', '')
else
let dir = fnamemodify(substitute(current_dir, '[/\\]$', '', ''), ':h')
endif
if dir == '//'
return current_dir . '/home'
endif
elseif dir == '/'
" Root.
if vimfiler#util#is_windows() && current_dir =~ '^//'
" For UNC path.
let dir = matchstr(current_dir, '^//[^/]*/[^/]*')
else
let dir = vimfiler#util#is_windows() ?
\ matchstr(fnamemodify(current_dir, ':p'),
\ '^\a\+:[/\\]') : dir
endif
elseif dir == '~'
" Home.
let dir = expand('~')
elseif dir =~ ':'
\ || (vimfiler#util#is_windows() && dir =~ '^//')
\ || (!vimfiler#util#is_windows() && dir =~ '^/')
" Network drive or absolute path.
elseif b:vimfiler.source ==# 'file'
" Relative path.
let dir = simplify(current_dir . dir)
endif
let fullpath = vimfiler#util#substitute_path_separator(dir)
if vimfiler#util#is_windows()
let fullpath = vimfiler#util#resolve(fullpath)
endif
if fullpath !~ '/$'
let fullpath .= '/'
endif
return fullpath
endfunction
function! vimfiler#helper#_complete(arglead, cmdline, cursorpos) abort
let _ = []
" Option names completion.
let _ += filter(vimfiler#variables#options(),
\ 'stridx(v:val, a:arglead) == 0')
" Source path completion.
let _ += vimfiler#complete_path(a:arglead,
\ join(split(a:cmdline)[1:]), a:cursorpos)
let args = split(join(split(a:cmdline,
\ '\\\@<!\s\+')[1:]), '\\\@<!\s\+')
if !empty(args) && args[-1] !=# a:arglead
call map(_, "v:val[len(args[-1])-len(a:arglead) :]")
endif
return sort(_)
endfunction
function! vimfiler#helper#_complete_path(arglead, cmdline, cursorpos) abort
let ret = vimfiler#parse_path(a:cmdline)
let source_name = ret[0]
let source_args = ret[1:]
let _ = []
" Source args completion.
let _ += unite#vimfiler_complete(
\ [insert(copy(source_args), source_name)],
\ join(source_args, ':'), a:cmdline, a:cursorpos)
if a:arglead !~ ':'
" Source name completion.
let _ += map(filter(unite#get_vimfiler_source_names(),
\ 'stridx(v:val, a:arglead) == 0'), 'v:val.":"')
else
" Add "{source-name}:".
let _ = map(_, 'source_name.":".v:val')
endif
let args = split(join(split(a:cmdline,
\ '\\\@<!\s\+')[1:]), '\\\@<!\s\+')
if !empty(args) && args[-1] !=# a:arglead
call map(_, "v:val[len(args[-1])-len(a:arglead) :]")
endif
return sort(_)
endfunction
function! vimfiler#helper#_get_file_directory(...) abort
let line_num = get(a:000, 0, line('.'))
let file = vimfiler#get_file(b:vimfiler, line_num)
if empty(file)
let directory = b:vimfiler.current_dir
else
let directory = unite#helper#get_candidate_directory(file)
if file.vimfiler__is_directory
\ && !file.vimfiler__is_opened
let directory = vimfiler#util#substitute_path_separator(
\ fnamemodify(directory, ':h'))
endif
endif
return directory
endfunction
function! vimfiler#helper#_get_buffer_directory(bufnr) abort
let filetype = getbufvar(a:bufnr, '&filetype')
if filetype ==# 'vimfiler'
let dir = getbufvar(a:bufnr, 'vimfiler').current_dir
elseif filetype ==# 'vimshell'
let dir = getbufvar(a:bufnr, 'vimshell').current_dir
elseif filetype ==# 'vinarise'
let dir = getbufvar(a:bufnr, 'vinarise').current_dir
elseif filetype ==# 'deol'
let dir = t:deol.cwd
else
let path = vimfiler#util#substitute_path_separator(bufname(a:bufnr))
let dir = vimfiler#util#path2directory(path)
endif
return dir
endfunction
function! vimfiler#helper#_set_cursor() abort
let pos = getpos('.')
execute 'normal!' (line('.') <= winheight(0) ? 'zb' :
\ line('$') - line('.') > winheight(0) ? 'zz' : line('$').'zb')
call setpos('.', pos)
endfunction
function! vimfiler#helper#_call_filters(files, context) abort
let files = a:files
for filter in b:vimfiler.filters
let files = filter.filter(files, a:context)
endfor
return files
endfunction
function! s:sort(files, type) abort
let ignorecase_save = &ignorecase
try
let &ignorecase = vimfiler#util#is_windows()
if a:type =~? '^n\%[one]$'
" Ignore.
let files = a:files
elseif a:type =~? '^s\%[ize]$'
let files = vimfiler#util#sort_by(
\ a:files, 'v:val.vimfiler__filesize')
elseif a:type =~? '^e\%[xtension]$'
let files = vimfiler#util#sort_by(
\ a:files, 'v:val.vimfiler__extension')
elseif a:type =~? '^f\%[ilename]$'
let files = vimfiler#helper#_sort_human(
\ a:files, vimfiler#util#has_lua())
elseif a:type =~? '^t\%[ime]$'
let files = vimfiler#util#sort_by(
\ a:files, 'v:val.vimfiler__filetime')
elseif a:type =~? '^m\%[anual]$'
" Not implemented.
let files = a:files
else
throw 'Invalid sort type.'
endif
finally
let &ignorecase = ignorecase_save
endtry
if a:type =~ '^\u'
" Reverse order.
let files = reverse(files)
endif
return files
endfunction
function! vimfiler#helper#_sort_human(candidates, has_lua) abort
if !a:has_lua || len(filter(copy(a:candidates),
\ "v:val.vimfiler__filename =~ '\\d'")) >= 2
return sort(a:candidates, 's:compare_filename')
endif
" Use lua interface.
lua << EOF
do
local ignorecase = vim.eval('&ignorecase')
local candidates = vim.eval('a:candidates')
local t = {}
for i = 1, #candidates do
t[i] = candidates[i-1]
if ignorecase ~= 0 then
t[i].vimfiler__filename = string.lower(t[i].vimfiler__filename)
end
end
table.sort(t, function(a, b)
return a.vimfiler__filename < b.vimfiler__filename
end)
for i = 0, #candidates-1 do
candidates[i] = t[i+1]
end
end
EOF
return a:candidates
endfunction
" Compare filename by human order.
function! s:compare_filename(i1, i2) abort
let words_1 = s:get_words(a:i1.vimfiler__filename)
let words_2 = s:get_words(a:i2.vimfiler__filename)
let words_1_len = len(words_1)
let words_2_len = len(words_2)
for i in range(0, min([words_1_len, words_2_len])-1)
if words_1[i] >? words_2[i]
return 1
elseif words_1[i] <? words_2[i]
return -1
endif
endfor
return words_1_len - words_2_len
endfunction
function! s:get_words(filename) abort
let words = []
for split in split(a:filename, '\d\+\zs\ze')
let words += split(split, '\D\zs\ze\d\+')
endfor
return map(words, "v:val =~ '^\\d\\+$' ? str2nr(v:val) : v:val")
endfunction