aboutsummaryrefslogtreecommitdiff
path: root/dotfiles/.vim/autoload/node.vim
blob: 3954e4ccfc4b6672135aeac6e47aa7163e662bcb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
" Vim by default sets the filetype to JavaScript for the following suffices.
" And, yes, it has .jsx there.
let node#suffixesadd = [".js", ".json", ".es", ".jsx"]

function! node#initialize(root)
	let b:node_root = a:root

	command! -bar -bang -nargs=1 -buffer -complete=customlist,s:complete Nedit
		\ exe s:nedit(<q-args>, bufname("%"), "edit<bang>")
	command! -bar -bang -nargs=1 -buffer -complete=customlist,s:complete Nopen
		\ exe s:nopen(<q-args>, bufname("%"), "edit<bang>")

	nnoremap <buffer><silent> <Plug>NodeGotoFile
		\ :call <SID>edit(expand("<cfile>"), bufname("%"))<CR>
	nnoremap <buffer><silent> <Plug>NodeSplitGotoFile
		\ :call <SID>edit(expand("<cfile>"), bufname("%"), "split")<CR>
	nnoremap <buffer><silent> <Plug>NodeVSplitGotoFile
		\ :call <SID>edit(expand("<cfile>"), bufname("%"), "vsplit")<CR>
	nnoremap <buffer><silent> <Plug>NodeTabGotoFile
		\ :call <SID>edit(expand("<cfile>"), bufname("%"), "tab split")<CR>

	silent doautocmd User Node
endfunction

function! node#javascript()
	" This might be called multiple times if multiple filetypes match.
	if exists("b:node_javascript") && b:node_javascript | return | endif
	let b:node_javascript = 1

	setlocal path-=/usr/include
	let &l:suffixesadd .= "," . join(g:node#suffixesadd, ",")
	let &l:include = '\<require(\(["'']\)\zs[^\1]\+\ze\1'
	let &l:includeexpr = "node#lib#find(v:fname, bufname('%'))"

	" @ is used for scopes, but isn't a default filename character on
	" non-Windows sytems.
	setlocal isfname+=@-@

	if !hasmapto("<Plug>NodeGotoFile")
		" Split gotofiles don't take a count for the new window's width, but for
		" opening the nth file. Though Node.vim doesn't support counts atm.
		nmap <buffer> gf <Plug>NodeGotoFile
		nmap <buffer> <C-w>f <Plug>NodeSplitGotoFile
		nmap <buffer> <C-w><C-f> <Plug>NodeSplitGotoFile
		nmap <buffer> <C-w>gf <Plug>NodeTabGotoFile
	endif
endfunction

function! s:edit(name, from, ...)
	if empty(a:name) | return | endif
	let dir = isdirectory(a:from) ? a:from : fnamemodify(a:from, ":h")
	let command = a:0 == 1 ? a:1 : "edit"

	" If just a plain filename with no directory part, check if it exists:
	if a:name !~# '^\v(/|\./|\.\./)' && filereadable(dir . "/" . a:name)
		let path = dir . "/" . a:name
	else
		let path = node#lib#find(a:name, dir)
	end

	if empty(path)
		return s:error("E447: Can't find file \"" . a:name . "\" in path")
	endif

	exe command . " " . fnameescape(path)
endfunction

function! s:nedit(name, from, ...)
	let command = a:0 == 1 ? a:1 : "edit"
	call s:edit(a:name, b:node_root, command)
endfunction

function! s:nopen(name, from, ...)
	let command = a:0 == 1 ? a:1 : "edit"
	call s:nedit(a:name, a:from, command)
	if exists("b:node_root") | exe "lcd " . fnameescape(b:node_root) | endif
endfunction

function! s:complete(arg, cmd, cursor)
	let matches = node#lib#glob(s:dirname(a:arg))

	" Show private modules (_*) only if explicitly asked:
	if a:arg[0] != "_" | call filter(matches, "v:val[0] != '_'") | endif

	let filter = "stridx(v:val, a:arg) == 0"
	let ignorecase = 0
	let ignorecase = ignorecase || exists("&fileignorecase") && &fileignorecase
	let ignorecase = ignorecase || exists("&wildignorecase") && &wildignorecase
	if ignorecase | let filter = "stridx(tolower(v:val),tolower(a:arg)) == 0" | en

	return filter(matches, filter)
endfunction

function! s:dirname(path)
	let dirname = fnamemodify(a:path, ":h")
	if dirname == "." | return "" | endif

	" To not change the amount of final consecutive slashes, using this
	" dirname/basename trick:
	let basename = fnamemodify(a:path, ":t")
	return a:path[0 : 0 - len(basename) - 1]
endfunction

" Using the built-in :echoerr prints a stacktrace, which isn't that nice.
function! s:error(msg)
	echohl ErrorMsg
	echomsg a:msg
	echohl NONE
	let v:errmsg = a:msg
endfunction