"============================================================================= " FILE: include.vim " AUTHOR: Shougo Matsushita " License: MIT license "============================================================================= function! neoinclude#include#initialize() abort let s:include_info = {} let s:include_cache = {} let s:async_include_cache = {} let s:cached_pattern = {} augroup neoinclude autocmd BufWritePost * call s:check_buffer('', 0) augroup END endfunction function! neoinclude#include#get_include_files(...) abort call neoinclude#initialize() call s:check_buffer('', 0) let bufnr = get(a:000, 0, bufnr('%')) if has_key(s:include_info, bufnr) return copy(s:include_info[bufnr].include_files) else return s:get_buffer_include_files(bufnr) endif endfunction function! neoinclude#include#get_tag_files(...) abort call neoinclude#initialize() call s:check_buffer('', 0) let bufnr = get(a:000, 0, bufnr('%')) let include_files = neoinclude#include#get_include_files(bufnr) return filter(map(filter(map(include_files, \ 'get(s:async_include_cache, v:val, {})'), \ '!empty(v:val)'), 'v:val.cachename'), 'filereadable(v:val)') endfunction " For Debug. function! neoinclude#include#get_current_include_files() abort call neoinclude#initialize() return s:get_buffer_include_files(bufnr('%')) endfunction function! s:check_buffer(bufnr, is_force) abort let bufnr = (a:bufnr == '') ? bufnr('%') : a:bufnr let filename = fnamemodify(bufname(bufnr), ':p') if !has_key(s:include_info, bufnr) " Initialize. let s:include_info[bufnr] = { \ 'include_files' : [], 'lines' : [], \ 'async_files' : {}, \ } endif let include_info = s:include_info[bufnr] if a:is_force || include_info.lines !=# getbufline(bufnr, 1, 100) let include_info.lines = getbufline(bufnr, 1, 100) " Check include files contained bufname. let include_files = s:get_buffer_include_files(bufnr) " Check include files from function. let filetype = getbufvar(a:bufnr, '&filetype') let function = neoinclude#get_function(filetype) if function != '' && getbufvar(bufnr, '&buftype') !~ 'nofile' let path = neoinclude#get_path(a:bufnr, filetype) let include_files += call(function, \ [getbufline(bufnr, 1, (a:is_force ? '$' : 1000)), path]) endif if getbufvar(bufnr, '&buftype') !~ 'nofile' \ && filereadable(filename) call add(include_files, filename) endif let include_info.include_files = neoinclude#util#uniq(include_files) endif let filetype = getbufvar(bufnr, '&filetype') if filetype == '' let filetype = 'nothing' endif let ctags = neoinclude#util#get_buffer_config(filetype, \ 'b:neoinclude_ctags_commands', \ g:neoinclude#ctags_commands, \ g:neoinclude#_ctags_commands, '') if g:neoinclude#max_processes <= 0 || !executable(ctags) return endif for filename in include_info.include_files if (a:is_force || !has_key(include_info.async_files, filename)) \ && !has_key(s:include_cache, filename) if !a:is_force && has_key(s:async_include_cache, filename) \ && len(s:async_include_cache[filename]) \ >= g:neoinclude#max_processes break endif let s:async_include_cache[filename] \ = s:initialize_include(filename, filetype, ctags, a:is_force) let include_info.async_files[filename] = 1 endif endfor endfunction function! s:get_buffer_include_files(bufnr) abort let filetype = getbufvar(a:bufnr, '&filetype') if filetype == '' return [] endif call neoinclude#set_filetype_paths(a:bufnr, filetype) let pattern = neoinclude#get_pattern(a:bufnr, filetype) if pattern == '' return [] endif let path = neoinclude#get_path(a:bufnr, filetype) let expr = neoinclude#get_expr(a:bufnr, filetype) let suffixes = &l:suffixesadd " Change current directory. let buffer_dir = fnamemodify(bufname(a:bufnr), ':p:h') let cwd_save = neoinclude#util#cd(buffer_dir) try let include_files = s:get_include_files(0, \ getbufline(a:bufnr, 1, 100), filetype, pattern, path, expr) finally if !empty(cwd_save) execute cwd_save[0] fnameescape(cwd_save[1]) endif " Restore option. let &l:suffixesadd = suffixes endtry return neoinclude#util#uniq(include_files) endfunction function! s:get_include_files(nestlevel, lines, filetype, pattern, path, expr) abort let include_files = [] for line in a:lines if line =~ a:pattern let match_end = matchend(line, a:pattern) if a:expr != '' let eval = substitute(a:expr, 'v:fname', \ string(matchstr(line[match_end :], '\f\+')), 'g') try let filename = fnamemodify(findfile(eval(eval), a:path), ':p') catch " Error let filename = '' endtry else let filename = fnamemodify(findfile( \ matchstr(line[match_end :], '\f\+'), a:path), ':p') endif if filereadable(filename) call add(include_files, filename) if a:nestlevel < 1 " Nested include files. let include_files += s:get_include_files( \ a:nestlevel + 1, readfile(filename, '', 100), \ a:filetype, a:pattern, a:path, a:expr) endif elseif isdirectory(filename) && a:filetype ==# 'java' " For Java import with *. " Ex: import lejos.nxt.* let include_files += neoinclude#util#glob(filename . '/*.java') endif endif endfor return include_files endfunction function! s:initialize_include(filename, filetype, ctags, is_force) abort " Initialize include list from tags. let tags_file_name = tempname() let args = neoinclude#util#get_buffer_config(a:filetype, \ 'b:neoinclude_ctags_arguments', \ g:neoinclude#ctags_arguments, \ g:neoinclude#_ctags_arguments, '') if a:ctags == 'jsctags' let command = printf('%s ''%s'' %s >''%s''', \ a:ctags, a:filename, args, tags_file_name) elseif has('win32') || has('win64') let filename = \ neoinclude#util#substitute_path_separator(a:filename) let command = printf('%s -f "%s" %s "%s" ', \ a:ctags, tags_file_name, args, filename) else let command = printf('%s -f ''%s'' 2>/dev/null %s ''%s''', \ a:ctags, tags_file_name, args, a:filename) endif if a:is_force call neoinclude#util#system(command) else call neoinclude#util#async_system(command) endif return { \ 'filename' : a:filename, \ 'cachename' : tags_file_name, \ } endfunction function! neoinclude#include#make_cache(bufname) abort call neoinclude#initialize() let bufnr = (a:bufname == '') ? bufnr('%') : bufnr(a:bufname) " Initialize. if has_key(s:include_info, bufnr) call remove(s:include_info, bufnr) endif call s:check_buffer(bufnr, 1) endfunction