]> git.r.bdr.sh - rbdr/dotfiles/blob - vim/ftplugin/javascript/jslint.vim
2ce7605e065c4c2b2abf0b6816cfac6ebe7d7c03
[rbdr/dotfiles] / vim / ftplugin / javascript / jslint.vim
1
2 " Global Options
3 "
4 " Enable/Disable highlighting of errors in source.
5 " Default is Enable
6 " To disable the highlighting put the line
7 " let g:JSLintHighlightErrorLine = 0
8 " in your .vimrc
9 "
10 if exists("b:did_jslint_plugin")
11 finish
12 else
13 let b:did_jslint_plugin = 1
14 endif
15
16 let s:install_dir = expand('<sfile>:p:h')
17
18 au BufLeave <buffer> call s:JSLintClear()
19
20 au BufEnter <buffer> call s:JSLint()
21 au InsertLeave <buffer> call s:JSLint()
22 "au InsertEnter <buffer> call s:JSLint()
23 au BufWritePost <buffer> call s:JSLint()
24
25 " due to http://tech.groups.yahoo.com/group/vimdev/message/52115
26 if(!has("win32") || v:version>702)
27 au CursorHold <buffer> call s:JSLint()
28 au CursorHoldI <buffer> call s:JSLint()
29
30 au CursorHold <buffer> call s:GetJSLintMessage()
31 endif
32
33 au CursorMoved <buffer> call s:GetJSLintMessage()
34
35 if !exists("g:JSLintHighlightErrorLine")
36 let g:JSLintHighlightErrorLine = 1
37 endif
38
39 if !exists("*s:JSLintUpdate")
40 function s:JSLintUpdate()
41 silent call s:JSLint()
42 call s:GetJSLintMessage()
43 endfunction
44 endif
45
46 if !exists(":JSLintUpdate")
47 command JSLintUpdate :call s:JSLintUpdate()
48 endif
49 if !exists(":JSLintToggle")
50 command JSLintToggle exec ":let b:jslint_disabled = exists('b:jslint_disabled') ? b:jslint_disabled ? 0 : 1 : 1" |
51 \ echo 'JSLint ' . ['enabled', 'disabled'][b:jslint_disabled] . '.'
52 endif
53
54 noremap <buffer><silent> dd dd:JSLintUpdate<CR>
55 noremap <buffer><silent> dw dw:JSLintUpdate<CR>
56 noremap <buffer><silent> u u:JSLintUpdate<CR>
57 noremap <buffer><silent> <C-R> <C-R>:JSLintUpdate<CR>
58
59 " Set up command and parameters
60 if has("win32")
61 let s:runjslint_ext = 'js'
62 if exists("%JS_CMD%")
63 let s:cmd = "$JS_CMD"
64 elseif executable('node')
65 let s:cmd = "node"
66 else
67 let s:cmd = 'cscript /NoLogo '
68 let s:runjslint_ext = 'wsf'
69 endif
70 else
71 let s:runjslint_ext = 'js'
72 if exists("$JS_CMD")
73 let s:cmd = "$JS_CMD"
74 elseif executable('node')
75 let s:cmd = 'node'
76 elseif executable('nodejs')
77 let s:cmd = 'nodejs'
78 elseif executable('/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc')
79 let s:cmd = '/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc'
80 elseif executable('js')
81 let s:cmd = 'js'
82 else
83 echoerr('No JS interpreter found. Checked for jsc, js (spidermonkey), and node')
84 endif
85 endif
86 let s:plugin_path = s:install_dir . "/jslint/"
87 if has('win32')
88 let s:plugin_path = substitute(s:plugin_path, '/', '\', 'g')
89 endif
90 if has('win32')
91 let s:cmd = 'cmd.exe /C "cd /d "' . s:plugin_path . '" && ' . s:cmd . ' "' . s:plugin_path . 'runjslint.' . s:runjslint_ext . '""'
92 else
93 let s:cmd = 'cd "' . s:plugin_path . '" && ' . s:cmd . ' "' . s:plugin_path . 'runjslint.' . s:runjslint_ext . '"'
94 endif
95
96 let s:jslintrc_file = expand('~/.jslintrc')
97 if filereadable(s:jslintrc_file)
98 let s:jslintrc = readfile(s:jslintrc_file)
99 else
100 let s:jslintrc = []
101 end
102
103 " load .jslintrc file from the current (pwd) directory if exists
104 let s:localrc_file = fnamemodify(".", ":p") . '/.jslintrc'
105 if filereadable(s:localrc_file)
106 let s:localrc = readfile(s:localrc_file)
107 let s:jslintrc = s:jslintrc + s:localrc
108 endif
109 " load .jslintrc file from the directory where the file is if exists
110 let s:file_dir_file = expand('%:p:h') . '/.jslintrc'
111 if filereadable(s:file_dir_file)
112 let s:filedir_rc = readfile(s:file_dir_file)
113 let s:jslintrc = s:jslintrc + s:filedir_rc
114 endif
115
116 " WideMsg() prints [long] message up to (&columns-1) length
117 " guaranteed without "Press Enter" prompt.
118 if !exists("*s:WideMsg")
119 function s:WideMsg(msg)
120 let x=&ruler | let y=&showcmd
121 set noruler noshowcmd
122 redraw
123 echo a:msg
124 let &ruler=x | let &showcmd=y
125 endfun
126 endif
127
128
129 function! s:JSLintClear()
130 " Delete previous matches
131 let s:matches = getmatches()
132 for s:matchId in s:matches
133 if s:matchId['group'] == 'JSLintError'
134 call matchdelete(s:matchId['id'])
135 endif
136 endfor
137 let b:matched = []
138 let b:matchedlines = {}
139 let b:cleared = 1
140 endfunction
141
142 function! s:JSLint()
143 if exists("b:jslint_disabled") && b:jslint_disabled == 1
144 return
145 endif
146
147 highlight link JSLintError SpellBad
148
149 if exists("b:cleared")
150 if b:cleared == 0
151 call s:JSLintClear()
152 endif
153 let b:cleared = 1
154 endif
155
156 let b:matched = []
157 let b:matchedlines = {}
158
159 " Detect range
160 if a:firstline == a:lastline
161 " Skip a possible shebang line, e.g. for node.js script.
162 if getline(1)[0:1] == "#!"
163 let b:firstline = 2
164 else
165 let b:firstline = 1
166 endif
167 let b:lastline = '$'
168 else
169 let b:firstline = a:firstline
170 let b:lastline = a:lastline
171 endif
172
173 let b:qf_list = []
174 let b:qf_window_count = -1
175
176 let lines = join(s:jslintrc + getline(b:firstline, b:lastline), "\n")
177 if len(lines) == 0
178 return
179 endif
180 if has('win32') || has('win64')
181 let b:jslint_output = system(s:cmd, lines . "\n")
182 else
183 let old_shell = &shell
184 let &shell = '/bin/bash'
185 let b:jslint_output = system(s:cmd, lines . "\n")
186 let &shell = old_shell
187 endif
188 if v:shell_error
189 echoerr b:jslint_output
190 echoerr 'could not invoke JSLint!'
191 let b:jslint_disabled = 1
192 end
193
194 for error in split(b:jslint_output, "\n")
195 " Match {line}:{char}:{message}
196 let b:parts = matchlist(error, '\v(\d+):(\d+):([A-Z]+):(.*)')
197 if !empty(b:parts)
198 let l:line = b:parts[1] + (b:firstline - 1 - len(s:jslintrc)) " Get line relative to selection
199 let l:errorMessage = b:parts[4]
200
201 if l:line < 1
202 echoerr 'error in jslintrc, line ' . b:parts[1] . ', character ' . b:parts[2] . ': ' . l:errorMessage
203 else
204 " Store the error for an error under the cursor
205 let s:matchDict = {}
206 let s:matchDict['lineNum'] = l:line
207 let s:matchDict['message'] = l:errorMessage
208 let b:matchedlines[l:line] = s:matchDict
209 if b:parts[3] == 'ERROR'
210 let l:errorType = 'E'
211 else
212 let l:errorType = 'W'
213 endif
214 if g:JSLintHighlightErrorLine == 1
215 let s:mID = matchadd('JSLintError', '\v%' . l:line . 'l\S.*(\S|$)')
216 endif
217 " Add line to match list
218 call add(b:matched, s:matchDict)
219
220 " Store the error for the quickfix window
221 let l:qf_item = {}
222 let l:qf_item.bufnr = bufnr('%')
223 let l:qf_item.filename = expand('%')
224 let l:qf_item.lnum = l:line
225 let l:qf_item.text = l:errorMessage
226 let l:qf_item.type = l:errorType
227
228 " Add line to quickfix list
229 call add(b:qf_list, l:qf_item)
230 endif
231 endif
232 endfor
233
234 if exists("s:jslint_qf")
235 " if jslint quickfix window is already created, reuse it
236 call s:ActivateJSLintQuickFixWindow()
237 call setqflist(b:qf_list, 'r')
238 else
239 " one jslint quickfix window for all buffers
240 call setqflist(b:qf_list, '')
241 let s:jslint_qf = s:GetQuickFixStackCount()
242 endif
243 let b:cleared = 0
244 endfunction
245
246 let b:showing_message = 0
247
248 if !exists("*s:GetJSLintMessage")
249 function s:GetJSLintMessage()
250 let s:cursorPos = getpos(".")
251
252 " Bail if RunJSLint hasn't been called yet
253 if !exists('b:matchedlines')
254 return
255 endif
256
257 if has_key(b:matchedlines, s:cursorPos[1])
258 let s:jslintMatch = get(b:matchedlines, s:cursorPos[1])
259 call s:WideMsg(s:jslintMatch['message'])
260 let b:showing_message = 1
261 return
262 endif
263
264 if b:showing_message == 1
265 echo
266 let b:showing_message = 0
267 endif
268 endfunction
269 endif
270
271 if !exists("*s:GetQuickFixStackCount")
272 function s:GetQuickFixStackCount()
273 let l:stack_count = 0
274 try
275 silent colder 9
276 catch /E380:/
277 endtry
278
279 try
280 for i in range(9)
281 silent cnewer
282 let l:stack_count = l:stack_count + 1
283 endfor
284 catch /E381:/
285 return l:stack_count
286 endtry
287 endfunction
288 endif
289
290 if !exists("*s:ActivateJSLintQuickFixWindow")
291 function s:ActivateJSLintQuickFixWindow()
292 try
293 silent colder 9 " go to the bottom of quickfix stack
294 catch /E380:/
295 catch /E788:/
296 endtry
297
298 if s:jslint_qf > 0
299 try
300 exe "silent cnewer " . s:jslint_qf
301 catch /E381:/
302 echoerr "Could not activate JSLint Quickfix Window."
303 endtry
304 endif
305 endfunction
306 endif
307