comparison runtime/indent/javascript.vim @ 11229:146a1e213b60

Update runtime files. Add Rust support. commit https://github.com/vim/vim/commit/3c2881dc1195f53ebafc387378399ddd6cb677a7 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Mar 21 19:18:29 2017 +0100 Update runtime files. Add Rust support.
author Christian Brabandt <cb@256bit.org>
date Tue, 21 Mar 2017 19:30:06 +0100
parents 74effdaa369e
children 63b0b7b79b25
comparison
equal deleted inserted replaced
11228:641b98249145 11229:146a1e213b60
1 " Vim indent file 1 " Vim indent file
2 " Language: Javascript 2 " Language: Javascript
3 " Maintainer: Chris Paul ( https://github.com/bounceme ) 3 " Maintainer: Chris Paul ( https://github.com/bounceme )
4 " URL: https://github.com/pangloss/vim-javascript 4 " URL: https://github.com/pangloss/vim-javascript
5 " Last Change: December 31, 2016 5 " Last Change: March 21, 2017
6 6
7 " Only load this indent file when no other was loaded. 7 " Only load this indent file when no other was loaded.
8 if exists('b:did_indent') 8 if exists('b:did_indent')
9 finish 9 finish
10 endif 10 endif
12 12
13 " Now, set up our indentation expression and keys that trigger it. 13 " Now, set up our indentation expression and keys that trigger it.
14 setlocal indentexpr=GetJavascriptIndent() 14 setlocal indentexpr=GetJavascriptIndent()
15 setlocal autoindent nolisp nosmartindent 15 setlocal autoindent nolisp nosmartindent
16 setlocal indentkeys+=0],0) 16 setlocal indentkeys+=0],0)
17 " Testable with something like:
18 " vim -eNs "+filetype plugin indent on" "+syntax on" "+set ft=javascript" \
19 " "+norm! gg=G" '+%print' '+:q!' testfile.js \
20 " | diff -uBZ testfile.js -
17 21
18 let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<' 22 let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<'
19 23
20 " Only define the function once. 24 " Only define the function once.
21 if exists('*GetJavascriptIndent') 25 if exists('*GetJavascriptIndent')
30 function s:sw() 34 function s:sw()
31 return shiftwidth() 35 return shiftwidth()
32 endfunction 36 endfunction
33 else 37 else
34 function s:sw() 38 function s:sw()
35 return &sw 39 return &l:shiftwidth == 0 ? &l:tabstop : &l:shiftwidth
36 endfunction 40 endfunction
37 endif 41 endif
42
43 " Performance for forwards search(): start search at pos rather than masking
44 " matches before pos.
45 let s:z = has('patch-7.4.984') ? 'z' : ''
38 46
39 " searchpair() wrapper 47 " searchpair() wrapper
40 if has('reltime') 48 if has('reltime')
41 function s:GetPair(start,end,flags,skip,time,...) 49 function s:GetPair(start,end,flags,skip,time,...)
42 return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 2000,0] + a:000),a:time) 50 return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 2000,0] + a:000),a:time)
46 return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 1000,get(a:000,1)])) 54 return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 1000,get(a:000,1)]))
47 endfunction 55 endfunction
48 endif 56 endif
49 57
50 " Regex of syntax group names that are or delimit string or are comments. 58 " Regex of syntax group names that are or delimit string or are comments.
51 let s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template' 59 let s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template\%(braces\)\@!'
52 let s:syng_str = 'string\|template' 60 let s:syng_str = 'string\|template\|special'
53 let s:syng_com = 'comment\|doc' 61 let s:syng_com = 'comment\|doc'
54 " Expression used to check whether we should skip a match with searchpair(). 62 " Expression used to check whether we should skip a match with searchpair().
55 let s:skip_expr = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'" 63 let s:skip_expr = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'"
56 64
65 function s:parse_cino(f) abort
66 return float2nr(eval(substitute(substitute(join(split(
67 \ matchstr(&cino,'.*'.a:f.'\zs[^,]*'), 's',1), '*'.s:W)
68 \ , '^-\=\zs\*','',''), '^-\=\zs\.','0.','')))
69 endfunction
70
57 function s:skip_func() 71 function s:skip_func()
58 if !s:free || search('\m`\|\*\/','nW',s:looksyn) 72 if getline('.') =~ '\%<'.col('.').'c\/.\{-}\/\|\%>'.col('.').'c[''"]\|\\$'
59 let s:free = !eval(s:skip_expr) 73 return eval(s:skip_expr)
60 let s:looksyn = s:free ? line('.') : s:looksyn 74 elseif s:checkIn || search('\m`\|\${\|\*\/','nW'.s:z,s:looksyn)
61 return !s:free 75 let s:checkIn = eval(s:skip_expr)
62 endif 76 endif
63 let s:looksyn = line('.') 77 let s:looksyn = line('.')
64 return (search('\m\/','nbW',s:looksyn) || search('\m[''"]\|\\$','nW',s:looksyn)) && eval(s:skip_expr) 78 return s:checkIn
65 endfunction 79 endfunction
66 80
67 function s:alternatePair(stop) 81 function s:alternatePair(stop)
68 let pos = getpos('.')[1:2] 82 let pos = getpos('.')[1:2]
69 while search('\m[][(){}]','bW',a:stop) 83 let pat = '[][(){};]'
70 if !s:skip_func() 84 while search('\m'.pat,'bW',a:stop)
71 let idx = stridx('])}',s:looking_at()) 85 if s:skip_func() | continue | endif
72 if idx + 1 86 let idx = stridx('])};',s:looking_at())
73 if !s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop) 87 if idx is 3 | let pat = '[{}()]' | continue | endif
74 break 88 if idx + 1
75 endif 89 if s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop) <= 0
76 else 90 break
77 return
78 endif 91 endif
92 else
93 return
79 endif 94 endif
80 endwhile 95 endwhile
81 call call('cursor',pos) 96 call call('cursor',pos)
82 endfunction 97 endfunction
83 98
98 113
99 function s:token() 114 function s:token()
100 return s:looking_at() =~ '\k' ? expand('<cword>') : s:looking_at() 115 return s:looking_at() =~ '\k' ? expand('<cword>') : s:looking_at()
101 endfunction 116 endfunction
102 117
103 function s:b_token()
104 if s:looking_at() =~ '\k'
105 call search('\m\<','cbW')
106 endif
107 return search('\m\S','bW')
108 endfunction
109
110 function s:previous_token() 118 function s:previous_token()
111 let l:n = line('.') 119 let l:pos = getpos('.')[1:2]
112 while s:b_token() 120 if search('\m\k\{1,}\zs\k\|\S','bW')
113 if (s:looking_at() == '/' || line('.') != l:n && search('\m\/\/','nbW', 121 if (getline('.')[col('.')-2:col('.')-1] == '*/' || line('.') != l:pos[0] &&
114 \ line('.'))) && s:syn_at(line('.'),col('.')) =~? s:syng_com 122 \ getline('.') =~ '\%<'.col('.').'c\/\/') && s:syn_at(line('.'),col('.')) =~? s:syng_com
115 call search('\m\_[^/]\zs\/[/*]','bW') 123 while search('\m\S\ze\_s*\/[/*]','bW')
124 if s:syn_at(line('.'),col('.')) !~? s:syng_com
125 return s:token()
126 endif
127 endwhile
116 else 128 else
117 return s:token() 129 return s:token()
118 endif 130 endif
119 endwhile 131 endif
132 call call('cursor',l:pos)
120 return '' 133 return ''
121 endfunction 134 endfunction
122 135
123 function s:others(p) 136 function s:expr_col()
124 return "((line2byte(line('.')) + col('.')) <= ".(line2byte(a:p[0]) + a:p[1]).") || ".s:skip_expr 137 if getline('.')[col('.')-2] == ':'
125 endfunction 138 return 1
126 139 endif
127 function s:tern_skip(p) 140 let bal = 0
128 return s:GetPair('{','}','nbW',s:others(a:p),200,a:p[0]) > 0 141 while search('\m[{}?:;]','bW')
129 endfunction 142 if eval(s:skip_expr) | continue | endif
130 143 " switch (looking_at())
131 function s:tern_col(p) 144 exe { '}': "if s:GetPair('{','}','bW',s:skip_expr,200) <= 0 | return | endif",
132 return s:GetPair('?',':\@<!::\@!','nbW',s:others(a:p) 145 \ ';': "return",
133 \ .' || s:tern_skip('.string(a:p).')',200,a:p[0]) > 0 146 \ '{': "return getpos('.')[1:2] != b:js_cache[1:] && !s:IsBlock()",
134 endfunction 147 \ ':': "let bal -= getline('.')[max([col('.')-2,0]):col('.')] !~ '::'",
135 148 \ '?': "let bal += 1 | if bal > 0 | return 1 | endif" }[s:looking_at()]
136 function s:label_col() 149 endwhile
137 let pos = getpos('.')[1:2]
138 let [s:looksyn,s:free] = pos
139 call s:alternatePair(0)
140 if s:save_pos('s:IsBlock')
141 let poss = getpos('.')[1:2]
142 return call('cursor',pos) || !s:tern_col(poss)
143 elseif s:looking_at() == ':'
144 return !s:tern_col([0,0])
145 endif
146 endfunction 150 endfunction
147 151
148 " configurable regexes that define continuation lines, not including (, {, or [. 152 " configurable regexes that define continuation lines, not including (, {, or [.
149 let s:opfirst = '^' . get(g:,'javascript_opfirst', 153 let s:opfirst = '^' . get(g:,'javascript_opfirst',
150 \ '\%([<>=,?^%|*/&]\|\([-.:+]\)\1\@!\|!=\|in\%(stanceof\)\=\>\)') 154 \ '\C\%([<>=,?^%|*/&]\|\([-.:+]\)\1\@!\|!=\|in\%(stanceof\)\=\>\)')
151 let s:continuation = get(g:,'javascript_continuation', 155 let s:continuation = get(g:,'javascript_continuation',
152 \ '\%([<=,.~!?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<\%(typeof\|delete\|void\|in\|instanceof\)\)') . '$' 156 \ '\C\%([-+<>=,.~!?/*^%|&:]\|\<\%(typeof\|new\|delete\|void\|in\|instanceof\|await\)\)') . '$'
153 157
154 function s:continues(ln,con) 158 function s:continues(ln,con)
155 return !cursor(a:ln, match(' '.a:con,s:continuation)) && 159 if !cursor(a:ln, match(' '.a:con,s:continuation))
156 \ eval((['s:syn_at(line("."),col(".")) !~? "regex"'] + 160 let teol = s:looking_at()
157 \ repeat(['s:previous_token() != "."'],5) + [1])[ 161 if teol == '/'
158 \ index(split('/ typeof in instanceof void delete'),s:token())]) 162 return s:syn_at(line('.'),col('.')) !~? 'regex'
163 elseif teol =~ '[-+>]'
164 return getline('.')[col('.')-2] != tr(teol,'>','=')
165 elseif teol =~ '\l'
166 return s:previous_token() != '.'
167 elseif teol == ':'
168 return s:expr_col()
169 endif
170 return 1
171 endif
159 endfunction 172 endfunction
160 173
161 " get the line of code stripped of comments and move cursor to the last 174 " get the line of code stripped of comments and move cursor to the last
162 " non-comment char. 175 " non-comment char.
163 function s:Trim(ln) 176 function s:Trim(ln)
164 let pline = substitute(getline(a:ln),'\s*$','','') 177 let pline = substitute(getline(a:ln),'\s*$','','')
165 let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0]) 178 let l:max = max([strridx(pline,'//'), strridx(pline,'/*')])
166 while l:max && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com 179 while l:max != -1 && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com
167 let pline = substitute(strpart(pline, 0, l:max),'\s*$','','') 180 let pline = pline[: l:max]
168 let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0]) 181 let l:max = max([strridx(pline,'//'), strridx(pline,'/*')])
169 endwhile 182 let pline = substitute(pline[:-2],'\s*$','','')
170 return cursor(a:ln,strlen(pline)) ? pline : pline 183 endwhile
184 return pline is '' || cursor(a:ln,strlen(pline)) ? pline : pline
171 endfunction 185 endfunction
172 186
173 " Find line above 'lnum' that isn't empty or in a comment 187 " Find line above 'lnum' that isn't empty or in a comment
174 function s:PrevCodeLine(lnum) 188 function s:PrevCodeLine(lnum)
175 let l:n = prevnonblank(a:lnum) 189 let [l:pos, l:n] = [getpos('.')[1:2], prevnonblank(a:lnum)]
176 while l:n 190 while l:n
177 if getline(l:n) =~ '^\s*\/[/*]' 191 if getline(l:n) =~ '^\s*\/[/*]'
178 if (stridx(getline(l:n),'`') > 0 || getline(l:n-1)[-1:] == '\') &&
179 \ s:syn_at(l:n,1) =~? s:syng_str
180 return l:n
181 endif
182 let l:n = prevnonblank(l:n-1) 192 let l:n = prevnonblank(l:n-1)
183 elseif s:syn_at(l:n,1) =~? s:syng_com 193 elseif stridx(getline(l:n), '*/') + 1 && s:syn_at(l:n,1) =~? s:syng_com
184 let l:n = s:save_pos('eval', 194 call cursor(l:n,1)
185 \ 'cursor('.l:n.',1) + search(''\m\/\*'',"bW")') 195 keepjumps norm! [*
186 else 196 let l:n = search('\m\S','nbW')
187 return l:n 197 else
188 endif 198 break
189 endwhile 199 endif
200 endwhile
201 call call('cursor',l:pos)
202 return l:n
190 endfunction 203 endfunction
191 204
192 " Check if line 'lnum' has a balanced amount of parentheses. 205 " Check if line 'lnum' has a balanced amount of parentheses.
193 function s:Balanced(lnum) 206 function s:Balanced(lnum)
194 let l:open = 0 207 let l:open = 0
199 let l:open += match(' ' . l:line[pos],'[[({]') 212 let l:open += match(' ' . l:line[pos],'[[({]')
200 if l:open < 0 213 if l:open < 0
201 return 214 return
202 endif 215 endif
203 endif 216 endif
204 let pos = match(l:line, '[][(){}]', pos + 1) 217 let pos = match(l:line, (l:open ?
218 \ '['.escape(tr(l:line[pos],'({[]})',')}][{(').l:line[pos],']').']' :
219 \ '[][(){}]'), pos + 1)
205 endwhile 220 endwhile
206 return !l:open 221 return !l:open
207 endfunction 222 endfunction
208 223
209 function s:OneScope(lnum) 224 function s:OneScope(lnum)
210 let pline = s:Trim(a:lnum) 225 let pline = s:Trim(a:lnum)
211 let kw = 'else do' 226 let kw = 'else do'
212 if pline[-1:] == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 227 if pline[-1:] == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0
213 call s:previous_token() 228 if s:previous_token() =~# '^\%(await\|each\)$'
214 let kw = 'for if let while with'
215 if index(split('await each'),s:token()) + 1
216 call s:previous_token() 229 call s:previous_token()
217 let kw = 'for' 230 let kw = 'for'
231 else
232 let kw = 'for if let while with'
218 endif 233 endif
219 endif 234 endif
220 return pline[-2:] == '=>' || index(split(kw),s:token()) + 1 && 235 return pline[-2:] == '=>' || index(split(kw),s:token()) + 1 &&
221 \ s:save_pos('s:previous_token') != '.' 236 \ s:save_pos('s:previous_token') != '.'
222 endfunction 237 endfunction
244 " https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader 259 " https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
245 function s:IsBlock() 260 function s:IsBlock()
246 if s:looking_at() == '{' 261 if s:looking_at() == '{'
247 let l:n = line('.') 262 let l:n = line('.')
248 let char = s:previous_token() 263 let char = s:previous_token()
249 let syn = char =~ '[{>/]' ? s:syn_at(line('.'),col('.')-(char == '{')) : '' 264 if match(s:stack,'\cxml\|jsx') + 1 && s:syn_at(line('.'),col('.')-1) =~? 'xml\|jsx'
250 if syn =~? 'xml\|jsx'
251 return char != '{' 265 return char != '{'
252 elseif char =~ '\k' 266 elseif char =~ '\k'
253 return index(split('return const let import export yield default delete var await void typeof throw case new in instanceof') 267 if char ==# 'type'
254 \ ,char) < (line('.') != l:n) || s:previous_token() == '.' 268 return s:previous_token() !~# '^\%(im\|ex\)port$'
269 endif
270 return index(split('return const let import export extends yield default delete var await void typeof throw case new of in instanceof')
271 \ ,char) < (line('.') != l:n) || s:save_pos('s:previous_token') == '.'
255 elseif char == '>' 272 elseif char == '>'
256 return getline('.')[col('.')-2] == '=' || syn =~? '^jsflow' 273 return getline('.')[col('.')-2] == '=' || s:syn_at(line('.'),col('.')) =~? '^jsflow'
257 elseif char == ':' 274 elseif char == ':'
258 return getline('.')[col('.')-2] != ':' && s:label_col() 275 return !s:save_pos('s:expr_col')
259 endif 276 elseif char == '/'
260 return syn =~? 'regex' || char !~ '[-=~!<*+,/?^%|&([]' 277 return s:syn_at(line('.'),col('.')) =~? 'regex'
278 endif
279 return char !~ '[=~!<*,?^%|&([]' &&
280 \ (char !~ '[-+]' || l:n != line('.') && getline('.')[col('.')-2] == char)
261 endif 281 endif
262 endfunction 282 endfunction
263 283
264 function GetJavascriptIndent() 284 function GetJavascriptIndent()
265 let b:js_cache = get(b:,'js_cache',[0,0,0]) 285 let b:js_cache = get(b:,'js_cache',[0,0,0])
266 " Get the current line. 286 " Get the current line.
267 call cursor(v:lnum,1) 287 call cursor(v:lnum,1)
268 let l:line = getline('.') 288 let l:line = getline('.')
269 let syns = s:syn_at(v:lnum, 1) 289 " use synstack as it validates syn state and works in an empty line
290 let s:stack = map(synstack(v:lnum,1),"synIDattr(v:val,'name')")
291 let syns = get(s:stack,-1,'')
270 292
271 " start with strings,comments,etc. 293 " start with strings,comments,etc.
272 if syns =~? s:syng_com 294 if syns =~? s:syng_com
273 if l:line =~ '^\s*\*' 295 if l:line =~ '^\s*\*'
274 return cindent(v:lnum) 296 return cindent(v:lnum)
275 elseif l:line !~ '^\s*\/[/*]' 297 elseif l:line !~ '^\s*\/[/*]'
276 return -1 298 return -1
277 endif 299 endif
278 elseif syns =~? s:syng_str && l:line !~ '^[''"]' 300 elseif syns =~? s:syng_str
279 if b:js_cache[0] == v:lnum - 1 && s:Balanced(v:lnum-1) 301 if b:js_cache[0] == v:lnum - 1 && s:Balanced(v:lnum-1)
280 let b:js_cache[0] = v:lnum 302 let b:js_cache[0] = v:lnum
281 endif 303 endif
282 return -1 304 return -1
283 endif 305 endif
293 if l:line =~ '^\/[/*]' 315 if l:line =~ '^\/[/*]'
294 let l:line = '' 316 let l:line = ''
295 endif 317 endif
296 318
297 " the containing paren, bracket, or curly. Many hacks for performance 319 " the containing paren, bracket, or curly. Many hacks for performance
298 let idx = strlen(l:line) ? stridx('])}',l:line[0]) : -1 320 let idx = index([']',')','}'],l:line[0])
299 if b:js_cache[0] >= l:lnum && b:js_cache[0] < v:lnum && 321 if b:js_cache[0] >= l:lnum && b:js_cache[0] < v:lnum &&
300 \ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum)) 322 \ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum))
301 call call('cursor',b:js_cache[1:]) 323 call call('cursor',b:js_cache[1:])
302 else 324 else
303 let [s:looksyn, s:free, top] = [v:lnum - 1, 1, (!indent(l:lnum) && 325 let [s:looksyn, s:checkIn, top] = [v:lnum - 1, 0, (!indent(l:lnum) &&
304 \ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum] 326 \ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum]
305 if idx + 1 327 if idx + 1
306 call s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,top) 328 call s:GetPair(['\[','(','{'][idx],'])}'[idx],'bW','s:skip_func()',2000,top)
307 elseif indent(v:lnum) && syns =~? 'block' 329 elseif getline(v:lnum) !~ '^\S' && syns =~? 'block'
308 call s:GetPair('{','}','bW','s:skip_func()',2000,top) 330 call s:GetPair('{','}','bW','s:skip_func()',2000,top)
309 else 331 else
310 call s:alternatePair(top) 332 call s:alternatePair(top)
311 endif 333 endif
312 endif
313
314 if idx + 1 || l:line[:1] == '|}'
315 if idx == 2 && search('\m\S','bW',line('.')) && s:looking_at() == ')'
316 call s:GetPair('(',')','bW',s:skip_expr,200)
317 endif
318 return indent('.')
319 endif 334 endif
320 335
321 let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,0] : getpos('.')[1:2]) 336 let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,0] : getpos('.')[1:2])
322 let num = b:js_cache[1] 337 let num = b:js_cache[1]
323 338
324 let [s:W, isOp, bL, switch_offset] = [s:sw(),0,0,0] 339 let [s:W, isOp, bL, switch_offset] = [s:sw(),0,0,0]
325 if !num || s:IsBlock() 340 if !num || s:IsBlock()
341 let ilnum = line('.')
326 let pline = s:save_pos('s:Trim',l:lnum) 342 let pline = s:save_pos('s:Trim',l:lnum)
327 if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 343 if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0
328 let num = line('.') 344 let num = ilnum == num ? line('.') : num
329 if s:previous_token() ==# 'switch' && s:previous_token() != '.' 345 if idx < 0 && s:previous_token() ==# 'switch' && s:previous_token() != '.'
330 if &cino !~ ':' || !has('float') 346 if &cino !~ ':'
331 let switch_offset = s:W 347 let switch_offset = s:W
332 else 348 else
333 let cinc = matchlist(&cino,'.*:\(-\)\=\([0-9.]*\)\(s\)\=\C') 349 let switch_offset = max([-indent(num),s:parse_cino(':')])
334 let switch_offset = float2nr(str2float(cinc[1].(strlen(cinc[2]) ? cinc[2] : strlen(cinc[3])))
335 \ * (strlen(cinc[3]) ? s:W : 1))
336 endif 350 endif
337 if pline[-1:] != '.' && l:line =~# '^\%(default\|case\)\>' 351 if pline[-1:] != '.' && l:line =~# '^\%(default\|case\)\>'
338 return indent(num) + switch_offset 352 return indent(num) + switch_offset
339 endif 353 endif
340 endif 354 endif
341 endif 355 endif
342 if pline[-1:] !~ '[{;]' 356 if idx < 0 && pline[-1:] !~ '[{;]'
343 if pline =~# ':\@<!:$' 357 let isOp = (l:line =~# s:opfirst || s:continues(l:lnum,pline)) * s:W
344 call cursor(l:lnum,strlen(pline)) 358 let bL = s:iscontOne(l:lnum,b:js_cache[1],isOp)
345 let isOp = s:tern_col(b:js_cache[1:2])
346 else
347 let isOp = l:line =~# s:opfirst || s:continues(l:lnum,pline)
348 endif
349 let bL = s:iscontOne(l:lnum,num,isOp)
350 let bL -= (bL && l:line[0] == '{') * s:W 359 let bL -= (bL && l:line[0] == '{') * s:W
351 endif 360 endif
361 elseif idx < 0 && getline(b:js_cache[1])[b:js_cache[2]-1] == '(' && &cino =~ '('
362 let pval = s:parse_cino('(')
363 return !pval ? (s:parse_cino('w') ? 0 : -(!!search('\m\S','W'.s:z,num))) + virtcol('.') :
364 \ max([indent('.') + pval + (s:GetPair('(',')','nbrmW',s:skip_expr,100,num) * s:W),0])
352 endif 365 endif
353 366
354 " main return 367 " main return
355 if isOp 368 if l:line =~ '^\%([])}]\||}\)'
356 return (num ? indent(num) : -s:W) + (s:W * 2) + switch_offset + bL 369 return max([indent(num),0])
357 elseif num 370 elseif num
358 return indent(num) + s:W + switch_offset + bL 371 return indent(num) + s:W + switch_offset + bL + isOp
359 endif 372 endif
360 return bL 373 return bL + isOp
361 endfunction 374 endfunction
362 375
363 let &cpo = s:cpo_save 376 let &cpo = s:cpo_save
364 unlet s:cpo_save 377 unlet s:cpo_save