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 |