11" Vim indent file
22" Language: Javascript
3- " Maintainer: vim-javascript community
3+ " Maintainer: Chris Paul ( https://github.com/bounceme )
44" URL: https://github.com/pangloss/vim-javascript
5- " Last Change: September 4 , 2016
5+ " Last Change: October 9 , 2016
66
77" Only load this indent file when no other was loaded.
88if exists (' b:did_indent' )
@@ -38,63 +38,124 @@ else
3838endif
3939
4040let s: line_pre = ' ^\s*\%(\%(\%(\/\*.\{-}\)\=\*\+\/\s*\)\=\)\@>'
41- let s: expr_case = s: line_pre . ' \%(\%(case\>.\+\)\|default\)\s*:\C'
41+ let s: line_term = ' \s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$'
42+
43+ let s: expr_case = ' \<\%(\%(case\>\s*\S.\{-}\)\|default\)\s*:\C'
4244" Regex of syntax group names that are or delimit string or are comments.
4345let s: syng_strcom = ' \%(s\%(tring\|pecial\)\|comment\|regex\|doc\|template\)'
4446
45- " Regex of syntax group names that are strings or documentation.
46- let s: syng_comment = ' \%(comment\|doc\)'
47-
4847" Expression used to check whether we should skip a match with searchpair().
4948let s: skip_expr = " synIDattr(synID(line('.'),col('.'),0),'name') =~? '" .s: syng_strcom ." '"
5049function s: skip_func (lnum)
51- if ! s: free || getline ( line ( ' . ' )) = ~ ' [ '' /"\\] ' || search (' `' ,' nW' ,a: lnum ) || search (' \*\/' ,' nW' ,a: lnum )
50+ if ! s: free || search (' `' ,' nW' ,a: lnum ) || search (' \*\/' ,' nW' ,a: lnum )
5251 let s: free = ! eval (s: skip_expr )
52+ let s: looksyn = s: free ? line (' .' ) : s: looksyn
53+ return ! s: free
5354 endif
54- let s: looksyn = s: free ? line (' .' ) : s: looksyn
55- return ! s: free
55+ let s: looksyn = line (' .' )
56+ return ( search ( ' \/ ' , ' nbW ' , line ( ' . ' )) || search ( ' [ '' "\\] ' , ' nW ' , line ( ' . ' ))) && eval ( s: skip_expr )
5657endfunction
5758
5859if has (' reltime' )
59- function s: GetPair (start ,end ,flags,skip ,time)
60- return searchpair (a: start ,' ' ,a: end ,a: flags ,a: skip ,max ([prevnonblank (v: lnum ) - 2000 ,0 ]),a: time )
60+ function s: GetPair (start ,end ,flags,skip ,time, ... )
61+ return searchpair (a: start ,' ' ,a: end ,a: flags ,a: skip ,max ([prevnonblank (v: lnum ) - 2000 ,0 ] + a: 000 ),a: time )
6162 endfunction
6263else
6364 function s: GetPair (start ,end ,flags,... )
64- return searchpair (a: start ,' ' ,a: end ,a: flags ,0 , max ([ prevnonblank (v: lnum ) - 2000 , 0 ]) )
65+ return searchpair (a: start ,' ' ,a: end ,a: flags ," line('.') < prevnonblank(v:lnum) - 2000 ? dummy : 0 " )
6566 endfunction
6667endif
6768
68- let s: line_term = ' \s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$'
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*$' ,' ' ,' ' )
86+ endfunction
6987
7088" configurable regexes that define continuation lines, not including (, {, or [.
7189if ! exists (' g:javascript_opfirst' )
72- let g: javascript_opfirst = ' \%([<>,?^%|*&]\|\/[^ /*]\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
90+ let g: javascript_opfirst = ' \%([<>,?^%|*&]\|\/[/*]\@! \|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
7391endif
7492if ! exists (' g:javascript_continuation' )
7593 let g: javascript_continuation = ' \%([<=,.?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)'
7694endif
7795
78- let g: javascript_opfirst = s: line_pre . g: javascript_opfirst
79- let g: javascript_continuation .= s: line_term
96+ let g: javascript_opfirst = ' ^ ' . g: javascript_opfirst
97+ let g: javascript_continuation .= ' $ '
8098
8199function s: OneScope (lnum,text)
82- return a: text = ~# ' \%(\<else\|\<do\|=>\)' . s: line_term ? ' no b' :
83- \ cursor (a: lnum , match (' ' . a: text , ' )' . s: line_term )) > -1 &&
84- \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 && search (' \C\l\+\_s*\%#' ,' bW' ) &&
85- \ (expand (' <cword>' ) !=# ' while' || s: GetPair (' \C\<do\>' , ' \C\<while\>' ,' nbW' ,s: skip_expr ,100 ) <= 0 ) &&
86- \ (expand (' <cword>' ) !=# ' each' || search (' \C\<for\_s\+\%#' ,' nbW' )) ? expand (' <cword>' ) : ' '
100+ return cursor (a: lnum , match (' ' . a: text , ' \%(\<else\|\<do\|=>\)$' )) > -1 ||
101+ \ cursor (a: lnum , match (' ' . a: text , ' )$' )) > -1 &&
102+ \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 &&
103+ \ search (' \C\<\%(for\%(\_s\+\%(await\|each\)\)\=\|if\|let\|w\%(hile\|ith\)\)\_s*\%#' ,' bW' )
104+ endfunction
105+
106+ function s: iscontOne (i ,num,cont)
107+ 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 )
110+ let bL = 0
111+ while l: i >= l: num && (! l: cont || ind > pind + s: W )
112+ 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 ))
114+ if expand (' <cword>' ) == # ' while' &&
115+ \ s: GetPair (s: line_pre . ' \C\<do\>' ,' \C\<while\>' ,' bW' ,s: skip_expr ,100 ,l: num + ! ! a: num ) > 0
116+ return 0
117+ endif
118+ let bL += 1
119+ let [l: cont , l: i ] = [0 , line (' .' )]
120+ elseif ! l: cont
121+ break
122+ endif
123+ let ind = indent (l: i )
124+ endif
125+ let l: i = s: PrevCodeLine (l: i - 1 )
126+ endwhile
127+ return bL * s: W
87128endfunction
88129
89130" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
90131function s: IsBlock ()
91- return getline (line (' .' ))[col (' .' )-1 ] == ' {' && ! search (
92- \ ' \C\%(\<return\s*\|\%([-=~!<*+,.?^%|&\[(]\|=\@<!>\|\*\@<!\/\|\<\%(var\|const\|let\|import\|export\%(\_s\+default\)\=\|yield\|delete\|void\|t\%(ypeof\|hrow\)\|new\|in\%(stanceof\)\=\)\)\_s*\)\%#' ,' bnW' ) &&
93- \ (search (s: expr_case . ' \_s*\%#' ,' nbW' ) || ! search (' [{:]\_s*\%#' ,' bW' ) || 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' )
138+ 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 !~# ' [-=~!<*+,./?^%|&\[(]'
152+ endif
153+ else
154+ return 1
155+ endif
156+ endif
94157endfunction
95158
96- " Auxiliary Functions {{{2
97-
98159" Find line above 'lnum' that isn't empty, in a comment, or in a string.
99160function s: PrevCodeLine (lnum)
100161 let l: lnum = prevnonblank (a: lnum )
@@ -114,7 +175,7 @@ function s:Balanced(lnum)
114175 while pos != -1
115176 if synIDattr (synID (a: lnum ,pos + 1 ,0 ),' name' ) !~? s: syng_strcom
116177 let idx = stridx (' (){}[]' , l: line [pos])
117- if idx % 2 == 0
178+ if ! ( idx % 2 )
118179 let open_{idx} += 1
119180 else
120181 let open_{idx - 1 } -= 1
@@ -125,78 +186,99 @@ function s:Balanced(lnum)
125186 endif
126187 let pos = match (l: line , ' [][(){}]' , pos + 1 )
127188 endwhile
128- return ( ! open_4 + ! open_2 + ! open_0) - 2
189+ return ! ( open_4 || open_2 || open_0)
129190endfunction
130- " }}}
131191
132192function GetJavascriptIndent ()
193+ try
194+ let save_magic = &magic
195+ set magic
133196 if ! exists (' b:js_cache' )
134197 let b: js_cache = [0 ,0 ,0 ]
135198 endif
136199 " Get the current line.
137200 let l: line = getline (v: lnum )
138201 let syns = synIDattr (synID (v: lnum , 1 , 0 ), ' name' )
139202
140- " start with strings,comments,etc.{{{2
141- if (l: line !~ ' ^['' "]' && syns = ~? ' \%(string\|template\)' ) ||
142- \ (l: line !~ ' ^\s*[/*]' && syns = ~? s: syng_comment )
203+ " start with strings,comments,etc.
204+ if syns = ~? ' \%(comment\|doc\)'
205+ if l: line = ~ ' ^\s*\*'
206+ return cindent (v: lnum )
207+ elseif l: line !~ ' ^\s*\/'
208+ return -1
209+ endif
210+ elseif syns = ~? ' \%(string\|template\)' && l: line !~ ' ^['' "]'
143211 return -1
144212 endif
145- if l: line !~ ' ^\%(\/\*\|\s*\/\/\)' && syns = ~? s: syng_comment
146- return cindent (v: lnum )
147- endif
148213 let l: lnum = s: PrevCodeLine (v: lnum - 1 )
149214 if l: lnum == 0
150215 return 0
151216 endif
152217
153- if (l: line = ~# s: expr_case )
218+ let l: line = substitute (l: line ,' ^\s*\%(\/\*.\{-}\*\/\s*\)*' ,' ' ,' ' )
219+
220+ if l: line = ~# ' ^' . s: expr_case
154221 let cpo_switch = &cpo
155222 set cpo += %
156223 let ind = cindent (v: lnum )
157224 let &cpo = cpo_switch
158225 return ind
159226 endif
160- " }}}
161227
162228 " the containing paren, bracket, curly. Memoize, last lineNr either has the
163229 " same scope or starts a new one, unless if it closed a scope.
164- let [s: looksyn ,s: free ] = [v: lnum - 1 ,1 ]
165230 call cursor (v: lnum ,1 )
166- if b: js_cache [0 ] < v: lnum && b: js_cache [0 ] >= l: lnum &&
167- \ (b: js_cache [0 ] > l: lnum || s: Balanced (l: lnum ) > 0 )
168- let num = b: js_cache [1 ]
169- elseif syns != ' ' && l: line [0 ] = ~ ' \s'
170- let pattern = syns = ~? ' block' ? [' {' ,' }' ] : syns = ~? ' jsparen' ? [' (' ,' )' ] :
171- \ syns = ~? ' jsbracket' ? [' \[' ,' \]' ] : [' [({[]' ,' [])}]' ]
172- let num = s: GetPair (pattern[0 ],pattern[1 ],' bW' ,' s:skip_func(s:looksyn)' ,2000 )
231+ if getline (l: lnum ) !~ ' ^\S'
232+ let [s: looksyn ,s: free ] = [v: lnum - 1 ,1 ]
233+ if b: js_cache [0 ] >= l: lnum && b: js_cache [0 ] < v: lnum &&
234+ \ (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 )
243+ else
244+ let num = s: GetPair (' [({[]' ,' [])}]' ,' bW' ,' s:skip_func(s:looksyn)' ,2000 )
245+ endif
173246 else
174- let num = s: GetPair (' [({[]' ,' [])}]' ,' bW' ,' s:skip_func(s:looksyn) ' , 2000 )
247+ let num = s: GetPair (' [({[]' ,' [])}]' ,' bW' ,s: skip_expr , 200 , l: lnum )
175248 endif
176249
250+ let num = (num > 0 ) * num
251+ if l: line = ~ ' ^[])}]'
252+ return ! ! num * indent (num)
253+ endif
177254 let b: js_cache = [v: lnum ,num,line (' .' ) == v: lnum ? b: js_cache [2 ] : col (' .' )]
178255
179- if l: line = ~ s: line_pre . ' [])}]'
180- return indent (num)
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 (' .' ))
181259 endif
182260
183- let pline = substitute (substitute (getline (l: lnum ),s: expr_case ,' \=repeat(" ",strlen(submatch(0)))' ,' ' ), ' \%(:\@<!\/\/.*\)$' , ' ' ,' ' )
261+ let s: W = s: sw ()
262+ let pline = s: Trimline (l: lnum )
184263 call cursor (b: js_cache [1 ],b: js_cache [2 ])
185- let switch_offset = num <= 0 || ! (search (' )\_s*\%#' ,' bW' ) &&
264+ let switch_offset = ! num || ! (search (' )\_s*\%#' ,' bW' ) &&
186265 \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 && search (' \C\<switch\_s*\%#' ,' bW' )) ? 0 :
187- \ &cino !~ ' :' || ! has (' float' ) ? s: sw () :
188- \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (&cino = ~# ' .*:[^,]*s' ? s: sw () : 1 ))
266+ \ &cino !~ ' :' || ! has (' float' ) ? s: W :
267+ \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (&cino = ~# ' .*:[^,]*s' ? s: W : 1 ))
189268
190269 " most significant, find the indent amount
191- let isOp = l: line = ~# g: javascript_opfirst || pline = ~# g: javascript_continuation
192- if isOp && (num <= 0 || cursor ( b: js_cache [ 1 ], b: js_cache [ 2 ]) || s: IsBlock ()) ||
193- \ s: OneScope ( l: lnum ,pline) = ~# ' \<\%(for\|each\|if\|let\|no\sb\|w\%(hile\|ith\)\)\> ' &&
194- \ l: line !~ s: line_pre . ' { '
195- return (num > 0 ? indent (num) : - s: sw ()) + (s: sw () * 2 ) + switch_offset
196- elseif num > 0
197- return indent (num) + s: sw () + switch_offset
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 ())
274+ return (num ? indent (num) : - s: W ) + (s: W * 2 ) + switch_offset + bL
275+ elseif num
276+ return indent (num) + s: W + switch_offset + bL
198277 endif
199-
278+ return bL
279+ finally
280+ let &magic = save_magic
281+ endtry
200282endfunction
201283
202284
0 commit comments