4 " Enable/Disable highlighting of errors in source.
6 " To disable the highlighting put the line
7 " let g:JSLintHighlightErrorLine = 0
10 if exists("b:did_jslint_plugin")
13 let b:did_jslint_plugin = 1
16 let s:install_dir = expand('<sfile>:p:h')
18 au BufLeave <buffer> call s:JSLintClear()
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()
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()
30 au CursorHold <buffer> call s:GetJSLintMessage()
33 au CursorMoved <buffer> call s:GetJSLintMessage()
35 if !exists("g:JSLintHighlightErrorLine")
36 let g:JSLintHighlightErrorLine = 1
39 if !exists("*s:JSLintUpdate")
40 function s:JSLintUpdate()
41 silent call s:JSLint()
42 call s:GetJSLintMessage()
46 if !exists(":JSLintUpdate")
47 command JSLintUpdate :call s:JSLintUpdate()
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] . '.'
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>
59 " Set up command and parameters
61 let s:runjslint_ext = 'js'
64 elseif executable('node')
67 let s:cmd = 'cscript /NoLogo '
68 let s:runjslint_ext = 'wsf'
71 let s:runjslint_ext = 'js'
74 elseif executable('node')
76 elseif executable('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')
83 echoerr('No JS interpreter found. Checked for jsc, js (spidermonkey), and node')
86 let s:plugin_path = s:install_dir . "/jslint/"
88 let s:plugin_path = substitute(s:plugin_path, '/', '\', 'g')
91 let s:cmd = 'cmd.exe /C "cd /d "' . s:plugin_path . '" && ' . s:cmd . ' "' . s:plugin_path . 'runjslint.' . s:runjslint_ext . '""'
93 let s:cmd = 'cd "' . s:plugin_path . '" && ' . s:cmd . ' "' . s:plugin_path . 'runjslint.' . s:runjslint_ext . '"'
96 let s:jslintrc_file = expand('~/.jslintrc')
97 if filereadable(s:jslintrc_file)
98 let s:jslintrc = readfile(s:jslintrc_file)
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
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
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
124 let &ruler=x | let &showcmd=y
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'])
138 let b:matchedlines = {}
143 if exists("b:jslint_disabled") && b:jslint_disabled == 1
147 highlight link JSLintError SpellBad
149 if exists("b:cleared")
157 let b:matchedlines = {}
160 if a:firstline == a:lastline
161 " Skip a possible shebang line, e.g. for node.js script.
162 if getline(1)[0:1] == "#!"
169 let b:firstline = a:firstline
170 let b:lastline = a:lastline
174 let b:qf_window_count = -1
176 let lines = join(s:jslintrc + getline(b:firstline, b:lastline), "\n")
180 if has('win32') || has('win64')
181 let b:jslint_output = system(s:cmd, lines . "\n")
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
189 echoerr b:jslint_output
190 echoerr 'could not invoke JSLint!'
191 let b:jslint_disabled = 1
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]+):(.*)')
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]
202 echoerr 'error in jslintrc, line ' . b:parts[1] . ', character ' . b:parts[2] . ': ' . l:errorMessage
204 " Store the error for an error under the cursor
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'
212 let l:errorType = 'W'
214 if g:JSLintHighlightErrorLine == 1
215 let s:mID = matchadd('JSLintError', '\v%' . l:line . 'l\S.*(\S|$)')
217 " Add line to match list
218 call add(b:matched, s:matchDict)
220 " Store the error for the quickfix window
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
228 " Add line to quickfix list
229 call add(b:qf_list, l:qf_item)
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')
239 " one jslint quickfix window for all buffers
240 call setqflist(b:qf_list, '')
241 let s:jslint_qf = s:GetQuickFixStackCount()
246 let b:showing_message = 0
248 if !exists("*s:GetJSLintMessage")
249 function s:GetJSLintMessage()
250 let s:cursorPos = getpos(".")
252 " Bail if RunJSLint hasn't been called yet
253 if !exists('b:matchedlines')
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
264 if b:showing_message == 1
266 let b:showing_message = 0
271 if !exists("*s:GetQuickFixStackCount")
272 function s:GetQuickFixStackCount()
273 let l:stack_count = 0
282 let l:stack_count = l:stack_count + 1
290 if !exists("*s:ActivateJSLintQuickFixWindow")
291 function s:ActivateJSLintQuickFixWindow()
293 silent colder 9 " go to the bottom of quickfix stack
300 exe "silent cnewer " . s:jslint_qf
302 echoerr "Could not activate JSLint Quickfix Window."