22" Language: Javascript
33" Maintainer: Chris Paul ( https://github.com/bounceme )
44" URL: https://github.com/pangloss/vim-javascript
5- " Last Change: October 9 , 2016
5+ " Last Change: October 24 , 2016
66
77" Only load this indent file when no other was loaded.
88if exists (' b:did_indent' )
@@ -12,7 +12,7 @@ let b:did_indent = 1
1212
1313" Now, set up our indentation expression and keys that trigger it.
1414setlocal indentexpr = GetJavascriptIndent ()
15- setlocal nolisp noautoindent nosmartindent
15+ setlocal autoindent nolisp nosmartindent
1616setlocal indentkeys = 0 {,0 },0 ),0 ],:,! ^F,o ,O,e
1717setlocal cinoptions += j1,J1
1818
3737 endfunction
3838endif
3939
40- let s: line_pre = ' ^\s*\%(\%(\%(\/\*.\{-}\)\=\*\+\/\s*\)\=\)\@>'
41- let s: line_term = ' \s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$'
42-
4340let s: expr_case = ' \<\%(\%(case\>\s*\S.\{-}\)\|default\)\s*:\C'
4441" Regex of syntax group names that are or delimit string or are comments.
4542let s: syng_strcom = ' \%(s\%(tring\|pecial\)\|comment\|regex\|doc\|template\)'
@@ -53,114 +50,110 @@ function s:skip_func(lnum)
5350 return ! s: free
5451 endif
5552 let s: looksyn = line (' .' )
56- return (search ( ' \/ ' , ' nbW ' , line (' .' )) || search (' ['' "\\]' ,' nW' ,line ( ' . ' ) )) && eval (s: skip_expr )
53+ return (strridx ( getline ( ' . ' ), ' / ' , col (' .' )-1 ) + 1 || search (' ['' "\\]' ,' nW' ,s: looksyn )) && eval (s: skip_expr )
5754endfunction
5855
5956if has (' reltime' )
6057 function s: GetPair (start ,end ,flags,skip ,time,... )
6158 return searchpair (a: start ,' ' ,a: end ,a: flags ,a: skip ,max ([prevnonblank (v: lnum ) - 2000 ,0 ] + a: 000 ),a: time )
6259 endfunction
6360else
64- function s: GetPair (start ,end ,flags,... )
65- return searchpair (a: start ,' ' ,a: end ,a: flags ," line('.') < prevnonblank(v:lnum) - 2000 ? dummy : 0 " )
61+ function s: GetPair (start ,end ,flags,skip , ... )
62+ return searchpair (a: start ,' ' ,a: end ,a: flags ,a: skip , max ([ prevnonblank (v: lnum ) - 1000 , get ( a: 000 , 1 )]) )
6663 endfunction
6764endif
6865
69- " indent/python.vim
70- function s: Trimline (ln )
71- let pline = getline (a: ln )
72- let min = match (pline,' \/[/*]' ) + 1
73- if min && synIDattr (synID (a: ln , strlen (pline), 0 ), ' name' ) = ~? ' \%(comment\|doc\)'
74- let max = match (pline,' .*\zs\/[/*]' ) + 1
75- while min < max
76- let col = (min + max ) / 2
77- if synIDattr (synID (a: ln , col , 0 ), ' name' ) = ~? ' \%(comment\|doc\)'
78- let max = col
79- else
80- let min = match (pline,' \/[/*]' ,col ) + 1
81- endif
82- endwhile
83- let pline = strpart (pline, 0 , min - 1 )
84- endif
85- return substitute (pline,' \s*$' ,' ' ,' ' )
66+ function s: Trim (ln )
67+ let pline = substitute (getline (a: ln ),' \s*$' ,' ' ,' ' )
68+ let l: max = max ([strridx (pline,' //' ),strridx (pline,' /*' ),0 ])
69+ while l: max && synIDattr (synID (a: ln , strlen (pline), 0 ), ' name' ) = ~? ' \%(comment\|doc\)'
70+ let pline = substitute (strpart (pline, 0 , l: max ),' \s*$' ,' ' ,' ' )
71+ let l: max = max ([strridx (pline,' //' ),strridx (pline,' /*' ),0 ])
72+ endwhile
73+ return pline
8674endfunction
8775
8876" configurable regexes that define continuation lines, not including (, {, or [.
89- if ! exists (' g:javascript_opfirst' )
90- let g: javascript_opfirst = ' \%([<>,?^%|*&]\|\/[/*]\@!\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
91- endif
92- if ! exists (' g:javascript_continuation' )
93- let g: javascript_continuation = ' \%([<=,.?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)'
94- endif
95-
96- let g: javascript_opfirst = ' ^' . g: javascript_opfirst
97- let g: javascript_continuation .= ' $'
77+ let s: opfirst = ' ^' . get (g: ,' javascript_opfirst' ,
78+ \ ' \%([<>,?^%|*&]\|\/[/*]\@!\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' )
79+ let s: continuation = get (g: ,' javascript_continuation' ,
80+ \ ' \%([<=,.?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)' ) . ' $'
9881
9982function s: OneScope (lnum,text)
100- return cursor (a: lnum , match (' ' . a: text , ' \%(\<else\|\<do\|=>\)$' )) > - 1 ||
101- \ cursor (a: lnum , match (' ' . a: text , ' )$' )) > - 1 &&
83+ return cursor (a: lnum , match (' ' . a: text , ' \%(\<else\|\<do\|=>\)$' )) + 1 ||
84+ \ cursor (a: lnum , match (' ' . a: text , ' )$' )) + 1 &&
10285 \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 &&
10386 \ search (' \C\<\%(for\%(\_s\+\%(await\|each\)\)\=\|if\|let\|w\%(hile\|ith\)\)\_s*\%#' ,' bW' )
10487endfunction
10588
10689function s: iscontOne (i ,num,cont)
10790 let [l: i , l: cont , l: num ] = [a: i , a: cont , a: num + ! a: num ]
108- let pind = a: num ? indent (l: num ) : - s: W
109- let ind = indent (l: i ) + (! l : cont * s: W )
91+ let pind = a: num ? indent (l: num ) + s: W : 0
92+ let ind = indent (l: i ) + (a : cont ? 0 : s: W )
11093 let bL = 0
111- while l: i >= l: num && (! l: cont || ind > pind + s: W )
94+ while l: i >= l: num && (! l: cont || ind > pind)
11295 if indent (l: i ) < ind " first line always true for !a:cont, false for !!a:cont
113- if s: OneScope (l: i ,s: Trimline (l: i ))
96+ if s: OneScope (l: i ,s: Trim (l: i ))
11497 if expand (' <cword>' ) == # ' while' &&
115- \ s: GetPair (s: line_pre . ' \C\<do\>' ,' \C\<while\>' ,' bW' ,s: skip_expr ,100 ,l: num + ! ! a: num ) > 0
98+ \ s: GetPair (' \C\<do\>' ,' \C\<while\>' ,' bW' ,' line2byte(line(".")) + col(".") <'
99+ \ . (line2byte (l: num ) + b: js_cache [2 ]) . ' ||'
100+ \ . s: skip_expr . ' || !s:IsBlock()' ,100 ,l: num ) > 0
116101 return 0
117102 endif
118- let bL += 1
103+ let bL += s: W
119104 let [l: cont , l: i ] = [0 , line (' .' )]
120105 elseif ! l: cont
121106 break
122107 endif
123108 let ind = indent (l: i )
109+ elseif ! a: cont
110+ break
124111 endif
125112 let l: i = s: PrevCodeLine (l: i - 1 )
126113 endwhile
127- return bL * s: W
114+ return bL
128115endfunction
129116
130117" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
131118function s: IsBlock ()
132- if getline (line (' .' ))[col (' .' )-1 ] == ' {'
133- if search (' \C\<return\s*\%#' ,' nbW' )
134- return 0
135- endif
136- if search (' \*\/\_s*\%#' ,' bW' ) && synIDattr (synID (line (' .' ),col (' .' ),0 ),' name' ) = ~? ' comment'
137- call searchpair (' \/\*' ,' ' ,' \*\/' ,' bW' )
119+ let l: ln = line (' .' )
120+ if search (' \S' ,' bW' )
121+ let char = getline (' .' )[col (' .' )-1 ]
122+ let pchar = getline (' .' )[col (' .' )-2 ]
123+ let syn = synIDattr (synID (line (' .' ),col (' .' )-1 ,0 ),' name' )
124+ if pchar . char == ' */' && syn = ~? ' comment'
125+ if ! search (' \/\*' ,' bW' ) || ! search (' \S' ,' bW' )
126+ return 1
127+ endif
128+ let char = getline (' .' )[col (' .' )-1 ]
129+ let pchar = getline (' .' )[col (' .' )-2 ]
130+ let syn = synIDattr (synID (line (' .' ),col (' .' )-1 ,0 ),' name' )
138131 endif
139- if search (' \S' ,' bW' )
140- let char = getline (line (' .' ))[col (' .' )-1 ]
141- if char = ~# ' \l'
142- return expand (' <cword>' ) !~#
143- \ ' ^\%(var\|const\|let\|\%(im\|ex\)port\|yield\|de\%(fault\|lete\)\|void\|t\%(ypeof\|hrow\)\|new\|in\%(stanceof\)\=\)$'
144- elseif char == ' >'
145- return search (' =\%#' ,' bW' ) || synIDattr (synID (line (' .' ),col (' .' ),0 ),' name' ) = ~? ' flownoise'
146- elseif char == ' :'
147- return strpart (getline (line (' .' )),0 ,col (' .' )) = ~# s: expr_case . ' $'
148- elseif char == ' {'
149- return s: IsBlock ()
150- else
151- return char !~# ' [-=~!<*+,./?^%|&\[(]'
132+ if syn = ~? ' \%(xml\|jsx\)'
133+ return char != ' {'
134+ elseif char = ~# ' \l'
135+ if line (' .' ) == l: ln && expand (' <cword>' ) == # ' return'
136+ return 0
152137 endif
138+ return index (split (' const let import export yield default delete var void typeof throw new in instanceof' )
139+ \ , expand (' <cword>' )) < 0
140+ elseif char == ' >'
141+ return pchar == ' =' || syn = ~? ' ^jsflow'
142+ elseif char == ' :'
143+ return strpart (getline (' .' ),0 ,col (' .' )) = ~# s: expr_case . ' $'
153144 else
154- return 1
145+ return stridx ( ' -=~!<*+,/?^%|&([ ' ,char) < 0
155146 endif
147+ else
148+ return 1
156149 endif
157150endfunction
158151
159152" Find line above 'lnum' that isn't empty, in a comment, or in a string.
160153function s: PrevCodeLine (lnum)
161154 let l: lnum = prevnonblank (a: lnum )
162155 while l: lnum
163- if synIDattr (synID (l: lnum ,matchend (getline (l: lnum ), ' ^\s*[^'' "]' ),0 ),' name' ) !~? s: syng_strcom
156+ if synIDattr (synID (l: lnum ,matchend (getline (l: lnum ), ' ^\s*[^'' "` ]' ),0 ),' name' ) !~? s: syng_strcom
164157 return l: lnum
165158 endif
166159 let l: lnum = prevnonblank (l: lnum - 1 )
@@ -169,33 +162,30 @@ endfunction
169162
170163" Check if line 'lnum' has a balanced amount of parentheses.
171164function s: Balanced (lnum)
172- let [open_0,open_2,open_4] = [ 0 , 0 , 0 ]
165+ let l: open = 0
173166 let l: line = getline (a: lnum )
174167 let pos = match (l: line , ' [][(){}]' , 0 )
175168 while pos != -1
176169 if synIDattr (synID (a: lnum ,pos + 1 ,0 ),' name' ) !~? s: syng_strcom
177- let idx = stridx (' (){}[]' , l: line [pos])
178- if ! (idx % 2 )
179- let open_{idx} += 1
170+ if stridx (' [({' ,l: line [pos]) + 1
171+ let l: open += 1
180172 else
181- let open_{idx - 1 } -= 1
182- if open_{idx - 1 } < 0
173+ let l: open -= 1
174+ if l: open < 0
183175 return 0
184176 endif
185177 endif
186178 endif
187179 let pos = match (l: line , ' [][(){}]' , pos + 1 )
188180 endwhile
189- return ! (open_4 || open_2 || open_0)
181+ return ! l: open
190182endfunction
191183
192184function GetJavascriptIndent ()
193185 try
194186 let save_magic = &magic
195187 set magic
196- if ! exists (' b:js_cache' )
197- let b: js_cache = [0 ,0 ,0 ]
198- endif
188+ let b: js_cache = get (b: ,' js_cache' ,[0 ,0 ,0 ])
199189 " Get the current line.
200190 let l: line = getline (v: lnum )
201191 let syns = synIDattr (synID (v: lnum , 1 , 0 ), ' name' )
@@ -211,76 +201,84 @@ function GetJavascriptIndent()
211201 return -1
212202 endif
213203 let l: lnum = s: PrevCodeLine (v: lnum - 1 )
214- if l: lnum == 0
204+ if ! l: lnum
215205 return 0
216206 endif
217207
218208 let l: line = substitute (l: line ,' ^\s*\%(\/\*.\{-}\*\/\s*\)*' ,' ' ,' ' )
219209
220- if l: line = ~# ' ^' . s: expr_case
221- let cpo_switch = &cpo
222- set cpo += %
223- let ind = cindent (v: lnum )
224- let &cpo = cpo_switch
225- return ind
226- endif
227-
228- " the containing paren, bracket, curly. Memoize, last lineNr either has the
229- " same scope or starts a new one, unless if it closed a scope.
210+ " the containing paren, bracket, curly. Many hacks for performance
230211 call cursor (v: lnum ,1 )
231- if getline (l: lnum ) !~ ' ^\S'
212+ let idx = strlen (l: line ) ? stridx (' ])}' ,l: line [0 ]) : -1
213+ if indent (l: lnum )
232214 let [s: looksyn ,s: free ] = [v: lnum - 1 ,1 ]
233215 if b: js_cache [0 ] >= l: lnum && b: js_cache [0 ] < v: lnum &&
234216 \ (b: js_cache [0 ] > l: lnum || s: Balanced (l: lnum ))
235- let num = b: js_cache [1 ]
236- elseif l: line = ~ ' ^[])}]'
237- let id = stridx (' ])}' ,l: line [0 ])
238- let num = s: GetPair (escape (' [({' [id],' [' ), escape (' ])}' [id],' ]' ),' bW' ,' s:skip_func(s:looksyn)' ,2000 )
239- elseif syns != ' ' && getline (v: lnum )[0 ] = ~ ' \s'
240- let pattern = syns = ~? ' block' ? [' {' ,' }' ] : syns = ~? ' jsparen' ? [' (' ,' )' ] :
241- \ syns = ~? ' jsbracket' ? [' \[' ,' \]' ] : [' [({[]' ,' [])}]' ]
242- let num = s: GetPair (pattern[0 ],pattern[1 ],' bW' ,' s:skip_func(s:looksyn)' ,2000 )
217+ call call (' cursor' ,b: js_cache [1 :])
218+ elseif idx + 1
219+ call s: GetPair ([' \[' ,' (' ,' {' ][idx], ' ])}' [idx],' bW' ,' s:skip_func(s:looksyn)' ,2000 )
220+ elseif indent (v: lnum ) && syns = ~? ' block'
221+ call s: GetPair (' {' ,' }' ,' bW' ,' s:skip_func(s:looksyn)' ,2000 )
243222 else
244- let num = s: GetPair (' [({[]' ,' [])}]' ,' bW' ,' s:skip_func(s:looksyn)' ,2000 )
223+ call s: GetPair (' [({[]' ,' [])}]' ,' bW' ,' s:skip_func(s:looksyn)' ,2000 )
245224 endif
246225 else
247- let num = s: GetPair (' [({[]' ,' [])}]' ,' bW' ,s: skip_expr ,200 ,l: lnum )
226+ call s: GetPair (' [({[]' ,' [])}]' ,' bW' ,s: skip_expr ,200 ,l: lnum )
248227 endif
249228
250- let num = (num > 0 ) * num
251- if l: line = ~ ' ^[])}]'
252- return ! ! num * indent (num)
229+ if idx + 1
230+ if idx == 2 && search (' \S' ,' bW' ,line (' .' )) && getline (' .' )[col (' .' )-1 ] == ' )'
231+ call s: GetPair (' (' ,' )' ,' bW' ,s: skip_expr ,200 )
232+ endif
233+ return indent (line (' .' ))
253234 endif
254- let b: js_cache = [v: lnum ,num,line (' .' ) == v: lnum ? b: js_cache [2 ] : col (' .' )]
255235
256- call cursor (v: lnum ,1 )
257- if l: line = ~# ' ^while\>' && s: GetPair (s: line_pre . ' \C\<do\>' ,' \C\<while\>' ,' bW' ,s: skip_expr ,100 ,num + 1 ) > 0
258- return indent (line (' .' ))
236+ let b: js_cache = [v: lnum ] + (line (' .' ) == v: lnum ? [0 ,0 ] : [line (' .' ),col (' .' )])
237+ let num = b: js_cache [1 ]
238+
239+ let [s: W , pline, isOp, stmt, bL, switch_offset] = [s: sw (), s: Trim (l: lnum ),0 ,0 ,0 ,0 ]
240+ if num
241+ if getline (' .' )[col (' .' )-1 ] == ' {'
242+ if search (' )\_s*\%#' ,' bW' )
243+ let stmt = 1
244+ if s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 && search (' \C\<switch\_s*\%#' ,' bW' )
245+ let switch_offset = &cino !~ ' :' || ! has (' float' ) ? s: W :
246+ \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (&cino = ~# ' .*:[^,]*s' ? s: W : 1 ))
247+ if l: line = ~# ' ^' . s: expr_case
248+ return indent (num) + switch_offset
249+ endif
250+ let stmt = pline !~# s: expr_case . ' $'
251+ endif
252+ elseif s: IsBlock ()
253+ let stmt = 1
254+ endif
255+ endif
256+ else
257+ let stmt = 1
259258 endif
260259
261- let s: W = s: sw ()
262- let pline = s: Trimline (l: lnum )
263- call cursor (b: js_cache [1 ],b: js_cache [2 ])
264- let switch_offset = ! num || ! (search (' )\_s*\%#' ,' bW' ) &&
265- \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 && search (' \C\<switch\_s*\%#' ,' bW' )) ? 0 :
266- \ &cino !~ ' :' || ! has (' float' ) ? s: W :
267- \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (&cino = ~# ' .*:[^,]*s' ? s: W : 1 ))
260+ if stmt
261+ call cursor (v: lnum ,1 )
262+ if l: line = ~# ' ^while\>' && s: GetPair (' \C\<do\>' ,' \C\<while\>' ,' bW' ,s: skip_expr . ' || !s:IsBlock()' ,100 ,num + 1 ) > 0
263+ return indent (line (' .' ))
264+ endif
265+ let isOp = l: line = ~# s: opfirst || pline = ~# s: continuation
266+ let bL = s: iscontOne (l: lnum ,num,isOp)
267+ let bL -= (bL && l: line [0 ] == ' {' ) * s: W
268+ endif
268269
269- " most significant, find the indent amount
270- let isOp = l: line = ~# g: javascript_opfirst || pline !~# s: expr_case . ' $' && pline = ~# g: javascript_continuation
271- let bL = s: iscontOne (l: lnum ,num,isOp)
272- let bL -= (bL && l: line = ~ ' ^{' ) * s: W
273- if isOp && (! num || cursor (b: js_cache [1 ],b: js_cache [2 ]) || s: IsBlock ())
270+ " main return
271+ if isOp
274272 return (num ? indent (num) : - s: W ) + (s: W * 2 ) + switch_offset + bL
275273 elseif num
276274 return indent (num) + s: W + switch_offset + bL
277275 endif
278276 return bL
277+
279278 finally
280279 let &magic = save_magic
281280 endtry
282281endfunction
283282
284-
285283let &cpo = s: cpo_save
286284unlet s: cpo_save
0 commit comments