Skip to content

Commit

Permalink
Merge pull request #653 from pangloss/develop
Browse files Browse the repository at this point in the history
Develop -> Master
  • Loading branch information
bounceme authored Oct 11, 2016
2 parents 25e9865 + 7d30463 commit d736e95
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 71 deletions.
2 changes: 1 addition & 1 deletion extras/flow.vim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ syntax region jsFlowParens contained matchgroup=jsFlowNoise start=/(/
syntax match jsFlowNoise contained /[:;,<>]/
syntax keyword jsFlowType contained boolean number string null void any mixed JSON array function object array bool class
syntax keyword jsFlowTypeof contained typeof skipempty skipempty nextgroup=jsFlowTypeCustom,jsFlowType
syntax match jsFlowTypeCustom contained /\k*/ skipwhite skipempty nextgroup=jsFlowGroup
syntax match jsFlowTypeCustom contained /[0-9a-zA-Z_.]*/ skipwhite skipempty nextgroup=jsFlowGroup
syntax region jsFlowGroup contained matchgroup=jsFlowNoise start=/</ end=/>/ contains=@jsFlowCluster
syntax region jsFlowArrowArguments contained matchgroup=jsFlowNoise start=/(/ end=/)\%(\s*=>\)\@=/ oneline skipwhite skipempty nextgroup=jsFlowArrow contains=@jsFlowCluster
syntax match jsFlowArrow contained /=>/ skipwhite skipempty nextgroup=jsFlowType,jsFlowTypeCustom,jsFlowParens
Expand Down
202 changes: 142 additions & 60 deletions indent/javascript.vim
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
" Vim indent file
" Language: Javascript
" Maintainer: vim-javascript community
" Maintainer: Chris Paul ( https://github.com/bounceme )
" URL: https://github.com/pangloss/vim-javascript
" Last Change: September 4, 2016
" Last Change: October 9, 2016

" Only load this indent file when no other was loaded.
if exists('b:did_indent')
Expand Down Expand Up @@ -38,63 +38,124 @@ else
endif

let s:line_pre = '^\s*\%(\%(\%(\/\*.\{-}\)\=\*\+\/\s*\)\=\)\@>'
let s:expr_case = s:line_pre . '\%(\%(case\>.\+\)\|default\)\s*:\C'
let s:line_term = '\s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$'

let s:expr_case = '\<\%(\%(case\>\s*\S.\{-}\)\|default\)\s*:\C'
" Regex of syntax group names that are or delimit string or are comments.
let s:syng_strcom = '\%(s\%(tring\|pecial\)\|comment\|regex\|doc\|template\)'

" Regex of syntax group names that are strings or documentation.
let s:syng_comment = '\%(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 || getline(line('.')) =~ '[''/"\\]' || search('`','nW',a:lnum) || search('\*\/','nW',a:lnum)
if !s:free || search('`','nW',a:lnum) || search('\*\/','nW',a:lnum)
let s:free = !eval(s:skip_expr)
let s:looksyn = s:free ? line('.') : s:looksyn
return !s:free
endif
let s:looksyn = s:free ? line('.') : s:looksyn
return !s:free
let s:looksyn = line('.')
return (search('\/','nbW',line('.')) || search('[''"\\]','nW',line('.'))) && eval(s:skip_expr)
endfunction

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:time)
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)
endfunction
else
function s:GetPair(start,end,flags,...)
return searchpair(a:start,'',a:end,a:flags,0,max([prevnonblank(v:lnum) - 2000,0]))
return searchpair(a:start,'',a:end,a:flags,"line('.') < prevnonblank(v:lnum) - 2000 ? dummy : 0")
endfunction
endif

let s:line_term = '\s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$'
" indent/python.vim
function s:Trimline(ln)
let pline = getline(a:ln)
let min = match(pline,'\/[/*]') + 1
if min && synIDattr(synID(a:ln, strlen(pline), 0), 'name') =~? '\%(comment\|doc\)'
let max = match(pline,'.*\zs\/[/*]') + 1
while min < max
let col = (min + max) / 2
if synIDattr(synID(a:ln, col, 0), 'name') =~? '\%(comment\|doc\)'
let max = col
else
let min = match(pline,'\/[/*]',col) + 1
endif
endwhile
let pline = strpart(pline, 0, min - 1)
endif
return substitute(pline,'\s*$','','')
endfunction

" configurable regexes that define continuation lines, not including (, {, or [.
if !exists('g:javascript_opfirst')
let g:javascript_opfirst = '\%([<>,?^%|*&]\|\/[^/*]\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
let g:javascript_opfirst = '\%([<>,?^%|*&]\|\/[/*]\@!\|\([-.:+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)'
endif
if !exists('g:javascript_continuation')
let g:javascript_continuation = '\%([<=,.?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)'
endif

let g:javascript_opfirst = s:line_pre . g:javascript_opfirst
let g:javascript_continuation .= s:line_term
let g:javascript_opfirst = '^' . g:javascript_opfirst
let g:javascript_continuation .= '$'

function s:OneScope(lnum,text)
return a:text =~# '\%(\<else\|\<do\|=>\)' . s:line_term ? 'no b' :
\ cursor(a:lnum, match(' ' . a:text, ')' . s:line_term)) > -1 &&
\ s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 && search('\C\l\+\_s*\%#','bW') &&
\ (expand('<cword>') !=# 'while' || s:GetPair('\C\<do\>', '\C\<while\>','nbW',s:skip_expr,100) <= 0) &&
\ (expand('<cword>') !=# 'each' || search('\C\<for\_s\+\%#','nbW')) ? expand('<cword>') : ''
return cursor(a:lnum, match(' ' . a:text, '\%(\<else\|\<do\|=>\)$')) > -1 ||
\ cursor(a:lnum, match(' ' . a:text, ')$')) > -1 &&
\ s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 &&
\ search('\C\<\%(for\%(\_s\+\%(await\|each\)\)\=\|if\|let\|w\%(hile\|ith\)\)\_s*\%#','bW')
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
let ind = indent(l:i) + (!l:cont * s:W)
let bL = 0
while l:i >= l:num && (!l:cont || ind > pind + s:W)
if indent(l:i) < ind " first line always true for !a:cont, false for !!a:cont
if s:OneScope(l:i,s:Trimline(l:i))
if expand('<cword>') ==# 'while' &&
\ s:GetPair(s:line_pre . '\C\<do\>','\C\<while\>','bW',s:skip_expr,100,l:num + !!a:num) > 0
return 0
endif
let bL += 1
let [l:cont, l:i] = [0, line('.')]
elseif !l:cont
break
endif
let ind = indent(l:i)
endif
let l:i = s:PrevCodeLine(l:i - 1)
endwhile
return bL * s:W
endfunction

" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader
function s:IsBlock()
return getline(line('.'))[col('.')-1] == '{' && !search(
\ '\C\%(\<return\s*\|\%([-=~!<*+,.?^%|&\[(]\|=\@<!>\|\*\@<!\/\|\<\%(var\|const\|let\|import\|export\%(\_s\+default\)\=\|yield\|delete\|void\|t\%(ypeof\|hrow\)\|new\|in\%(stanceof\)\=\)\)\_s*\)\%#','bnW') &&
\ (search(s:expr_case . '\_s*\%#','nbW') || !search('[{:]\_s*\%#','bW') || s:IsBlock())
if getline(line('.'))[col('.')-1] == '{'
if search('\C\<return\s*\%#','nbW')
return 0
endif
if search('\*\/\_s*\%#','bW') && synIDattr(synID(line('.'),col('.'),0),'name') =~? 'comment'
call searchpair('\/\*','','\*\/','bW')
endif
if search('\S','bW')
let char = getline(line('.'))[col('.')-1]
if char =~# '\l'
return expand('<cword>') !~#
\ '^\%(var\|const\|let\|\%(im\|ex\)port\|yield\|de\%(fault\|lete\)\|void\|t\%(ypeof\|hrow\)\|new\|in\%(stanceof\)\=\)$'
elseif char == '>'
return search('=\%#','bW') || synIDattr(synID(line('.'),col('.'),0),'name') =~? 'flownoise'
elseif char == ':'
return strpart(getline(line('.')),0,col('.')) =~# s:expr_case . '$'
elseif char == '{'
return s:IsBlock()
else
return char !~# '[-=~!<*+,./?^%|&\[(]'
endif
else
return 1
endif
endif
endfunction

" Auxiliary Functions {{{2

" Find line above 'lnum' that isn't empty, in a comment, or in a string.
function s:PrevCodeLine(lnum)
let l:lnum = prevnonblank(a:lnum)
Expand All @@ -114,7 +175,7 @@ function s:Balanced(lnum)
while pos != -1
if synIDattr(synID(a:lnum,pos + 1,0),'name') !~? s:syng_strcom
let idx = stridx('(){}[]', l:line[pos])
if idx % 2 == 0
if !(idx % 2)
let open_{idx} += 1
else
let open_{idx - 1} -= 1
Expand All @@ -125,78 +186,99 @@ function s:Balanced(lnum)
endif
let pos = match(l:line, '[][(){}]', pos + 1)
endwhile
return (!open_4 + !open_2 + !open_0) - 2
return !(open_4 || open_2 || open_0)
endfunction
" }}}

function GetJavascriptIndent()
try
let save_magic = &magic
set magic
if !exists('b:js_cache')
let b:js_cache = [0,0,0]
endif
" Get the current line.
let l:line = getline(v:lnum)
let syns = synIDattr(synID(v:lnum, 1, 0), 'name')

" start with strings,comments,etc.{{{2
if (l:line !~ '^[''"]' && syns =~? '\%(string\|template\)') ||
\ (l:line !~ '^\s*[/*]' && syns =~? s:syng_comment)
" start with strings,comments,etc.
if syns =~? '\%(comment\|doc\)'
if l:line =~ '^\s*\*'
return cindent(v:lnum)
elseif l:line !~ '^\s*\/'
return -1
endif
elseif syns =~? '\%(string\|template\)' && l:line !~ '^[''"]'
return -1
endif
if l:line !~ '^\%(\/\*\|\s*\/\/\)' && syns =~? s:syng_comment
return cindent(v:lnum)
endif
let l:lnum = s:PrevCodeLine(v:lnum - 1)
if l:lnum == 0
return 0
endif

if (l:line =~# s:expr_case)
let l:line = substitute(l:line,'^\s*\%(\/\*.\{-}\*\/\s*\)*','','')

if l:line =~# '^' . s:expr_case
let cpo_switch = &cpo
set cpo+=%
let ind = cindent(v:lnum)
let &cpo = cpo_switch
return ind
endif
"}}}

" the containing paren, bracket, curly. Memoize, last lineNr either has the
" same scope or starts a new one, unless if it closed a scope.
let [s:looksyn,s:free] = [v:lnum - 1,1]
call cursor(v:lnum,1)
if b:js_cache[0] < v:lnum && b:js_cache[0] >= l:lnum &&
\ (b:js_cache[0] > l:lnum || s:Balanced(l:lnum) > 0)
let num = b:js_cache[1]
elseif syns != '' && l:line[0] =~ '\s'
let pattern = syns =~? 'block' ? ['{','}'] : syns =~? 'jsparen' ? ['(',')'] :
\ syns =~? 'jsbracket'? ['\[','\]'] : ['[({[]','[])}]']
let num = s:GetPair(pattern[0],pattern[1],'bW','s:skip_func(s:looksyn)',2000)
if getline(l:lnum) !~ '^\S'
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))
let num = b:js_cache[1]
elseif l:line =~ '^[])}]'
let id = stridx('])}',l:line[0])
let num = s:GetPair(escape('[({'[id],'['), escape('])}'[id],']'),'bW','s:skip_func(s:looksyn)',2000)
elseif syns != '' && getline(v:lnum)[0] =~ '\s'
let pattern = syns =~? 'block' ? ['{','}'] : syns =~? 'jsparen' ? ['(',')'] :
\ syns =~? 'jsbracket'? ['\[','\]'] : ['[({[]','[])}]']
let num = s:GetPair(pattern[0],pattern[1],'bW','s:skip_func(s:looksyn)',2000)
else
let num = s:GetPair('[({[]','[])}]','bW','s:skip_func(s:looksyn)',2000)
endif
else
let num = s:GetPair('[({[]','[])}]','bW','s:skip_func(s:looksyn)',2000)
let num = s:GetPair('[({[]','[])}]','bW',s:skip_expr,200,l:lnum)
endif

let num = (num > 0) * num
if l:line =~ '^[])}]'
return !!num * indent(num)
endif
let b:js_cache = [v:lnum,num,line('.') == v:lnum ? b:js_cache[2] : col('.')]

if l:line =~ s:line_pre . '[])}]'
return indent(num)
call cursor(v:lnum,1)
if l:line =~# '^while\>' && s:GetPair(s:line_pre . '\C\<do\>','\C\<while\>','bW',s:skip_expr,100,num + 1) > 0
return indent(line('.'))
endif

let pline = substitute(substitute(getline(l:lnum),s:expr_case,'\=repeat(" ",strlen(submatch(0)))',''), '\%(:\@<!\/\/.*\)$', '','')
let s:W = s:sw()
let pline = s:Trimline(l:lnum)
call cursor(b:js_cache[1],b:js_cache[2])
let switch_offset = num <= 0 || !(search(')\_s*\%#','bW') &&
let switch_offset = !num || !(search(')\_s*\%#','bW') &&
\ s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 && search('\C\<switch\_s*\%#','bW')) ? 0 :
\ &cino !~ ':' || !has('float') ? s:sw() :
\ float2nr(str2float(matchstr(&cino,'.*:\zs[-0-9.]*')) * (&cino =~# '.*:[^,]*s' ? s:sw() : 1))
\ &cino !~ ':' || !has('float') ? s:W :
\ float2nr(str2float(matchstr(&cino,'.*:\zs[-0-9.]*')) * (&cino =~# '.*:[^,]*s' ? s:W : 1))

" most significant, find the indent amount
let isOp = l:line =~# g:javascript_opfirst || pline =~# g:javascript_continuation
if isOp && (num <= 0 || cursor(b:js_cache[1],b:js_cache[2]) || s:IsBlock()) ||
\ s:OneScope(l:lnum,pline) =~# '\<\%(for\|each\|if\|let\|no\sb\|w\%(hile\|ith\)\)\>' &&
\ l:line !~ s:line_pre . '{'
return (num > 0 ? indent(num) : -s:sw()) + (s:sw() * 2) + switch_offset
elseif num > 0
return indent(num) + s:sw() + switch_offset
let isOp = l:line =~# g:javascript_opfirst || pline !~# s:expr_case . '$' && pline =~# g:javascript_continuation
let bL = s:iscontOne(l:lnum,num,isOp)
let bL -= (bL && l:line =~ '^{') * s:W
if isOp && (!num || cursor(b:js_cache[1],b:js_cache[2]) || s:IsBlock())
return (num ? indent(num) : -s:W) + (s:W * 2) + switch_offset + bL
elseif num
return indent(num) + s:W + switch_offset + bL
endif

return bL
finally
let &magic = save_magic
endtry
endfunction


Expand Down
Loading

0 comments on commit d736e95

Please sign in to comment.