1
0
mirror of https://github.com/gryf/.vim.git synced 2025-12-17 19:40:29 +01:00
Files
.vim/bundle/git_vim-nodejs-complete/after/autoload/nodejscomplete.vim
2013-01-27 20:59:07 +01:00

297 lines
7.7 KiB
VimL

" Vim completion script
" Language: Javascript(node)
" Maintainer: Lin Zhang ( myhere.2009 AT gmail DOT com )
" Last Change: 2012-8-18 1:32:00
" save current dir
let s:nodejs_doc_file = expand('<sfile>:p:h') . '/nodejs-doc.vim'
function! nodejscomplete#CompleteJS(findstart, base)
if a:findstart
if exists('g:node_usejscomplete') && g:node_usejscomplete
let start = jscomplete#CompleteJS(a:findstart, a:base)
else
let start = javascriptcomplete#CompleteJS(a:findstart, a:base)
endif
" complete context
let line = getline('.')
let b:nodecompl_context = line[0:start-1]
"Decho 'start: ' . start
return start
else
let nodeCompl = s:findNodeComplete(a:base)
if exists('g:node_usejscomplete') && g:node_usejscomplete
let jsCompl = jscomplete#CompleteJS(a:findstart, a:base)
else
let jsCompl = javascriptcomplete#CompleteJS(a:findstart, a:base)
endif
return nodeCompl + jsCompl
endif
endfunction
" complete node's build-in module
function! s:findNodeComplete(base)
" get complete context
let context = b:nodecompl_context
unlet b:nodecompl_context
"Decho 'context: ' . context
"Decho 'base: ' . a:base
let ret = []
" get object name
let obj_name = matchstr(context, '\k\+\ze\.$')
if (len(obj_name) == 0) " variable complete
let ret = s:getVariableComplete(context, a:base)
else " module complete
"Decho 'obj_name: ' . obj_name
" get variable declared line number
let decl_line = search(obj_name . '\s*=\s*require\s*(.\{-})', 'bn')
"Decho 'decl_line: ' . decl_line
if (decl_line == 0)
" maybe a global module
let ret = s:getModuleComplete(obj_name, a:base, 'globals')
else
" find the node module name
let mod_name = matchstr(getline(decl_line), obj_name . '\s*=\s*require\s*(\s*\([''"]\)\zs.\{-}\ze\(\1\)\s*)')
if exists('mod_name')
let ret = s:getModuleComplete(mod_name, a:base, 'modules')
endif
endif
endif
return ret
endfunction
function! s:getModuleComplete(mod_name, prop_name, type)
"Decho 'mod_name: ' . a:mod_name
"Decho 'prop_name: ' . a:prop_name
"Decho 'type: ' . a:type
call s:loadNodeDocData()
let ret = []
let mods = {}
let mod = []
if (has_key(g:nodejs_complete_data, a:type))
let mods = g:nodejs_complete_data[a:type]
endif
if (has_key(mods, a:mod_name))
let mod = mods[a:mod_name]
endif
" no prop_name suplied
if (len(a:prop_name) == 0)
let ret = mod
else
" filter properties with prop_name
let ret = filter(copy(mod), 'v:val["word"] =~# "' . a:prop_name . '"')
endif
"Decho string(ret)
return ret
endfunction
function! s:getVariableComplete(context, var_name)
"Decho 'var_name: ' . a:var_name
" complete require's arguments
let matched = matchlist(a:context, 'require\s*(\s*\%(\([''"]\)\(\.\{1,2}.*\)\=\)\=$')
if (len(matched) > 0)
"Decho 'require: ' . string(matched)
if (len(matched[2]) > 0) " complete -> require('./
let mod_names = s:getModuleInCurrentDir(a:context, a:var_name, matched)
else
let mod_names = s:getModuleNames()
if (len(matched[1]) == 0) " complete -> require(
call map(mod_names, '"''" . v:val . "'')"')
elseif (len(a:var_name) == 0) " complete -> require('
call map(mod_names, 'v:val . "' . escape(matched[1], '"') . ')"')
else " complete -> require('ti
let mod_names = filter(mod_names, 'v:val =~# "^' . a:var_name . '"')
call map(mod_names, 'v:val . "' . escape(matched[1], '"') . ')"')
endif
endif
return mod_names
endif
" complete global variables
let vars = []
if (len(a:var_name) == 0)
return vars
endif
call s:loadNodeDocData()
if (has_key(g:nodejs_complete_data, 'vars'))
let vars = g:nodejs_complete_data.vars
endif
let ret = filter(copy(vars), 'v:val["word"] =~# "^' . a:var_name . '"')
return ret
endfunction
function! s:getModuleInCurrentDir(context, var_name, matched)
let mod_names = []
let path = a:matched[2] . a:var_name
" typed as require('..
" complete as require('../
" cause the latter one is more common
let compl_prefix = ''
if (path =~# '\.\.$')
let compl_prefix = '/'
let path = path . compl_prefix
endif
"Decho 'path: ' . path
let current_dir = expand('%:p:h')
let glob_path = current_dir . '/' . path . '*'
let files = s:fuzglob(glob_path)
"Decho 'glob: ' . glob_path
"Decho 'current dir files: ' . string(files)
for file in files
" not '.' and '..'
if ((isdirectory(file) ) || file =~? '\.json$\|\.js$')
let mod_file = file
" directory
if (file !~? '\.json$\|\.js$')
let mod_file = mod_file . '/'
endif
" get complete word
let mod_file = substitute(mod_file, '\', '/', 'g')
let start = len(glob_path) - 1 " substract character '*'
let compl_infix = strpart(mod_file, start)
"Decho 'idx: ' . start
"Decho 'compl_infix: ' . compl_infix
"Decho 'relative file: ' . mod_file
let mod_name = compl_prefix . a:var_name . compl_infix
" file module, not a directory
if (compl_infix !~# '/$')
let mod_name = mod_name . a:matched[1] . ')'
endif
"Decho 'mod_name: ' . mod_name
call add(mod_names, mod_name)
endif
endfor
"Decho 'relative path: ' . path
return mod_names
endfunction
function! s:getModuleNames()
call s:loadNodeDocData()
let mod_names = []
" build-in module name
if (has_key(g:nodejs_complete_data, 'modules'))
let mod_names = keys(g:nodejs_complete_data.modules)
endif
" find module in 'module_dir' folder
if (!exists('b:npm_module_names'))
let current_dir = expand('%:p:h')
let b:npm_module_names = s:getModuleNamesInNode_modulesFolder(current_dir)
endif
let mod_names = mod_names + b:npm_module_names
return sort(mod_names)
endfunction
function! s:getModuleNamesInNode_modulesFolder(current_dir)
" ensure platform coincidence
let base_dir = substitute(a:current_dir, '\', '/', 'g')
"Decho 'base_dir: ' . base_dir
let ret = []
let parts = split(base_dir, '/', 1)
"Decho 'parts: ' . string(parts)
let idx = 0
let len = len(parts)
let sub_parts = []
while idx < len
let sub_parts = add(sub_parts, parts[idx])
let module_dir = join(sub_parts, '/') . '/node_modules'
"Decho 'directory: ' . module_dir
if (isdirectory(module_dir))
let files = s:fuzglob(module_dir . '/*')
"Decho 'node_module files: ' . string(files)
for file in files
if (isdirectory(file) || file =~? '\.json$\|\.js$')
let mod_name = matchstr(file, '[^/\\]\+$')
let ret = add(ret, mod_name)
endif
endfor
endif
let idx = idx + 1
endwhile
"Decho 'npm modules: ' . string(ret)
return ret
endfunction
function! s:loadNodeDocData()
" load node module data
if (!exists('g:nodejs_complete_data'))
" load data from external file
let filename = s:nodejs_doc_file
"Decho 'filename: ' . filename
if (filereadable(filename))
"Decho 'readable'
execute 'so ' . filename
"Decho string(g:nodejs_complete_data)
else
"Decho 'not readable'
endif
endif
endfunction
" copied from FuzzyFinder/autoload/fuf.vim
" returns list of paths.
" An argument for glob() is normalized in order to avoid a bug on Windows.
function! s:fuzglob(expr)
" Substitutes "\", because on Windows, "**\" doesn't include ".\",
" but "**/" include "./". I don't know why.
return split(glob(substitute(a:expr, '\', '/', 'g')), "\n")
endfunction
"
" use plugin Decho(https://github.com/vim-scripts/Decho) for debug
"
" turn off debug mode
" :%s;^\(\s*\)\(Decho\);\1"\2;g
"
" turn on debug mode
" :%s;^\(\s*\)"\(Decho\);\1\2;g
"