43
43
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\)'
44
44
let s: expr_case = ' ^\s*\(case\s\+[^\:]*\|default\)\s*:\s*'
45
45
" Regex of syntax group names that are or delimit string or are comments.
46
- let s: syng_strcom = ' string\|regex\|comment\c'
46
+ let s: syng_strcom = ' \%(\%(template\)\@<!string\|regex\|comment\)\c'
47
+
48
+ " Regex of syntax group names that are or delimit template strings
49
+ let s: syng_template = ' template\c'
47
50
48
51
" Regex of syntax group names that are strings.
49
52
let s: syng_string = ' regex\c'
@@ -60,25 +63,24 @@ let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_st
60
63
let s: line_term = ' \s*\%(\%(\/\/\).*\)\=$'
61
64
62
65
" Regex that defines continuation lines, not including (, {, or [.
63
- let s: continuation_regex = ' \%([\\*+ /.:]\|\ %(<%\)\@<![=-] \|\W[|&?]\|||\|&&\|[^=]=[^=].*,\)' . s: line_term
66
+ let s: continuation_regex = ' \%([\\*/.:]\|+\@<!+\|-\@<!-\|\ %(<%\)\@<!= \|\W[|&?]\|||\|&&\|[^=]=[^=> ].*,\)' . s: line_term
64
67
65
68
" Regex that defines continuation lines.
66
69
" TODO: this needs to deal with if ...: and so on
67
- let s: msl_regex = s: continuation_regex .' |' .s: expr_case
70
+ let s: msl_regex = s: continuation_regex .' \ |' .s: expr_case
68
71
69
- let s: one_line_scope_regex = ' \%(\<else\>\|\<\%(if\|for\|while\)\>\s*(.*) \)' . s: line_term
72
+ let s: one_line_scope_regex = ' \%(\%(\ <else\>\|\<\%(if\|for\|while\)\>\s*(\%([^()]*\|[^()]*(\%([^()]*\|[^()]*(\%([^()]*\|[^()]*([^()]*)[^()]*\))[^()]*\))[^()]*\))\)\|=> \)' . s: line_term
70
73
71
74
" Regex that defines blocks.
72
- let s: block_regex = ' \%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s: line_term
75
+ let s: block_regex = ' \%([{([]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s: line_term
76
+
77
+ let s: operator_first = ' ^\s*\%([*/.:?]\|\([-+]\)\1\@!\|||\|&&\)'
73
78
74
- let s: var_stmt = ' ^\s*(const\|let\|var)'
79
+ let s: var_stmt = ' ^\s*\% (const\|let\|var\ )'
75
80
76
81
let s: comma_first = ' ^\s*,'
77
82
let s: comma_last = ' ,\s*$'
78
83
79
- let s: ternary = ' ^\s\+[?|:]'
80
- let s: ternary_q = ' ^\s\+?'
81
-
82
84
let s: case_indent = s: sw ()
83
85
let s: case_indent_after = s: sw ()
84
86
let s: m = matchlist (&cinoptions , ' :\(.\)' )
@@ -102,6 +104,11 @@ function s:IsInString(lnum, col)
102
104
return synIDattr (synID (a: lnum , a: col , 1 ), ' name' ) = ~ s: syng_string
103
105
endfunction
104
106
107
+ " Check if the character at lnum:col is inside a template string.
108
+ function s: IsInTempl (lnum, col )
109
+ return synIDattr (synID (a: lnum , a: col , 1 ), ' name' ) = ~ s: syng_template
110
+ endfunction
111
+
105
112
" Check if the character at lnum:col is inside a multi-line comment.
106
113
function s: IsInMultilineComment (lnum, col )
107
114
return ! s: IsLineComment (a: lnum , a: col ) && synIDattr (synID (a: lnum , a: col , 1 ), ' name' ) = ~ s: syng_multiline
@@ -120,13 +127,13 @@ function s:PrevNonBlankNonString(lnum)
120
127
" Go in and out of blocks comments as necessary.
121
128
" If the line isn't empty (with opt. comment) or in a string, end search.
122
129
let line = getline (lnum)
123
- if line = ~ ' /\*'
130
+ if s: IsInMultilineComment (lnum, matchend ( line , ' /\*' ) - 1 )
124
131
if in_block
125
132
let in_block = 0
126
133
else
127
134
break
128
135
endif
129
- elseif ! in_block && line = ~ ' \*/'
136
+ elseif ! in_block && s: IsInMultilineComment (lnum, matchend ( line , ' \*/' ) - 1 )
130
137
let in_block = 1
131
138
elseif ! in_block && line !~ ' ^\s*\%(//\).*$' && ! (s: IsInStringOrComment (lnum, 1 ) && s: IsInStringOrComment (lnum, strlen (line )))
132
139
break
@@ -146,9 +153,21 @@ function s:GetMSL(lnum, in_one_line_scope)
146
153
" Otherwise, terminate search as we have found our MSL already.
147
154
let line = getline (lnum)
148
155
let col = match (line , s: msl_regex ) + 1
156
+ let line2 = getline (msl)
157
+ let col2 = matchend (line2, ' )' )
149
158
if (col > 0 && ! s: IsInStringOrComment (lnum, col )) || s: IsInString (lnum, strlen (line ))
150
159
let msl = lnum
160
+
161
+ " if there are more closing brackets, continue from the line which has the matching opening bracket
162
+ elseif col2 > 0 && ! s: IsInStringOrComment (msl, col2) && s: LineHasOpeningBrackets (msl)[0 ] == ' 2' && ! a: in_one_line_scope
163
+ call cursor (msl, 1 )
164
+ if searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr ) > 0
165
+ let lnum = line (' .' )
166
+ let msl = lnum
167
+ endif
168
+
151
169
else
170
+
152
171
" Don't use lines that are part of a one line scope as msl unless the
153
172
" flag in_one_line_scope is set to 1
154
173
"
@@ -159,7 +178,7 @@ function s:GetMSL(lnum, in_one_line_scope)
159
178
if msl_one_line == 0
160
179
break
161
180
endif
162
- endif
181
+ end
163
182
let lnum = s: PrevNonBlankNonString (lnum - 1 )
164
183
endwhile
165
184
return msl
@@ -240,7 +259,7 @@ function s:LineHasOpeningBrackets(lnum)
240
259
endif
241
260
let pos = match (line , ' [][(){}]' , pos + 1 )
242
261
endwhile
243
- return (open_0 > 0 ) . (open_2 > 0 ) . (open_4 > 0 )
262
+ return (open_0 > 0 ? 1 : (open_0 == 0 ? 0 : 2 ) ) . (open_2 > 0 ) . (open_4 > 0 )
244
263
endfunction
245
264
246
265
function s: Match (lnum, regex)
@@ -378,12 +397,45 @@ function GetJavascriptIndent()
378
397
return indent (prevline) + s: case_indent_after
379
398
endif
380
399
381
- if (line = ~ s: ternary )
382
- if (getline (prevline) = ~ s: ternary_q )
400
+ " If line starts with an operator...
401
+ if (s: Match (v: lnum , s: operator_first ))
402
+ if (s: Match (prevline, s: operator_first ))
403
+ " and so does previous line, don't indent
383
404
return indent (prevline)
384
- else
405
+ end
406
+ let counts = s: LineHasOpeningBrackets (prevline)
407
+ if counts[0 ] == ' 2'
408
+ call cursor (prevline, 1 )
409
+ " Search for the opening tag
410
+ let mnum = searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr )
411
+ if mnum > 0 && s: Match (mnum, s: operator_first )
412
+ return indent (mnum)
413
+ end
414
+ elseif counts[0 ] != ' 1' && counts[1 ] != ' 1' && counts[2 ] != ' 1'
415
+ " otherwise, indent 1 level
416
+ return indent (prevline) + s: sw ()
417
+ end
418
+ " If previous line starts with an operator...
419
+ elseif s: Match (prevline, s: operator_first ) && ! s: Match (prevline, s: comma_last ) && ! s: Match (prevline, ' };\=' . s: line_term )
420
+ let counts = s: LineHasOpeningBrackets (prevline)
421
+ if counts[0 ] == ' 2' && counts[1 ] == ' 1'
422
+ call cursor (prevline, 1 )
423
+ " Search for the opening tag
424
+ let mnum = searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr )
425
+ if mnum > 0 && ! s: Match (mnum, s: operator_first )
426
+ return indent (mnum) + s: sw ()
427
+ end
428
+ elseif counts[0 ] != ' 1' && counts[1 ] != ' 1' && counts[2 ] != ' 1'
429
+ return indent (prevline) - s: sw ()
430
+ end
431
+ end
432
+
433
+ if getline (prevline) = ~ ' ^\s*`$' && s: IsInTempl (v: lnum , 1 )
434
+ if line !~ ' ^\s*`$'
385
435
return indent (prevline) + s: sw ()
386
436
endif
437
+ elseif line = ~ ' ^\s*`$' && s: IsInTempl (prevline, 1 )
438
+ return indent (prevline) - s: sw ()
387
439
endif
388
440
389
441
" If we are in a multi-line comment, cindent does the right thing.
@@ -438,17 +490,36 @@ function GetJavascriptIndent()
438
490
if line = ~ ' [[({]'
439
491
let counts = s: LineHasOpeningBrackets (lnum)
440
492
if counts[0 ] == ' 1' && searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr ) > 0
441
- if col (' .' ) + 1 == col (' $' )
493
+ if col (' .' ) + 1 == col (' $' ) || line = ~ s: one_line_scope_regex
442
494
return ind + s: sw ()
443
495
else
444
496
return virtcol (' .' )
445
497
endif
446
- elseif counts[1 ] == ' 1' || counts[2 ] == ' 1'
498
+ elseif counts[1 ] == ' 1' || counts[2 ] == ' 1' && counts[ 0 ] != ' 2 '
447
499
return ind + s: sw ()
448
500
else
449
501
call cursor (v: lnum , vcol)
450
502
end
451
- endif
503
+ elseif line = ~ ' .\+};\=' . s: line_term
504
+ call cursor (lnum, 1 )
505
+ " Search for the opening tag
506
+ let mnum = searchpair (' {' , ' ' , ' }' , ' bW' , s: skip_expr )
507
+ if mnum > 0
508
+ return indent (s: GetMSL (mnum, 0 ))
509
+ end
510
+ elseif line = ~ ' .\+);\=' || line = ~ s: comma_last
511
+ let counts = s: LineHasOpeningBrackets (lnum)
512
+ if counts[0 ] == ' 2'
513
+ call cursor (lnum, 1 )
514
+ " Search for the opening tag
515
+ let mnum = searchpair (' (' , ' ' , ' )' , ' bW' , s: skip_expr )
516
+ if mnum > 0
517
+ return indent (s: GetMSL (mnum, 0 ))
518
+ end
519
+ elseif line !~ s: var_stmt
520
+ return indent (prevline)
521
+ end
522
+ end
452
523
453
524
" 3.4. Work on the MSL line. {{{2
454
525
" --------------------------
0 commit comments