@ -2,7 +2,7 @@
" Language: Javascript
" Maintainer: Chris Paul ( https://github.com/bounceme )
" URL: https://github.com/pangloss/vim-javascript
" Last Change: November 6, 2016
" Last Change: August 12, 2017
" Only load this indent file when no other was loaded.
if exists ( 'b:did_indent' )
@ -10,13 +10,27 @@ if exists('b:did_indent')
endif
let b :did_indent = 1
" indent correctly if inside <script>
" vim/vim@690afe1 for the switch from cindent
let b :html_indent_script1 = 'inc'
" Now, set up our indentation expression and keys that trigger it.
setlocal indentexpr = GetJavascriptIndent ( )
setlocal autoindent nolisp nosmartindent
setlocal indentkeys = 0 {, 0 }, 0 ) , 0 ], :, ! ^F , o , O , e
setlocal cinoptions + = j1 , J1
setlocal indentkeys + = 0 ], 0 )
" Testable with something like:
" vim -eNs "+filetype plugin indent on" "+syntax on" "+set ft=javascript" \
" "+norm! gg=G" '+%print' '+:q!' testfile.js \
" | diff -uBZ testfile.js -
let b :undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<'
let b :undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys< cinoptions<'
" Regex of syntax group names that are or delimit string or are comments.
let b :syng_strcom = get ( b :, 'syng_strcom' , 'string\|comment\|regex\|special\|doc\|template\%(braces\)\@!' )
let b :syng_str = get ( b :, 'syng_str' , 'string\|template\|special' )
" template strings may want to be excluded when editing graphql:
" au! Filetype javascript let b:syng_str = '^\%(.*template\)\@!.*string\|special'
" au! Filetype javascript let b:syng_strcom = '^\%(.*template\)\@!.*string\|comment\|regex\|special\|doc'
" Only define the function once.
if exists ( '*GetJavascriptIndent' )
@ -33,165 +47,343 @@ if exists('*shiftwidth')
endfunction
else
function s :sw ( )
return & sw
return &l: shift width ? &l :shiftwidth : &l :tabstop
endfunction
endif
let s :case_stmt = '\<\%(case\>\s*[^ \t:].*\|default\s*\):\C'
" Performance for forwards search(): start search at pos rather than masking
" matches before pos.
let s :z = has ( 'patch-7.4.984' ) ? 'z' : ''
" Regex of syntax group names that are or delimit string or are comments.
let s :syng_strcom = 'string\|comment\|regex\|special\|doc\|template'
let s :syng_com = 'comment\|doc'
" Expression used to check whether we should skip a match with searchpair().
let s :skip_expr = "synIDattr(synID(line('.'),col('.'),0),'name') =~? '" .s :syng_strcom ."'"
function s :skip_func ( lnum )
if ! s :free | | search ( '`\|\*\/' , 'nW' , a :lnum )
let s :free = ! eval ( s :skip_expr . " . '\\|html'" )
let s :looksyn = s :free ? line ( '.' ) : s :looksyn
return ! s :free
endif
let s :looksyn = line ( '.' )
return ( search ( '\/' , 'nbW' , s :looksyn ) | | search ( '[''"\\]' , 'nW' , s :looksyn ) ) && eval ( s :skip_expr . " . '\\|html'" )
endfunction
let s :skip_expr = "s:SynAt(line('.'),col('.')) =~? b:syng_strcom"
" searchpair() wrapper
if has ( 'reltime' )
function s :GetPair ( start , end , flags , skip , time , ...)
return searchpair ( a :start , '' , a :end , a :flags , a :skip , max ( [prevnonblank ( v :lnum ) - 2000 , 0 ] + a :000 ) , a :time )
return searchpair ( '\m' .( a :start = = '[' ? '\[' : a :start ) , '' , '\m' .a :end ,
\ a :flags , a :skip , max ( [prevnonblank ( v :lnum ) - 2000 , 0 ] + a :000 ) , a :time )
endfunction
else
function s :GetPair ( start , end , flags , skip , ...)
return searchpair ( a :start , '' , a :end , a :flags , a :skip , max ( [prevnonblank ( v :lnum ) - 1000 , get ( a :000 , 1 ) ]) )
return searchpair ( '\m' .( a :start = = '[' ? '\[' : a :start ) , '' , '\m' .a :end ,
\ a :flags , a :skip , max ( [prevnonblank ( v :lnum ) - 1000 , 0 , get ( a :000 , 1 ) ]) )
endfunction
endif
function s :current_char ( )
return getline ( '.' ) [col ( '.' ) -1 ]
function s :SynAt ( l , c )
let byte = line2byte ( a :l ) + a :c - 1
let pos = index ( s :synid_cache [0 ], byte )
if pos = = -1
let s :synid_cache [:] + = [[byte ], [synIDattr ( synID ( a :l , a :c , 0 ) , 'name' ) ]]
endif
return s :synid_cache [1 ][pos ]
endfunction
function s :token ( )
return s :current_char ( ) = ~ '\k' ? expand ( '<cword>' ) : s :current_char ( )
function s :ParseCino ( f )
let [cin , divider , n ] = [strridx ( &cino , a :f ) , 0 , '' ]
if cin = = -1
return
endif
let [sign , cstr ] = &cino [cin + 1 ] = = '-' ? [-1 , &cino [cin + 2 :]] : [1 , &cino [cin + 1 :]]
for c in split ( cstr , '\zs' )
if c = = '.' && ! divider
let divider = 1
elseif c = = # 's'
if n is ''
let n = s :sw ( )
else
let n = str2nr ( n ) * s :sw ( )
endif
break
elseif c = ~ '\d'
let [n , divider ] .= [c , 0 ]
else
break
endif
endfor
return sign * str2nr ( n ) / max ( [str2nr ( divider ) , 1 ])
endfunction
" NOTE: moves the cursor
function s :previous_token ( )
return search ( '\<\|[][`^!"%-/:-?{-~]' , 'bW' ) ? s :token ( ) : ''
" Optimized {skip} expr, only callable from the search loop which
" GetJavascriptIndent does to find the containing [[{(] (relies on s:vars)
function s :SkipFunc ( )
if s :top_col = = 1
throw 'out of bounds'
endif
let s :top_col = 0
if s :check_in
if eval ( s :skip_expr )
return 1
endif
let s :check_in = 0
elseif getline ( '.' ) = ~ '\%<' .col ( '.' ) .'c\/.\{-}\/\|\%>' .col ( '.' ) .'c[''"]\|\\$'
if eval ( s :skip_expr )
let s :looksyn = line ( '.' )
return 1
endif
elseif search ( '\m`\|\${\|\*\/' , 'nW' .s :z , s :looksyn ) && eval ( s :skip_expr )
let s :check_in = 1
return 1
endif
let [s :looksyn , s :top_col ] = getpos ( '.' ) [1 :2 ]
endfunction
function s :Trim ( ln )
let pline = substitute ( getline ( a :ln ) , '\s*$' , '' , '' )
let l :max = max ( [strridx ( pline , '//' ) , strridx ( pline , '/*' ) , 0 ])
while l :max && synIDattr ( synID ( a :ln , strlen ( pline ) , 0 ) , 'name' ) = ~ ? 'comment\|doc'
let pline = substitute ( strpart ( pline , 0 , l :max ) , '\s*$' , '' , '' )
let l :max = max ( [strridx ( pline , '//' ) , strridx ( pline , '/*' ) , 0 ])
function s :AlternatePair ( )
let [pat , l :for ] = ['[][(){};]' , 2 ]
while s :SearchLoop ( '\m' .pat , 'bW' , s :script_tag , 's:SkipFunc()' )
if s :LookingAt ( ) = = ';'
if ! l :for
if s :GetPair ( '{' , '}' , 'bW' , 's:SkipFunc()' , 2000 , s :script_tag )
return
endif
break
else
let [pat , l :for ] = ['[{}();]' , l :for - 1 ]
endif
else
let idx = stridx ( '])}' , s :LookingAt ( ) )
if idx = = -1
return
elseif ! s :GetPair ( '[({' [idx ], '])}' [idx ], 'bW' , 's:SkipFunc()' , 2000 , s :script_tag )
break
endif
endif
endwhile
return pline
throw 'out of bounds'
endfunction
" configurable regexes that define continuation lines, not including (, {, or [.
let s :opfirst = '^' . get ( g :, 'javascript_opfirst' ,
\ '\%([<>,?^%|*/&]\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' )
let s :continuation = get ( g :, 'javascript_continuation' ,
\ '\%([<=,.?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)' ) . '$'
function s :Nat ( int )
return a :int * ( a :int > 0 )
endfunction
function s :LookingAt ( )
return getline ( '.' ) [col ( '.' ) -1 ]
endfunction
function s :Token ( )
return s :LookingAt ( ) = ~ '\k' ? expand ( '<cword>' ) : s :LookingAt ( )
endfunction
function s :OneScope ( lnum , text )
if cursor ( a :lnum , match ( ' ' . a :text , ')$' ) ) + 1 &&
\ s :GetPair ( '(' , ')' , 'bW' , s :skip_expr , 100 ) > 0
let token = s :previous_token ( )
if index ( split ( 'await each' ) , token ) + 1
return s :previous_token ( ) = = # 'for'
function s :PreviousToken ( )
let l :pos = getpos ( '.' )
if search ( '\m\k\{1,}\|\S' , 'ebW' )
if ( strpart ( getline ( '.' ) , col ( '.' ) -2 , 2 ) = = '*/' | | line ( '.' ) ! = l :pos [1 ] &&
\ getline ( '.' ) [:col ( '.' ) -1 ] = ~ '\/\/' ) && s :SynAt ( line ( '.' ) , col ( '.' ) ) = ~ ? s :syng_com
if s :SearchLoop ( '\m\S\ze\_s*\/[/*]' , 'bW' , "s:SynAt(line('.'),col('.')) =~? s:syng_com" )
return s :Token ( )
endif
return index ( split ( 'for if let while with' ) , token ) + 1
call setpos ( '.' , l :pos )
else
return s :Token ( )
endif
endif
return ''
endfunction
function s :Pure ( f , ...)
let l :pos = getpos ( '.' )
let ret = call ( a :f , a :000 )
call setpos ( '.' , l :pos )
return ret
endfunction
function s :SearchLoop ( ...)
let l :pos = getpos ( '.' )
while call ( 'search' , a :000 [:-2 ]) " search flags [^nc]
if ! eval ( a :000 [-1 ])
return line ( '.' )
endif
return cursor ( a :lnum , match ( ' ' . a :text , '\%(\<else\|\<do\|=>\)$\C' ) ) + 1
endwhile
call setpos ( '.' , l :pos )
endfunction
function s :iscontOne ( i , num , cont )
let [l :i , l :cont , l :num ] = [a :i , a :cont , a :num + ! a :num ]
let pind = a :num ? indent ( l :num ) + s :W : 0
let ind = indent ( l :i ) + ( a :cont ? 0 : s :W )
let bL = 0
while l :i > = l :num && ( ! l :cont | | ind > pind )
if indent ( l :i ) < ind " first line always true for !a:cont, false for !!a:cont
if s :OneScope ( l :i , s :Trim ( l :i ) )
let bL + = s :W
let [l :cont , l :i ] = [0 , line ( '.' ) ]
elseif ! l :cont
function s :ExprCol( )
if getline ( '.' ) [col ( '.' ) -2 ] = = ':'
return 1
endif
let [bal , l :pos ] = [0 , getpos ( '.' ) ]
while s:SearchLoop ( '\m[{}?:]' , 'bW' , s :script_tag , s :skip_expr )
if s:LookingAt ( ) = = ':'
let bal - = strpart ( getline ( '.' ) , col ( '.' ) -2 , 3 ) ! ~ '::'
elseif s :LookingAt ( ) = = '?'
let bal + = 1
if bal = = 1
break
endif
elseif ! a :cont
elseif s :LookingAt ( ) = = '{'
let bal = ! s :IsBlock ( )
break
elseif ! s :GetPair ( '{' , '}' , 'bW' , s :skip_expr , 200 )
break
endif
let ind = min ( [ind , indent ( l :i ) ])
let l :i = s :PrevCodeLine ( l :i - 1 )
endwhile
return bL
call setpos ( '.' , l :pos )
return s :Nat ( bal )
endfunction
" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
function s :IsBlock ( ...)
let l :ln = get ( a :000 , 0 , line ( '.' ) )
let char = s :previous_token ( )
let syn = char = ~ '[{>/]' | | l :ln ! = line ( '.' ) ? synIDattr ( synID ( line ( '.' ) , col ( '.' ) - ( char = = '{' ) , 0 ) , 'name' ) : ''
if char is ''
return 1
elseif syn = ~ ? 'xml\|jsx'
return char ! = '{'
elseif syn = ~ ? 'comment'
return search ( '\/[/*]' , 'bW' ) && s :IsBlock ( l :ln )
elseif char = = '>'
return getline ( '.' ) [col ( '.' ) -2 ] = = '=' | | syn = ~ ? '^jsflow'
elseif char = = ':'
return cursor ( 0 , match ( ' ' . strpart ( getline ( '.' ) , 0 , col ( '.' ) ) , '.*\zs' . s :case_stmt . '$' ) ) + 1 &&
\ ( expand ( '<cword>' ) ! = # 'default' | | s :previous_token ( ) ! ~ '[,{]' )
endif
return index ( split ( 'return const let import export yield default delete var void typeof throw new in instanceof'
\ . ' - = ~ ! < * + , / ? ^ % | & ( [' ) , char ) < ( 0 + ( line ( '.' ) ! = l :ln ) )
" configurable regexes that define continuation lines, not including (, {, or [.
let s :opfirst = '^' . get ( g :, 'javascript_opfirst' ,
\ '\C\%([<>=,.?^%|/&]\|\([-:+]\)\1\@!\|\*\+\|!=\|in\%(stanceof\)\=\>\)' )
let s :continuation = get ( g :, 'javascript_continuation' ,
\ '\C\%([<=,.~!?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<\%(typeof\|new\|delete\|void\|in\|instanceof\|await\)\)' ) . '$'
function s :Continues ( ln , con )
let tok = matchstr ( a :con [-15 :], s :continuation )
if tok = ~ '[a-z:]'
call cursor ( a :ln , len ( a :con ) )
return tok = = ':' ? s :ExprCol ( ) : s :PreviousToken ( ) ! = '.'
elseif tok ! ~ '[/>]'
return tok isnot ''
endif
return s :SynAt ( a :ln , len ( a :con ) ) ! ~ ? ( tok = = '>' ? 'jsflow\|^html' : 'regex' )
endfunction
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
function s :Trim ( ln )
let divi = split ( getline ( a :ln ) , '\s\+$\|\S\zs\ze\s*\/[/*]' )
while len ( divi ) > 1 && s :SynAt ( a :ln , len ( join ( divi , '' ) ) ) = ~ ? s :syng_com
call remove ( divi , -1 )
endwhile
return join ( divi , '' )
endfunction
" Find line above 'lnum' that isn't empty or in a comment
function s :PrevCodeLine ( lnum )
let l :lnum = prevnonblank ( a :lnum )
while l :lnum
let syn = synIDattr ( synID ( l :lnum , matchend ( getline ( l :lnum ) , '^\s*[^''"`]' ) , 0 ) , 'name' )
if syn = ~ ? 'html'
return
elseif syn ! ~ ? s :syng_strcom
return l :lnum
let [l :multi , l :n , l :pos ] = [0 , prevnonblank ( a :lnum ) , getpos ( '.' ) ]
while l :n
if getline ( l :n ) = ~ '^\s*\/[/*]' && ( getline ( l :n ) ! ~ '`' &&
\ getline ( l :n -1 ) [-1 :] ! = '\' | | s :SynAt ( l :n , 1 ) ! ~ ? b :syng_str )
let l :n = prevnonblank ( l :n -1 )
continue
elseif l :multi | | getline ( l :n ) = ~ '\*\/'
call cursor ( l :n , 1 )
if search ( '\m\/\*\|\(\*\/\)' , 'bWp' ) = = 1 && s :SynAt ( l :n , 1 ) = ~ ? s :syng_com
let [l :multi , l :n ] = [1 , line ( '.' ) ]
continue
endif
let l :lnum = prevnonblank ( l :lnum - 1 )
endif
break
endwhile
call setpos ( '.' , l :pos )
return l :n
endfunction
" Check if line 'lnum' has a balanced amount of parentheses.
function s :Balanced ( lnum )
let l :open = 0
let l :line = getline ( a :lnum )
let pos = match ( l :line , '[][(){}]' , 0 )
let [l :open , l :line ] = [0 , getline ( a :lnum ) ]
let pos = match ( l :line , '[][(){}]' )
while pos ! = -1
if s ynIDattr( synID ( a :lnum , pos + 1 , 0 ) , 'name' ) ! ~ ? s :syng_strcom
if s :SynAt ( a :lnum , pos + 1 ) ! ~ ? b :syng_strcom
let l :open + = match ( ' ' . l :line [pos ], '[[({]' )
if l :open < 0
return
endif
endif
let pos = match ( l :line , '[][(){}]' , pos + 1 )
let pos = match ( l :line , l :open ?
\ matchstr ( ['[][]' , '[()]' , '[{}]' ], l :line [pos ]) :
\ '[][(){}]' , pos + 1 )
endwhile
return ! l :open
endfunction
function s :OneScope ( lnum )
call cursor ( a :lnum , len ( s :Trim ( a :lnum ) ) )
if s :LookingAt ( ) = = ')' && s :GetPair ( '(' , ')' , 'bW' , s :skip_expr , 100 )
let tok = s :PreviousToken ( )
return ( tok = ~ # '^\%(for\|if\|let\|while\|with\)$' | |
\ tok = ~ # '^await$\|^each$' && s :PreviousToken ( ) = = # 'for' ) &&
\ s :Pure ( 's:PreviousToken' ) ! = '.' && ! ( tok = = 'while' && s :DoWhile ( ) )
elseif s :Token ( ) = ~ # '^else$\|^do$'
return s :Pure ( 's:PreviousToken' ) ! = '.'
endif
return strpart ( getline ( '.' ) , col ( '.' ) -2 , 2 ) = = '=>'
endfunction
function s :DoWhile ( )
let cpos = searchpos ( '\m\<' , 'cbW' )
if s :SearchLoop ( '\m\C[{}]\|\<\%(do\|while\)\>' , 'bW' , s :skip_expr )
if s :{s :LookingAt ( ) = = '}' && s :GetPair ( '{' , '}' , 'bW' , s :skip_expr , 200 ) ?
\ 'Previous' : '' }Token ( ) = = # 'do' && s :IsBlock ( )
return 1
endif
call call ( 'cursor' , cpos )
endif
endfunction
" returns braceless levels started by 'i' and above lines * &sw. 'num' is the
" lineNr which encloses the entire context, 'cont' if whether line 'i' + 1 is
" a continued expression, which could have started in a braceless context
function s :IsContOne ( i , num , cont )
let [l :i , l :num , b_l ] = [a :i , a :num + ! a :num , 0 ]
let pind = a :num ? indent ( a :num ) + s :sw ( ) : 0
let ind = indent ( a :i ) + ( a :cont ? 0 : s :sw ( ) )
while l :i > l :num && ind > pind | | l :i = = l :num
if indent ( l :i ) < ind && s :OneScope ( l :i )
let b_l + = 1
let l :i = line ( '.' )
elseif ! a :cont | | b_l | | ind < indent ( a :i )
break
endif
let ind = min ( [ind , indent ( l :i ) ])
let l :i = s :PrevCodeLine ( l :i - 1 )
endwhile
return b_l
endfunction
function s :IsSwitch ( )
return s :PreviousToken ( ) ! ~ '[.*]' &&
\ ( ! s :GetPair ( '{' , '}' , 'cbW' , s :skip_expr , 100 ) | | s :IsBlock ( ) &&
\ ( s :Token ( ) ! ~ '^\K\k*$' | | expand ( '<cword>' ) ! = # 'class' &&
\ s :PreviousToken ( ) ! ~ # '^class$\|^extends$' | | s :PreviousToken ( ) = = '.' ) )
endfunction
" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
function s :IsBlock ( )
let l :n = line ( '.' )
let tok = s :PreviousToken ( )
if match ( s :stack , '\cxml\|jsx' ) ! = -1 && s :SynAt ( line ( '.' ) , col ( '.' ) -1 ) = ~ ? 'xml\|jsx'
return tok ! = '{'
elseif tok = ~ '\k'
if tok = = # 'type'
return s :Pure ( 'eval' , "s:PreviousToken() !~# '^\\%(im\\|ex\\)port$' || s:PreviousToken() == '.'" )
endif
return index ( split ( 'return const let import export extends yield default delete var await void typeof throw case new of in instanceof' )
\ , tok ) < ( line ( '.' ) ! = l :n ) | | s :Pure ( 's:PreviousToken' ) = = '.'
elseif tok = = '>'
return getline ( '.' ) [col ( '.' ) -2 ] = = '=' | | s :SynAt ( line ( '.' ) , col ( '.' ) ) = ~ ? 'jsflow\|^html'
elseif tok = = '*'
return s :Pure ( 's:PreviousToken' ) = = ':'
elseif tok = = ':'
return ! s :ExprCol ( )
elseif tok = = '/'
return s :SynAt ( line ( '.' ) , col ( '.' ) ) = ~ ? 'regex'
elseif tok ! ~ '[=~!<,.?^%|&([]'
return tok ! ~ '[-+]' | | l :n ! = line ( '.' ) && getline ( '.' ) [col ( '.' ) -2 ] = = tok
endif
endfunction
function GetJavascriptIndent ( )
let b :js_cache = get ( b :, 'js_cache' , [0 , 0 , 0 ])
" Get the current line.
let l :line = getline ( v :lnum )
let syns = synIDattr ( synID ( v :lnum , 1 , 0 ) , 'name' )
let [b :js_cache , s :synid_cache , l :line , s :stack ] = [
\ get ( b :, 'js_cache' , [0 , 0 , 0 ]) ,
\ [[], []],
\ getline ( v :lnum ) ,
\ map ( synstack ( v :lnum , 1 ) , "synIDattr(v:val,'name')" ) ,
\ ]
" use synstack as it validates syn state and works in an empty line
let syns = get ( s :stack , -1 , '' )
" start with strings,comments,etc.
if syns = ~ ? 'comment\|doc'
if syns = ~ ? s :syng_com
if l :line = ~ '^\s*\*'
return cindent ( v :lnum )
elseif l :line ! ~ '^\s*\/'
elseif l :line ! ~ '^\s*\/ [/*] '
return -1
endif
elseif syns = ~ ? 'string\|template' && l :line ! ~ '^[''"]'
elseif syns = ~ ? b :syng_str
if b :js_cache [0 ] = = v :lnum - 1 && s :Balanced ( v :lnum -1 )
let b :js_cache [0 ] = v :lnum
endif
return -1
endif
let l :lnum = s :PrevCodeLine ( v :lnum - 1 )
@ -199,63 +391,97 @@ function GetJavascriptIndent()
return
endif
let l :line = substitute ( substitute ( l :line , '^\s*\%(\/\*.\{-}\*\/\s*\)*' , '' , '' ) , '^\/[/*].*' , '' , '' )
" the containing paren, bracket, curly. Many hacks for performance
call cursor ( v :lnum , 1 )
let idx = strlen ( l :line ) ? stridx ( '])}' , l :line [0 ]) : -1
if indent ( l :lnum )
let [s :looksyn , s :free ] = [v :lnum - 1 , 1 ]
if b :js_cache [0 ] > = l :lnum && b :js_cache [0 ] < v :lnum &&
\ ( b :js_cache [0 ] > l :lnum | | s :Balanced ( l :lnum ) )
call call ( 'cursor' , b :js_cache [1 :])
elseif idx + 1
call s :GetPair ( ['\[' , '(' , '{' ][idx ], '])}' [idx ], 'bW' , 's:skip_func(s:looksyn)' , 2000 )
elseif indent ( v :lnum ) && syns = ~ ? 'block'
call s :GetPair ( '{' , '}' , 'bW' , 's:skip_func(s:looksyn)' , 2000 )
else
call s :GetPair ( '[({[]' , '[])}]' , 'bW' , 's:skip_func(s:looksyn)' , 2000 )
let l :line = substitute ( l :line , '^\s*' , '' , '' )
let l :line_raw = l :line
if l :line [:1 ] = = '/*'
let l :line = substitute ( l :line , '^\%(\/\*.\{-}\*\/\s*\)*' , '' , '' )
endif
else
call s :GetPair ( '[({[]' , '[])}]' , 'bW' , s :skip_expr , 200 , l :lnum )
if l :line = ~ '^\/[/*]'
let l :line = ''
endif
if idx + 1
if idx = = 2 && search ( '\S' , 'bW' , line ( '.' ) ) && s :current_char ( ) = = ')'
call s :GetPair ( '(' , ')' , 'bW' , s :skip_expr , 200 )
" the containing paren, bracket, or curly. Many hacks for performance
let [ s :script_tag , idx ] = [ get ( get ( b :, 'hi_indent' , {}) , 'blocklnr' ) ,
\ index ( [']' , ')' , '}' ], l :line [0 ]) ]
if b :js_cache [0 ] > l :lnum && b :js_cache [0 ] < v :lnum | |
\ b :js_cache [0 ] = = l :lnum && s :Balanced ( l :lnum )
call call ( 'cursor' , b :js_cache [2 ] ? b :js_cache [1 :] : [v :lnum , 1 ])
else
call cursor ( v :lnum , 1 )
let [s :looksyn , s :check_in , s :top_col ] = [v :lnum - 1 , 0 , 0 ]
try
if idx ! = -1
call s :GetPair ( '[({' [idx ], '])}' [idx ], 'bW' , 's:SkipFunc()' , 2000 , s :script_tag )
elseif getline ( v :lnum ) ! ~ '^\S' && syns = ~ ? 'block'
call s :GetPair ( '{' , '}' , 'bW' , 's:SkipFunc()' , 2000 , s :script_tag )
else
call s :AlternatePair ( )
endif
return indent ( line ( '.' ) )
catch
call cursor ( v :lnum , 1 )
endtry
endif
let b :js_cache = [v :lnum ] + ( line ( '.' ) = = v :lnum ? [0 , 0 ] : [line ( '.' ) , col ( '.' ) ])
let b :js_cache = [v :lnum ] + ( line ( '.' ) = = v :lnum ? [s :script_tag , 0 ] : getpos ( '.' ) [1 :2 ])
let num = b :js_cache [1 ]
let [s :W , pline , isOp , stmt , bL , switch_offset ] = [s :sw ( ) , s :Trim ( l :lnum ) , 0 , 0 , 0 , 0 ]
if num && s :current_char ( ) = = '{' && s :IsBlock ( )
let stmt = 1
if s :current_char ( ) = = ')' && s :GetPair ( '(' , ')' , 'bW' , s :skip_expr , 100 ) > 0 && s :previous_token ( ) = = # 'switch'
let switch_offset = &cino ! ~ ':' | | ! has ( 'float' ) ? s :W :
\ float2nr ( str2float ( matchstr ( &cino , '.*:\zs[-0-9.]*' ) ) * ( &cino = ~ # '\%(.*:\)\@>[^,]*s' ? s :W : 1 ) )
if l :line = ~ # '^' . s :case_stmt
return indent ( num ) + switch_offset
let [num_ind , is_op , b_l , l :switch_offset ] = [s :Nat ( indent ( num ) ) , 0 , 0 , 0 ]
if ! b :js_cache [2 ] | | s :LookingAt ( ) = = '{' && s :IsBlock ( )
let [ilnum , pline ] = [line ( '.' ) , s :Trim ( l :lnum ) ]
if b :js_cache [2 ] && s :LookingAt ( ) = = ')' && s :GetPair ( '(' , ')' , 'bW' , s :skip_expr , 100 )
if ilnum = = num
let [num , num_ind ] = [line ( '.' ) , indent ( '.' ) ]
endif
let stmt = pline ! ~ # s :case_stmt . '$'
if idx = = -1 && s :PreviousToken ( ) = = # 'switch' && s :IsSwitch ( )
let l :switch_offset = &cino ! ~ ':' ? s :sw ( ) : s :ParseCino ( ':' )
if pline [-1 :] ! = '.' && l :line = ~ # '^\%(default\|case\)\>'
return s :Nat ( num_ind + l :switch_offset )
elseif &cino = ~ '='
let l :case_offset = s :ParseCino ( '=' )
endif
endif
if stmt | | ! num
let isOp = l :line = ~ # s :opfirst | | pline = ~ # s :continuation
let bL = s :iscontOne ( l :lnum , num , isOp )
let bL - = ( bL && l :line [0 ] = = '{' ) * s :W
endif
if idx = = -1 && pline [-1 :] ! ~ '[{;]'
let sol = matchstr ( l :line , s :opfirst )
if sol = ~ # '^\%(in\%(stanceof\)\=\|\*\)$'
call cursor ( l :lnum , len ( pline ) )
if pline [-1 :] = = '}' && s :GetPair ( '{' , '}' , 'bW' , s :skip_expr , 200 ) && s :IsBlock ( )
return num_ind + s :sw ( )
endif
let is_op = s :sw ( )
elseif sol isnot '' | | s :Continues ( l :lnum , pline )
let is_op = s :sw ( )
endif
let b_l = s :Nat ( s :IsContOne ( l :lnum , b :js_cache [1 ], is_op ) -
\ ( ! is_op && l :line = ~ '^{' ) ) * s :sw ( )
endif
elseif idx = = -1 && getline ( b :js_cache [1 ]) [b :js_cache [2 ]-1 ] = = '(' && &cino = ~ '(' &&
\ ( search ( '\m\S' , 'nbW' , num ) | | s :ParseCino ( 'U' ) )
let pval = s :ParseCino ( '(' )
if ! pval
let [Wval , vcol ] = [s :ParseCino ( 'W' ) , virtcol ( '.' ) ]
if search ( '\m\S' , 'W' , num )
return s :ParseCino ( 'w' ) ? vcol : virtcol ( '.' ) -1
endif
return Wval ? s :Nat ( num_ind + Wval ) : vcol
endif
return s :Nat ( num_ind + pval + s :GetPair ( '(' , ')' , 'nbrmW' , s :skip_expr , 100 , num ) * s :sw ( ) )
endif
" main return
if isOp
return ( num ? indent ( num ) : - s :W ) + ( s :W * 2 ) + switch_offset + bL
if l :line = ~ '^[])}]\|^|}'
if l :line_raw [0 ] = = ')' && getline ( b :js_cache [1 ]) [b :js_cache [2 ]-1 ] = = '('
if s :ParseCino ( 'M' )
return indent ( l :lnum )
elseif &cino = ~ # 'm' && ! s :ParseCino ( 'm' )
return virtcol ( '.' ) - 1
endif
endif
return num_ind
elseif num
return indent ( num ) + s :W + switch_offset + bL
return s:Nat ( num_ind + get ( l :, 'case_offset' , s :sw ( ) ) + l :switch_offset + b_l + is_op )
endif
return bL
return b _l + is_op
endfunction
let &cpo = s :cpo_save