1dd2a3cdaSBram Moolenaar" Vim indent file 2dd2a3cdaSBram Moolenaar" Language: Javascript 3e4a3bcf2SBram Moolenaar" Maintainer: Chris Paul ( https://github.com/bounceme ) 409521313SBram Moolenaar" URL: https://github.com/pangloss/vim-javascript 5*3c2881dcSBram Moolenaar" Last Change: March 21, 2017 6dd2a3cdaSBram Moolenaar 7dd2a3cdaSBram Moolenaar" Only load this indent file when no other was loaded. 809521313SBram Moolenaarif exists('b:did_indent') 9dd2a3cdaSBram Moolenaar finish 10dd2a3cdaSBram Moolenaarendif 11dd2a3cdaSBram Moolenaarlet b:did_indent = 1 12dd2a3cdaSBram Moolenaar 1309521313SBram Moolenaar" Now, set up our indentation expression and keys that trigger it. 1409521313SBram Moolenaarsetlocal indentexpr=GetJavascriptIndent() 1568563937SBram Moolenaarsetlocal autoindent nolisp nosmartindent 1668563937SBram Moolenaarsetlocal indentkeys+=0],0) 17*3c2881dcSBram Moolenaar" Testable with something like: 18*3c2881dcSBram Moolenaar" vim -eNs "+filetype plugin indent on" "+syntax on" "+set ft=javascript" \ 19*3c2881dcSBram Moolenaar" "+norm! gg=G" '+%print' '+:q!' testfile.js \ 20*3c2881dcSBram Moolenaar" | diff -uBZ testfile.js - 21dd2a3cdaSBram Moolenaar 2268563937SBram Moolenaarlet b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<' 2309521313SBram Moolenaar 2409521313SBram Moolenaar" Only define the function once. 2509521313SBram Moolenaarif exists('*GetJavascriptIndent') 2609521313SBram Moolenaar finish 2709521313SBram Moolenaarendif 2809521313SBram Moolenaar 2909521313SBram Moolenaarlet s:cpo_save = &cpo 3009521313SBram Moolenaarset cpo&vim 3109521313SBram Moolenaar 3209521313SBram Moolenaar" Get shiftwidth value 3309521313SBram Moolenaarif exists('*shiftwidth') 3409521313SBram Moolenaar function s:sw() 3509521313SBram Moolenaar return shiftwidth() 3609521313SBram Moolenaar endfunction 3709521313SBram Moolenaarelse 3809521313SBram Moolenaar function s:sw() 39*3c2881dcSBram Moolenaar return &l:shiftwidth == 0 ? &l:tabstop : &l:shiftwidth 4009521313SBram Moolenaar endfunction 4109521313SBram Moolenaarendif 4209521313SBram Moolenaar 43*3c2881dcSBram Moolenaar" Performance for forwards search(): start search at pos rather than masking 44*3c2881dcSBram Moolenaar" matches before pos. 45*3c2881dcSBram Moolenaarlet s:z = has('patch-7.4.984') ? 'z' : '' 46*3c2881dcSBram Moolenaar 4768563937SBram Moolenaar" searchpair() wrapper 4868563937SBram Moolenaarif has('reltime') 4968563937SBram Moolenaar function s:GetPair(start,end,flags,skip,time,...) 5068563937SBram Moolenaar return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 2000,0] + a:000),a:time) 5168563937SBram Moolenaar endfunction 5268563937SBram Moolenaarelse 5368563937SBram Moolenaar function s:GetPair(start,end,flags,skip,...) 5468563937SBram Moolenaar return searchpair('\m'.a:start,'','\m'.a:end,a:flags,a:skip,max([prevnonblank(v:lnum) - 1000,get(a:000,1)])) 5568563937SBram Moolenaar endfunction 5668563937SBram Moolenaarendif 5768563937SBram Moolenaar 5809521313SBram Moolenaar" Regex of syntax group names that are or delimit string or are comments. 59*3c2881dcSBram Moolenaarlet s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template\%(braces\)\@!' 60*3c2881dcSBram Moolenaarlet s:syng_str = 'string\|template\|special' 6168563937SBram Moolenaarlet s:syng_com = 'comment\|doc' 6209521313SBram Moolenaar" Expression used to check whether we should skip a match with searchpair(). 63e4a3bcf2SBram Moolenaarlet s:skip_expr = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '".s:syng_strcom."'" 6409521313SBram Moolenaar 65*3c2881dcSBram Moolenaarfunction s:parse_cino(f) abort 66*3c2881dcSBram Moolenaar return float2nr(eval(substitute(substitute(join(split( 67*3c2881dcSBram Moolenaar \ matchstr(&cino,'.*'.a:f.'\zs[^,]*'), 's',1), '*'.s:W) 68*3c2881dcSBram Moolenaar \ , '^-\=\zs\*','',''), '^-\=\zs\.','0.',''))) 69*3c2881dcSBram Moolenaarendfunction 70*3c2881dcSBram Moolenaar 7168563937SBram Moolenaarfunction s:skip_func() 72*3c2881dcSBram Moolenaar if getline('.') =~ '\%<'.col('.').'c\/.\{-}\/\|\%>'.col('.').'c[''"]\|\\$' 73*3c2881dcSBram Moolenaar return eval(s:skip_expr) 74*3c2881dcSBram Moolenaar elseif s:checkIn || search('\m`\|\${\|\*\/','nW'.s:z,s:looksyn) 75*3c2881dcSBram Moolenaar let s:checkIn = eval(s:skip_expr) 76e4a3bcf2SBram Moolenaar endif 7768563937SBram Moolenaar let s:looksyn = line('.') 78*3c2881dcSBram Moolenaar return s:checkIn 7968563937SBram Moolenaarendfunction 8009521313SBram Moolenaar 8168563937SBram Moolenaarfunction s:alternatePair(stop) 8268563937SBram Moolenaar let pos = getpos('.')[1:2] 83*3c2881dcSBram Moolenaar let pat = '[][(){};]' 84*3c2881dcSBram Moolenaar while search('\m'.pat,'bW',a:stop) 85*3c2881dcSBram Moolenaar if s:skip_func() | continue | endif 86*3c2881dcSBram Moolenaar let idx = stridx('])};',s:looking_at()) 87*3c2881dcSBram Moolenaar if idx is 3 | let pat = '[{}()]' | continue | endif 8868563937SBram Moolenaar if idx + 1 89*3c2881dcSBram Moolenaar if s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop) <= 0 9068563937SBram Moolenaar break 9168563937SBram Moolenaar endif 9268563937SBram Moolenaar else 9368563937SBram Moolenaar return 9468563937SBram Moolenaar endif 9568563937SBram Moolenaar endwhile 9668563937SBram Moolenaar call call('cursor',pos) 9768563937SBram Moolenaarendfunction 9868563937SBram Moolenaar 9968563937SBram Moolenaarfunction s:save_pos(f,...) 10068563937SBram Moolenaar let l:pos = getpos('.')[1:2] 10168563937SBram Moolenaar let ret = call(a:f,a:000) 10268563937SBram Moolenaar call call('cursor',l:pos) 10368563937SBram Moolenaar return ret 10468563937SBram Moolenaarendfunction 10568563937SBram Moolenaar 10668563937SBram Moolenaarfunction s:syn_at(l,c) 10768563937SBram Moolenaar return synIDattr(synID(a:l,a:c,0),'name') 10868563937SBram Moolenaarendfunction 10968563937SBram Moolenaar 11068563937SBram Moolenaarfunction s:looking_at() 11168563937SBram Moolenaar return getline('.')[col('.')-1] 11268563937SBram Moolenaarendfunction 11368563937SBram Moolenaar 11468563937SBram Moolenaarfunction s:token() 11568563937SBram Moolenaar return s:looking_at() =~ '\k' ? expand('<cword>') : s:looking_at() 11668563937SBram Moolenaarendfunction 11768563937SBram Moolenaar 11868563937SBram Moolenaarfunction s:previous_token() 119*3c2881dcSBram Moolenaar let l:pos = getpos('.')[1:2] 120*3c2881dcSBram Moolenaar if search('\m\k\{1,}\zs\k\|\S','bW') 121*3c2881dcSBram Moolenaar if (getline('.')[col('.')-2:col('.')-1] == '*/' || line('.') != l:pos[0] && 122*3c2881dcSBram Moolenaar \ getline('.') =~ '\%<'.col('.').'c\/\/') && s:syn_at(line('.'),col('.')) =~? s:syng_com 123*3c2881dcSBram Moolenaar while search('\m\S\ze\_s*\/[/*]','bW') 124*3c2881dcSBram Moolenaar if s:syn_at(line('.'),col('.')) !~? s:syng_com 12568563937SBram Moolenaar return s:token() 12668563937SBram Moolenaar endif 12768563937SBram Moolenaar endwhile 128*3c2881dcSBram Moolenaar else 129*3c2881dcSBram Moolenaar return s:token() 130*3c2881dcSBram Moolenaar endif 131*3c2881dcSBram Moolenaar endif 132*3c2881dcSBram Moolenaar call call('cursor',l:pos) 13368563937SBram Moolenaar return '' 13468563937SBram Moolenaarendfunction 13568563937SBram Moolenaar 136*3c2881dcSBram Moolenaarfunction s:expr_col() 137*3c2881dcSBram Moolenaar if getline('.')[col('.')-2] == ':' 138*3c2881dcSBram Moolenaar return 1 13968563937SBram Moolenaar endif 140*3c2881dcSBram Moolenaar let bal = 0 141*3c2881dcSBram Moolenaar while search('\m[{}?:;]','bW') 142*3c2881dcSBram Moolenaar if eval(s:skip_expr) | continue | endif 143*3c2881dcSBram Moolenaar " switch (looking_at()) 144*3c2881dcSBram Moolenaar exe { '}': "if s:GetPair('{','}','bW',s:skip_expr,200) <= 0 | return | endif", 145*3c2881dcSBram Moolenaar \ ';': "return", 146*3c2881dcSBram Moolenaar \ '{': "return getpos('.')[1:2] != b:js_cache[1:] && !s:IsBlock()", 147*3c2881dcSBram Moolenaar \ ':': "let bal -= getline('.')[max([col('.')-2,0]):col('.')] !~ '::'", 148*3c2881dcSBram Moolenaar \ '?': "let bal += 1 | if bal > 0 | return 1 | endif" }[s:looking_at()] 149*3c2881dcSBram Moolenaar endwhile 15068563937SBram Moolenaarendfunction 15109521313SBram Moolenaar 15209521313SBram Moolenaar" configurable regexes that define continuation lines, not including (, {, or [. 15368563937SBram Moolenaarlet s:opfirst = '^' . get(g:,'javascript_opfirst', 154*3c2881dcSBram Moolenaar \ '\C\%([<>=,?^%|*/&]\|\([-.:+]\)\1\@!\|!=\|in\%(stanceof\)\=\>\)') 15568563937SBram Moolenaarlet s:continuation = get(g:,'javascript_continuation', 156*3c2881dcSBram Moolenaar \ '\C\%([-+<>=,.~!?/*^%|&:]\|\<\%(typeof\|new\|delete\|void\|in\|instanceof\|await\)\)') . '$' 157e4a3bcf2SBram Moolenaar 15868563937SBram Moolenaarfunction s:continues(ln,con) 159*3c2881dcSBram Moolenaar if !cursor(a:ln, match(' '.a:con,s:continuation)) 160*3c2881dcSBram Moolenaar let teol = s:looking_at() 161*3c2881dcSBram Moolenaar if teol == '/' 162*3c2881dcSBram Moolenaar return s:syn_at(line('.'),col('.')) !~? 'regex' 163*3c2881dcSBram Moolenaar elseif teol =~ '[-+>]' 164*3c2881dcSBram Moolenaar return getline('.')[col('.')-2] != tr(teol,'>','=') 165*3c2881dcSBram Moolenaar elseif teol =~ '\l' 166*3c2881dcSBram Moolenaar return s:previous_token() != '.' 167*3c2881dcSBram Moolenaar elseif teol == ':' 168*3c2881dcSBram Moolenaar return s:expr_col() 169*3c2881dcSBram Moolenaar endif 170*3c2881dcSBram Moolenaar return 1 171*3c2881dcSBram Moolenaar endif 172e4a3bcf2SBram Moolenaarendfunction 173e4a3bcf2SBram Moolenaar 17468563937SBram Moolenaar" get the line of code stripped of comments and move cursor to the last 17568563937SBram Moolenaar" non-comment char. 17668563937SBram Moolenaarfunction s:Trim(ln) 17768563937SBram Moolenaar let pline = substitute(getline(a:ln),'\s*$','','') 178*3c2881dcSBram Moolenaar let l:max = max([strridx(pline,'//'), strridx(pline,'/*')]) 179*3c2881dcSBram Moolenaar while l:max != -1 && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com 180*3c2881dcSBram Moolenaar let pline = pline[: l:max] 181*3c2881dcSBram Moolenaar let l:max = max([strridx(pline,'//'), strridx(pline,'/*')]) 182*3c2881dcSBram Moolenaar let pline = substitute(pline[:-2],'\s*$','','') 18368563937SBram Moolenaar endwhile 184*3c2881dcSBram Moolenaar return pline is '' || cursor(a:ln,strlen(pline)) ? pline : pline 18509521313SBram Moolenaarendfunction 18609521313SBram Moolenaar 18768563937SBram Moolenaar" Find line above 'lnum' that isn't empty or in a comment 18809521313SBram Moolenaarfunction s:PrevCodeLine(lnum) 189*3c2881dcSBram Moolenaar let [l:pos, l:n] = [getpos('.')[1:2], prevnonblank(a:lnum)] 19068563937SBram Moolenaar while l:n 19168563937SBram Moolenaar if getline(l:n) =~ '^\s*\/[/*]' 19268563937SBram Moolenaar let l:n = prevnonblank(l:n-1) 193*3c2881dcSBram Moolenaar elseif stridx(getline(l:n), '*/') + 1 && s:syn_at(l:n,1) =~? s:syng_com 194*3c2881dcSBram Moolenaar call cursor(l:n,1) 195*3c2881dcSBram Moolenaar keepjumps norm! [* 196*3c2881dcSBram Moolenaar let l:n = search('\m\S','nbW') 19768563937SBram Moolenaar else 198*3c2881dcSBram Moolenaar break 19968563937SBram Moolenaar endif 20009521313SBram Moolenaar endwhile 201*3c2881dcSBram Moolenaar call call('cursor',l:pos) 202*3c2881dcSBram Moolenaar return l:n 20309521313SBram Moolenaarendfunction 20409521313SBram Moolenaar 20509521313SBram Moolenaar" Check if line 'lnum' has a balanced amount of parentheses. 20609521313SBram Moolenaarfunction s:Balanced(lnum) 20768563937SBram Moolenaar let l:open = 0 20809521313SBram Moolenaar let l:line = getline(a:lnum) 20909521313SBram Moolenaar let pos = match(l:line, '[][(){}]', 0) 21009521313SBram Moolenaar while pos != -1 21168563937SBram Moolenaar if s:syn_at(a:lnum,pos + 1) !~? s:syng_strcom 21268563937SBram Moolenaar let l:open += match(' ' . l:line[pos],'[[({]') 21368563937SBram Moolenaar if l:open < 0 21468563937SBram Moolenaar return 21509521313SBram Moolenaar endif 21609521313SBram Moolenaar endif 217*3c2881dcSBram Moolenaar let pos = match(l:line, (l:open ? 218*3c2881dcSBram Moolenaar \ '['.escape(tr(l:line[pos],'({[]})',')}][{(').l:line[pos],']').']' : 219*3c2881dcSBram Moolenaar \ '[][(){}]'), pos + 1) 22009521313SBram Moolenaar endwhile 22168563937SBram Moolenaar return !l:open 22209521313SBram Moolenaarendfunction 22368563937SBram Moolenaar 22468563937SBram Moolenaarfunction s:OneScope(lnum) 22568563937SBram Moolenaar let pline = s:Trim(a:lnum) 22668563937SBram Moolenaar let kw = 'else do' 22768563937SBram Moolenaar if pline[-1:] == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 228*3c2881dcSBram Moolenaar if s:previous_token() =~# '^\%(await\|each\)$' 22968563937SBram Moolenaar call s:previous_token() 23068563937SBram Moolenaar let kw = 'for' 231*3c2881dcSBram Moolenaar else 232*3c2881dcSBram Moolenaar let kw = 'for if let while with' 23368563937SBram Moolenaar endif 23468563937SBram Moolenaar endif 23568563937SBram Moolenaar return pline[-2:] == '=>' || index(split(kw),s:token()) + 1 && 23668563937SBram Moolenaar \ s:save_pos('s:previous_token') != '.' 23768563937SBram Moolenaarendfunction 23868563937SBram Moolenaar 23968563937SBram Moolenaar" returns braceless levels started by 'i' and above lines * &sw. 'num' is the 24068563937SBram Moolenaar" lineNr which encloses the entire context, 'cont' if whether line 'i' + 1 is 24168563937SBram Moolenaar" a continued expression, which could have started in a braceless context 24268563937SBram Moolenaarfunction s:iscontOne(i,num,cont) 24368563937SBram Moolenaar let [l:i, l:num, bL] = [a:i, a:num + !a:num, 0] 24468563937SBram Moolenaar let pind = a:num ? indent(l:num) + s:W : 0 24568563937SBram Moolenaar let ind = indent(l:i) + (a:cont ? 0 : s:W) 24668563937SBram Moolenaar while l:i >= l:num && (ind > pind || l:i == l:num) 24768563937SBram Moolenaar if indent(l:i) < ind && s:OneScope(l:i) 24868563937SBram Moolenaar let bL += s:W 24968563937SBram Moolenaar let l:i = line('.') 25068563937SBram Moolenaar elseif !a:cont || bL || ind < indent(a:i) 25168563937SBram Moolenaar break 25268563937SBram Moolenaar endif 25368563937SBram Moolenaar let ind = min([ind, indent(l:i)]) 25468563937SBram Moolenaar let l:i = s:PrevCodeLine(l:i - 1) 25568563937SBram Moolenaar endwhile 25668563937SBram Moolenaar return bL 25768563937SBram Moolenaarendfunction 25868563937SBram Moolenaar 25968563937SBram Moolenaar" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader 26068563937SBram Moolenaarfunction s:IsBlock() 26168563937SBram Moolenaar if s:looking_at() == '{' 26268563937SBram Moolenaar let l:n = line('.') 26368563937SBram Moolenaar let char = s:previous_token() 264*3c2881dcSBram Moolenaar if match(s:stack,'\cxml\|jsx') + 1 && s:syn_at(line('.'),col('.')-1) =~? 'xml\|jsx' 26568563937SBram Moolenaar return char != '{' 26668563937SBram Moolenaar elseif char =~ '\k' 267*3c2881dcSBram Moolenaar if char ==# 'type' 268*3c2881dcSBram Moolenaar return s:previous_token() !~# '^\%(im\|ex\)port$' 26968563937SBram Moolenaar endif 270*3c2881dcSBram Moolenaar return index(split('return const let import export extends yield default delete var await void typeof throw case new of in instanceof') 271*3c2881dcSBram Moolenaar \ ,char) < (line('.') != l:n) || s:save_pos('s:previous_token') == '.' 272*3c2881dcSBram Moolenaar elseif char == '>' 273*3c2881dcSBram Moolenaar return getline('.')[col('.')-2] == '=' || s:syn_at(line('.'),col('.')) =~? '^jsflow' 274*3c2881dcSBram Moolenaar elseif char == ':' 275*3c2881dcSBram Moolenaar return !s:save_pos('s:expr_col') 276*3c2881dcSBram Moolenaar elseif char == '/' 277*3c2881dcSBram Moolenaar return s:syn_at(line('.'),col('.')) =~? 'regex' 278*3c2881dcSBram Moolenaar endif 279*3c2881dcSBram Moolenaar return char !~ '[=~!<*,?^%|&([]' && 280*3c2881dcSBram Moolenaar \ (char !~ '[-+]' || l:n != line('.') && getline('.')[col('.')-2] == char) 28168563937SBram Moolenaar endif 28268563937SBram Moolenaarendfunction 28309521313SBram Moolenaar 28409521313SBram Moolenaarfunction GetJavascriptIndent() 28568563937SBram Moolenaar let b:js_cache = get(b:,'js_cache',[0,0,0]) 28609521313SBram Moolenaar " Get the current line. 28768563937SBram Moolenaar call cursor(v:lnum,1) 28868563937SBram Moolenaar let l:line = getline('.') 289*3c2881dcSBram Moolenaar " use synstack as it validates syn state and works in an empty line 290*3c2881dcSBram Moolenaar let s:stack = map(synstack(v:lnum,1),"synIDattr(v:val,'name')") 291*3c2881dcSBram Moolenaar let syns = get(s:stack,-1,'') 29209521313SBram Moolenaar 29368563937SBram Moolenaar " start with strings,comments,etc. 29468563937SBram Moolenaar if syns =~? s:syng_com 29568563937SBram Moolenaar if l:line =~ '^\s*\*' 29668563937SBram Moolenaar return cindent(v:lnum) 29768563937SBram Moolenaar elseif l:line !~ '^\s*\/[/*]' 29809521313SBram Moolenaar return -1 29909521313SBram Moolenaar endif 300*3c2881dcSBram Moolenaar elseif syns =~? s:syng_str 30168563937SBram Moolenaar if b:js_cache[0] == v:lnum - 1 && s:Balanced(v:lnum-1) 30268563937SBram Moolenaar let b:js_cache[0] = v:lnum 30368563937SBram Moolenaar endif 30468563937SBram Moolenaar return -1 30509521313SBram Moolenaar endif 30609521313SBram Moolenaar let l:lnum = s:PrevCodeLine(v:lnum - 1) 30768563937SBram Moolenaar if !l:lnum 30868563937SBram Moolenaar return 30909521313SBram Moolenaar endif 31009521313SBram Moolenaar 31168563937SBram Moolenaar let l:line = substitute(l:line,'^\s*','','') 31268563937SBram Moolenaar if l:line[:1] == '/*' 31368563937SBram Moolenaar let l:line = substitute(l:line,'^\%(\/\*.\{-}\*\/\s*\)*','','') 31409521313SBram Moolenaar endif 31568563937SBram Moolenaar if l:line =~ '^\/[/*]' 31668563937SBram Moolenaar let l:line = '' 31768563937SBram Moolenaar endif 31809521313SBram Moolenaar 31968563937SBram Moolenaar " the containing paren, bracket, or curly. Many hacks for performance 320*3c2881dcSBram Moolenaar let idx = index([']',')','}'],l:line[0]) 32168563937SBram Moolenaar if b:js_cache[0] >= l:lnum && b:js_cache[0] < v:lnum && 32268563937SBram Moolenaar \ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum)) 32368563937SBram Moolenaar call call('cursor',b:js_cache[1:]) 32409521313SBram Moolenaar else 325*3c2881dcSBram Moolenaar let [s:looksyn, s:checkIn, top] = [v:lnum - 1, 0, (!indent(l:lnum) && 32668563937SBram Moolenaar \ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum] 32768563937SBram Moolenaar if idx + 1 32868563937SBram Moolenaar call s:GetPair(['\[','(','{'][idx],'])}'[idx],'bW','s:skip_func()',2000,top) 329*3c2881dcSBram Moolenaar elseif getline(v:lnum) !~ '^\S' && syns =~? 'block' 33068563937SBram Moolenaar call s:GetPair('{','}','bW','s:skip_func()',2000,top) 33168563937SBram Moolenaar else 33268563937SBram Moolenaar call s:alternatePair(top) 33309521313SBram Moolenaar endif 33409521313SBram Moolenaar endif 33509521313SBram Moolenaar 33668563937SBram Moolenaar let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,0] : getpos('.')[1:2]) 33768563937SBram Moolenaar let num = b:js_cache[1] 33868563937SBram Moolenaar 33968563937SBram Moolenaar let [s:W, isOp, bL, switch_offset] = [s:sw(),0,0,0] 34068563937SBram Moolenaar if !num || s:IsBlock() 341*3c2881dcSBram Moolenaar let ilnum = line('.') 34268563937SBram Moolenaar let pline = s:save_pos('s:Trim',l:lnum) 34368563937SBram Moolenaar if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 344*3c2881dcSBram Moolenaar let num = ilnum == num ? line('.') : num 345*3c2881dcSBram Moolenaar if idx < 0 && s:previous_token() ==# 'switch' && s:previous_token() != '.' 346*3c2881dcSBram Moolenaar if &cino !~ ':' 34768563937SBram Moolenaar let switch_offset = s:W 34868563937SBram Moolenaar else 349*3c2881dcSBram Moolenaar let switch_offset = max([-indent(num),s:parse_cino(':')]) 35068563937SBram Moolenaar endif 35168563937SBram Moolenaar if pline[-1:] != '.' && l:line =~# '^\%(default\|case\)\>' 35268563937SBram Moolenaar return indent(num) + switch_offset 35368563937SBram Moolenaar endif 35468563937SBram Moolenaar endif 35568563937SBram Moolenaar endif 356*3c2881dcSBram Moolenaar if idx < 0 && pline[-1:] !~ '[{;]' 357*3c2881dcSBram Moolenaar let isOp = (l:line =~# s:opfirst || s:continues(l:lnum,pline)) * s:W 358*3c2881dcSBram Moolenaar let bL = s:iscontOne(l:lnum,b:js_cache[1],isOp) 35968563937SBram Moolenaar let bL -= (bL && l:line[0] == '{') * s:W 36068563937SBram Moolenaar endif 361*3c2881dcSBram Moolenaar elseif idx < 0 && getline(b:js_cache[1])[b:js_cache[2]-1] == '(' && &cino =~ '(' 362*3c2881dcSBram Moolenaar let pval = s:parse_cino('(') 363*3c2881dcSBram Moolenaar return !pval ? (s:parse_cino('w') ? 0 : -(!!search('\m\S','W'.s:z,num))) + virtcol('.') : 364*3c2881dcSBram Moolenaar \ max([indent('.') + pval + (s:GetPair('(',')','nbrmW',s:skip_expr,100,num) * s:W),0]) 36568563937SBram Moolenaar endif 36668563937SBram Moolenaar 36768563937SBram Moolenaar " main return 368*3c2881dcSBram Moolenaar if l:line =~ '^\%([])}]\||}\)' 369*3c2881dcSBram Moolenaar return max([indent(num),0]) 37068563937SBram Moolenaar elseif num 371*3c2881dcSBram Moolenaar return indent(num) + s:W + switch_offset + bL + isOp 37268563937SBram Moolenaar endif 373*3c2881dcSBram Moolenaar return bL + isOp 37409521313SBram Moolenaarendfunction 37509521313SBram Moolenaar 37609521313SBram Moolenaarlet &cpo = s:cpo_save 37709521313SBram Moolenaarunlet s:cpo_save 378