"============================================================================= " FILE: view.vim " AUTHOR: Shougo Matsushita " 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 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"}}} let &cpo = s:save_cpo unlet s:save_cpo " vim: foldmethod=marker