summaryrefslogtreecommitdiffstats
path: root/indent
diff options
context:
space:
mode:
Diffstat (limited to 'indent')
-rw-r--r--indent/clojure.vim4
-rw-r--r--indent/dart.vim26
-rw-r--r--indent/elixir.vim224
-rw-r--r--indent/gohtmltmpl.vim4
-rw-r--r--indent/haskell.vim24
-rw-r--r--indent/html.vim41
-rw-r--r--indent/javascript.vim338
-rw-r--r--indent/plantuml.vim59
-rw-r--r--indent/ruby.vim6
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