diff options
Diffstat (limited to 'indent')
| -rw-r--r-- | indent/ansible.vim | 5 | ||||
| -rw-r--r-- | indent/elixir.vim | 127 | ||||
| -rw-r--r-- | indent/haskell.vim | 90 | ||||
| -rw-r--r-- | indent/javascript.vim | 262 | ||||
| -rw-r--r-- | indent/plantuml.vim | 4 | ||||
| -rw-r--r-- | indent/ruby.vim | 96 | ||||
| -rw-r--r-- | indent/vue.vim | 59 | 
7 files changed, 357 insertions, 286 deletions
| diff --git a/indent/ansible.vim b/indent/ansible.vim index b3a9642f..d94d3a2c 100644 --- a/indent/ansible.vim +++ b/indent/ansible.vim @@ -27,7 +27,12 @@ endif  function GetAnsibleIndent(lnum)    if a:lnum == 1 || !prevnonblank(a:lnum-1) +    return 0 +  endif +  if exists("g:ansible_unindent_after_newline") +    if (a:lnum -1) != prevnonblank(a:lnum - 1)        return 0 +    endif    endif    let prevlnum = prevnonblank(a:lnum - 1)    let maintain = indent(prevlnum) diff --git a/indent/elixir.vim b/indent/elixir.vim index d1ea4ad4..0ddaec44 100644 --- a/indent/elixir.vim +++ b/indent/elixir.vim @@ -1,97 +1,48 @@  if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elixir') == -1 -setlocal nosmartindent -setlocal indentexpr=elixir#indent() -setlocal indentkeys+=0),0],0=\|>,=-> -setlocal indentkeys+=0=end,0=else,0=match,0=elsif,0=catch,0=after,0=rescue - -if exists("b:did_indent") || exists("*elixir#indent") +if exists("b:did_indent")    finish  end  let b:did_indent = 1 -let s:cpo_save = &cpo -set cpo&vim - -function! elixir#indent() -  " initiates the `old_ind` dictionary -  let b:old_ind = get(b:, 'old_ind', {}) -  " initiates the `line` dictionary -  let line = s:build_line(v:lnum) - -  if s:is_beginning_of_file(line) -    " Reset `old_ind` dictionary at the beginning of the file -    let b:old_ind = {} -    " At the start of the file use zero indent. -    return 0 -  elseif !s:is_indentable_line(line) -    " Keep last line indentation if the current line does not have an -    " indentable syntax -    return indent(line.last_non_blank.num) -  else -    " Calculates the indenation level based on the rules -    " All the rules are defined in `autoload/elixir/indent.vim` -    let ind = indent(line.last_non_blank.num) -    call s:debug('>>> line = ' . string(line.current)) -    call s:debug('>>> ind = ' . ind) -    let ind = s:indent('deindent_case_arrow', ind, line) -    let ind = s:indent('indent_parenthesis', ind, line) -    let ind = s:indent('indent_square_brackets', ind, line) -    let ind = s:indent('indent_brackets', ind, line) -    let ind = s:indent('deindent_opened_symbols', ind, line) -    let ind = s:indent('indent_pipeline_assignment', ind, line) -    let ind = s:indent('indent_pipeline_continuation', ind, line) -    let ind = s:indent('indent_after_pipeline', ind, line) -    let ind = s:indent('indent_assignment', ind, line) -    let ind = s:indent('indent_ending_symbols', ind, line) -    let ind = s:indent('indent_keywords', ind, line) -    let ind = s:indent('deindent_keywords', ind, line) -    let ind = s:indent('deindent_ending_symbols', ind, line) -    let ind = s:indent('indent_case_arrow', ind, line) -    let ind = s:indent('indent_ecto_queries', ind, line) -    call s:debug('<<< final = ' . ind) -    return ind -  end -endfunction - -function s:indent(rule, ind, line) -  let Fn = function('elixir#indent#'.a:rule) -  let ind = Fn(a:ind, a:line) -  call s:debug(a:rule . ' = ' . ind) -  return ind -endfunction - -function s:debug(message) -  if get(g:, 'elixir_indent_debug', 0) -    echom a:message -  end -endfunction - -function! s:is_beginning_of_file(line) -  return a:line.last_non_blank.num == 0 +setlocal indentexpr=elixir#indent(v:lnum) + +setlocal indentkeys+=0=end,0=catch,0=rescue,0=after,0=else,=->,0},0],0),0=\|>,0=<> +" TODO: @jbodah 2017-02-27: all operators should cause reindent when typed + +function! elixir#indent(lnum) +  let lnum = a:lnum +  let text = getline(lnum) +  let prev_nb_lnum = prevnonblank(lnum-1) +  let prev_nb_text = getline(prev_nb_lnum) + +  call elixir#indent#debug("==> Indenting line " . lnum) +  call elixir#indent#debug("text = '" . text . "'") + +  let handlers = [ +        \'top_of_file', +        \'starts_with_end', +        \'starts_with_mid_or_end_block_keyword', +        \'following_trailing_do', +        \'following_trailing_binary_operator', +        \'starts_with_pipe', +        \'starts_with_close_bracket', +        \'starts_with_binary_operator', +        \'inside_nested_construct', +        \'starts_with_comment', +        \'inside_generic_block' +        \] +  for handler in handlers +    call elixir#indent#debug('testing handler elixir#indent#handle_'.handler) +    let indent = function('elixir#indent#handle_'.handler)(lnum, text, prev_nb_lnum, prev_nb_text) +    if indent != -1 +      call elixir#indent#debug('line '.lnum.': elixir#indent#handle_'.handler.' returned '.indent) +      return indent +    endif +  endfor + +  call elixir#indent#debug("defaulting") +  return 0  endfunction -function! s:is_indentable_line(line) -  return elixir#util#is_indentable_at(a:line.current.num, 1) -endfunction - -function! s:build_line(line) -  let line = { 'current': {}, 'last': {}, 'last_non_blank': {} } -  let line.current = s:new_line(a:line) -  let line.last = s:new_line(line.current.num - 1) -  let line.last_non_blank = s:new_line(prevnonblank(line.current.num - 1)) - -  return line -endfunction - -function! s:new_line(num) -  return { -        \ "num": a:num, -        \ "text": getline(a:num) -        \ } -endfunction - -let &cpo = s:cpo_save -unlet s:cpo_save -  endif diff --git a/indent/haskell.vim b/indent/haskell.vim index 43dc97a6..e63515ce 100644 --- a/indent/haskell.vim +++ b/indent/haskell.vim @@ -13,11 +13,7 @@ if exists('b:did_indent')    finish  endif -if !exists('g:haskell_indent_disable') -    let g:haskell_indent_disable = 0 -endif - -if g:haskell_indent_disable != 0 +if get(g:, 'haskell_indent_disable', 0)    finish  endif @@ -68,7 +64,7 @@ if !exists('g:haskell_indent_guard')  endif  setlocal indentexpr=GetHaskellIndent() -setlocal indentkeys=0},0),0],!^F,o,O,0\=,0=where,0=let,0=deriving,<space> +setlocal indentkeys=0},0),0],!^F,o,O,0=where,0=let,0=deriving,<space>  function! s:isInBlock(hlstack)    return index(a:hlstack, 'haskellDelimiter') > -1 || index(a:hlstack, 'haskellParens') > -1 || index(a:hlstack, 'haskellBrackets') > -1 || index(a:hlstack, 'haskellBlock') > -1 || index(a:hlstack, 'haskellBlockComment') > -1 || index(a:hlstack, 'haskellPragma') > -1 @@ -159,15 +155,6 @@ function! GetHaskellIndent()      return 0    endif -  " " comment indentation -  " if l:line =~ '^\s*--' -  "   let l:s = match(l:prevline, '-- ') -  "   if l:s > -1 -  " endif -  " " if l:prevline =~ '^\s*--' -  " "   return match(l:prevline, '\S') -  " " endif -    "   { foo :: Int    " >>,    " @@ -258,12 +245,16 @@ function! GetHaskellIndent()    " where    " >>foo    " +  if l:prevline =~ '\C\<where\>\s*$' +    return match(l:prevline, '\S') + get(g:, 'haskell_indent_after_bare_where', &shiftwidth) +  endif +    " do    " >>foo    "    " foo =    " >>bar -  if l:prevline =~ '\C\(\<where\>\|\<do\>\|=\)\s*$' +  if l:prevline =~ '\C\(\<do\>\|=\)\s*$'      return match(l:prevline, '\S') + &shiftwidth    endif @@ -279,7 +270,7 @@ function! GetHaskellIndent()    " case foo of    " >>bar -> quux    if l:prevline =~ '\C\<case\>.\+\<of\>\s*$' -    if exists('g:haskell_indent_case_alternative') && g:haskell_indent_case_alternative +    if get(g:,'haskell_indent_case_alternative', 0)        return match(l:prevline, '\S') + &shiftwidth      else        return match(l:prevline, '\C\<case\>') + g:haskell_indent_case @@ -321,38 +312,50 @@ function! GetHaskellIndent()    " foo :: Int    "     -> Int +  " >>>>-> Int +  " +  " foo :: Monad m +  "     => Functor f +  " >>>>=> Int +  " +  " foo :: Int +  "     -> Int    " foo x    "    " foo    "   :: Int    "   -> Int    " foo x -  if l:prevline =~ '^\s*[-=]>' && l:line !~ '^\s*[-=]>' -    if s:isInBlock(l:hlstack) -      return match(l:prevline, '[^\s-=>]') +  if l:prevline =~ '^\s*[-=]>' +    if l:line =~ '^\s*[-=]>' +      return match(l:prevline, '[-=]')      else -      let l:m = matchstr(l:line, '^\s*\zs\<\S\+\>\ze') -      let l:l = l:prevline -      let l:c = 1 - -      while v:lnum != l:c -        " fun decl -        if l:l =~ ('^\s*' . l:m . '\(\s*::\|\n\s\+::\)') -          let l:s = match(l:l, l:m) -          if match(l:l, '\C^\s*\<default\>') > -1 -            return l:s - 8 -          else -            return l:s +      if s:isInBlock(l:hlstack) +        return match(l:prevline, '[^-=]') +      else +        let l:m = matchstr(l:line, '^\s*\zs\<\S\+\>\ze') +        let l:l = l:prevline +        let l:c = 1 + +        while v:lnum != l:c +          " fun decl +          if l:l =~ ('^\s*' . l:m . '\(\s*::\|\n\s\+::\)') +            let l:s = match(l:l, l:m) +            if match(l:l, '\C^\s*\<default\>') > -1 +              return l:s - 8 +            else +              return l:s +            endif +          " empty line, stop looking +          elseif l:l =~ '^$' +             return 0            endif -        " empty line, stop looking -        elseif l:l =~ '^$' -           return 0 -        endif -        let l:c += 1 -        let l:l = getline(v:lnum - l:c) -      endwhile +          let l:c += 1 +          let l:l = getline(v:lnum - l:c) +        endwhile -      return 0 +        return 0 +      endif      endif    endif @@ -403,12 +406,17 @@ function! GetHaskellIndent()    "  in foo    " where bar +  " +  " or +  " +  " foo +  " >>where    if l:line =~ '\C^\s*\<where\>'      if match(l:prevline, '\C^\s\+in\s\+') == 0        return match(l:prevline, 'in') - g:haskell_indent_in      endif -    return match(l:prevline, '\S') + &shiftwidth +    return match(l:prevline, '\S') + get(g:, 'haskell_indent_before_where', &shiftwidth)    endif    " let x = 1 diff --git a/indent/javascript.vim b/indent/javascript.vim index 7029ed22..8f922eca 100644 --- a/indent/javascript.vim +++ b/indent/javascript.vim @@ -4,7 +4,7 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'javascript') ==  " Language: Javascript  " Maintainer: Chris Paul ( https://github.com/bounceme )  " URL: https://github.com/pangloss/vim-javascript -" Last Change: March 9, 2017 +" Last Change: May 16, 2017  " Only load this indent file when no other was loaded.  if exists('b:did_indent') @@ -12,6 +12,10 @@ 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 @@ -23,6 +27,13 @@ setlocal indentkeys+=0],0)  let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<' +" 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')    finish @@ -38,7 +49,7 @@ if exists('*shiftwidth')    endfunction  else    function s:sw() -    return &l:shiftwidth == 0 ? &l:tabstop : &l:shiftwidth +    return &l:shiftwidth ? &l:shiftwidth : &l:tabstop    endfunction  endif @@ -46,6 +57,10 @@ endif  " matches before pos.  let s:z = has('patch-7.4.984') ? 'z' : '' +let s:syng_com = 'comment\|doc' +" Expression used to check whether we should skip a match with searchpair(). +let s:skip_expr = "s:syn_at(line('.'),col('.')) =~? b:syng_strcom" +  " searchpair() wrapper  if has('reltime')    function s:GetPair(start,end,flags,skip,time,...) @@ -57,56 +72,80 @@ else    endfunction  endif -" Regex of syntax group names that are or delimit string or are comments. -let s:syng_strcom = 'string\|comment\|regex\|special\|doc\|template\%(braces\)\@!' -let s:syng_str = 'string\|template\|special' -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:syn_at(l,c) +  let pos = join([a:l,a:c],',') +  if has_key(s:synId_cache,pos) +    return s:synId_cache[pos] +  endif +  let s:synId_cache[pos] = synIDattr(synID(a:l,a:c,0),'name') +  return s:synId_cache[pos] +endfunction -function s:parse_cino(f) abort -  return float2nr(eval(substitute(substitute(join(split( -        \ matchstr(&cino,'\C.*'.a:f.'\zs[^,]*'), 's',1), '*'.s:W) -        \ , '^-\=\zs\*','',''), '^-\=\zs\.','0.',''))) +function s:parse_cino(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:W +      else +        let n = str2nr(n) * s:W +      endif +      break +    elseif c =~ '\d' +      let [n, divider] .= [c, 0] +    else +      break +    endif +  endfor +  return sign * str2nr(n) / max([str2nr(divider),1])  endfunction +" Optimized {skip} expr, used only once per GetJavascriptIndent() call  function s:skip_func() -  if getline('.') =~ '\%<'.col('.').'c\/.\{-}\/\|\%>'.col('.').'c[''"]\|\\$' -    return eval(s:skip_expr) +  if s:topCol == 1 || line('.') < s:scriptTag +    return {} " E728, used as limit condition for loops and searchpair() +  endif +  let s:topCol = col('.') +  if getline('.') =~ '\%<'.s:topCol.'c\/.\{-}\/\|\%>'.s:topCol.'c[''"]\|\\$' +    if eval(s:skip_expr) +      let s:topCol = 0 +    endif +    return !s:topCol    elseif s:checkIn || search('\m`\|\${\|\*\/','nW'.s:z,s:looksyn)      let s:checkIn = eval(s:skip_expr) +    if s:checkIn +      let s:topCol = 0 +    endif    endif    let s:looksyn = line('.')    return s:checkIn  endfunction -function s:alternatePair(stop) -  let pos = getpos('.')[1:2] -  let pat = '[][(){};]' -  while search('\m'.pat,'bW',a:stop) +function s:alternatePair() +  let [l:pos, pat, l:for] = [getpos('.'), '[][(){};]', 3] +  while search('\m'.pat,'bW')      if s:skip_func() | continue | endif      let idx = stridx('])};',s:looking_at()) -    if idx is 3 | let pat = '[{}()]' | continue | endif -    if idx + 1 -      if s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop) <= 0 +    if idx is 3 +      if l:for is 1 +        return s:GetPair('{','}','bW','s:skip_func()',2000) > 0 || setpos('.',l:pos) +      endif +      let [pat, l:for] = ['[{}();]', l:for - 1] +    elseif idx + 1 +      if s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000) < 1          break        endif      else        return      endif    endwhile -  call call('cursor',pos) -endfunction - -function s:save_pos(f,...) -  let l:pos = getpos('.')[1:2] -  let ret = call(a:f,a:000) -  call call('cursor',l:pos) -  return ret -endfunction - -function s:syn_at(l,c) -  return synIDattr(synID(a:l,a:c,0),'name') +  call setpos('.',l:pos)  endfunction  function s:looking_at() @@ -118,10 +157,10 @@ function s:token()  endfunction  function s:previous_token() -  let l:pos = getpos('.')[1:2] +  let l:pos = getpos('.')    if search('\m\k\{1,}\|\S','ebW') -    if (getline('.')[col('.')-2:col('.')-1] == '*/' || line('.') != l:pos[0] && -          \ getline('.') =~ '\%<'.col('.').'c\/\/') && s:syn_at(line('.'),col('.')) =~? s:syng_com +    if (strpart(getline('.'),col('.')-2,2) == '*/' || line('.') != l:pos[1] && +          \ getline('.')[:col('.')-1] =~ '\/\/') && s:syn_at(line('.'),col('.')) =~? s:syng_com        while search('\m\S\ze\_s*\/[/*]','bW')          if s:syn_at(line('.'),col('.')) !~? s:syng_com            return s:token() @@ -130,51 +169,66 @@ function s:previous_token()      else        return s:token()      endif +    call setpos('.',l:pos)    endif -  call call('cursor',l:pos)    return ''  endfunction +for s:__ in ['__previous_token','__IsBlock'] +  function s:{s:__}(...) +    let l:pos = getpos('.') +    try +      return call('s:'.matchstr(expand('<sfile>'),'.*__\zs\w\+'),a:000) +    catch +    finally +      call setpos('.',l:pos) +    endtry +  endfunction +endfor +  function s:expr_col()    if getline('.')[col('.')-2] == ':'      return 1    endif -  let bal = 0 -  while search('\m[{}?:;]','bW') -    if eval(s:skip_expr) | continue | endif -    " switch (looking_at()) -    exe {   '}': "if s:GetPair('{','}','bW',s:skip_expr,200) <= 0 | return | endif", -          \ ';': "return", -          \ '{': "return getpos('.')[1:2] != b:js_cache[1:] && !s:IsBlock()", -          \ ':': "let bal -= getline('.')[max([col('.')-2,0]):col('.')] !~ '::'", -          \ '?': "let bal += 1 | if bal > 0 | return 1 | endif" }[s:looking_at()] +  let [bal, l:pos] = [0, getpos('.')] +  while bal < 1 && search('\m[{}?:;]','bW',s:scriptTag) +    if eval(s:skip_expr) +      continue +    elseif s:looking_at() == ':' +      let bal -= strpart(getline('.'),col('.')-2,3) !~ '::' +    elseif s:looking_at() == '?' +      let bal += 1 +    elseif s:looking_at() == '{' && getpos('.')[1:2] != b:js_cache[1:] && !s:IsBlock() +      let bal = 1 +    elseif s:looking_at() != '}' || s:GetPair('{','}','bW',s:skip_expr,200) < 1 +      break +    endif    endwhile +  call setpos('.',l:pos) +  return max([bal,0])  endfunction  " 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\)\)') . '$' +      \ '\C\%([<=,.~!?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<\%(typeof\|new\|delete\|void\|in\|instanceof\|await\)\)') . '$'  function s:continues(ln,con) -  if !cursor(a:ln, match(' '.a:con,s:continuation)) -    let teol = s:looking_at() -    if teol == '/' -      return s:syn_at(line('.'),col('.')) !~? 'regex' -    elseif teol =~ '[-+>]' -      return getline('.')[col('.')-2] != tr(teol,'>','=') -    elseif teol =~ '\l' +  let token = matchstr(a:con[-15:],s:continuation) +  if strlen(token) +    call cursor(a:ln,strlen(a:con)) +    if token =~ '[/>]' +      return s:syn_at(a:ln,col('.')) !~? (token == '>' ? 'jsflow\|^html' : 'regex') +    elseif token =~ '\l'        return s:previous_token() != '.' -    elseif teol == ':' +    elseif token == ':'        return s:expr_col()      endif      return 1    endif  endfunction -" get the line of code stripped of comments and move cursor to the last -" non-comment char.  function s:Trim(ln)    let pline = substitute(getline(a:ln),'\s*$','','')    let l:max = max([strridx(pline,'//'), strridx(pline,'/*')]) @@ -183,24 +237,28 @@ function s:Trim(ln)      let l:max = max([strridx(pline,'//'), strridx(pline,'/*')])      let pline = substitute(pline[:-2],'\s*$','','')    endwhile -  return pline is '' || cursor(a:ln,strlen(pline)) ? pline : pline +  return pline  endfunction  " Find line above 'lnum' that isn't empty or in a comment  function s:PrevCodeLine(lnum) -  let [l:pos, l:n] = [getpos('.')[1:2], prevnonblank(a:lnum)] +  let l:n = prevnonblank(a:lnum)    while l:n      if getline(l:n) =~ '^\s*\/[/*]' +      if (stridx(getline(l:n),'`') > 0 || getline(l:n-1)[-1:] == '\') && +            \ s:syn_at(l:n,1) =~? b:syng_str +        break +      endif        let l:n = prevnonblank(l:n-1)      elseif stridx(getline(l:n), '*/') + 1 && s:syn_at(l:n,1) =~? s:syng_com +      let l:pos = getpos('.')        call cursor(l:n,1) -      keepjumps norm! [* -      let l:n = search('\m\S','nbW') +      let l:n = search('\m\S\_s*\/\*','nbW') +      call setpos('.',l:pos)      else        break      endif    endwhile -  call call('cursor',l:pos)    return l:n  endfunction @@ -210,7 +268,7 @@ function s:Balanced(lnum)    let l:line = getline(a:lnum)    let pos = match(l:line, '[][(){}]', 0)    while pos != -1 -    if s:syn_at(a:lnum,pos + 1) !~? s:syng_strcom +    if s:syn_at(a:lnum,pos + 1) !~? b:syng_strcom        let l:open += match(' ' . l:line[pos],'[[({]')        if l:open < 0          return @@ -225,6 +283,7 @@ endfunction  function s:OneScope(lnum)    let pline = s:Trim(a:lnum) +  call cursor(a:lnum,strlen(pline))    let kw = 'else do'    if pline[-1:] == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0      if s:previous_token() =~# '^\%(await\|each\)$' @@ -235,7 +294,27 @@ function s:OneScope(lnum)      endif    endif    return pline[-2:] == '=>' || index(split(kw),s:token()) + 1 && -        \ s:save_pos('s:previous_token') != '.' +        \ s:__previous_token() != '.' && !s:doWhile() +endfunction + +function s:doWhile() +  if expand('<cword>') ==# 'while' +    let [bal, l:pos] = [0, getpos('.')] +    call search('\m\<','cbW') +    while bal < 1 && search('\m\C[{}]\|\<\%(do\|while\)\>','bW') +      if eval(s:skip_expr) +        continue +      elseif s:looking_at() ==# 'd' +        let bal += s:__IsBlock(1) +      elseif s:looking_at() ==# 'w' +        let bal -= s:__previous_token() != '.' +      elseif s:looking_at() != '}' || s:GetPair('{','}','bW',s:skip_expr,200) < 1 +        break +      endif +    endwhile +    call setpos('.',l:pos) +    return max([bal,0]) +  endif  endfunction  " returns braceless levels started by 'i' and above lines * &sw. 'num' is the @@ -259,32 +338,36 @@ function s:iscontOne(i,num,cont)  endfunction  " https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader -function s:IsBlock() -  if s:looking_at() == '{' +function s:IsBlock(...) +  if a:0 || s:looking_at() == '{'      let l:n = line('.')      let char = s:previous_token()      if match(s:stack,'\cxml\|jsx') + 1 && s:syn_at(line('.'),col('.')-1) =~? 'xml\|jsx'        return char != '{'      elseif char =~ '\k'        if char ==# 'type' -        return s:previous_token() !~# '^\%(im\|ex\)port$' +        return s:__previous_token() !~# '^\%(im\|ex\)port$'        endif        return index(split('return const let import export extends yield default delete var await void typeof throw case new of in instanceof') -            \ ,char) < (line('.') != l:n) || s:save_pos('s:previous_token') == '.' +            \ ,char) < (line('.') != l:n) || s:__previous_token() == '.'      elseif char == '>' -      return getline('.')[col('.')-2] == '=' || s:syn_at(line('.'),col('.')) =~? '^jsflow' +      return getline('.')[col('.')-2] == '=' || s:syn_at(line('.'),col('.')) =~? 'jsflow\|^html' +    elseif char == '*' +      return s:__previous_token() == ':'      elseif char == ':' -      return !s:save_pos('s:expr_col') +      return !s:expr_col()      elseif char == '/'        return s:syn_at(line('.'),col('.')) =~? 'regex'      endif -    return char !~ '[=~!<*,?^%|&([]' && +    return char !~ '[=~!<,.?^%|&([]' &&            \ (char !~ '[-+]' || l:n != line('.') && getline('.')[col('.')-2] == char)    endif  endfunction +  function GetJavascriptIndent()    let b:js_cache = get(b:,'js_cache',[0,0,0]) +  let s:synId_cache = {}    " Get the current line.    call cursor(v:lnum,1)    let l:line = getline('.') @@ -299,7 +382,7 @@ function GetJavascriptIndent()      elseif l:line !~ '^\s*\/[/*]'        return -1      endif -  elseif syns =~? s:syng_str +  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 @@ -319,37 +402,33 @@ function GetJavascriptIndent()    endif    " the containing paren, bracket, or curly. Many hacks for performance -  let idx = index([']',')','}'],l:line[0]) +  let [ s:scriptTag, 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[1:]) +    call call('cursor',b:js_cache[2] ? b:js_cache[1:] : [0,0])    else -    let [s:looksyn, s:checkIn, top] = [v:lnum - 1, 0, (!indent(l:lnum) && -          \ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum] +    let [s:looksyn, s:checkIn, s:topCol] = [v:lnum - 1, 0, 0]      if idx + 1 -      call s:GetPair(['\[','(','{'][idx],'])}'[idx],'bW','s:skip_func()',2000,top) +      call s:GetPair(['\[','(','{'][idx],'])}'[idx],'bW','s:skip_func()',2000)      elseif getline(v:lnum) !~ '^\S' && syns =~? 'block' -      call s:GetPair('{','}','bW','s:skip_func()',2000,top) +      call s:GetPair('{','}','bW','s:skip_func()',2000)      else -      call s:alternatePair(top) +      call s:alternatePair()      endif    endif -  let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,0] : getpos('.')[1:2]) +  let b:js_cache = [v:lnum] + (line('.') == v:lnum ? [s:scriptTag,0] : getpos('.')[1:2])    let num = b:js_cache[1]    let [s:W, isOp, bL, switch_offset] = [s:sw(),0,0,0] -  if !num || s:IsBlock() +  if !b:js_cache[2] || s:IsBlock()      let ilnum = line('.') -    let pline = s:save_pos('s:Trim',l:lnum) -    if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 +    let pline = s:Trim(l:lnum) +    if b:js_cache[2] && s:looking_at() == ')' && s:GetPair('(',')','bW',s:skip_expr,100) > 0        let num = ilnum == num ? line('.') : num        if idx < 0 && s:previous_token() ==# 'switch' && s:previous_token() != '.' -        if &cino !~ ':' -          let switch_offset = s:W -        else -          let switch_offset = max([-indent(num),s:parse_cino(':')]) -        endif +        let switch_offset = &cino !~ ':' ? s:W : max([-indent(num),s:parse_cino(':')])          if pline[-1:] != '.' && l:line =~# '^\%(default\|case\)\>'            return indent(num) + switch_offset          endif @@ -362,12 +441,13 @@ function GetJavascriptIndent()      endif    elseif idx < 0 && getline(b:js_cache[1])[b:js_cache[2]-1] == '(' && &cino =~ '('      let pval = s:parse_cino('(') -    return !pval ? (s:parse_cino('w') ? 0 : -(!!search('\m\S','W'.s:z,num))) + virtcol('.') : -          \ max([indent('.') + pval + (s:GetPair('(',')','nbrmW',s:skip_expr,100,num) * s:W),0]) +    return !pval || !search('\m\S','nbW',num) && !s:parse_cino('U') ? +          \ (s:parse_cino('w') ? 0 : -!!search('\m\S','W'.s:z,num)) + virtcol('.') : +          \ max([indent('.') + pval + s:GetPair('(',')','nbrmW',s:skip_expr,100,num) * s:W,0])    endif    " main return -  if l:line =~ '^\%([])}]\||}\)' +  if l:line =~ '^[])}]\|^|}'      return max([indent(num),0])    elseif num      return indent(num) + s:W + switch_offset + bL + isOp diff --git a/indent/plantuml.vim b/indent/plantuml.vim index b2d3d8c3..a5e6fcdf 100644 --- a/indent/plantuml.vim +++ b/indent/plantuml.vim @@ -1,6 +1,6 @@  if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'plantuml') == -1 -if exists("b:did_indent") +if exists('b:did_indent')    finish  endif  let b:did_indent = 1 @@ -9,7 +9,7 @@ setlocal indentexpr=GetPlantUMLIndent()  setlocal indentkeys=o,O,<CR>,<:>,!^F,0end,0else,}  " only define the indent code once -if exists("*GetPlantUMLIndent") +if exists('*GetPlantUMLIndent')    finish  endif diff --git a/indent/ruby.vim b/indent/ruby.vim index 8fa929be..3617a925 100644 --- a/indent/ruby.vim +++ b/indent/ruby.vim @@ -49,22 +49,21 @@ set cpo&vim  " 1. Variables {{{1  " ============ -" Regex of syntax group names that are or delimit strings/symbols or are comments. -let s:syng_strcom = '\<ruby\%(Regexp\|RegexpDelimiter\|RegexpEscape' . -      \ '\|Symbol\|String\|StringDelimiter\|StringEscape\|ASCIICode' . -      \ '\|Interpolation\|InterpolationDelimiter\|NoInterpolation\|Comment\|Documentation\)\>' - -" Regex of syntax group names that are strings. +" Syntax group names that are strings.  let s:syng_string = -      \ '\<ruby\%(String\|Interpolation\|InterpolationDelimiter\|NoInterpolation\|StringEscape\)\>' +      \ ['String', 'Interpolation', 'InterpolationDelimiter', 'NoInterpolation', 'StringEscape'] + +" Syntax group names that are strings or documentation. +let s:syng_stringdoc = s:syng_string + ['Documentation'] -" Regex of syntax group names that are strings or documentation. -let s:syng_stringdoc = -      \ '\<ruby\%(String\|Interpolation\|InterpolationDelimiter\|NoInterpolation\|StringEscape\|Documentation\)\>' +" Syntax group names that are or delimit strings/symbols/regexes or are comments. +let s:syng_strcom = s:syng_stringdoc + +      \ ['Regexp', 'RegexpDelimiter', 'RegexpEscape', +      \ 'Symbol', 'StringDelimiter', 'ASCIICode', 'Comment']  " Expression used to check whether we should skip a match with searchpair().  let s:skip_expr = -      \ "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'" +      \ 'index(map('.string(s:syng_strcom).',"hlID(''ruby''.v:val)"), synID(line("."),col("."),1)) >= 0'  " Regex used for words that, at the start of a line, add a level of indent.  let s:ruby_indent_keywords = @@ -152,7 +151,7 @@ let s:leading_operator_regex = '^\s*[.]'  " 2. GetRubyIndent Function {{{1  " ========================= -function GetRubyIndent(...) +function! GetRubyIndent(...) abort    " 2.1. Setup {{{2    " ---------- @@ -255,7 +254,7 @@ endfunction  " 3. Indenting Logic Callbacks {{{1  " ============================ -function! s:AccessModifier(cline_info) +function! s:AccessModifier(cline_info) abort    let info = a:cline_info    " If this line is an access modifier keyword, align according to the closest @@ -279,7 +278,7 @@ function! s:AccessModifier(cline_info)    return -1  endfunction -function! s:ClosingBracketOnEmptyLine(cline_info) +function! s:ClosingBracketOnEmptyLine(cline_info) abort    let info = a:cline_info    " If we got a closing bracket on an empty line, find its match and indent @@ -308,7 +307,7 @@ function! s:ClosingBracketOnEmptyLine(cline_info)    return -1  endfunction -function! s:BlockComment(cline_info) +function! s:BlockComment(cline_info) abort    " If we have a =begin or =end set indent to first column.    if match(a:cline_info.cline, '^\s*\%(=begin\|=end\)$') != -1      return 0 @@ -316,7 +315,7 @@ function! s:BlockComment(cline_info)    return -1  endfunction -function! s:DeindentingKeyword(cline_info) +function! s:DeindentingKeyword(cline_info) abort    let info = a:cline_info    " If we have a deindenting keyword, find its match and indent to its level. @@ -357,7 +356,7 @@ function! s:DeindentingKeyword(cline_info)    return -1  endfunction -function! s:MultilineStringOrLineComment(cline_info) +function! s:MultilineStringOrLineComment(cline_info) abort    let info = a:cline_info    " If we are in a multi-line string or line-comment, don't do anything to it. @@ -367,7 +366,7 @@ function! s:MultilineStringOrLineComment(cline_info)    return -1  endfunction -function! s:ClosingHeredocDelimiter(cline_info) +function! s:ClosingHeredocDelimiter(cline_info) abort    let info = a:cline_info    " If we are at the closing delimiter of a "<<" heredoc-style string, set the @@ -381,7 +380,7 @@ function! s:ClosingHeredocDelimiter(cline_info)    return -1  endfunction -function! s:LeadingOperator(cline_info) +function! s:LeadingOperator(cline_info) abort    " If the current line starts with a leading operator, add a level of indent.    if s:Match(a:cline_info.clnum, s:leading_operator_regex)      return indent(s:GetMSL(a:cline_info.clnum)) + a:cline_info.sw @@ -389,7 +388,7 @@ function! s:LeadingOperator(cline_info)    return -1  endfunction -function! s:EmptyInsideString(pline_info) +function! s:EmptyInsideString(pline_info) abort    " If the line is empty and inside a string (plnum would not be the real    " prevnonblank in that case), use the previous line's indent    let info = a:pline_info @@ -400,7 +399,7 @@ function! s:EmptyInsideString(pline_info)    return -1  endfunction -function! s:StartOfFile(pline_info) +function! s:StartOfFile(pline_info) abort    " At the start of the file use zero indent.    if a:pline_info.plnum == 0      return 0 @@ -408,7 +407,7 @@ function! s:StartOfFile(pline_info)    return -1  endfunction -function! s:AfterAccessModifier(pline_info) +function! s:AfterAccessModifier(pline_info) abort    let info = a:pline_info    if g:ruby_indent_access_modifier_style == 'indent' @@ -434,7 +433,7 @@ endfunction  "     puts "foo"  "   end  " -function! s:ContinuedLine(pline_info) +function! s:ContinuedLine(pline_info) abort    let info = a:pline_info    let col = s:Match(info.plnum, s:ruby_indent_keywords) @@ -456,7 +455,7 @@ function! s:ContinuedLine(pline_info)    return -1  endfunction -function! s:AfterBlockOpening(pline_info) +function! s:AfterBlockOpening(pline_info) abort    let info = a:pline_info    " If the previous line ended with a block opening, add a level of indent. @@ -482,7 +481,7 @@ function! s:AfterBlockOpening(pline_info)    return -1  endfunction -function! s:AfterLeadingOperator(pline_info) +function! s:AfterLeadingOperator(pline_info) abort    " If the previous line started with a leading operator, use its MSL's level    " of indent    if s:Match(a:pline_info.plnum, s:leading_operator_regex) @@ -491,7 +490,7 @@ function! s:AfterLeadingOperator(pline_info)    return -1  endfunction -function! s:AfterHangingSplat(pline_info) +function! s:AfterHangingSplat(pline_info) abort    let info = a:pline_info    " If the previous line ended with the "*" of a splat, add a level of indent @@ -501,7 +500,7 @@ function! s:AfterHangingSplat(pline_info)    return -1  endfunction -function! s:AfterUnbalancedBracket(pline_info) +function! s:AfterUnbalancedBracket(pline_info) abort    let info = a:pline_info    " If the previous line contained unclosed opening brackets and we are still @@ -541,7 +540,7 @@ function! s:AfterUnbalancedBracket(pline_info)    return -1  endfunction -function! s:AfterEndKeyword(pline_info) +function! s:AfterEndKeyword(pline_info) abort    let info = a:pline_info    " If the previous line ended with an "end", match that "end"s beginning's    " indent. @@ -562,7 +561,7 @@ function! s:AfterEndKeyword(pline_info)    return -1  endfunction -function! s:AfterIndentKeyword(pline_info) +function! s:AfterIndentKeyword(pline_info) abort    let info = a:pline_info    let col = s:Match(info.plnum, s:ruby_indent_keywords) @@ -589,7 +588,7 @@ function! s:AfterIndentKeyword(pline_info)    return -1  endfunction -function! s:PreviousNotMSL(msl_info) +function! s:PreviousNotMSL(msl_info) abort    let info = a:msl_info    " If the previous line wasn't a MSL @@ -608,7 +607,7 @@ function! s:PreviousNotMSL(msl_info)    return -1  endfunction -function! s:IndentingKeywordInMSL(msl_info) +function! s:IndentingKeywordInMSL(msl_info) abort    let info = a:msl_info    " If the MSL line had an indenting keyword in it, add a level of indent.    " TODO: this does not take into account contrived things such as @@ -632,7 +631,7 @@ function! s:IndentingKeywordInMSL(msl_info)    return -1  endfunction -function! s:ContinuedHangingOperator(msl_info) +function! s:ContinuedHangingOperator(msl_info) abort    let info = a:msl_info    " If the previous line ended with [*+/.,-=], but wasn't a block ending or a @@ -652,32 +651,37 @@ endfunction  " 4. Auxiliary Functions {{{1  " ====================== +function! s:IsInRubyGroup(groups, lnum, col) abort +  let ids = map(copy(a:groups), 'hlID("ruby".v:val)') +  return index(ids, synID(a:lnum, a:col, 1)) >= 0 +endfunction +  " Check if the character at lnum:col is inside a string, comment, or is ascii. -function s:IsInStringOrComment(lnum, col) -  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom +function! s:IsInStringOrComment(lnum, col) abort +  return s:IsInRubyGroup(s:syng_strcom, a:lnum, a:col)  endfunction  " Check if the character at lnum:col is inside a string. -function s:IsInString(lnum, col) -  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_string +function! s:IsInString(lnum, col) abort +  return s:IsInRubyGroup(s:syng_string, a:lnum, a:col)  endfunction  " Check if the character at lnum:col is inside a string or documentation. -function s:IsInStringOrDocumentation(lnum, col) -  return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_stringdoc +function! s:IsInStringOrDocumentation(lnum, col) abort +  return s:IsInRubyGroup(s:syng_stringdoc, a:lnum, a:col)  endfunction  " Check if the character at lnum:col is inside a string delimiter -function s:IsInStringDelimiter(lnum, col) -  return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'rubyStringDelimiter' +function! s:IsInStringDelimiter(lnum, col) abort +  return s:IsInRubyGroup(['StringDelimiter'], a:lnum, a:col)  endfunction -function s:IsAssignment(str, pos) +function! s:IsAssignment(str, pos) abort    return strpart(a:str, 0, a:pos - 1) =~ '=\s*$'  endfunction  " Find line above 'lnum' that isn't empty, in a comment, or in a string. -function s:PrevNonBlankNonString(lnum) +function! s:PrevNonBlankNonString(lnum) abort    let in_block = 0    let lnum = prevnonblank(a:lnum)    while lnum > 0 @@ -702,7 +706,7 @@ function s:PrevNonBlankNonString(lnum)  endfunction  " Find line above 'lnum' that started the continuation 'lnum' may be part of. -function s:GetMSL(lnum) +function! s:GetMSL(lnum) abort    " Start on the line we're at and use its indent.    let msl = a:lnum    let lnum = s:PrevNonBlankNonString(a:lnum - 1) @@ -807,7 +811,7 @@ function s:GetMSL(lnum)  endfunction  " Check if line 'lnum' has more opening brackets than closing ones. -function s:ExtraBrackets(lnum) +function! s:ExtraBrackets(lnum) abort    let opening = {'parentheses': [], 'braces': [], 'brackets': []}    let closing = {'parentheses': [], 'braces': [], 'brackets': []} @@ -869,7 +873,7 @@ function s:ExtraBrackets(lnum)    return [rightmost_opening, rightmost_closing]  endfunction -function s:Match(lnum, regex) +function! s:Match(lnum, regex) abort    let line   = getline(a:lnum)    let offset = match(line, '\C'.a:regex)    let col    = offset + 1 @@ -889,7 +893,7 @@ endfunction  " Locates the containing class/module's definition line, ignoring nested classes  " along the way.  " -function! s:FindContainingClass() +function! s:FindContainingClass() abort    let saved_position = getpos('.')    while searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW', diff --git a/indent/vue.vim b/indent/vue.vim index e754ff6b..038996ba 100644 --- a/indent/vue.vim +++ b/indent/vue.vim @@ -5,41 +5,64 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'vue') == -1  " Maintainer: Eduardo San Martin Morote  " Author: Adriaan Zonnenberg -if exists("b:did_indent") +if exists('b:did_indent')    finish  endif -" Load indent files for required languages -for language in ['stylus', 'pug', 'css', 'javascript', 'html', 'coffee'] +function! s:get_indentexpr(language)    unlet! b:did_indent -  exe "runtime! indent/".language.".vim" -  exe "let s:".language."indent = &indentexpr" +  execute 'runtime! indent/' . a:language . '.vim' +  return &indentexpr +endfunction + +" The order is important here, tags without attributes go last. +" HTML is left out, it will be used when there is no match. +let s:languages = [ +      \   { 'name': 'pug', 'pairs': ['<template lang="pug"', '</template>'] }, +      \   { 'name': 'stylus', 'pairs': ['<style lang="stylus"', '</style>'] }, +      \   { 'name': 'css', 'pairs': ['<style', '</style>'] }, +      \   { 'name': 'coffee', 'pairs': ['<script lang="coffee"', '</script>'] }, +      \   { 'name': 'javascript', 'pairs': ['<script', '</script>'] }, +      \ ] + +for language in s:languages +  " Set 'indentexpr' if the user has an indent file installed for the language +  if strlen(globpath(&rtp, 'indent/'. language.name .'.vim')) +    let language.indentexpr = s:get_indentexpr(language.name) +  endif  endfor +let s:html_indent = s:get_indentexpr('html') +  let b:did_indent = 1  setlocal indentexpr=GetVueIndent() -if exists("*GetVueIndent") +if exists('*GetVueIndent')    finish  endif  function! GetVueIndent() -  if searchpair('<template lang="pug"', '', '</template>', 'bWr') -    exe "let indent = ".s:pugindent -  elseif searchpair('<style lang="stylus"', '', '</style>', 'bWr') -    exe "let indent = ".s:stylusindent -  elseif searchpair('<style', '', '</style>', 'bWr') -    exe "let indent = ".s:cssindent -  elseif searchpair('<script lang="coffee"', '', '</script>', 'bWr') -    exe "let indent = ".s:coffeeindent -  elseif searchpair('<script', '', '</script>', 'bWr') -    exe "let indent = ".s:javascriptindent +  for language in s:languages +    let opening_tag_line = searchpair(language.pairs[0], '', language.pairs[1], 'bWr') + +    if opening_tag_line +      execute 'let indent = ' . get(language, 'indentexpr', -1) +      break +    endif +  endfor + +  if exists('l:indent') +    if (opening_tag_line == prevnonblank(v:lnum - 1) || opening_tag_line == v:lnum) +          \ || getline(v:lnum) =~ '\v^\s*\</(script|style|template)' +      return 0 +    endif    else -    exe "let indent = ".s:htmlindent +    " Couldn't find language, fall back to html +    execute 'let indent = ' . s:html_indent    endif -  return indent > -1 ? indent : s:htmlindent +  return indent  endfunction  endif | 
