mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 09:30:04 +08:00
416 lines
12 KiB
VimL
Vendored
416 lines
12 KiB
VimL
Vendored
"=============================================================================
|
|
" FILE: view.vim
|
|
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
|
|
" License: MIT license
|
|
"=============================================================================
|
|
|
|
let g:vimfiler_min_cache_files =
|
|
\ get(g:, 'vimfiler_min_cache_files', 100)
|
|
|
|
let s:Cache = vimfiler#util#get_vital_cache()
|
|
|
|
function! vimfiler#view#_force_redraw_screen(...) abort
|
|
let is_manualed = get(a:000, 0, 0)
|
|
|
|
let old_original_files = {}
|
|
for file in filter(copy(b:vimfiler.original_files),
|
|
\ "v:val.vimfiler__is_directory &&
|
|
\ (v:val.vimfiler__is_opened
|
|
\ || v:val.vimfiler__abbr =~ './.')")
|
|
if file.vimfiler__abbr =~ './.'
|
|
let path = (file.vimfiler__is_opened ||
|
|
\ !has_key(file, 'vimfiler__parent')) ?
|
|
\ file.action__path : file.vimfiler__parent.action__path
|
|
let old_original_files[path] = 1
|
|
|
|
let old_path = ''
|
|
while path != '' && path !=# old_path
|
|
let old_original_files[path] = 1
|
|
let old_path = path
|
|
let path = fnamemodify(old_path, ':h')
|
|
endwhile
|
|
else
|
|
let old_original_files[file.action__path] = 1
|
|
endif
|
|
endfor
|
|
|
|
" Check cache file.
|
|
let cache_dir = vimfiler#variables#get_data_directory() . '/files'
|
|
if is_manualed || !s:Cache.filereadable(cache_dir, b:vimfiler.current_dir)
|
|
\ || (b:vimfiler.source ==# 'file' &&
|
|
\ s:Cache.check_old_cache(cache_dir, b:vimfiler.current_dir))
|
|
" Get files.
|
|
let files = vimfiler#get_directory_files(
|
|
\ b:vimfiler.current_dir, is_manualed)
|
|
if len(files) >= g:vimfiler_min_cache_files && !vimfiler#util#is_sudo()
|
|
call s:Cache.writefile(cache_dir,
|
|
\ b:vimfiler.current_dir, [string(files)])
|
|
endif
|
|
else
|
|
sandbox let files = eval(s:Cache.readfile(
|
|
\ cache_dir, b:vimfiler.current_dir)[0])
|
|
let files = vimfiler#helper#_sort_files(files)
|
|
endif
|
|
|
|
" Use matcher_glob.
|
|
let b:vimfiler.original_files = files
|
|
let index = 0
|
|
for file in copy(b:vimfiler.original_files)
|
|
if file.vimfiler__is_directory
|
|
\ && has_key(old_original_files, file.action__path)
|
|
|
|
" Insert children.
|
|
let children = vimfiler#mappings#expand_tree_rec(file, old_original_files)
|
|
|
|
let b:vimfiler.original_files = b:vimfiler.original_files[: index]
|
|
\ + children + b:vimfiler.original_files[index+1 :]
|
|
let index += len(children)
|
|
endif
|
|
|
|
let index += 1
|
|
endfor
|
|
|
|
call vimfiler#view#_redraw_screen()
|
|
endfunction
|
|
function! vimfiler#view#_redraw_screen(...) abort
|
|
if &filetype !=# 'vimfiler'
|
|
" Not vimfiler window.
|
|
return
|
|
endif
|
|
|
|
if !has_key(b:vimfiler, 'original_files')
|
|
return
|
|
endif
|
|
|
|
let current_file = vimfiler#get_file(b:vimfiler)
|
|
|
|
let b:vimfiler.all_files =
|
|
\ unite#filters#matcher_vimfiler_mask#define().filter(
|
|
\ copy(b:vimfiler.original_files),
|
|
\ { 'input' : b:vimfiler.current_mask })
|
|
if !b:vimfiler.is_visible_ignore_files
|
|
let b:vimfiler.all_files = vimfiler#helper#_call_filters(
|
|
\ b:vimfiler.all_files, b:vimfiler.context)
|
|
let b:vimfiler.all_files =
|
|
\ s:check_tree(b:vimfiler.all_files)
|
|
endif
|
|
|
|
let b:vimfiler.all_files_len = len(b:vimfiler.all_files)
|
|
|
|
let b:vimfiler.winwidth = (winwidth(0)+1)/2*2
|
|
|
|
let b:vimfiler.current_files = b:vimfiler.all_files
|
|
|
|
setlocal modifiable
|
|
setlocal noreadonly
|
|
|
|
let savedView = winsaveview()
|
|
|
|
try
|
|
let last_line = line('.')
|
|
|
|
" Clean up the screen.
|
|
if line('$') > 1 &&
|
|
\ b:vimfiler.prompt_linenr + len(b:vimfiler.current_files) < line('$')
|
|
silent execute '$-'.(line('$')-b:vimfiler.prompt_linenr-
|
|
\ len(b:vimfiler.current_files)).',$delete _'
|
|
endif
|
|
|
|
call s:redraw_prompt()
|
|
|
|
" Print files.
|
|
call setline(b:vimfiler.prompt_linenr + 1,
|
|
\ vimfiler#view#_get_print_lines(b:vimfiler.current_files))
|
|
finally
|
|
setlocal nomodifiable
|
|
setlocal readonly
|
|
endtry
|
|
|
|
call winrestview(savedView)
|
|
|
|
let index = index(b:vimfiler.current_files, current_file)
|
|
if index >= 0
|
|
call cursor(vimfiler#get_line_number(b:vimfiler, index), 0)
|
|
else
|
|
call cursor(last_line, 0)
|
|
endif
|
|
endfunction
|
|
function! vimfiler#view#_force_redraw_all_vimfiler(...) abort
|
|
let is_manualed = get(a:000, 0, 0)
|
|
|
|
let current_nr = winnr()
|
|
|
|
try
|
|
" Search vimfiler window.
|
|
for winnr in filter(range(1, winnr('$')),
|
|
\ "getwinvar(v:val, '&filetype') ==# 'vimfiler'")
|
|
call vimfiler#util#winmove(winnr)
|
|
call vimfiler#view#_force_redraw_screen(is_manualed)
|
|
endfor
|
|
finally
|
|
call vimfiler#util#winmove(current_nr)
|
|
endtry
|
|
endfunction
|
|
function! vimfiler#view#_redraw_all_vimfiler() abort
|
|
let current_nr = winnr()
|
|
try
|
|
" Search vimfiler window.
|
|
for winnr in filter(range(1, winnr('$')),
|
|
\ "getwinvar(v:val, '&filetype') ==# 'vimfiler'")
|
|
call vimfiler#util#winmove(winnr)
|
|
call vimfiler#view#_redraw_screen()
|
|
endfor
|
|
finally
|
|
call vimfiler#util#winmove(current_nr)
|
|
endtry
|
|
endfunction
|
|
function! s:redraw_prompt() abort
|
|
if &filetype !=# 'vimfiler'
|
|
return
|
|
endif
|
|
|
|
let mask = (!b:vimfiler.is_visible_ignore_files
|
|
\ && b:vimfiler.current_mask == '') ?
|
|
\ '' : '[' . (b:vimfiler.is_visible_ignore_files ? '.:' : '')
|
|
\ . b:vimfiler.current_mask . ']'
|
|
|
|
let sort = (b:vimfiler.local_sort_type ==# b:vimfiler.global_sort_type) ?
|
|
\ '' : ' <' . b:vimfiler.local_sort_type . '>'
|
|
|
|
let safe = (b:vimfiler.is_safe_mode) ? ' *safe*' : ''
|
|
|
|
let prefix = (b:vimfiler.source ==# 'file') ? '' : b:vimfiler.source.':'
|
|
|
|
let dir = b:vimfiler.current_dir
|
|
if b:vimfiler.source ==# 'file'
|
|
let home = vimfiler#util#substitute_path_separator(expand('~')).'/'
|
|
if stridx(dir, home) >= 0
|
|
let dir = '~/' . dir[len(home):]
|
|
endif
|
|
endif
|
|
|
|
if strwidth(prefix.dir) > winwidth(0)
|
|
let dir = fnamemodify(substitute(dir, '/$', '', ''), ':t')
|
|
endif
|
|
|
|
if dir !~ '/$'
|
|
let dir .= '/'
|
|
endif
|
|
let b:vimfiler.status = prefix . dir . mask . sort . safe
|
|
|
|
let context = b:vimfiler.context
|
|
|
|
" Append up directory.
|
|
let modifiable_save = &l:modifiable
|
|
let readonly_save = &l:readonly
|
|
setlocal modifiable
|
|
setlocal noreadonly
|
|
|
|
try
|
|
if (context.parent || empty(b:vimfiler.current_files))
|
|
\ && getline(b:vimfiler.prompt_linenr) != '..'
|
|
if line('$') == 1
|
|
" Note: Dirty Hack for open file.
|
|
call append(1, '')
|
|
call setline(2, '..')
|
|
silent delete _
|
|
else
|
|
call setline(1, '..')
|
|
endif
|
|
endif
|
|
|
|
if context.status
|
|
if getline(1) == '..'
|
|
call append(0, '[in]: ' . b:vimfiler.status)
|
|
else
|
|
call setline(1, '[in]: ' . b:vimfiler.status)
|
|
endif
|
|
endif
|
|
finally
|
|
let &l:modifiable = modifiable_save
|
|
let &l:readonly = readonly_save
|
|
endtry
|
|
endfunction
|
|
function! vimfiler#view#_get_print_lines(files) abort
|
|
" Clear previous syntax.
|
|
for syntax in b:vimfiler.syntaxes
|
|
silent! execute 'syntax clear' syntax
|
|
endfor
|
|
|
|
let columns = (b:vimfiler.context.simple) ? [] : b:vimfiler.columns
|
|
|
|
let max_len = vimfiler#view#_get_max_len(a:files)
|
|
|
|
call s:define_filename_regions(max_len)
|
|
|
|
call s:define_column_regions(max_len, columns)
|
|
|
|
" Print files.
|
|
let lines = []
|
|
for file in a:files
|
|
let filename = file.vimfiler__abbr
|
|
if file.vimfiler__is_directory
|
|
\ && filename !~ '/$'
|
|
let filename .= '/'
|
|
endif
|
|
|
|
let mark = ''
|
|
if file.vimfiler__nest_level > 0
|
|
let mark .= repeat(' ', file.vimfiler__nest_level
|
|
\ * g:vimfiler_tree_indentation)
|
|
\ . g:vimfiler_tree_leaf_icon
|
|
endif
|
|
if file.vimfiler__is_marked
|
|
let mark .= g:vimfiler_marked_file_icon
|
|
elseif file.vimfiler__is_directory
|
|
let mark .= !get(file, 'vimfiler__is_writable', 1)
|
|
\ && !file.vimfiler__is_opened ?
|
|
\ g:vimfiler_readonly_file_icon :
|
|
\ file.vimfiler__is_opened ? g:vimfiler_tree_opened_icon :
|
|
\ g:vimfiler_tree_closed_icon
|
|
else
|
|
let mark .= (!get(file, 'vimfiler__is_writable', 1) ?
|
|
\ g:vimfiler_readonly_file_icon : g:vimfiler_file_icon)
|
|
endif
|
|
let mark .= ' '
|
|
|
|
let line = mark . filename
|
|
if len(line) > max_len
|
|
let line = vimfiler#util#truncate_smart(
|
|
\ line, max_len, max_len/2, '..')
|
|
else
|
|
let line .= repeat(' ', max_len - strwidth(line))
|
|
endif
|
|
|
|
for column in columns
|
|
let column_string = column.get(file, b:vimfiler.context)
|
|
if len(column_string) > column.vimfiler__length
|
|
let column_string = vimfiler#util#truncate(
|
|
\ column_string, column.vimfiler__length)
|
|
endif
|
|
let line .= ' ' . column_string
|
|
endfor
|
|
|
|
if line[-1] == ' '
|
|
let line = substitute(line, '\s\+$', '', '')
|
|
endif
|
|
|
|
call add(lines, line)
|
|
endfor
|
|
|
|
return lines
|
|
endfunction
|
|
function! vimfiler#view#_get_max_len(files) abort
|
|
let columns = (b:vimfiler.context.simple) ? [] : b:vimfiler.columns
|
|
|
|
for column in columns
|
|
let column.vimfiler__length = column.length(
|
|
\ a:files, b:vimfiler.context)
|
|
endfor
|
|
let columns = filter(columns, 'v:val.vimfiler__length > 0')
|
|
|
|
" Calc padding width.
|
|
let padding = 0
|
|
for column in columns
|
|
let padding += column.vimfiler__length + 1
|
|
endfor
|
|
|
|
if &l:number || (exists('&relativenumber') && &l:relativenumber)
|
|
let padding += max([&l:numberwidth,
|
|
\ len(line('$') + len(a:files))+1])
|
|
endif
|
|
|
|
let padding += &l:foldcolumn
|
|
|
|
if has('signs')
|
|
" Delete signs.
|
|
silent execute 'sign unplace buffer='.bufnr('%')
|
|
endif
|
|
|
|
let max_len = max([winwidth(0) - padding, 10])
|
|
if b:vimfiler.context.fnamewidth > 0
|
|
let max_len = min([max_len, b:vimfiler.context.fnamewidth])
|
|
endif
|
|
return max_len
|
|
endfunction
|
|
function! vimfiler#view#_define_syntax() abort
|
|
for column in filter(
|
|
\ copy(b:vimfiler.columns), "get(v:val, 'syntax', '') != ''")
|
|
call column.define_syntax(b:vimfiler.context)
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:check_tree(files) abort
|
|
let level = 0
|
|
let _ = []
|
|
for file in a:files
|
|
if file.vimfiler__nest_level == 0 ||
|
|
\ file.vimfiler__nest_level <= level + 1
|
|
call add(_, file)
|
|
let level = file.vimfiler__nest_level
|
|
endif
|
|
endfor
|
|
|
|
return _
|
|
endfunction
|
|
function! s:define_filename_regions(max_len) abort
|
|
let leaf_icon = vimfiler#util#escape_pattern(
|
|
\ g:vimfiler_tree_leaf_icon)
|
|
let file_icon = vimfiler#util#escape_pattern(
|
|
\ g:vimfiler_file_icon)
|
|
let marked_file_icon = vimfiler#util#escape_pattern(
|
|
\ g:vimfiler_marked_file_icon)
|
|
let opened_icon = vimfiler#util#escape_pattern(
|
|
\ g:vimfiler_tree_opened_icon)
|
|
let closed_icon = vimfiler#util#escape_pattern(
|
|
\ g:vimfiler_tree_closed_icon)
|
|
let ro_file_icon = vimfiler#util#escape_pattern(
|
|
\ g:vimfiler_readonly_file_icon)
|
|
|
|
" Filename regions.
|
|
for [icon, syntax] in [
|
|
\ [file_icon, 'vimfilerNormalFile'],
|
|
\ [marked_file_icon, 'vimfilerMarkedFile'],
|
|
\ [opened_icon, 'vimfilerOpenedFile'],
|
|
\ [closed_icon, 'vimfilerClosedFile'],
|
|
\ [ro_file_icon, 'vimfilerROFile'],
|
|
\ ]
|
|
execute 'syntax region '.syntax.
|
|
\ ' start=''^\s*\%('.leaf_icon.'\)\?'.
|
|
\ icon . ''' end=''\%'.a:max_len .
|
|
\ 'v'' oneline contains=vimfilerNonMark'
|
|
call add(b:vimfiler.syntaxes, syntax)
|
|
endfor
|
|
endfunction
|
|
function! s:define_column_regions(max_len, columns) abort
|
|
" Column regions.
|
|
let start = a:max_len + 1
|
|
let syntaxes = [
|
|
\ [strwidth(g:vimfiler_tree_opened_icon), 'vimfilerOpenedFile'],
|
|
\ [strwidth(g:vimfiler_tree_closed_icon), 'vimfilerClosedFile'],
|
|
\ [strwidth(g:vimfiler_readonly_file_icon), 'vimfilerROFile'],
|
|
\ [strwidth(g:vimfiler_file_icon), 'vimfilerNormalFile'],
|
|
\ [strwidth(g:vimfiler_marked_file_icon), 'vimfilerMarkedFile'],
|
|
\ ]
|
|
if empty(filter(copy(syntaxes), 'v:val[0] != '.
|
|
\ strwidth(g:vimfiler_file_icon)))
|
|
" Optimize if columns are same.
|
|
let syntaxes = [[strwidth(g:vimfiler_file_icon),
|
|
\ 'vimfilerNormalFile,vimfilerOpenedFile,'.
|
|
\ 'vimfilerClosedFile,vimfilerROFile']]
|
|
endif
|
|
for column in a:columns
|
|
if get(column, 'syntax', '') != '' && a:max_len > 0
|
|
for [offset, syntax] in syntaxes
|
|
execute 'syntax region' column.syntax 'start=''\%'.(start+offset).
|
|
\ 'v'' end=''\%'.(start + column.vimfiler__length+offset).
|
|
\ 'v'' keepend oneline containedin=' . syntax
|
|
endfor
|
|
|
|
call add(b:vimfiler.syntaxes, column.syntax)
|
|
endif
|
|
|
|
let start += column.vimfiler__length + 1
|
|
endfor
|
|
endfunction
|