Skip to content

Commit 6b58cd0

Browse files
authored
Merge pull request #472 from pangloss/develop
Develop -> Master
2 parents 0f0e4a7 + 9e5b60a commit 6b58cd0

File tree

3 files changed

+255
-304
lines changed

3 files changed

+255
-304
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# vim-javascript v1.0.0
1+
# vim-javascript
22

33
JavaScript bundle for vim, this bundle provides syntax highlighting and
44
improved indentation.

indent/javascript.vim

+85-116
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ setlocal nosmartindent
1616
" Now, set up our indentation expression and keys that trigger it.
1717
setlocal indentexpr=GetJavascriptIndent()
1818
setlocal formatexpr=Fixedgq(v:lnum,v:count)
19-
setlocal indentkeys=0{,0},0),0],0\,:,!^F,o,O,e
19+
setlocal indentkeys=0{,0},0),0],0\,*<Return>,:,!^F,o,O,e
2020
setlocal cinoptions+=j1,J1
2121

2222
" Only define the function once.
@@ -42,23 +42,28 @@ endif
4242
" ============
4343

4444
let s:line_pre = '^\s*\%(\/\*.*\*\/\s*\)*'
45-
let s:js_keywords = s:line_pre . '\%(break\|catch\|const\|continue\|debugger\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|let\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)\>\C'
45+
let s:js_keywords = s:line_pre . '\%(break\|import\|export\|catch\|const\|continue\|debugger\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|let\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)\>\C'
4646
let s:expr_case = s:line_pre . '\%(case\s\+[^\:]*\|default\)\s*:\s*\C'
4747
" Regex of syntax group names that are or delimit string or are comments.
48-
let s:syng_strcom = '\%(string\|regex\|comment\|template\)\c'
48+
let s:syng_strcom = '\%(string\|regex\|special\|comment\|template\)\c'
4949

5050
" Regex of syntax group names that are strings.
5151
let s:syng_string = 'regex\c'
5252

5353
" Regex of syntax group names that are strings or documentation.
54-
let s:syng_multiline = '\%(comment\|doc\)\c'
55-
56-
" Regex of syntax group names that are line comment.
57-
let s:syng_linecom = 'linecomment\c'
54+
let s:syng_comment = '\%(comment\|doc\)\c'
5855

5956
" Expression used to check whether we should skip a match with searchpair().
6057
let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'"
6158

59+
func s:lookForParens(start,end,flags,stop)
60+
try
61+
return searchpair(a:start,'',a:end,a:flags,s:skip_expr,a:stop,300)
62+
catch /E118/
63+
return searchpair(a:start,'',a:end,a:flags,0,a:stop)
64+
endtry
65+
endfunc
66+
6267
let s:line_term = '\s*\%(\%(\/\/.*\)\=\|\%(\/\*.*\*\/\s*\)*\)$'
6368

6469
" Regex that defines continuation lines, not including (, {, or [.
@@ -73,7 +78,7 @@ function s:Onescope(lnum)
7378
let mypos = col('.')
7479
call cursor(a:lnum, 1)
7580
if search('\<\%(while\|for\|if\)\>\s*(\C', 'ce', a:lnum) > 0 &&
76-
\ searchpair('(', '', ')', 'W', s:skip_expr, a:lnum) > 0 &&
81+
\ s:lookForParens('(', ')', 'W', a:lnum) > 0 &&
7782
\ col('.') == strlen(s:RemoveTrailingComments(getline(a:lnum)))
7883
call cursor(a:lnum, mypos)
7984
return 1
@@ -86,7 +91,7 @@ endfunction
8691
" Regex that defines blocks.
8792
let s:block_regex = '[{([]' . s:line_term
8893

89-
let s:operator_first = s:line_pre . '\%([.,:?]\|\([-/+*]\)\%(\1\|\*\|\/\)\@!\|||\|&&\)'
94+
let s:operator_first = s:line_pre . '\%([,:?]\|\([-/.+*]\)\%(\1\|\*\|\/\)\@!\|||\|&&\)'
9095

9196
let s:var_stmt = s:line_pre . '\%(const\|let\|var\)\s\+\C'
9297

@@ -106,32 +111,23 @@ function s:IsInString(lnum, col)
106111
endfunction
107112

108113
" Check if the character at lnum:col is inside a multi-line comment.
109-
function s:IsInMultilineComment(lnum, col)
110-
return !s:IsLineComment(a:lnum, a:col) && synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_multiline
111-
endfunction
112-
113-
" Check if the character at lnum:col is a line comment.
114-
function s:IsLineComment(lnum, col)
115-
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_linecom
114+
function s:IsInComment(lnum, col)
115+
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_comment
116116
endfunction
117117

118118
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
119119
function s:PrevNonBlankNonString(lnum)
120-
let in_block = 0
121120
let lnum = prevnonblank(a:lnum)
122121
while lnum > 0
123-
" Go in and out of blocks comments as necessary.
124-
" If the line isn't empty (with opt. comment) or in a string, end search.
125122
let line = getline(lnum)
126-
if s:IsInMultilineComment(lnum, matchend(line, '^\s*/\*') - 1) && line !~ s:line_pre . '$'
127-
if in_block
128-
let in_block = 0
129-
else
130-
break
131-
endif
132-
elseif !in_block && s:IsInMultilineComment(lnum, match(line, '\*/\s*$') + 1) && line !~ s:line_pre . '$'
133-
let in_block = 1
134-
elseif !in_block && line !~ s:line_pre . '\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line)))
123+
let com = match(line, '\%(\/\*.*\)\@<!\*\/') + 1
124+
if s:IsInComment(lnum, com)
125+
call cursor(lnum, com)
126+
let parlnum = search('\%(\/\/.*\)\@<!\/\*', 'nbW')
127+
if parlnum > 0
128+
let lnum = parlnum
129+
end
130+
elseif line !~ '^' . s:line_term && !s:IsInStringOrComment(lnum,1)
135131
break
136132
endif
137133
let lnum = prevnonblank(lnum - 1)
@@ -148,21 +144,18 @@ function s:GetMSL(lnum, in_one_line_scope)
148144
" If we have a continuation line, or we're in a string, use line as MSL.
149145
" Otherwise, terminate search as we have found our MSL already.
150146
let line = getline(lnum)
151-
let col = match(line, s:continuation_regex) + 1
152-
let coal = match(line, s:comma_last) + 1
153147
let line2 = getline(msl)
154-
let col2 = matchend(line2, ')')
155-
if ((col > 0 && !s:IsInStringOrComment(lnum, col) || coal > 0 && !s:IsInStringOrComment(lnum,coal)) &&
148+
if ((s:Match(lnum,s:continuation_regex) || s:Match(lnum, s:comma_last)) &&
156149
\ !s:Match(lnum, s:expr_case)) || s:IsInString(lnum, strlen(line))
157150
let msl = lnum
158-
159-
" if there are more closing brackets, continue from the line which has the matching opening bracket
160-
elseif col2 > 0 && !s:IsInStringOrComment(msl, col2) && s:LineHasOpeningBrackets(msl)[0] == '2' && !a:in_one_line_scope
161-
call cursor(msl, 1)
162-
if searchpair('(', '', ')', 'bW', s:skip_expr) > 0
163-
let lnum = line('.')
164-
let msl = lnum
165-
endif
151+
if s:Match(lnum, s:line_pre . '[]})]') && !a:in_one_line_scope
152+
call cursor(lnum,1)
153+
let parlnum = s:lookForParens('(\|{\|\[', ')\|}\|\]', 'nbW', 0)
154+
if parlnum > 0
155+
let lnum = parlnum
156+
continue
157+
end
158+
end
166159

167160
else
168161

@@ -191,18 +184,22 @@ endfunction
191184
" Find if the string is inside var statement (but not the first string)
192185
function s:InMultiVarStatement(lnum, cont, prev)
193186
let lnum = s:PrevNonBlankNonString(a:lnum - 1)
187+
let cont = a:cont
188+
let prev = a:prev
194189

195190
" let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name')
196191

197192
" loop through previous expressions to find a var statement
198-
while lnum > 0 && (s:Match(lnum, s:comma_last) ||(a:cont && getline(lnum) =~ s:line_pre . '}') ||
199-
\ s:Match(lnum,s:continuation_regex)) || (a:prev && (s:Match(a:prev, s:comma_last) ||
200-
\ s:Match(a:prev,s:continuation_regex)))
193+
while lnum > 0 && (s:Match(lnum, s:comma_last) ||(cont && getline(lnum) =~ s:line_pre . '[]})]') ||
194+
\ s:Match(lnum,s:continuation_regex)) || (prev && (s:Match(prev, s:comma_last) ||
195+
\ s:Match(prev,s:continuation_regex)))
201196
" if the line is a js keyword
202-
if a:cont
197+
if cont
198+
let cont = 0
203199
call cursor(lnum,1)
204-
if searchpair('{', '', '}', 'bW', s:skip_expr) > 0
205-
let lnum = line('.')
200+
let parlnum = s:lookForParens('(\|{\|\[', ')\|}\|\]', 'nbW', 0)
201+
if parlnum > 0
202+
let lnum = parlnum
206203
end
207204
end
208205
if s:Match(lnum, s:js_keywords)
@@ -219,33 +216,13 @@ function s:InMultiVarStatement(lnum, cont, prev)
219216
end
220217
endif
221218
let lnum = s:PrevNonBlankNonString(lnum - 1)
219+
let prev = prev && lnum > 0 ? prev : 0
222220
endwhile
223221

224222
" beginning of program, not a var
225223
return 0
226224
endfunction
227225

228-
" Find line above with beginning of the var statement or returns 0 if it's not"{{{2
229-
" this statement
230-
" function s:GetVarIndent(lnum)
231-
" let lvar = s:InMultiVarStatement(a:lnum, 0,0)
232-
" let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1)
233-
234-
" if lvar
235-
" let line = s:RemoveTrailingComments(getline(prev_lnum))
236-
237-
" " if the previous line doesn't end in a comma, return to regular indent
238-
" if (line !~ s:comma_last)
239-
" return indent(prev_lnum) - s:sw()
240-
" else
241-
" return indent(lvar) + s:sw()
242-
" endif
243-
" endif
244-
245-
" return -1
246-
" endfunction"}}}
247-
248-
249226
" Check if line 'lnum' has more opening brackets than closing ones.
250227
function s:LineHasOpeningBrackets(lnum)
251228
let open_0 = 0
@@ -345,20 +322,22 @@ function GetJavascriptIndent()
345322
let line = getline(v:lnum)
346323
" previous nonblank line number
347324
let prevline = prevnonblank(v:lnum - 1)
348-
325+
" previous line of code
326+
let lnum = s:PrevNonBlankNonString(v:lnum - 1)
327+
349328
" to not change multiline string values
350-
if synIDattr(synID(v:lnum, 1, 1), 'name') =~? 'string\|template' && line !~ s:line_pre . '[''"`]'
351-
return indent(v:lnum)
329+
if line !~ '^[''"`]' && synIDattr(synID(v:lnum, 1, 1), 'name') =~? 'string\|template'
330+
return -1
352331
endif
353332

354333
" If we are in a multi-line comment, cindent does the right thing.
355-
if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1) &&
356-
\ s:IsInMultilineComment(v:lnum, match(line, '\s*$')) && line !~ '^\/\*'
334+
if line !~ '^\%(\/\*\|\s*\/\/\)' && s:IsInComment(v:lnum, 1)
357335
return cindent(v:lnum)
358336
endif
359337

360338
" single opening bracket will assume you want a c style of indenting
361-
if s:Match(v:lnum, s:line_pre . '{' . s:line_term)
339+
if s:Match(v:lnum, s:line_pre . '{' . s:line_term) && !s:Match(lnum,s:block_regex) &&
340+
\ !s:Match(lnum,s:comma_last)
362341
return cindent(v:lnum)
363342
endif
364343

@@ -373,47 +352,48 @@ function GetJavascriptIndent()
373352
let col = matchend(line, s:line_pre . '[]})]')
374353
if col > 0 && !s:IsInStringOrComment(v:lnum, col)
375354
call cursor(v:lnum, col)
376-
377-
378-
let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
379-
if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0
380-
let ind = s:InMultiVarStatement(line('.'), 0, 0) ? indent(line('.')) : indent(s:GetMSL(line('.'), 0))
355+
let parlnum = s:lookForParens('(\|{\|\[', ')\|}\|\]', 'nbW', 0)
356+
if parlnum > 0
357+
let ind = s:InMultiVarStatement(parlnum, 0, 0) ? indent(parlnum) : indent(s:GetMSL(parlnum, 0))
381358
endif
382359
return ind
383360
endif
384361

362+
385363
" If line starts with an operator...
386364
if (line =~ s:operator_first)
387-
if (s:Match(prevline, s:operator_first))
365+
if (s:Match(lnum, s:operator_first))
388366
" and so does previous line, don't indent
389-
return indent(prevline)
367+
return indent(lnum)
390368
end
391-
let counts = s:LineHasOpeningBrackets(prevline)
392-
if counts[0] == '2' || counts[1] == '2' || counts[2] == '2'
393-
call cursor(prevline, 1)
369+
let counts = s:LineHasOpeningBrackets(lnum)
370+
if counts =~ '2'
371+
call cursor(lnum, 1)
394372
" Search for the opening tag
395-
let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
396-
if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0 && s:Match(line('.'), s:operator_first)
397-
return indent(line('.'))
373+
let parlnum = s:lookForParens('(\|{\|\[', ')\|}\|\]', 'nbW', 0)
374+
if parlnum > 0
375+
return !s:Match(parlnum, s:operator_first) &&
376+
\ synIDattr(synID(v:lnum, 1, 1), 'name') !~? 'jsbracket\|jsparen\|jsobject' ?
377+
\ indent(lnum) + s:sw() : indent(parlnum)
398378
end
399-
elseif counts[0] != '1' && counts[1] != '1' && counts[2] != '1'
400-
" otherwise, indent 1 level
401-
return indent(prevline) + s:sw()
379+
elseif synIDattr(synID(v:lnum, 1, 1), 'name') !~? 'jsbracket\|jsparen\|jsobject'
380+
" otherwise, if not in an key/val;array item;param, indent 1 level
381+
return indent(lnum) + s:sw()
402382
end
403383

404384
" If previous line starts with an operator...
405-
elseif (s:Match(prevline, s:operator_first) && !s:Match(prevline,s:continuation_regex))||getline(prevline) =~ ');\=' . s:line_term
406-
let counts = s:LineHasOpeningBrackets(prevline)
407-
if counts[0] == '2' && !s:Match(prevline, s:operator_first)
408-
call cursor(prevline, 1)
385+
elseif (s:Match(lnum, s:operator_first) && !s:Match(lnum,s:continuation_regex))||getline(lnum) =~ ');\=' . s:line_term
386+
let counts = s:LineHasOpeningBrackets(lnum)
387+
if counts[0] == '2' && !s:Match(lnum, s:operator_first)
388+
call cursor(lnum, 1)
409389
" Search for the opening tag
410-
let mnum = searchpair('(', '', ')', 'bW', s:skip_expr)
390+
let mnum = s:lookForParens('(', ')', 'nbW', 0)
411391
if mnum > 0 && s:Match(mnum, s:operator_first)
412392
return indent(mnum) - s:sw()
413393
end
414-
elseif s:Match(prevline, s:operator_first)
415-
if counts[0] != '1' && counts[1] != '1' && counts[2] != '1'
416-
return indent(prevline) - s:sw()
394+
elseif s:Match(lnum, s:operator_first)
395+
if counts !~ '1'
396+
return indent(lnum) - s:sw()
417397
end
418398
end
419399
end
@@ -424,12 +404,12 @@ function GetJavascriptIndent()
424404
" If the line is empty and the previous nonblank line was a multi-line
425405
" comment, use that comment's indent. Deduct one char to account for the
426406
" space in ' */'.
427-
if line =~ '^\s*$' && s:IsInMultilineComment(prevline, 1)
407+
if line =~ '^\s*$' && getline(prevline) !~ '\%(\%(^\s*\/\/\|\/\*\).*\)\@<!\*\/' &&
408+
\ s:IsInComment(prevline, 1)
428409
return indent(prevline) - 1
429410
endif
430411

431412
" Find a non-blank, non-multi-line string line above the current line.
432-
let lnum = s:PrevNonBlankNonString(v:lnum - 1)
433413

434414
" If the line is empty and inside a string, use the previous line.
435415
if line =~ '^\s*$' && lnum != prevline
@@ -454,25 +434,14 @@ function GetJavascriptIndent()
454434
" add indent depending on the bracket type.
455435
if s:Match(lnum, '[[({})\]]')
456436
let counts = s:LineHasOpeningBrackets(lnum)
457-
if counts[0] == '2'
458-
call cursor(lnum, 1)
459-
" Search for the opening tag
460-
if searchpair('(', '', ')', 'bW', s:skip_expr) > 0
461-
return indent(s:GetMSL(line('.'), 0))
462-
end
463-
elseif counts[1] == '2' && !s:Match(lnum, s:line_pre . '}')
464-
call cursor(lnum, 1)
465-
" Search for the opening tag
466-
if searchpair('{', '', '}', 'bW', s:skip_expr) > 0
467-
return indent(s:GetMSL(line('.'), 0))
468-
end
469-
elseif counts[2] == '2' && !s:Match(lnum, s:line_pre . ']')
437+
if counts =~ '2'
470438
call cursor(lnum, 1)
471439
" Search for the opening tag
472-
if searchpair('\[', '', '\]', 'bW', s:skip_expr) > 0
473-
return indent(s:GetMSL(line('.'), 0))
440+
let parlnum = s:lookForParens('(\|{\|\[', ')\|}\|\]', 'nbW', 0)
441+
if parlnum > 0 && !s:InMultiVarStatement(parlnum,0,0)
442+
return indent(s:GetMSL(parlnum, 0))
474443
end
475-
elseif counts[1] == '1' || counts[2] == '1' || counts[0] == '1' || s:Onescope(lnum)
444+
elseif counts =~ '1' || s:Onescope(lnum)
476445
return ind + s:sw()
477446
else
478447
call cursor(v:lnum, vcol)
@@ -525,7 +494,7 @@ function! Fixedgq(lnum, count)
525494
endif
526495

527496
" This gq is only meant to do code with strings, not comments
528-
if s:IsLineComment(a:lnum, l:first_char) || s:IsInMultilineComment(a:lnum, l:first_char)
497+
if s:IsInComment(a:lnum, l:first_char)
529498
return 1
530499
endif
531500

0 commit comments

Comments
 (0)