22" Language: Javascript
33" Maintainer: Chris Paul ( https://github.com/bounceme )
44" URL: https://github.com/pangloss/vim-javascript
5- " Last Change: October 24 , 2016
5+ " Last Change: November 6 , 2016
66
77" Only load this indent file when no other was loaded.
88if exists (' b:did_indent' )
3737 endfunction
3838endif
3939
40- let s: expr_case = ' \<\%(\%(case\>\s*\S.\{-}\)\|default\)\s*:\C'
41- " Regex of syntax group names that are or delimit string or are comments.
42- let s: syng_strcom = ' \%(s\%(tring\|pecial\)\|comment\|regex\|doc\|template\)'
40+ let s: case_stmt = ' \<\%(case\>\s*[^ \t:].*\|default\s*\):\C'
4341
42+ " Regex of syntax group names that are or delimit string or are comments.
43+ let s: syng_strcom = ' string\|comment\|regex\|special\|doc\|template'
4444" Expression used to check whether we should skip a match with searchpair().
4545let s: skip_expr = " synIDattr(synID(line('.'),col('.'),0),'name') =~? '" .s: syng_strcom ." '"
4646function s: skip_func (lnum)
47- if ! s: free || search (' `' , ' nW ' , a: lnum ) || search ( ' \*\/' ,' nW' ,a: lnum )
48- let s: free = ! eval (s: skip_expr )
47+ if ! s: free || search (' `\| \*\/' ,' nW' ,a: lnum )
48+ let s: free = ! eval (s: skip_expr . " . ' \\ |html' " )
4949 let s: looksyn = s: free ? line (' .' ) : s: looksyn
5050 return ! s: free
5151 endif
5252 let s: looksyn = line (' .' )
53- return (strridx ( getline ( ' . ' ), ' /' ,col ( ' . ' ) -1 ) + 1 || search (' ['' "\\]' ,' nW' ,s: looksyn )) && eval (s: skip_expr )
53+ return (search ( ' \ /' ,' nbW ' , s: looksyn ) || search (' ['' "\\]' ,' nW' ,s: looksyn )) && eval (s: skip_expr . " . ' \\ |html' " )
5454endfunction
5555
5656if has (' reltime' )
6363 endfunction
6464endif
6565
66+ function s: current_char ()
67+ return getline (' .' )[col (' .' )-1 ]
68+ endfunction
69+
70+ function s: token ()
71+ return s: current_char () = ~ ' \k' ? expand (' <cword>' ) : s: current_char ()
72+ endfunction
73+
74+ " NOTE: moves the cursor
75+ function s: previous_token ()
76+ return search (' \<\|[][`^!"%-/:-?{-~]' ,' bW' ) ? s: token () : ' '
77+ endfunction
78+
6679function s: Trim (ln )
6780 let pline = substitute (getline (a: ln ),' \s*$' ,' ' ,' ' )
6881 let l: max = max ([strridx (pline,' //' ),strridx (pline,' /*' ),0 ])
69- while l: max && synIDattr (synID (a: ln , strlen (pline), 0 ), ' name' ) = ~? ' \%( comment\|doc\) '
82+ while l: max && synIDattr (synID (a: ln , strlen (pline), 0 ), ' name' ) = ~? ' comment\|doc'
7083 let pline = substitute (strpart (pline, 0 , l: max ),' \s*$' ,' ' ,' ' )
7184 let l: max = max ([strridx (pline,' //' ),strridx (pline,' /*' ),0 ])
7285 endwhile
@@ -75,15 +88,20 @@ endfunction
7588
7689" configurable regexes that define continuation lines, not including (, {, or [.
7790let s: opfirst = ' ^' . get (g: ,' javascript_opfirst' ,
78- \ ' \%([<>,?^%|*&]\|\/[/*]\@! \|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' )
91+ \ ' \%([<>,?^%|*/&] \|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' )
7992let s: continuation = get (g: ,' javascript_continuation' ,
8093 \ ' \%([<=,.?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)' ) . ' $'
8194
8295function s: OneScope (lnum,text)
83- return cursor (a: lnum , match (' ' . a: text , ' \%(\<else\|\<do\|=>\)$' )) + 1 ||
84- \ cursor (a: lnum , match (' ' . a: text , ' )$' )) + 1 &&
85- \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 &&
86- \ search (' \C\<\%(for\%(\_s\+\%(await\|each\)\)\=\|if\|let\|w\%(hile\|ith\)\)\_s*\%#' ,' bW' )
96+ if cursor (a: lnum , match (' ' . a: text , ' )$' )) + 1 &&
97+ \ s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0
98+ let token = s: previous_token ()
99+ if index (split (' await each' ),token) + 1
100+ return s: previous_token () == # ' for'
101+ endif
102+ return index (split (' for if let while with' ),token) + 1
103+ endif
104+ return cursor (a: lnum , match (' ' . a: text , ' \%(\<else\|\<do\|=>\)$\C' )) + 1
87105endfunction
88106
89107function s: iscontOne (i ,num,cont)
@@ -94,66 +112,49 @@ function s:iscontOne(i,num,cont)
94112 while l: i >= l: num && (! l: cont || ind > pind)
95113 if indent (l: i ) < ind " first line always true for !a:cont, false for !!a:cont
96114 if s: OneScope (l: i ,s: Trim (l: i ))
97- if expand (' <cword>' ) == # ' while' &&
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
101- return 0
102- endif
103115 let bL += s: W
104116 let [l: cont , l: i ] = [0 , line (' .' )]
105117 elseif ! l: cont
106118 break
107119 endif
108- let ind = indent (l: i )
109120 elseif ! a: cont
110121 break
111122 endif
123+ let ind = min ([ind, indent (l: i )])
112124 let l: i = s: PrevCodeLine (l: i - 1 )
113125 endwhile
114126 return bL
115127endfunction
116128
117129" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
118- function s: IsBlock ()
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' )
131- endif
132- if syn = ~? ' \%(xml\|jsx\)'
133- return char != ' {'
134- elseif char = ~# ' \l'
135- if line (' .' ) == l: ln && expand (' <cword>' ) == # ' return'
136- return 0
137- 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 . ' $'
144- else
145- return stridx (' -=~!<*+,/?^%|&([' ,char) < 0
146- endif
147- else
130+ function s: IsBlock (... )
131+ let l: ln = get (a: 000 ,0 ,line (' .' ))
132+ let char = s: previous_token ()
133+ let syn = char = ~ ' [{>/]' || l: ln != line (' .' ) ? synIDattr (synID (line (' .' ),col (' .' )- (char == ' {' ),0 ),' name' ) : ' '
134+ if char is ' '
148135 return 1
136+ elseif syn = ~? ' xml\|jsx'
137+ return char != ' {'
138+ elseif syn = ~? ' comment'
139+ return search (' \/[/*]' ,' bW' ) && s: IsBlock (l: ln )
140+ elseif char == ' >'
141+ return getline (' .' )[col (' .' )-2 ] == ' =' || syn = ~? ' ^jsflow'
142+ elseif char == ' :'
143+ return cursor (0 ,match (' ' . strpart (getline (' .' ),0 ,col (' .' )),' .*\zs' . s: case_stmt . ' $' )) + 1 &&
144+ \ (expand (' <cword>' ) !=# ' default' || s: previous_token () !~ ' [,{]' )
149145 endif
146+ return index (split (' return const let import export yield default delete var void typeof throw new in instanceof'
147+ \ . ' - = ~ ! < * + , / ? ^ % | & ( [' ), char) < (0 + (line (' .' ) != l: ln ))
150148endfunction
151149
152150" Find line above 'lnum' that isn't empty, in a comment, or in a string.
153151function s: PrevCodeLine (lnum)
154152 let l: lnum = prevnonblank (a: lnum )
155153 while l: lnum
156- if synIDattr (synID (l: lnum ,matchend (getline (l: lnum ), ' ^\s*[^'' "`]' ),0 ),' name' ) !~? s: syng_strcom
154+ let syn = synIDattr (synID (l: lnum ,matchend (getline (l: lnum ), ' ^\s*[^'' "`]' ),0 ),' name' )
155+ if syn = ~? ' html'
156+ return
157+ elseif syn !~? s: syng_strcom
157158 return l: lnum
158159 endif
159160 let l: lnum = prevnonblank (l: lnum - 1 )
@@ -167,13 +168,9 @@ function s:Balanced(lnum)
167168 let pos = match (l: line , ' [][(){}]' , 0 )
168169 while pos != -1
169170 if synIDattr (synID (a: lnum ,pos + 1 ,0 ),' name' ) !~? s: syng_strcom
170- if stridx (' [({' ,l: line [pos]) + 1
171- let l: open += 1
172- else
173- let l: open -= 1
174- if l: open < 0
175- return 0
176- endif
171+ let l: open += match (' ' . l: line [pos],' [[({]' )
172+ if l: open < 0
173+ return
177174 endif
178175 endif
179176 let pos = match (l: line , ' [][(){}]' , pos + 1 )
@@ -182,30 +179,27 @@ function s:Balanced(lnum)
182179endfunction
183180
184181function GetJavascriptIndent ()
185- try
186- let save_magic = &magic
187- set magic
188182 let b: js_cache = get (b: ,' js_cache' ,[0 ,0 ,0 ])
189183 " Get the current line.
190184 let l: line = getline (v: lnum )
191185 let syns = synIDattr (synID (v: lnum , 1 , 0 ), ' name' )
192186
193187 " start with strings,comments,etc.
194- if syns = ~? ' \%( comment\|doc\) '
188+ if syns = ~? ' comment\|doc'
195189 if l: line = ~ ' ^\s*\*'
196190 return cindent (v: lnum )
197191 elseif l: line !~ ' ^\s*\/'
198192 return -1
199193 endif
200- elseif syns = ~? ' \%( string\|template\) ' && l: line !~ ' ^['' "]'
194+ elseif syns = ~? ' string\|template' && l: line !~ ' ^['' "]'
201195 return -1
202196 endif
203197 let l: lnum = s: PrevCodeLine (v: lnum - 1 )
204198 if ! l: lnum
205- return 0
199+ return
206200 endif
207201
208- let l: line = substitute (l: line ,' ^\s*\%(\/\*.\{-}\*\/\s*\)*' ,' ' ,' ' )
202+ let l: line = substitute (substitute ( l: line ,' ^\s*\%(\/\*.\{-}\*\/\s*\)* ' , ' ' , ' ' ), ' ^\/[/*]. *' ,' ' ,' ' )
209203
210204 " the containing paren, bracket, curly. Many hacks for performance
211205 call cursor (v: lnum ,1 )
@@ -227,7 +221,7 @@ function GetJavascriptIndent()
227221 endif
228222
229223 if idx + 1
230- if idx == 2 && search (' \S' ,' bW' ,line (' .' )) && getline ( ' . ' )[ col ( ' . ' ) -1 ] == ' )'
224+ if idx == 2 && search (' \S' ,' bW' ,line (' .' )) && s: current_char () == ' )'
231225 call s: GetPair (' (' ,' )' ,' bW' ,s: skip_expr ,200 )
232226 endif
233227 return indent (line (' .' ))
@@ -237,31 +231,19 @@ function GetJavascriptIndent()
237231 let num = b: js_cache [1 ]
238232
239233 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
234+ if num && s: current_char () == ' {' && s: IsBlock ()
235+ let stmt = 1
236+ if s: current_char () == ' )' && s: GetPair (' (' , ' )' , ' bW' , s: skip_expr , 100 ) > 0 && s: previous_token () == # ' switch'
237+ let switch_offset = &cino !~ ' :' || ! has (' float' ) ? s: W :
238+ \ float2nr (str2float (matchstr (&cino ,' .*:\zs[-0-9.]*' )) * (&cino = ~# ' .*:[^,]*s' ? s: W : 1 ))
239+ if l: line = ~# ' ^' . s: case_stmt
240+ return indent (num) + switch_offset
254241 endif
242+ let stmt = pline !~# s: case_stmt . ' $'
255243 endif
256- else
257- let stmt = 1
258244 endif
259245
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
246+ if stmt || ! num
265247 let isOp = l: line = ~# s: opfirst || pline = ~# s: continuation
266248 let bL = s: iscontOne (l: lnum ,num,isOp)
267249 let bL -= (bL && l: line [0 ] == ' {' ) * s: W
@@ -274,10 +256,6 @@ function GetJavascriptIndent()
274256 return indent (num) + s: W + switch_offset + bL
275257 endif
276258 return bL
277-
278- finally
279- let &magic = save_magic
280- endtry
281259endfunction
282260
283261let &cpo = s: cpo_save
0 commit comments