diff options
author | Adam Stankiewicz <sheerun@sher.pl> | 2017-05-17 11:07:28 +0200 |
---|---|---|
committer | Adam Stankiewicz <sheerun@sher.pl> | 2017-05-17 11:07:28 +0200 |
commit | af870100716f20ee4daef9cc527a9ecf41b54114 (patch) | |
tree | 0859464c3145682cbfc29ad08de4527dd661abf7 /indent | |
parent | ef369d45a505403587ea0bae30ce6768ba51398c (diff) | |
download | vim-polyglot-af870100716f20ee4daef9cc527a9ecf41b54114.tar.gz vim-polyglot-af870100716f20ee4daef9cc527a9ecf41b54114.zip |
Update
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 |