@@ -18,7 +18,7 @@ setlocal nosmartindent
1818" Now, set up our indentation expression and keys that trigger it.
1919setlocal indentexpr = GetJavascriptIndent ()
2020setlocal formatexpr = Fixedgq (v: lnum ,v: count )
21- setlocal indentkeys = 0 {,0 },0 ),0 ],0 \, ,! ^F,o ,O,e
21+ setlocal indentkeys = 0 {,0 },0 ),0 ],0 \, : ,! ^F,o ,O,e
2222
2323" Only define the function once.
2424if exists (" *GetJavascriptIndent" )
@@ -28,13 +28,27 @@ endif
2828let s: cpo_save = &cpo
2929set cpo &vim
3030
31+ " Get shiftwidth value
32+ if exists (' *shiftwidth' )
33+ func s: sw ()
34+ return shiftwidth ()
35+ endfunc
36+ else
37+ func s: sw ()
38+ return &sw
39+ endfunc
40+ endif
41+
3142" 1. Variables {{{1
3243" ============
3344
34- let s: js_keywords = ' ^\s*\(break\|case\|catch \|continue\|debugger\|default\| delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)'
35-
45+ let s: js_keywords = ' ^\s*\(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\)'
46+ let s: expr_case = ' ^\s*\(case\s\+[^\:]*\|default\)\s*:\s* '
3647" Regex of syntax group names that are or delimit string or are comments.
37- let s: syng_strcom = ' string\|regex\|comment\c'
48+ let s: syng_strcom = ' \%(\%(template\)\@<!string\|regex\|comment\)\c'
49+
50+ " Regex of syntax group names that are or delimit template strings
51+ let s: syng_template = ' template\c'
3852
3953" Regex of syntax group names that are strings.
4054let s: syng_string = ' regex\c'
@@ -51,25 +65,34 @@ let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_st
5165let s: line_term = ' \s*\%(\%(\/\/\).*\)\=$'
5266
5367" Regex that defines continuation lines, not including (, {, or [.
54- let s: continuation_regex = ' \%([\\*+ /.:]\|\ %(<%\)\@<![=-] \|\W[|&?]\|||\|&&\|[^=]=[^=].*,\)' . s: line_term
68+ let s: continuation_regex = ' \%([\\*/.:]\|+\@<!+\|-\@<!-\|\ %(<%\)\@<!= \|\W[|&?]\|||\|&&\|[^=]=[^=> ].*,\)' . s: line_term
5569
5670" Regex that defines continuation lines.
5771" TODO: this needs to deal with if ...: and so on
58- let s: msl_regex = s: continuation_regex
72+ let s: msl_regex = s: continuation_regex. ' \| ' . s: expr_case
5973
60- let s: one_line_scope_regex = ' \< \%(if\| else\| for\|while\)\>[^{;]* ' . s: line_term
74+ let s: one_line_scope_regex = ' \%( \%(\< else\>\|\<\%(if\| for\|while\)\>\s*(\%([^()]*\|[^()]*(\%([^()]*\|[^()]*(\%([^()]*\|[^()]*([^()]*)[^()]*\))[^()]*\))[^()]*\))\)\|=>\) ' . s: line_term
6175
6276" Regex that defines blocks.
63- let s: block_regex = ' \%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s: line_term
77+ let s: block_regex = ' \%([{([]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s: line_term
78+
79+ let s: operator_first = ' ^\s*\%([*/.:?]\|\([-+]\)\1\@!\|||\|&&\)'
6480
65- let s: var_stmt = ' ^\s*var'
81+ let s: var_stmt = ' ^\s*\%(const\|let\| var\) '
6682
6783let s: comma_first = ' ^\s*,'
6884let s: comma_last = ' ,\s*$'
6985
70- let s: ternary = ' ^\s\+[?|:]'
71- let s: ternary_q = ' ^\s\+?'
72-
86+ let s: case_indent = s: sw ()
87+ let s: case_indent_after = s: sw ()
88+ let s: m = matchlist (&cinoptions , ' :\(.\)' )
89+ if (len (s: m ) > 2 )
90+ let s: case_indent = s: m [1 ]
91+ endif
92+ let s: m = matchlist (&cinoptions , ' =\(.\)' )
93+ if (len (s: m ) > 2 )
94+ let s: case_indent_after = s: m [1 ]
95+ endif
7396" 2. Auxiliary Functions {{{1
7497" ======================
7598
@@ -83,6 +106,11 @@ function s:IsInString(lnum, col)
83106 return synIDattr (synID (a: lnum , a: col , 1 ), ' name' ) = ~ s: syng_string
84107endfunction
85108
109+ " Check if the character at lnum:col is inside a template string.
110+ function s: IsInTempl (lnum, col )
111+ return synIDattr (synID (a: lnum , a: col , 1 ), ' name' ) = ~ s: syng_template
112+ endfunction
113+
86114" Check if the character at lnum:col is inside a multi-line comment.
87115function s: IsInMultilineComment (lnum, col )
88116 return ! s: IsLineComment (a: lnum , a: col ) && synIDattr (synID (a: lnum , a: col , 1 ), ' name' ) = ~ s: syng_multiline
@@ -101,13 +129,13 @@ function s:PrevNonBlankNonString(lnum)
101129 " Go in and out of blocks comments as necessary.
102130 " If the line isn't empty (with opt. comment) or in a string, end search.
103131 let line = getline (lnum)
104- if line = ~ ' /\*'
132+ if s: IsInMultilineComment (lnum, matchend ( line , ' /\*' ) - 1 )
105133 if in_block
106134 let in_block = 0
107135 else
108136 break
109137 endif
110- elseif ! in_block && line = ~ ' \*/'
138+ elseif ! in_block && s: IsInMultilineComment (lnum, matchend ( line , ' \*/' ) - 1 )
111139 let in_block = 1
112140 elseif ! in_block && line !~ ' ^\s*\%(//\).*$' && ! (s: IsInStringOrComment (lnum, 1 ) && s: IsInStringOrComment (lnum, strlen (line )))
113141 break
@@ -127,9 +155,21 @@ function s:GetMSL(lnum, in_one_line_scope)
127155 " Otherwise, terminate search as we have found our MSL already.
128156 let line = getline (lnum)
129157 let col = match (line , s: msl_regex ) + 1
158+ let line2 = getline (msl)
159+ let col2 = matchend (line2, ' )' )
130160 if (col > 0 && ! s: IsInStringOrComment (lnum, col )) || s: IsInString (lnum, strlen (line ))
131161 let msl = lnum
162+
163+ " if there are more closing brackets, continue from the line which has the matching opening bracket
164+ elseif col2 > 0 && ! s: IsInStringOrComment (msl, col2) && s: LineHasOpeningBrackets (msl)[0 ] == ' 2' && ! a: in_one_line_scope
165+ call cursor (msl, 1 )
166+ if searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr ) > 0
167+ let lnum = line (' .' )
168+ let msl = lnum
169+ endif
170+
132171 else
172+
133173 " Don't use lines that are part of a one line scope as msl unless the
134174 " flag in_one_line_scope is set to 1
135175 "
@@ -140,7 +180,7 @@ function s:GetMSL(lnum, in_one_line_scope)
140180 if msl_one_line == 0
141181 break
142182 endif
143- endif
183+ end
144184 let lnum = s: PrevNonBlankNonString (lnum - 1 )
145185 endwhile
146186 return msl
@@ -193,9 +233,9 @@ function s:GetVarIndent(lnum)
193233
194234 " if the previous line doesn't end in a comma, return to regular indent
195235 if (line !~ s: comma_last )
196- return indent (prev_lnum) - & sw
236+ return indent (prev_lnum) - s: sw ()
197237 else
198- return indent (lvar) + & sw
238+ return indent (lvar) + s: sw ()
199239 endif
200240 endif
201241
@@ -221,7 +261,7 @@ function s:LineHasOpeningBrackets(lnum)
221261 endif
222262 let pos = match (line , ' [][(){}]' , pos + 1 )
223263 endwhile
224- return (open_0 > 0 ) . (open_2 > 0 ) . (open_4 > 0 )
264+ return (open_0 > 0 ? 1 : (open_0 == 0 ? 0 : 2 ) ) . (open_2 > 0 ) . (open_4 > 0 )
225265endfunction
226266
227267function s: Match (lnum, regex)
@@ -302,6 +342,17 @@ function GetJavascriptIndent()
302342 " previous nonblank line number
303343 let prevline = prevnonblank (v: lnum - 1 )
304344
345+ if (line = ~ s: expr_case )
346+ if (getline (prevline) = ~ s: expr_case )
347+ return indent (prevline)
348+ else
349+ if (getline (prevline) = ~ s: block_regex )
350+ return indent (prevline) + s: case_indent
351+ else
352+ return indent (prevline) - s: case_indent_after
353+ endif
354+ endif
355+ endif
305356 " If we got a closing bracket on an empty line, find its match and indent
306357 " according to it. For parentheses we indent to its column - 1, for the
307358 " others we indent to the containing line's MSL's level. Return -1 if fail.
@@ -323,7 +374,7 @@ function GetJavascriptIndent()
323374 return indent (prevline)
324375 " otherwise we indent 1 level
325376 else
326- return indent (lvar) + & sw
377+ return indent (lvar) + s: sw ()
327378 endif
328379 endif
329380 endif
@@ -342,15 +393,51 @@ function GetJavascriptIndent()
342393
343394 " If the line is comma first, dedent 1 level
344395 if (getline (prevline) = ~ s: comma_first )
345- return indent (prevline) - &sw
396+ return indent (prevline) - s: sw ()
397+ endif
398+ if (getline (prevline) = ~ s: expr_case )
399+ return indent (prevline) + s: case_indent_after
346400 endif
347401
348- if (line = ~ s: ternary )
349- if (getline (prevline) = ~ s: ternary_q )
402+ " If line starts with an operator...
403+ if (s: Match (v: lnum , s: operator_first ))
404+ if (s: Match (prevline, s: operator_first ))
405+ " and so does previous line, don't indent
350406 return indent (prevline)
351- else
352- return indent (prevline) + &sw
407+ end
408+ let counts = s: LineHasOpeningBrackets (prevline)
409+ if counts[0 ] == ' 2'
410+ call cursor (prevline, 1 )
411+ " Search for the opening tag
412+ let mnum = searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr )
413+ if mnum > 0 && s: Match (mnum, s: operator_first )
414+ return indent (mnum)
415+ end
416+ elseif counts[0 ] != ' 1' && counts[1 ] != ' 1' && counts[2 ] != ' 1'
417+ " otherwise, indent 1 level
418+ return indent (prevline) + s: sw ()
419+ end
420+ " If previous line starts with an operator...
421+ elseif s: Match (prevline, s: operator_first ) && ! s: Match (prevline, s: comma_last ) && ! s: Match (prevline, ' };\=' . s: line_term )
422+ let counts = s: LineHasOpeningBrackets (prevline)
423+ if counts[0 ] == ' 2' && counts[1 ] == ' 1'
424+ call cursor (prevline, 1 )
425+ " Search for the opening tag
426+ let mnum = searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr )
427+ if mnum > 0 && ! s: Match (mnum, s: operator_first )
428+ return indent (mnum) + s: sw ()
429+ end
430+ elseif counts[0 ] != ' 1' && counts[1 ] != ' 1' && counts[2 ] != ' 1'
431+ return indent (prevline) - s: sw ()
432+ end
433+ end
434+
435+ if getline (prevline) = ~ ' ^\s*`$' && s: IsInTempl (v: lnum , 1 )
436+ if line !~ ' ^\s*`$'
437+ return indent (prevline) + s: sw ()
353438 endif
439+ elseif line = ~ ' ^\s*`$' && s: IsInTempl (prevline, 1 )
440+ return indent (prevline) - s: sw ()
354441 endif
355442
356443 " If we are in a multi-line comment, cindent does the right thing.
@@ -387,48 +474,71 @@ function GetJavascriptIndent()
387474 return 0
388475 endif
389476
390- " Set up variables for current line.
391- let line = getline (lnum)
392- let ind = indent (lnum)
393477
394478 " If the previous line ended with a block opening, add a level of indent.
395479 if s: Match (lnum, s: block_regex )
396- return indent (s: GetMSL (lnum, 0 )) + &sw
480+ if (line = ~ s: expr_case )
481+ return indent (s: GetMSL (lnum, 0 )) + s: sw ()/2
482+ else
483+ return indent (s: GetMSL (lnum, 0 )) + s: sw ()
484+ endif
397485 endif
398486
487+ " Set up variables for current line.
488+ let line = getline (lnum)
489+ let ind = indent (lnum)
399490 " If the previous line contained an opening bracket, and we are still in it,
400491 " add indent depending on the bracket type.
401492 if line = ~ ' [[({]'
402493 let counts = s: LineHasOpeningBrackets (lnum)
403494 if counts[0 ] == ' 1' && searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr ) > 0
404- if col (' .' ) + 1 == col (' $' )
405- return ind + & sw
495+ if col (' .' ) + 1 == col (' $' ) || line = ~ s: one_line_scope_regex
496+ return ind + s: sw ()
406497 else
407498 return virtcol (' .' )
408499 endif
409- elseif counts[1 ] == ' 1' || counts[2 ] == ' 1'
410- return ind + & sw
500+ elseif counts[1 ] == ' 1' || counts[2 ] == ' 1' && counts[ 0 ] != ' 2 '
501+ return ind + s: sw ()
411502 else
412503 call cursor (v: lnum , vcol)
413504 end
414- endif
505+ elseif line = ~ ' .\+};\=' . s: line_term
506+ call cursor (lnum, 1 )
507+ " Search for the opening tag
508+ let mnum = searchpair (' {' , ' ' , ' }' , ' bW' , s: skip_expr )
509+ if mnum > 0
510+ return indent (s: GetMSL (mnum, 0 ))
511+ end
512+ elseif line = ~ ' .\+);\=' || line = ~ s: comma_last
513+ let counts = s: LineHasOpeningBrackets (lnum)
514+ if counts[0 ] == ' 2'
515+ call cursor (lnum, 1 )
516+ " Search for the opening tag
517+ let mnum = searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr )
518+ if mnum > 0
519+ return indent (s: GetMSL (mnum, 0 ))
520+ end
521+ elseif line !~ s: var_stmt
522+ return indent (prevline)
523+ end
524+ end
415525
416526 " 3.4. Work on the MSL line. {{{2
417527 " --------------------------
418528
419529 let ind_con = ind
420- let ind = s: IndentWithContinuation (lnum, ind_con, & sw )
530+ let ind = s: IndentWithContinuation (lnum, ind_con, s: sw () )
421531
422532 " }}}2
423533 "
424534 "
425535 let ols = s: InOneLineScope (lnum)
426536 if ols > 0
427- let ind = ind + & sw
537+ let ind = ind + s: sw ()
428538 else
429539 let ols = s: ExitingOneLineScope (lnum)
430540 while ols > 0 && ind > 0
431- let ind = ind - & sw
541+ let ind = ind - s: sw ()
432542 let ols = s: InOneLineScope (ols - 1 )
433543 endwhile
434544 endif
0 commit comments