mirror of
https://github.com/gryf/.vim.git
synced 2025-12-17 11:30:29 +01:00
297 lines
7.7 KiB
VimL
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
|
|
"
|