diff options
Diffstat (limited to 'indent')
| -rw-r--r-- | indent/clojure.vim | 4 | ||||
| -rw-r--r-- | indent/dart.vim | 26 | ||||
| -rw-r--r-- | indent/elixir.vim | 224 | ||||
| -rw-r--r-- | indent/gohtmltmpl.vim | 4 | ||||
| -rw-r--r-- | indent/haskell.vim | 24 | ||||
| -rw-r--r-- | indent/html.vim | 41 | ||||
| -rw-r--r-- | indent/javascript.vim | 338 | ||||
| -rw-r--r-- | indent/plantuml.vim | 59 | ||||
| -rw-r--r-- | indent/ruby.vim | 6 | 
9 files changed, 398 insertions, 328 deletions
| diff --git a/indent/clojure.vim b/indent/clojure.vim index 1d474d8e..f538195a 100644 --- a/indent/clojure.vim +++ b/indent/clojure.vim @@ -89,7 +89,7 @@ if exists("*searchpairpos")  	function! s:match_pairs(open, close, stopat)  		" Stop only on vector and map [ resp. {. Ignore the ones in strings and  		" comments. -		if a:stopat == 0 +		if a:stopat == 0 && g:clojure_maxlines > 0  			let stopat = max([line(".") - g:clojure_maxlines, 0])  		else  			let stopat = a:stopat @@ -123,7 +123,7 @@ if exists("*searchpairpos")  			if s:syn_id_name() !~? "string"  				return -1  			endif -			if s:current_char() != '\\' +			if s:current_char() != '\'  				return -1  			endif  			call cursor(0, col("$") - 1) diff --git a/indent/dart.vim b/indent/dart.vim index af4cb7df..601abbb0 100644 --- a/indent/dart.vim +++ b/indent/dart.vim @@ -8,6 +8,32 @@ let b:did_indent = 1  setlocal cindent  setlocal cinoptions+=j1,J1 +setlocal indentexpr=DartIndent() +  let b:undo_indent = 'setl cin< cino<' +if exists("*DartIndent") +  finish +endif + +function! DartIndent() +  " Default to cindent in most cases +  let indentTo = cindent(v:lnum) + +  let previousLine = getline(prevnonblank(v:lnum - 1)) +  let currentLine = getline(v:lnum) + +  " Don't indent after an annotation +  if previousLine =~# '^\s*@.*$' +    let indentTo = indent(v:lnum - 1) +  endif + +  " Indent after opening List literal +  if previousLine =~# '\[$' && !(currentLine =~# '^\s*\]') +    let indentTo = indent(v:lnum - 1) + &shiftwidth +  endif + +  return indentTo +endfunction +  endif diff --git a/indent/elixir.vim b/indent/elixir.vim index 3e7b6de0..c5ce4f40 100644 --- a/indent/elixir.vim +++ b/indent/elixir.vim @@ -1,199 +1,71 @@  if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'elixir') == -1 -if exists("b:did_indent") -  finish -end -let b:did_indent = 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 -setlocal indentexpr=GetElixirIndent() -setlocal indentkeys+=0),0],0=end,0=else,0=match,0=elsif,0=catch,0=after,0=rescue,0=\|> - -if exists("*GetElixirIndent") +if exists("b:did_indent") || exists("*elixir#indent")    finish  end +let b:did_indent = 1  let s:cpo_save = &cpo  set cpo&vim -let s:no_colon_before = ':\@<!' -let s:no_colon_after = ':\@!' -let s:symbols_end = '\]\|}\|)' -let s:symbols_start = '\[\|{\|(' -let s:arrow = '^.*->$' -let s:skip_syntax = '\%(Comment\|String\)$' -let s:block_skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '".s:skip_syntax."'" -let s:block_start = '\<\%(do\|fn\)\>' -let s:block_middle = 'else\|match\|elsif\|catch\|after\|rescue' -let s:block_end = 'end' -let s:starts_with_pipeline = '^\s*|>.*$' -let s:ending_with_assignment = '=\s*$' - -let s:indent_keywords = '\<'.s:no_colon_before.'\%('.s:block_start.'\|'.s:block_middle.'\)$'.'\|'.s:arrow -let s:deindent_keywords = '^\s*\<\%('.s:block_end.'\|'.s:block_middle.'\)\>'.'\|'.s:arrow - -let s:pair_start = '\<\%('.s:no_colon_before.s:block_start.'\)\>'.s:no_colon_after -let s:pair_middle = '^\s*\%('.s:block_middle.'\)\>'.s:no_colon_after.'\zs' -let s:pair_end = '\<\%('.s:no_colon_before.s:block_end.'\)\>\zs' - -function! s:is_indentable_syntax() -  " TODO: Remove these 2 lines -  " I don't know why, but for the test on spec/indent/lists_spec.rb:24. -  " Vim is making some mess on parsing the syntax of 'end', it is being -  " recognized as 'elixirString' when should be recognized as 'elixirBlock'. -  call synID(s:current_line_ref, 1, 1) -  " This forces vim to sync the syntax. -  syntax sync fromstart - -  return synIDattr(synID(s:current_line_ref, 1, 1), "name") -        \ !~ s:skip_syntax -endfunction - -function! s:indent_opened_symbol(ind) -  if s:opened_symbol > 0 -    if s:pending_parenthesis > 0 -          \ && s:last_line !~ '^\s*def' -          \ && s:last_line !~ s:arrow -      let b:old_ind = a:ind -      return matchend(s:last_line, '(') -      " if start symbol is followed by a character, indent based on the -      " whitespace after the symbol, otherwise use the default shiftwidth -      " Avoid negative indentation index -    elseif s:last_line =~ '\('.s:symbols_start.'\).' -      let regex = '\('.s:symbols_start.'\)\s*' -      let opened_prefix = matchlist(s:last_line, regex)[0] -      return a:ind + (s:opened_symbol * strlen(opened_prefix)) -    else -      return a:ind + (s:opened_symbol * &sw) -    end -  elseif s:opened_symbol < 0 -    let ind = get(b:, 'old_ind', a:ind + (s:opened_symbol * &sw)) -    let ind = float2nr(ceil(floor(ind)/&sw)*&sw) -    return ind <= 0 ? 0 : ind -  else -    return a:ind -  end -endfunction - -function! s:indent_last_line_end_symbol_or_indent_keyword(ind) -  if s:last_line =~ '^\s*\('.s:symbols_end.'\)' -        \ || s:last_line =~ s:indent_keywords -    return a:ind + &sw -  else -    return a:ind -  end -endfunction - -function! s:indent_symbols_ending(ind) -  if s:current_line =~ '^\s*\('.s:symbols_end.'\)' -    return a:ind - &sw -  else -    return a:ind -  end -endfunction - -function! s:indent_assignment(ind) -  if s:last_line =~ s:ending_with_assignment -    let b:old_ind = indent(s:last_line_ref) " FIXME: side effect -    return a:ind + &sw -  else -    return a:ind -  end -endfunction +function! elixir#indent() +  " initiates the `old_ind` dictionary +  let b:old_ind = get(b:, 'old_ind', {}) +  " initialtes the `line` dictionary +  let line = s:build_line(v:lnum) -function! s:indent_pipeline(ind) -  if s:last_line =~ s:starts_with_pipeline -        \ && s:current_line =~ s:starts_with_pipeline -    indent(s:last_line_ref) -  elseif s:current_line =~ s:starts_with_pipeline -        \ && s:last_line =~ '^[^=]\+=.\+$' -    let b:old_ind = indent(s:last_line_ref) -    " if line starts with pipeline -    " and last line is an attribution -    " indents pipeline in same level as attribution -    return match(s:last_line, '=\s*\zs[^ ]') +  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.num)    else -    return a:ind +    " Calculates the indenation level based on the rules +    " All the rules are defined in `autoload/indent.vim` +    let ind = indent(line.last.num) +    let ind = elixir#indent#deindent_case_arrow(ind, line) +    let ind = elixir#indent#indent_parenthesis(ind, line) +    let ind = elixir#indent#indent_square_brackets(ind, line) +    let ind = elixir#indent#indent_brackets(ind, line) +    let ind = elixir#indent#deindent_opened_symbols(ind, line) +    let ind = elixir#indent#indent_pipeline_assignment(ind, line) +    let ind = elixir#indent#indent_pipeline_continuation(ind, line) +    let ind = elixir#indent#indent_after_pipeline(ind, line) +    let ind = elixir#indent#indent_assignment(ind, line) +    let ind = elixir#indent#indent_ending_symbols(ind, line) +    let ind = elixir#indent#indent_keywords(ind, line) +    let ind = elixir#indent#deindent_keywords(ind, line) +    let ind = elixir#indent#deindent_ending_symbols(ind, line) +    let ind = elixir#indent#indent_case_arrow(ind, line) +    return ind    end  endfunction -function! s:indent_after_pipeline(ind) -  if s:last_line =~ s:starts_with_pipeline -    if empty(substitute(s:current_line, ' ', '', 'g')) -          \ || s:current_line =~ s:starts_with_pipeline -      return indent(s:last_line_ref) -    elseif s:last_line !~ s:indent_keywords -      return b:old_ind -    else -      return a:ind -    end -  else -    return a:ind -  end +function! s:is_beginning_of_file(line) +  return a:line.last.num == 0  endfunction -function! s:deindent_keyword(ind) -  if s:current_line =~ s:deindent_keywords -    let bslnum = searchpair( -          \ s:pair_start, -          \ s:pair_middle, -          \ s:pair_end, -          \ 'nbW', -          \ s:block_skip -          \ ) - -    return indent(bslnum) -  else -    return a:ind -  end +function! s:is_indentable_line(line) +  return elixir#util#is_indentable_at(a:line.current.num, 1)  endfunction -function! s:indent_arrow(ind) -  if s:current_line =~ s:arrow -    " indent case statements '->' -    return a:ind + &sw -  else -    return a:ind -  end -endfunction - -function! GetElixirIndent() -  let s:current_line_ref = v:lnum -  let s:last_line_ref = prevnonblank(s:current_line_ref - 1) -  let s:current_line = getline(s:current_line_ref) -  let s:last_line = getline(s:last_line_ref) -  let s:pending_parenthesis = 0 -  let s:opened_symbol = 0 - -  if s:last_line !~ s:arrow -    let splitted_line = split(s:last_line, '\zs') -    let s:pending_parenthesis = -          \ + count(splitted_line, '(') - count(splitted_line, ')') -    let s:opened_symbol = -          \ + s:pending_parenthesis -          \ + count(splitted_line, '[') - count(splitted_line, ']') -          \ + count(splitted_line, '{') - count(splitted_line, '}') -  end +function! s:build_line(line) +  let line = { 'current': {}, 'last': {} } +  let line.current.num = a:line +  let line.current.text = getline(line.current.num) +  let line.last.num = prevnonblank(line.current.num - 1) +  let line.last.text = getline(line.last.num) -  if s:last_line_ref == 0 -    " At the start of the file use zero indent. -    return 0 -  elseif !s:is_indentable_syntax() -    " Current syntax is not indentable, keep last line indentation -    return indent(s:last_line_ref) -  else -    let ind = indent(s:last_line_ref) -    let ind = s:indent_opened_symbol(ind) -    let ind = s:indent_symbols_ending(ind) -    let ind = s:indent_pipeline(ind) -    let ind = s:indent_after_pipeline(ind) -    let ind = s:indent_assignment(ind) -    let ind = s:indent_last_line_end_symbol_or_indent_keyword(ind) -    let ind = s:deindent_keyword(ind) -    let ind = s:indent_arrow(ind) -    return ind -  end +  return line  endfunction  let &cpo = s:cpo_save diff --git a/indent/gohtmltmpl.vim b/indent/gohtmltmpl.vim index 898e36b0..ed9e2eb5 100644 --- a/indent/gohtmltmpl.vim +++ b/indent/gohtmltmpl.vim @@ -32,13 +32,13 @@ function! GetGoHTMLTmplIndent(lnum)    " If need to indent based on last line    let last_line = getline(a:lnum-1) -  if last_line =~ '^\s*{{\s*\%(if\|else\|range\|with\|define\|block\).*}}' +  if last_line =~ '^\s*{{-\=\s*\%(if\|else\|range\|with\|define\|block\).*}}'      let ind += sw    endif    " End of FuncMap block    let current_line = getline(a:lnum) -  if current_line =~ '^\s*{{\s*\%(else\|end\).*}}' +  if current_line =~ '^\s*{{-\=\s*\%(else\|end\).*}}'      let ind -= sw    endif diff --git a/indent/haskell.vim b/indent/haskell.vim index ebdab5e7..fa2ee7cf 100644 --- a/indent/haskell.vim +++ b/indent/haskell.vim @@ -15,6 +15,10 @@ endif  let b:did_indent = 1 +if !exists('g:haskell_indent_disable') +    let g:haskell_indent_disable = 0 +endif +  if !exists('g:haskell_indent_if')    " if x    " >>>then ... @@ -59,8 +63,14 @@ if !exists('g:haskell_indent_guard')    let g:haskell_indent_guard = 2  endif -setlocal indentexpr=GetHaskellIndent() -setlocal indentkeys=0{,0},0(,0),0[,0],!^F,o,O,0\=,0=where,0=let,0=deriving,<space> +if exists("g:haskell_indent_disable") && g:haskell_indent_disable == 0 +    setlocal indentexpr=GetHaskellIndent() +    setlocal indentkeys=0{,0},0(,0),0[,0],!^F,o,O,0\=,0=where,0=let,0=deriving,<space> +else +    setlocal nocindent +    setlocal nosmartindent +    setlocal autoindent +endif  function! s:isInBlock(hlstack)    return 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 @@ -270,7 +280,11 @@ function! GetHaskellIndent()    " case foo of    " >>bar -> quux    if l:prevline =~ '\C\<case\>.\+\<of\>\s*$' -    return match(l:prevline, '\C\<case\>') + g:haskell_indent_case +    if exists('g:haskell_indent_case_alternative') && g:haskell_indent_case_alternative +      return match(l:prevline, '\S') + &shiftwidth +    else +      return match(l:prevline, '\C\<case\>') + g:haskell_indent_case +    endif    endif    "" where foo @@ -324,8 +338,8 @@ function! GetHaskellIndent()        while v:lnum != l:c          " fun decl -        let l:s = match(l:l, l:m) -        if l:s >= 0 +        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 diff --git a/indent/html.vim b/indent/html.vim index 18c5bf15..0cbc3b17 100644 --- a/indent/html.vim +++ b/indent/html.vim @@ -42,6 +42,7 @@ setlocal indentkeys=o,O,*<Return>,<>>,{,},!^F  let s:tags = [] +let s:no_tags = []  " [-- <ELEMENT ? - - ...> --]  call add(s:tags, 'a') @@ -165,6 +166,44 @@ call add(s:tags, 'text')  call add(s:tags, 'textPath')  call add(s:tags, 'tref')  call add(s:tags, 'tspan') +" Common self closing SVG elements +call add(s:no_tags, 'animate') +call add(s:no_tags, 'animateTransform') +call add(s:no_tags, 'circle') +call add(s:no_tags, 'ellipse') +call add(s:no_tags, 'feBlend') +call add(s:no_tags, 'feColorMatrix') +call add(s:no_tags, 'feComposite') +call add(s:no_tags, 'feConvolveMatrix') +call add(s:no_tags, 'feDisplacementMap') +call add(s:no_tags, 'feFlood') +call add(s:no_tags, 'feFuncR') +call add(s:no_tags, 'feFuncG') +call add(s:no_tags, 'feFuncB') +call add(s:no_tags, 'feFuncA') +call add(s:no_tags, 'feGaussianBlur') +call add(s:no_tags, 'feImage') +call add(s:no_tags, 'feMergeNode') +call add(s:no_tags, 'feMorphology') +call add(s:no_tags, 'feOffset') +call add(s:no_tags, 'fePointLight') +call add(s:no_tags, 'feSpotLight') +call add(s:no_tags, 'feTile') +call add(s:no_tags, 'feTurbulence') +call add(s:no_tags, 'hatchpath') +call add(s:no_tags, 'hkern') +call add(s:no_tags, 'image') +call add(s:no_tags, 'line') +call add(s:no_tags, 'mpath') +call add(s:no_tags, 'polygon') +call add(s:no_tags, 'polyline') +call add(s:no_tags, 'path') +call add(s:no_tags, 'rect') +call add(s:no_tags, 'solidColor') +call add(s:no_tags, 'stop') +call add(s:no_tags, 'use') +call add(s:no_tags, 'view') +call add(s:no_tags, 'vkern')  call add(s:tags, 'html')  call add(s:tags, 'head') @@ -177,8 +216,6 @@ call add(s:tags, 'tr')  call add(s:tags, 'th')  call add(s:tags, 'td') -let s:no_tags = [] -  call add(s:no_tags, 'base')  call add(s:no_tags, 'link')  call add(s:no_tags, 'meta') diff --git a/indent/javascript.vim b/indent/javascript.vim index e8573790..ea6b551d 100644 --- a/indent/javascript.vim +++ b/indent/javascript.vim @@ -2,9 +2,9 @@ if !exists('g:polyglot_disabled') || index(g:polyglot_disabled, 'javascript') ==  " 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: August 20, 2016 +" Last Change: December 14, 2016  " Only load this indent file when no other was loaded.  if exists('b:did_indent') @@ -14,11 +14,10 @@ let b:did_indent = 1  " Now, set up our indentation expression and keys that trigger it.  setlocal indentexpr=GetJavascriptIndent() -setlocal nolisp noautoindent nosmartindent -setlocal indentkeys=0{,0},0),0],:,!^F,o,O,e -setlocal cinoptions+=j1,J1 +setlocal autoindent nolisp nosmartindent +setlocal indentkeys+=0],0) -let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys< cinoptions<' +let b:undo_indent = 'setlocal indentexpr< smartindent< autoindent< indentkeys<'  " Only define the function once.  if exists('*GetJavascriptIndent') @@ -39,159 +38,280 @@ else    endfunction  endif -let s:line_pre = '^\s*\%(\%(\%(\/\*.\{-}\)\=\*\+\/\s*\)\=\)\@>' -let s:expr_case = s:line_pre . '\%(\%(case\>.\+\)\|default\)\s*:' -" 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."'" - +" searchpair() wrapper  if has('reltime') -  function s:GetPair(start,end,flags,time) -    return searchpair(a:start,'',a:end,a:flags,s:skip_expr,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,n) -    return searchpair(a:start,'',a:end,a:flags,0,max([prevnonblank(v:lnum) - 2000,0])) +  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)]))    endfunction  endif -let s:line_term = '\s*\%(\%(\/\%(\%(\*.\{-}\*\/\)\|\%(\*\+\)\)\)\s*\)\=$' +" 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_str = 'string\|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() +  if !s:free || search('`\|\*\/','nW',s:looksyn) +    let s:free = !eval(s:skip_expr) +    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) +endfunction -" configurable regexes that define continuation lines, not including (, {, or [. -if !exists('g:javascript_opfirst') -  let g:javascript_opfirst = '\%([<>,:?^%|*&]\|\([-/.+]\)\1\@!\|=>\@!\|in\%(stanceof\)\=\>\)' -endif -if !exists('g:javascript_continuation') -  let g:javascript_continuation = '\%([<=,.?/*:^%|&]\|+\@<!+\|-\@<!-\|=\@<!>\|\<in\%(stanceof\)\=\)' -endif +function s:alternatePair(stop) +  while search('[][(){}]','bW',a:stop) +    if !s:skip_func() +      let idx = stridx('])}',s:looking_at()) +      if idx + 1 +        if !s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,a:stop) +          break +        endif +      else +        return +      endif +    endif +  endwhile +  call cursor(v:lnum,1) +endfunction -let g:javascript_opfirst = s:line_pre . g:javascript_opfirst -let g:javascript_continuation .= s:line_term +function s:syn_at(l,c) +  return synIDattr(synID(a:l,a:c,0),'name') +endfunction -function s:OneScope(lnum,text,add) -  return a:text =~# '\%(\<else\|\<do\|=>\)' . s:line_term ? 'no b' : -        \ ((a:add && a:text =~ s:line_pre . '$' && search('\%' . s:PrevCodeLine(a:lnum - 1) . 'l.)' . s:line_term)) || -        \ cursor(a:lnum, match(a:text, ')' . s:line_term)) > -1) && -        \ s:GetPair('(', ')', 'cbW', 100) > 0 && search('\C\l\+\_s*\%#','bW') && -        \ (a:add || ((expand('<cword>') !=# 'while' || !s:GetPair('\C\<do\>', '\C\<while\>','nbW',100)) && -        \ expand('cword') !=# 'each' || search('\C\<for\_s\+\%#','nbW'))) ? expand('<cword>') : '' +function s:looking_at() +  return getline('.')[col('.')-1]  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\|yield\|delete\|void\|t\%(ypeof\|hrow\)\|new\|\<in\%(stanceof\)\=\)\)\_s*\)\%#','bnW') && -        \ (!search(':\_s*\%#','bW') || (!s:GetPair('[({[]','[])}]','bW',200) || s:IsBlock())) +function s:token() +  return s:looking_at() =~ '\k' ? expand('<cword>') : s:looking_at()  endfunction -" Auxiliary Functions {{{2 +" NOTE: Moves the cursor, unless a arg is supplied. +function s:previous_token(...) +  let l:pos = getpos('.')[1:2] +  return [search('.\>\|[^[:alnum:][:space:]_$]','bW') ? +        \ (s:looking_at() == '/' || line('.') != l:pos[0] && getline('.') =~ '\/\/') && +        \ s:syn_at(line('.'),col('.')) =~? s:syng_com ? +        \ search('\_[^/]\zs\/[/*]','bW') ? s:previous_token() : '' +        \ : s:token() +        \ : ''][a:0 && call('cursor',l:pos)] +endfunction + +" switch case label pattern +let s:case_stmt = '\<\%(case\>\s*[^ \t:].*\|default\s*\):\C' + +function s:label_end(ln,con) +  return !cursor(a:ln,match(' '.a:con, '.*\zs' . s:case_stmt . '$')) && +        \ (expand('<cword>') !=# 'default' || s:previous_token(1) !~ '[{,.]') +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', +      \ '\%([<=,.~!?/*^%|&:]\|+\@<!+\|-\@<!-\|=\@<!>\|\<\%(typeof\|delete\|void\|in\|instanceof\)\)') . '$' + +function s:continues(ln,con) +  return !cursor(a:ln, match(' '.a:con,s:continuation)) && +        \ eval((['s:syn_at(line("."),col(".")) !~? "regex"'] + +        \ repeat(['s:previous_token() != "."'],5) + [1])[ +        \ index(split('/ typeof in instanceof void delete'),s:token())]) +endfunction -" Find line above 'lnum' that isn't empty, in a comment, or in a string. +" get the line of code stripped of comments. if called with two args, leave +" cursor at the last non-comment char. +function s:Trim(ln,...) +  let pline = substitute(getline(a:ln),'\s*$','','') +  let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0]) +  while l:max && s:syn_at(a:ln, strlen(pline)) =~? s:syng_com +    let pline = substitute(strpart(pline, 0, l:max),'\s*$','','') +    let l:max = max([match(pline,'.*[^/]\zs\/[/*]'),0]) +  endwhile +  return !a:0 || cursor(a:ln,strlen(pline)) ? pline : pline +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 -    if synIDattr(synID(l:lnum,matchend(getline(l:lnum), '^\s*[^''"]'),0),'name') !~? s:syng_strcom -      return l:lnum -    endif -    let l:lnum = prevnonblank(l:lnum - 1) +  let l:n = prevnonblank(a:lnum) +  while getline(l:n) =~ '^\s*\/[/*]' || s:syn_at(l:n,1) =~? s:syng_com +    let l:n = prevnonblank(l:n-1)    endwhile +  return l:n  endfunction  " Check if line 'lnum' has a balanced amount of parentheses.  function s:Balanced(lnum) -  let [open_0,open_2,open_4] = [0,0,0] +  let l:open = 0    let l:line = getline(a:lnum)    let pos = match(l:line, '[][(){}]', 0)    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 -        let open_{idx} = open_{idx} + 1 -      else -        let open_{idx - 1} = open_{idx - 1} - 1 +    if s:syn_at(a:lnum,pos + 1) !~? s:syng_strcom +      let l:open += match(' ' . l:line[pos],'[[({]') +      if l:open < 0 +        return        endif      endif      let pos = match(l:line, '[][(){}]', pos + 1)    endwhile -  return (!open_4 + !open_2 + !open_0) - 2 +  return !l:open  endfunction -" }}} -function GetJavascriptIndent() -  if !exists('b:js_cache') -    let b:js_cache = [0,0,0] +function s:OneScope(lnum) +  let pline = s:Trim(a:lnum,1) +  if pline[-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' +    endif +    return index(split('for if let while with'),token) + 1 +  endif +  return eval((['getline(".")[col(".")-2] == "="'] + +        \ repeat(['s:previous_token(1) != "."'],2) + [0])[ +        \ index(split('> else do'),s:token())]) +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, bL] = [a:i, a:num + !a:num, 0] +  let pind = a:num ? indent(l:num) + s:W : 0 +  let ind = indent(l:i) + (a:cont ? 0 : s:W) +  while l:i >= l:num && (ind > pind || l:i == l:num) +    if indent(l:i) < ind && s:OneScope(l:i) +      let bL += s:W +      let l:i = line('.') +    elseif !a:cont || bL || ind < indent(a:i) +      break +    endif +    let ind = min([ind, indent(l:i)]) +    let l:i = s:PrevCodeLine(l:i - 1) +  endwhile +  return bL +endfunction + +" https://github.com/sweet-js/sweet.js/wiki/design#give-lookbehind-to-the-reader +function s:IsBlock() +  let l:ln = line('.') +  let char = s:previous_token() +  let syn = char =~ '[{>/]' ? s:syn_at(line('.'),col('.')-(char == '{')) : '' +  if syn =~? 'xml\|jsx' +    return char != '{' +  elseif char =~ '\k' +    return index(split('return const let import export yield default delete var void typeof throw new in instanceof') +          \ ,char) < (0 + (line('.') != l:ln)) || s:previous_token() == '.' +  elseif char == '>' +    return getline('.')[col('.')-2] == '=' || syn =~? '^jsflow' +  elseif char == ':' +    return s:label_end(0,strpart(getline('.'),0,col('.')))    endif +  return syn =~? 'regex' || char !~ '[-=~!<*+,/?^%|&([]' +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 syns = s:syn_at(v:lnum, 1) -  " 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 =~? s:syng_com +    if l:line =~ '^\s*\*' +      return cindent(v:lnum) +    elseif l:line !~ '^\s*\/[/*]' +      return -1 +    endif +  elseif syns =~? s:syng_str && l:line !~ '^[''"]' +    if b:js_cache[0] == v:lnum - 1 && s:Balanced(v:lnum-1) +      let b:js_cache[0] = v:lnum +    endif      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 +  if !l:lnum +    return    endif -  if (l:line =~# s:expr_case) -    let cpo_switch = &cpo -    set cpo+=% -    let ind = cindent(v:lnum) -    let &cpo = cpo_switch -    return ind +  let l:line = substitute(l:line,'^\s*','','') +  if l:line[:1] == '/*' +    let l:line = substitute(l:line,'^\%(\/\*.\{-}\*\/\s*\)*','','') +  endif +  if l:line =~ '^\/[/*]' +    let l:line = ''    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. +  " the containing paren, bracket, or curly. Many hacks for performance    call cursor(v:lnum,1) -  if b:js_cache[0] >= l:lnum  && b:js_cache[0] < v:lnum && b:js_cache[0] && -        \ (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',2000) +  let idx = strlen(l:line) ? stridx('])}',l:line[0]) : -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:])    else -    let num = s:GetPair('[({[]','[])}]','bW',2000) +    let [s:looksyn, s:free, top] = [v:lnum - 1, 1, (!indent(l:lnum) && +          \ s:syn_at(l:lnum,1) !~? s:syng_str) * l:lnum] +    if idx + 1 +      call s:GetPair(['\[','(','{'][idx], '])}'[idx],'bW','s:skip_func()',2000,top) +    elseif indent(v:lnum) && syns =~? 'block' +      call s:GetPair('{','}','bW','s:skip_func()',2000,top) +    else +      call s:alternatePair(top) +    endif    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) +  if idx + 1 +    if idx == 2 && search('\S','bW',line('.')) && s:looking_at() == ')' +      call s:GetPair('(',')','bW',s:skip_expr,200) +    endif +    return indent('.')    endif -  call cursor(b:js_cache[1],b:js_cache[2]) - -  let swcase = getline(l:lnum) =~# s:expr_case -  let pline = swcase ? getline(l:lnum) : substitute(getline(l:lnum), '\%(:\@<!\/\/.*\)$', '','') -  let inb = num == 0 || num < l:lnum && ((l:line !~ s:line_pre . ',' && pline !~ ',' . s:line_term) || s:IsBlock()) -  let switch_offset = num == 0 || s:OneScope(num, strpart(getline(num),0,b:js_cache[2] - 1),1) !=# 'switch' ? 0 : -        \ &cino !~ ':' || !has('float') ?  s:sw() : -        \ float2nr(str2float(matchstr(&cino,'.*:\zs[-0-9.]*')) * (&cino =~# '.*:[^,]*s' ? s:sw() : 1)) - -  " most significant, find the indent amount -  if inb && !swcase && ((l:line =~# g:javascript_opfirst || pline =~# g:javascript_continuation) || -        \ num < l:lnum && s:OneScope(l:lnum,pline,0) =~# '\<\%(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 b:js_cache = [v:lnum] + (line('.') == v:lnum ? [0,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:looking_at() == '{' && s:IsBlock() +    let pline = s:Trim(l:lnum) +    if num && s:looking_at() == ')' && s:GetPair('(', ')', 'bW', s:skip_expr, 100) > 0 +      let num = line('.') +      if s:previous_token() ==# 'switch' +        if &cino !~ ':' || !has('float') +          let switch_offset = s:W +        else +          let cinc = matchlist(&cino,'.*:\(-\)\=\([0-9.]*\)\(s\)\=\C') +          let switch_offset = float2nr(str2float(cinc[1].(strlen(cinc[2]) ? cinc[2] : strlen(cinc[3]))) +                \ * (strlen(cinc[3]) ? s:W : 1)) +        endif +        if pline[-1:] != '.' && l:line =~# '^' . s:case_stmt +          return indent(num) + switch_offset +        elseif s:label_end(l:lnum,pline) +          return indent(l:lnum) + s:W +        endif +      endif +    endif +    if pline[-1:] !~ '[{;]' +      let isOp = l:line =~# s:opfirst || s:continues(l:lnum,pline) +      let bL = s:iscontOne(l:lnum,num,isOp) +      let bL -= (bL && l:line[0] == '{') * s:W +    endif    endif +  " main return +  if isOp +    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  endfunction -  let &cpo = s:cpo_save  unlet s:cpo_save diff --git a/indent/plantuml.vim b/indent/plantuml.vim index 3e0f455d..93ecb8cb 100644 --- a/indent/plantuml.vim +++ b/indent/plantuml.vim @@ -14,45 +14,46 @@ if exists("*GetPlantUMLIndent")  endif  let s:incIndent = -            \ '^\s*\(loop\|alt\|opt\|group\|critical\|else\|legend\|box\)\>\|' . -            \ '^\s*\([hr]\?note\|ref\)\>[^:]*$\|' . -            \ '^\s*title\s*$\|' . -            \ '^\s*skinparam\>.*{\s*$\|' . -            \ '^\s*state\>.*{' +      \ '^\s*\%(loop\|alt\|opt\|group\|critical\|else\|legend\|box\|if\|while\)\>\|' . +      \ '^\s*ref\>[^:]*$\|' . +      \ '^\s*[hr]\?note\>\%(\%("[^"]*" \<as\>\)\@![^:]\)*$\|' . +      \ '^\s*title\s*$\|' . +      \ '^\s*skinparam\>.*{\s*$\|' . +      \ '^\s*\%(state\|class\|partition\|rectangle\)\>.*{' -let s:decIndent = '^\s*\(end\|else\|}\)' +let s:decIndent = '^\s*\%(end\|else\|}\)'  function! GetPlantUMLIndent(...) abort -    "for current line, use arg if given or v:lnum otherwise -    let clnum = a:0 ? a:1 : v:lnum - -    if !s:insidePlantUMLTags(clnum) -        return indent(clnum) +  "for current line, use arg if given or v:lnum otherwise +  let clnum = a:0 ? a:1 : v:lnum + +  if !s:insidePlantUMLTags(clnum) +    return indent(clnum) +  endif + +  let pnum = prevnonblank(clnum-1) +  let pindent = indent(pnum) +  let pline = getline(pnum) +  let cline = getline(clnum) + +  if cline =~ s:decIndent +    if pline =~ s:incIndent +      return pindent +    else +      return pindent - shiftwidth()      endif -    let pnum = prevnonblank(clnum-1) -    let pindent = indent(pnum)  -    let pline = getline(pnum) -    let cline = getline(clnum) - -    if cline =~ s:decIndent -        if pline =~ s:incIndent -            return pindent -        else -            return pindent - shiftwidth() -        endif - -    elseif pline =~ s:incIndent -        return pindent + shiftwidth() -    endif +  elseif pline =~ s:incIndent +    return pindent + shiftwidth() +  endif -    return pindent +  return pindent  endfunction  function! s:insidePlantUMLTags(lnum) abort -    call cursor(a:lnum, 1) -    return search('@startuml', 'Wbn') && search('@enduml', 'Wn') +  call cursor(a:lnum, 1) +  return search('@startuml', 'Wbn') && search('@enduml', 'Wn')  endfunction  endif diff --git a/indent/ruby.vim b/indent/ruby.vim index 8d8fa2e9..84067fe9 100644 --- a/indent/ruby.vim +++ b/indent/ruby.vim @@ -51,11 +51,11 @@ let s:syng_strcom = '\<ruby\%(Regexp\|RegexpDelimiter\|RegexpEscape' .  " Regex of syntax group names that are strings.  let s:syng_string = -      \ '\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\)\>' +      \ '\<ruby\%(String\|Interpolation\|InterpolationDelimiter\|NoInterpolation\|StringEscape\)\>'  " Regex of syntax group names that are strings or documentation.  let s:syng_stringdoc = -      \'\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\|Documentation\)\>' +      \ '\<ruby\%(String\|Interpolation\|InterpolationDelimiter\|NoInterpolation\|StringEscape\|Documentation\)\>'  " Expression used to check whether we should skip a match with searchpair().  let s:skip_expr = @@ -392,7 +392,7 @@ function! s:FindContainingClass()        call setpos('.', saved_position)        return found_lnum      endif -  endif +  endwhile    call setpos('.', saved_position)    return 0 | 
