"=============================================================================
" FILE: helper.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
let s:save_cpo = &cpo
set cpo&vim
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:], ':')
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
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"}}}
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: foldmethod=marker