@@ -16,7 +16,7 @@ setlocal nosmartindent
16
16
" Now, set up our indentation expression and keys that trigger it.
17
17
setlocal indentexpr = GetJavascriptIndent ()
18
18
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
20
20
setlocal cinoptions += j1,J1
21
21
22
22
" Only define the function once.
@@ -42,23 +42,28 @@ endif
42
42
" ============
43
43
44
44
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'
46
46
let s: expr_case = s: line_pre . ' \%(case\s\+[^\:]*\|default\)\s*:\s*\C'
47
47
" 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'
49
49
50
50
" Regex of syntax group names that are strings.
51
51
let s: syng_string = ' regex\c'
52
52
53
53
" 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'
58
55
59
56
" Expression used to check whether we should skip a match with searchpair().
60
57
let s: skip_expr = " synIDattr(synID(line('.'),col('.'),1),'name') =~ '" .s: syng_strcom ." '"
61
58
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
+
62
67
let s: line_term = ' \s*\%(\%(\/\/.*\)\=\|\%(\/\*.*\*\/\s*\)*\)$'
63
68
64
69
" Regex that defines continuation lines, not including (, {, or [.
@@ -73,7 +78,7 @@ function s:Onescope(lnum)
73
78
let mypos = col (' .' )
74
79
call cursor (a: lnum , 1 )
75
80
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 &&
77
82
\ col (' .' ) == strlen (s: RemoveTrailingComments (getline (a: lnum )))
78
83
call cursor (a: lnum , mypos)
79
84
return 1
@@ -86,7 +91,7 @@ endfunction
86
91
" Regex that defines blocks.
87
92
let s: block_regex = ' [{([]' . s: line_term
88
93
89
- let s: operator_first = s: line_pre . ' \%([. ,:?]\|\([-/+*]\)\%(\1\|\*\|\/\)\@!\|||\|&&\)'
94
+ let s: operator_first = s: line_pre . ' \%([,:?]\|\([-/. +*]\)\%(\1\|\*\|\/\)\@!\|||\|&&\)'
90
95
91
96
let s: var_stmt = s: line_pre . ' \%(const\|let\|var\)\s\+\C'
92
97
@@ -106,32 +111,23 @@ function s:IsInString(lnum, col)
106
111
endfunction
107
112
108
113
" 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
116
116
endfunction
117
117
118
118
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
119
119
function s: PrevNonBlankNonString (lnum)
120
- let in_block = 0
121
120
let lnum = prevnonblank (a: lnum )
122
121
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.
125
122
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 )
135
131
break
136
132
endif
137
133
let lnum = prevnonblank (lnum - 1 )
@@ -148,21 +144,18 @@ function s:GetMSL(lnum, in_one_line_scope)
148
144
" If we have a continuation line, or we're in a string, use line as MSL.
149
145
" Otherwise, terminate search as we have found our MSL already.
150
146
let line = getline (lnum)
151
- let col = match (line , s: continuation_regex ) + 1
152
- let coal = match (line , s: comma_last ) + 1
153
147
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 )) &&
156
149
\ ! s: Match (lnum, s: expr_case )) || s: IsInString (lnum, strlen (line ))
157
150
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
166
159
167
160
else
168
161
@@ -191,18 +184,22 @@ endfunction
191
184
" Find if the string is inside var statement (but not the first string)
192
185
function s: InMultiVarStatement (lnum, cont, prev )
193
186
let lnum = s: PrevNonBlankNonString (a: lnum - 1 )
187
+ let cont = a: cont
188
+ let prev = a: prev
194
189
195
190
" let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name')
196
191
197
192
" 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 )))
201
196
" if the line is a js keyword
202
- if a: cont
197
+ if cont
198
+ let cont = 0
203
199
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
206
203
end
207
204
end
208
205
if s: Match (lnum, s: js_keywords )
@@ -219,33 +216,13 @@ function s:InMultiVarStatement(lnum, cont, prev)
219
216
end
220
217
endif
221
218
let lnum = s: PrevNonBlankNonString (lnum - 1 )
219
+ let prev = prev && lnum > 0 ? prev : 0
222
220
endwhile
223
221
224
222
" beginning of program, not a var
225
223
return 0
226
224
endfunction
227
225
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
-
249
226
" Check if line 'lnum' has more opening brackets than closing ones.
250
227
function s: LineHasOpeningBrackets (lnum)
251
228
let open_0 = 0
@@ -345,20 +322,22 @@ function GetJavascriptIndent()
345
322
let line = getline (v: lnum )
346
323
" previous nonblank line number
347
324
let prevline = prevnonblank (v: lnum - 1 )
348
-
325
+ " previous line of code
326
+ let lnum = s: PrevNonBlankNonString (v: lnum - 1 )
327
+
349
328
" 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
352
331
endif
353
332
354
333
" 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 )
357
335
return cindent (v: lnum )
358
336
endif
359
337
360
338
" 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 )
362
341
return cindent (v: lnum )
363
342
endif
364
343
@@ -373,47 +352,48 @@ function GetJavascriptIndent()
373
352
let col = matchend (line , s: line_pre . ' []})]' )
374
353
if col > 0 && ! s: IsInStringOrComment (v: lnum , col )
375
354
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 ))
381
358
endif
382
359
return ind
383
360
endif
384
361
362
+
385
363
" If line starts with an operator...
386
364
if (line = ~ s: operator_first )
387
- if (s: Match (prevline , s: operator_first ))
365
+ if (s: Match (lnum , s: operator_first ))
388
366
" and so does previous line, don't indent
389
- return indent (prevline )
367
+ return indent (lnum )
390
368
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 )
394
372
" 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)
398
378
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 ()
402
382
end
403
383
404
384
" 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 )
409
389
" Search for the opening tag
410
- let mnum = searchpair (' (' , ' ' , ' )' , ' bW ' , s: skip_expr )
390
+ let mnum = s: lookForParens (' (' , ' )' , ' nbW ' , 0 )
411
391
if mnum > 0 && s: Match (mnum, s: operator_first )
412
392
return indent (mnum) - s: sw ()
413
393
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 ()
417
397
end
418
398
end
419
399
end
@@ -424,12 +404,12 @@ function GetJavascriptIndent()
424
404
" If the line is empty and the previous nonblank line was a multi-line
425
405
" comment, use that comment's indent. Deduct one char to account for the
426
406
" space in ' */'.
427
- if line = ~ ' ^\s*$' && s: IsInMultilineComment (prevline, 1 )
407
+ if line = ~ ' ^\s*$' && getline (prevline) !~ ' \%(\%(^\s*\/\/\|\/\*\).*\)\@<!\*\/' &&
408
+ \ s: IsInComment (prevline, 1 )
428
409
return indent (prevline) - 1
429
410
endif
430
411
431
412
" Find a non-blank, non-multi-line string line above the current line.
432
- let lnum = s: PrevNonBlankNonString (v: lnum - 1 )
433
413
434
414
" If the line is empty and inside a string, use the previous line.
435
415
if line = ~ ' ^\s*$' && lnum != prevline
@@ -454,25 +434,14 @@ function GetJavascriptIndent()
454
434
" add indent depending on the bracket type.
455
435
if s: Match (lnum, ' [[({})\]]' )
456
436
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'
470
438
call cursor (lnum, 1 )
471
439
" 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 ))
474
443
end
475
- elseif counts[ 1 ] == ' 1 ' || counts[ 2 ] == ' 1 ' || counts[ 0 ] == ' 1' || s: Onescope (lnum)
444
+ elseif counts = ~ ' 1' || s: Onescope (lnum)
476
445
return ind + s: sw ()
477
446
else
478
447
call cursor (v: lnum , vcol)
@@ -525,7 +494,7 @@ function! Fixedgq(lnum, count)
525
494
endif
526
495
527
496
" 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 )
529
498
return 1
530
499
endif
531
500
0 commit comments