aboutsummaryrefslogtreecommitdiff
path: root/runtime/indent
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/indent')
-rw-r--r--runtime/indent/cs.vim74
-rw-r--r--runtime/indent/eruby.vim10
-rw-r--r--runtime/indent/falcon.vim2
-rw-r--r--runtime/indent/html.vim19
-rw-r--r--runtime/indent/matlab.vim187
-rw-r--r--runtime/indent/raml.vim12
-rw-r--r--runtime/indent/ruby.vim886
-rw-r--r--runtime/indent/sh.vim30
-rw-r--r--runtime/indent/tcl.vim50
-rw-r--r--runtime/indent/testdir/html.in26
-rw-r--r--runtime/indent/testdir/html.ok26
-rw-r--r--runtime/indent/testdir/matlab.in80
-rw-r--r--runtime/indent/testdir/matlab.ok80
-rw-r--r--runtime/indent/testdir/tcl.in19
-rw-r--r--runtime/indent/testdir/tcl.ok19
-rw-r--r--runtime/indent/testdir/xml.in32
-rw-r--r--runtime/indent/testdir/xml.ok32
-rw-r--r--runtime/indent/xml.vim121
18 files changed, 1236 insertions, 469 deletions
diff --git a/runtime/indent/cs.vim b/runtime/indent/cs.vim
index 4a040b6fe2..76c12efecf 100644
--- a/runtime/indent/cs.vim
+++ b/runtime/indent/cs.vim
@@ -1,15 +1,73 @@
" Vim indent file
-" Language: C#
-" Maintainer: Johannes Zellner <johannes@zellner.org>
-" Last Change: Fri, 15 Mar 2002 07:53:54 CET
+" Language: C#
+" Maintainer: Nick Jensen <nickspoon@gmail.com>
+" Former Maintainers: Aquila Deus
+" Johannes Zellner <johannes@zellner.org>
+" Last Change: 2018-11-21
+" Filenames: *.cs
+" License: Vim (see :h license)
+" Repository: https://github.com/nickspoons/vim-cs
+"
" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
- finish
+if exists('b:did_indent')
+ finish
endif
let b:did_indent = 1
-" C# is like indenting C
-setlocal cindent
+let s:save_cpo = &cpoptions
+set cpoptions&vim
-let b:undo_indent = "setl cin<"
+
+setlocal indentexpr=GetCSIndent(v:lnum)
+
+function! s:IsCompilerDirective(line)
+ return a:line =~? '^\s*#'
+endf
+
+function! s:IsAttributeLine(line)
+ return a:line =~? '^\s*\[[A-Za-z]' && a:line =~? '\]$'
+endf
+
+function! s:FindPreviousNonCompilerDirectiveLine(start_lnum)
+ for delta in range(0, a:start_lnum)
+ let lnum = a:start_lnum - delta
+ let line = getline(lnum)
+ let is_directive = s:IsCompilerDirective(line)
+ if !is_directive
+ return lnum
+ endif
+ endfor
+ return 0
+endf
+
+function! GetCSIndent(lnum) abort
+ " Hit the start of the file, use zero indent.
+ if a:lnum == 0
+ return 0
+ endif
+
+ let this_line = getline(a:lnum)
+
+ " Compiler directives use zero indent if so configured.
+ let is_first_col_macro = s:IsCompilerDirective(this_line) && stridx(&l:cinkeys, '0#') >= 0
+ if is_first_col_macro
+ return cindent(a:lnum)
+ endif
+
+ let lnum = s:FindPreviousNonCompilerDirectiveLine(a:lnum - 1)
+ let previous_code_line = getline(lnum)
+ if s:IsAttributeLine(previous_code_line)
+ let ind = indent(lnum)
+ return ind
+ else
+ return cindent(a:lnum)
+ endif
+endfunction
+
+let b:undo_indent = 'setlocal indentexpr<'
+
+let &cpoptions = s:save_cpo
+unlet s:save_cpo
+
+" vim:et:sw=2:sts=2
diff --git a/runtime/indent/eruby.vim b/runtime/indent/eruby.vim
index 5058325495..6ff15ab958 100644
--- a/runtime/indent/eruby.vim
+++ b/runtime/indent/eruby.vim
@@ -3,6 +3,7 @@
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2019 Jan 06
if exists("b:did_indent")
finish
@@ -12,7 +13,7 @@ runtime! indent/ruby.vim
unlet! b:did_indent
setlocal indentexpr=
-if exists("b:eruby_subtype")
+if exists("b:eruby_subtype") && b:eruby_subtype != '' && b:eruby_subtype !=# 'eruby'
exe "runtime! indent/".b:eruby_subtype.".vim"
else
runtime! indent/html.vim
@@ -47,7 +48,11 @@ set cpo&vim
function! GetErubyIndent(...)
" The value of a single shift-width
- let sw = shiftwidth()
+ if exists('*shiftwidth')
+ let sw = shiftwidth()
+ else
+ let sw = &sw
+ endif
if a:0 && a:1 == '.'
let v:lnum = line('.')
@@ -91,6 +96,7 @@ function! GetErubyIndent(...)
let ind = ind + sw
endif
if line !~# '^\s*<%' && line =~# '%>\s*$' && line !~# '^\s*end\>'
+ \ && synID(v:lnum, match(cline, '\S') + 1, 1) != hlID('htmlEndTag')
let ind = ind - sw
endif
if cline =~# '^\s*[-=]\=%>\s*$'
diff --git a/runtime/indent/falcon.vim b/runtime/indent/falcon.vim
index b34e7cfd47..664ad61aa5 100644
--- a/runtime/indent/falcon.vim
+++ b/runtime/indent/falcon.vim
@@ -368,7 +368,7 @@ function FalconGetIndent(...)
return indent('.')
endif
else
- call cursor(clnum, vcol)
+ call cursor(clnum, 0) " FIXME: column was vcol
end
endif
diff --git a/runtime/indent/html.vim b/runtime/indent/html.vim
index 6c866594c5..1a8177050a 100644
--- a/runtime/indent/html.vim
+++ b/runtime/indent/html.vim
@@ -216,8 +216,9 @@ endfunc "}}}
" Add known tag pairs.
" Self-closing tags and tags that are sometimes {{{
" self-closing (e.g., <p>) are not here (when encountering </p> we can find
-" the matching <p>, but not the other way around). Known self-closing tags:
-" 'p', 'img', 'source'.
+" the matching <p>, but not the other way around).
+" Known self-closing tags: " 'p', 'img', 'source', 'area', 'keygen', 'track',
+" 'wbr'.
" Old HTML tags:
call s:AddITags(s:indent_tags, [
\ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big',
@@ -232,11 +233,11 @@ call s:AddITags(s:indent_tags, [
" New HTML5 elements:
call s:AddITags(s:indent_tags, [
- \ 'area', 'article', 'aside', 'audio', 'bdi', 'canvas',
- \ 'command', 'data', 'datalist', 'details', 'embed', 'figcaption',
- \ 'figure', 'footer', 'header', 'keygen', 'main', 'mark', 'meter',
- \ 'nav', 'output', 'picture', 'progress', 'rp', 'rt', 'ruby', 'section',
- \ 'summary', 'svg', 'time', 'track', 'video', 'wbr'])
+ \ 'article', 'aside', 'audio', 'bdi', 'canvas', 'command', 'data',
+ \ 'datalist', 'details', 'dialog', 'embed', 'figcaption', 'figure',
+ \ 'footer', 'header', 'hgroup', 'main', 'mark', 'meter', 'nav', 'output',
+ \ 'picture', 'progress', 'rp', 'rt', 'ruby', 'section', 'summary',
+ \ 'svg', 'time', 'video'])
" Tags added for web components:
call s:AddITags(s:indent_tags, [
@@ -625,7 +626,7 @@ func! s:CSSIndent()
return eval(b:hi_css1indent)
endif
- " If the current line starts with "}" align with it's match.
+ " If the current line starts with "}" align with its match.
if curtext =~ '^\s*}'
call cursor(v:lnum, 1)
try
@@ -934,7 +935,7 @@ func! s:InsideTag(foundHtmlString)
let idx = match(text, '<' . s:tagname . '\s\+\zs\w')
endif
if idx == -1
- " after just <tag indent one level more
+ " after just "<tag" indent one level more
let idx = match(text, '<' . s:tagname . '$')
if idx >= 0
call cursor(lnum, idx)
diff --git a/runtime/indent/matlab.vim b/runtime/indent/matlab.vim
index 6a31624389..d2818a18ea 100644
--- a/runtime/indent/matlab.vim
+++ b/runtime/indent/matlab.vim
@@ -1,74 +1,121 @@
-" Matlab indent file
-" Language: Matlab
-" Maintainer: Christophe Poucet <christophe.poucet@pandora.be>
-" Last Change: 6 January, 2001
-
-" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
- finish
-endif
+" Vim indent file
+" Language: MATLAB
+" Maintainer: Axel Forsman <axelsfor@gmail.com>
+" Previous maintainer: Christophe Poucet <christophe.poucet@pandora.be>
+
+" Only load if no other indent file is loaded
+if exists('b:did_indent') | finish | endif
let b:did_indent = 1
-" Some preliminary setting
-setlocal indentkeys=!,o,O=end,=case,=else,=elseif,=otherwise,=catch
-
-
-setlocal indentexpr=GetMatlabIndent(v:lnum)
-
-" Only define the function once.
-if exists("*GetMatlabIndent")
- finish
-endif
-
-function GetMatlabIndent(lnum)
- " Give up if this line is explicitly joined.
- if getline(a:lnum - 1) =~ '\\$'
- return -1
- endif
-
- " Search backwards for the first non-empty line.
- let plnum = a:lnum - 1
- while plnum > 0 && getline(plnum) =~ '^\s*$'
- let plnum = plnum - 1
- endwhile
-
- if plnum == 0
- " This is the first non-empty line, use zero indent.
- return 0
- endif
-
- let curind = indent(plnum)
-
- " If the current line is a stop-block statement...
- if getline(v:lnum) =~ '^\s*\(end\|else\|elseif\|case\|otherwise\|catch\)\>'
- " See if this line does not follow the line right after an openblock
- if getline(plnum) =~ '^\s*\(for\|if\|else\|elseif\|case\|while\|switch\|try\|otherwise\|catch\)\>'
- " See if the user has already dedented
- elseif indent(v:lnum) > curind - shiftwidth()
- " If not, recommend one dedent
- let curind = curind - shiftwidth()
- else
- " Otherwise, trust the user
- return -1
- endif
-" endif
-
- " If the previous line opened a block
- elseif getline(plnum) =~ '^\s*\(for\|if\|else\|elseif\|case\|while\|switch\|try\|otherwise\|catch\)\>'
- " See if the user has already indented
- if indent(v:lnum) < curind + shiftwidth()
- "If not, recommend indent
- let curind = curind + shiftwidth()
- else
- " Otherwise, trust the user
- return -1
- endif
- endif
-
-
-
- " If we got to here, it means that the user takes the standardversion, so we return it
- return curind
+setlocal indentexpr=GetMatlabIndent()
+setlocal indentkeys=!,o,O,e,0=end,0=elseif,0=case,0=otherwise,0=catch,0=function,0=elsei
+
+" The value of the Function indenting format in
+" MATLAB Editor/Debugger Language Preferences.
+" The possible values are 0 for Classic, 1 for Indent nested functions
+" and 2 for Indent all functions (default).
+let b:MATLAB_function_indent = get(g:, 'MATLAB_function_indent', 2)
+" The previous value of b:changedtick
+let b:MATLAB_lasttick = -1
+" The previously indented line
+let b:MATLAB_lastline = -1
+" Whether the line above was a line continuation
+let b:MATLAB_waslc = 0
+let b:MATLAB_bracketlevel = 0
+
+" Only define the function once
+if exists("*GetMatlabIndent") | finish | endif
+
+let s:keepcpo = &cpo
+set cpo&vim
+
+let s:end = '\<end\>\%([^(]*)\)\@!' " Array indexing heuristic
+let s:open_pat = 'for\|if\|parfor\|spmd\|switch\|try\|while\|classdef\|properties\|methods\|events\|enumeration'
+let s:dedent_pat = '\C^\s*\zs\<\%(end\|else\|elseif\|catch\|\(case\|otherwise\|function\)\)\>'
+let s:start_pat = '\C\<\%(function\|' . s:open_pat . '\)\>'
+let s:bracket_pair_pat = '\(\[\|{\)\|\(\]\|}\)'
+let s:zflag = has('patch-7.4.984') ? 'z' : ''
+
+" Returns whether a comment or string envelops the specified column.
+function! s:IsCommentOrString(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), "name") =~# 'matlabComment\|matlabMultilineComment\|matlabString'
+endfunction
+
+" Returns whether the specified line continues on the next line.
+function! s:IsLineContinuation(lnum)
+ let l = getline(a:lnum) | let c = -3
+ while 1
+ let c = match(l, '\.\{3}', c + 3)
+ if c == -1 | return 0
+ elseif !s:IsCommentOrString(a:lnum, c) | return 1 | endif
+ endwhile
+endfunction
+
+function! s:SubmatchCount(lnum, pattern, ...)
+ let endcol = a:0 >= 1 ? a:1 : 1 / 0 | let x = [0, 0, 0, 0]
+ call cursor(a:lnum, 1)
+ while 1
+ let [lnum, c, submatch] = searchpos(a:pattern, 'cpe' . s:zflag, a:lnum)
+ if !submatch || c >= endcol | break | endif
+ if !s:IsCommentOrString(lnum, c) | let x[submatch - 2] += 1 | endif
+ if cursor(0, c + 1) == -1 || col('.') == c | break | endif
+ endwhile
+ return x
+endfunction
+
+function! s:GetOpenCloseCount(lnum, pattern, ...)
+ let counts = call('s:SubmatchCount', [a:lnum, a:pattern] + a:000)
+ return counts[0] - counts[1]
+endfunction
+
+function! GetMatlabIndent()
+ let prevlnum = prevnonblank(v:lnum - 1)
+
+ if b:MATLAB_lasttick != b:changedtick || b:MATLAB_lastline != prevlnum
+ " Recalculate bracket count (only have to check same block and line above)
+ let b:MATLAB_bracketlevel = 0
+ let previndent = indent(prevlnum) | let l = prevlnum
+ while 1
+ let l = prevnonblank(l - 1) | let indent = indent(l)
+ if l <= 0 || previndent < indent | break | endif
+ let b:MATLAB_bracketlevel += s:GetOpenCloseCount(l, s:bracket_pair_pat)
+ if previndent != indent | break | endif
+ endwhile
+
+ let b:MATLAB_waslc = s:IsLineContinuation(prevlnum - 1)
+ endif
+ " If line above was blank it can impossibly have been a LC
+ let above_lc = b:MATLAB_lasttick == b:changedtick && prevlnum != v:lnum - 1 && b:MATLAB_lastline == prevlnum ? 0 : s:IsLineContinuation(v:lnum - 1)
+
+ let pair_pat = '\C\<\(' . s:open_pat . '\|'
+ \ . (b:MATLAB_function_indent == 1 ? '^\@<!' : '')
+ \ . (b:MATLAB_function_indent >= 1 ? 'function\|' : '')
+ \ . '\|\%(^\s*\)\@<=\%(else\|elseif\|case\|otherwise\|catch\)\)\>'
+ \ . '\|\S\s*\zs\(' . s:end . '\)'
+ let [open, close, b_open, b_close] = prevlnum ? s:SubmatchCount(prevlnum,
+ \ pair_pat . '\|' . s:bracket_pair_pat) : [0, 0, 0, 0]
+ let curbracketlevel = b:MATLAB_bracketlevel + b_open - b_close
+
+ call cursor(v:lnum, 1)
+ let submatch = search(s:dedent_pat, 'cp' . s:zflag, v:lnum)
+ if submatch && !s:IsCommentOrString(v:lnum, col('.'))
+ " Align end, et cetera with start of block
+ let [lnum, col] = searchpairpos(s:start_pat, '', '\C' . s:end, 'bW', 's:IsCommentOrString(line("."), col("."))')
+ let result = lnum ? indent(lnum) + shiftwidth() * (s:GetOpenCloseCount(lnum, pair_pat, col) + submatch == 2) : 0
+ else
+ " Count how many blocks the previous line opens/closes
+ " Line continuations/brackets indent once per statement
+ let result = indent(prevlnum) + shiftwidth() * (open - close
+ \ + (b:MATLAB_bracketlevel ? -!curbracketlevel : !!curbracketlevel)
+ \ + (curbracketlevel <= 0) * (above_lc - b:MATLAB_waslc))
+ endif
+
+ let b:MATLAB_waslc = above_lc
+ let b:MATLAB_bracketlevel = curbracketlevel
+ let b:MATLAB_lasttick = b:changedtick
+ let b:MATLAB_lastline = v:lnum
+ return result
endfunction
-" vim:sw=2
+let &cpo = s:keepcpo
+unlet s:keepcpo
diff --git a/runtime/indent/raml.vim b/runtime/indent/raml.vim
new file mode 100644
index 0000000000..73756ae7de
--- /dev/null
+++ b/runtime/indent/raml.vim
@@ -0,0 +1,12 @@
+" Vim indent file
+" Language: RAML (RESTful API Modeling Language)
+" Maintainer: mucheng <leisurelicht@gmail.com>
+" License: VIM LICENSE
+" Latest Revision: 2018-11-03
+
+if exists("b:did_indent")
+ finish
+endif
+
+" Same as yaml indenting.
+runtime! indent/yaml.vim
diff --git a/runtime/indent/ruby.vim b/runtime/indent/ruby.vim
index d8733db305..5c420d7543 100644
--- a/runtime/indent/ruby.vim
+++ b/runtime/indent/ruby.vim
@@ -1,8 +1,10 @@
" Vim indent file
" Language: Ruby
-" Maintainer: Nikolai Weibull <now at bitwi.se>
+" Maintainer: Andrew Radev <andrey.radev@gmail.com>
+" Previous Maintainer: Nikolai Weibull <now at bitwi.se>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2019 Jan 06
" 0. Initialization {{{1
" =================
@@ -18,6 +20,11 @@ if !exists('g:ruby_indent_access_modifier_style')
let g:ruby_indent_access_modifier_style = 'normal'
endif
+if !exists('g:ruby_indent_assignment_style')
+ " Possible values: "variable", "hanging"
+ let g:ruby_indent_assignment_style = 'hanging'
+endif
+
if !exists('g:ruby_indent_block_style')
" Possible values: "expression", "do"
let g:ruby_indent_block_style = 'expression'
@@ -42,28 +49,27 @@ 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\|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\|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 =
\ '^\s*\zs\<\%(module\|class\|if\|for' .
\ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue' .
- \ '\|\%(public\|protected\|private\)\=\s*def\):\@!\>' .
+ \ '\|\%(\K\k*[!?]\?\)\=\s*def\):\@!\>' .
\ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\@!\>'
@@ -77,7 +83,7 @@ let s:ruby_deindent_keywords =
let s:end_start_regex =
\ '\C\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(module\|class\|if\|for\|while\|until\|case\|unless\|begin' .
- \ '\|\%(public\|protected\|private\)\=\s*def\):\@!\>' .
+ \ '\|\%(\K\k*[!?]\?\)\=\s*def\):\@!\>' .
\ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>'
" Regex that defines the middle-match for the 'end' keyword.
@@ -142,31 +148,562 @@ let s:block_continuation_regex = '^\s*[^])}\t ].*'.s:block_regex
" Regex that describes a leading operator (only a method call's dot for now)
let s:leading_operator_regex = '^\s*[.]'
-" 2. Auxiliary Functions {{{1
+" 2. GetRubyIndent Function {{{1
+" =========================
+
+function! GetRubyIndent(...) abort
+ " 2.1. Setup {{{2
+ " ----------
+
+ let indent_info = {}
+
+ " The value of a single shift-width
+ if exists('*shiftwidth')
+ let indent_info.sw = shiftwidth()
+ else
+ let indent_info.sw = &sw
+ endif
+
+ " For the current line, use the first argument if given, else v:lnum
+ let indent_info.clnum = a:0 ? a:1 : v:lnum
+ let indent_info.cline = getline(indent_info.clnum)
+
+ " Set up variables for restoring position in file. Could use clnum here.
+ let indent_info.col = col('.')
+
+ " 2.2. Work on the current line {{{2
+ " -----------------------------
+ let indent_callback_names = [
+ \ 's:AccessModifier',
+ \ 's:ClosingBracketOnEmptyLine',
+ \ 's:BlockComment',
+ \ 's:DeindentingKeyword',
+ \ 's:MultilineStringOrLineComment',
+ \ 's:ClosingHeredocDelimiter',
+ \ 's:LeadingOperator',
+ \ ]
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " 2.3. Work on the previous line. {{{2
+ " -------------------------------
+
+ " Special case: we don't need the real s:PrevNonBlankNonString for an empty
+ " line inside a string. And that call can be quite expensive in that
+ " particular situation.
+ let indent_callback_names = [
+ \ 's:EmptyInsideString',
+ \ ]
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " Previous line number
+ let indent_info.plnum = s:PrevNonBlankNonString(indent_info.clnum - 1)
+ let indent_info.pline = getline(indent_info.plnum)
+
+ let indent_callback_names = [
+ \ 's:StartOfFile',
+ \ 's:AfterAccessModifier',
+ \ 's:ContinuedLine',
+ \ 's:AfterBlockOpening',
+ \ 's:AfterHangingSplat',
+ \ 's:AfterUnbalancedBracket',
+ \ 's:AfterLeadingOperator',
+ \ 's:AfterEndKeyword',
+ \ 's:AfterIndentKeyword',
+ \ ]
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " 2.4. Work on the MSL line. {{{2
+ " --------------------------
+ let indent_callback_names = [
+ \ 's:PreviousNotMSL',
+ \ 's:IndentingKeywordInMSL',
+ \ 's:ContinuedHangingOperator',
+ \ ]
+
+ " Most Significant line based on the previous one -- in case it's a
+ " contination of something above
+ let indent_info.plnum_msl = s:GetMSL(indent_info.plnum)
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " }}}2
+
+ " By default, just return the previous line's indent
+" Decho "Default case matched"
+ return indent(indent_info.plnum)
+endfunction
+
+" 3. Indenting Logic Callbacks {{{1
+" ============================
+
+function! s:AccessModifier(cline_info) abort
+ let info = a:cline_info
+
+ " If this line is an access modifier keyword, align according to the closest
+ " class declaration.
+ if g:ruby_indent_access_modifier_style == 'indent'
+ if s:Match(info.clnum, s:access_modifier_regex)
+ let class_lnum = s:FindContainingClass()
+ if class_lnum > 0
+ return indent(class_lnum) + info.sw
+ endif
+ endif
+ elseif g:ruby_indent_access_modifier_style == 'outdent'
+ if s:Match(info.clnum, s:access_modifier_regex)
+ let class_lnum = s:FindContainingClass()
+ if class_lnum > 0
+ return indent(class_lnum)
+ endif
+ endif
+ endif
+
+ return -1
+endfunction
+
+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
+ " according to it. For parentheses we indent to its column - 1, for the
+ " others we indent to the containing line's MSL's level. Return -1 if fail.
+ let col = matchend(info.cline, '^\s*[]})]')
+
+ if col > 0 && !s:IsInStringOrComment(info.clnum, col)
+ call cursor(info.clnum, col)
+ let closing_bracket = info.cline[col - 1]
+ let bracket_pair = strpart('(){}[]', stridx(')}]', closing_bracket) * 2, 2)
+
+ if searchpair(escape(bracket_pair[0], '\['), '', bracket_pair[1], 'bW', s:skip_expr) > 0
+ if closing_bracket == ')' && col('.') != col('$') - 1
+ let ind = virtcol('.') - 1
+ elseif g:ruby_indent_block_style == 'do'
+ let ind = indent(line('.'))
+ else " g:ruby_indent_block_style == 'expression'
+ let ind = indent(s:GetMSL(line('.')))
+ endif
+ endif
+
+ return ind
+ endif
+
+ return -1
+endfunction
+
+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
+ endif
+ return -1
+endfunction
+
+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.
+ " TODO: this is messy
+ if s:Match(info.clnum, s:ruby_deindent_keywords)
+ call cursor(info.clnum, 1)
+
+ if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW',
+ \ s:end_skip_expr) > 0
+ let msl = s:GetMSL(line('.'))
+ let line = getline(line('.'))
+
+ if s:IsAssignment(line, col('.')) &&
+ \ strpart(line, col('.') - 1, 2) !~ 'do'
+ " assignment to case/begin/etc, on the same line
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = virtcol('.') - 1
+ else
+ " align with variable
+ let ind = indent(line('.'))
+ endif
+ elseif g:ruby_indent_block_style == 'do'
+ " align to line of the "do", not to the MSL
+ let ind = indent(line('.'))
+ elseif getline(msl) =~ '=\s*\(#.*\)\=$'
+ " in the case of assignment to the MSL, align to the starting line,
+ " not to the MSL
+ let ind = indent(line('.'))
+ else
+ " align to the MSL
+ let ind = indent(msl)
+ endif
+ endif
+ return ind
+ endif
+
+ return -1
+endfunction
+
+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.
+ if s:IsInStringOrDocumentation(info.clnum, matchend(info.cline, '^\s*') + 1)
+ return indent(info.clnum)
+ endif
+ return -1
+endfunction
+
+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
+ " indent to 0.
+ if info.cline =~ '^\k\+\s*$'
+ \ && s:IsInStringDelimiter(info.clnum, 1)
+ \ && search('\V<<'.info.cline, 'nbW') > 0
+ return 0
+ endif
+
+ return -1
+endfunction
+
+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
+ endif
+ return -1
+endfunction
+
+function! s:EmptyInsideString(pline_info) abort
+ " If the line is empty and inside a string (the previous line is a string,
+ " too), use the previous line's indent
+ let info = a:pline_info
+
+ let plnum = prevnonblank(info.clnum - 1)
+ let pline = getline(plnum)
+
+ if info.cline =~ '^\s*$'
+ \ && s:IsInStringOrComment(plnum, 1)
+ \ && s:IsInStringOrComment(plnum, strlen(pline))
+ return indent(plnum)
+ endif
+ return -1
+endfunction
+
+function! s:StartOfFile(pline_info) abort
+ " At the start of the file use zero indent.
+ if a:pline_info.plnum == 0
+ return 0
+ endif
+ return -1
+endfunction
+
+function! s:AfterAccessModifier(pline_info) abort
+ let info = a:pline_info
+
+ if g:ruby_indent_access_modifier_style == 'indent'
+ " If the previous line was a private/protected keyword, add a
+ " level of indent.
+ if s:Match(info.plnum, s:indent_access_modifier_regex)
+ return indent(info.plnum) + info.sw
+ endif
+ elseif g:ruby_indent_access_modifier_style == 'outdent'
+ " If the previous line was a private/protected/public keyword, add
+ " a level of indent, since the keyword has been out-dented.
+ if s:Match(info.plnum, s:access_modifier_regex)
+ return indent(info.plnum) + info.sw
+ endif
+ endif
+ return -1
+endfunction
+
+" Example:
+"
+" if foo || bar ||
+" baz || bing
+" puts "foo"
+" end
+"
+function! s:ContinuedLine(pline_info) abort
+ let info = a:pline_info
+
+ let col = s:Match(info.plnum, s:ruby_indent_keywords)
+ if s:Match(info.plnum, s:continuable_regex) &&
+ \ s:Match(info.plnum, s:continuation_regex)
+ if col > 0 && s:IsAssignment(info.pline, col)
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = col - 1
+ else
+ " align with variable
+ let ind = indent(info.plnum)
+ endif
+ else
+ let ind = indent(s:GetMSL(info.plnum))
+ endif
+ return ind + info.sw + info.sw
+ endif
+ return -1
+endfunction
+
+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.
+ if s:Match(info.plnum, s:block_regex)
+ if g:ruby_indent_block_style == 'do'
+ " don't align to the msl, align to the "do"
+ let ind = indent(info.plnum) + info.sw
+ else
+ let plnum_msl = s:GetMSL(info.plnum)
+
+ if getline(plnum_msl) =~ '=\s*\(#.*\)\=$'
+ " in the case of assignment to the msl, align to the starting line,
+ " not to the msl
+ let ind = indent(info.plnum) + info.sw
+ else
+ let ind = indent(plnum_msl) + info.sw
+ endif
+ endif
+
+ return ind
+ endif
+
+ return -1
+endfunction
+
+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)
+ return indent(s:GetMSL(a:pline_info.plnum))
+ endif
+ return -1
+endfunction
+
+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
+ if info.pline =~ s:splat_regex
+ return indent(info.plnum) + info.sw
+ endif
+ return -1
+endfunction
+
+function! s:AfterUnbalancedBracket(pline_info) abort
+ let info = a:pline_info
+
+ " If the previous line contained unclosed opening brackets and we are still
+ " in them, find the rightmost one and add indent depending on the bracket
+ " type.
+ "
+ " If it contained hanging closing brackets, find the rightmost one, find its
+ " match and indent according to that.
+ if info.pline =~ '[[({]' || info.pline =~ '[])}]\s*\%(#.*\)\=$'
+ let [opening, closing] = s:ExtraBrackets(info.plnum)
+
+ if opening.pos != -1
+ if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
+ if col('.') + 1 == col('$')
+ return indent(info.plnum) + info.sw
+ else
+ return virtcol('.')
+ endif
+ else
+ let nonspace = matchend(info.pline, '\S', opening.pos + 1) - 1
+ return nonspace > 0 ? nonspace : indent(info.plnum) + info.sw
+ endif
+ elseif closing.pos != -1
+ call cursor(info.plnum, closing.pos + 1)
+ normal! %
+
+ if s:Match(line('.'), s:ruby_indent_keywords)
+ return indent('.') + info.sw
+ else
+ return indent(s:GetMSL(line('.')))
+ endif
+ else
+ call cursor(info.clnum, info.col)
+ end
+ endif
+
+ return -1
+endfunction
+
+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.
+ let col = s:Match(info.plnum, '\%(^\|[^.:@$]\)\<end\>\s*\%(#.*\)\=$')
+ if col > 0
+ call cursor(info.plnum, col)
+ if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW',
+ \ s:end_skip_expr) > 0
+ let n = line('.')
+ let ind = indent('.')
+ let msl = s:GetMSL(n)
+ if msl != n
+ let ind = indent(msl)
+ end
+ return ind
+ endif
+ end
+ return -1
+endfunction
+
+function! s:AfterIndentKeyword(pline_info) abort
+ let info = a:pline_info
+ let col = s:Match(info.plnum, s:ruby_indent_keywords)
+
+ if col > 0
+ call cursor(info.plnum, col)
+ let ind = virtcol('.') - 1 + info.sw
+ " TODO: make this better (we need to count them) (or, if a searchpair
+ " fails, we know that something is lacking an end and thus we indent a
+ " level
+ if s:Match(info.plnum, s:end_end_regex)
+ let ind = indent('.')
+ elseif s:IsAssignment(info.pline, col)
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = col + info.sw - 1
+ else
+ " align with variable
+ let ind = indent(info.plnum) + info.sw
+ endif
+ endif
+ return ind
+ endif
+
+ return -1
+endfunction
+
+function! s:PreviousNotMSL(msl_info) abort
+ let info = a:msl_info
+
+ " If the previous line wasn't a MSL
+ if info.plnum != info.plnum_msl
+ " If previous line ends bracket and begins non-bracket continuation decrease indent by 1.
+ if s:Match(info.plnum, s:bracket_switch_continuation_regex)
+ " TODO (2016-10-07) Wrong/unused? How could it be "1"?
+ return indent(info.plnum) - 1
+ " If previous line is a continuation return its indent.
+ " TODO: the || s:IsInString() thing worries me a bit.
+ elseif s:Match(info.plnum, s:non_bracket_continuation_regex) || s:IsInString(info.plnum, strlen(line))
+ return indent(info.plnum)
+ endif
+ endif
+
+ return -1
+endfunction
+
+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
+ " module Foo; class Bar; end
+ let col = s:Match(info.plnum_msl, s:ruby_indent_keywords)
+ if col > 0
+ let ind = indent(info.plnum_msl) + info.sw
+ if s:Match(info.plnum_msl, s:end_end_regex)
+ let ind = ind - info.sw
+ elseif s:IsAssignment(getline(info.plnum_msl), col)
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = col + info.sw - 1
+ else
+ " align with variable
+ let ind = indent(info.plnum_msl) + info.sw
+ endif
+ endif
+ return ind
+ endif
+ return -1
+endfunction
+
+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
+ " closing bracket, indent one extra level.
+ if s:Match(info.plnum_msl, s:non_bracket_continuation_regex) && !s:Match(info.plnum_msl, '^\s*\([\])}]\|end\)')
+ if info.plnum_msl == info.plnum
+ let ind = indent(info.plnum_msl) + info.sw
+ else
+ let ind = indent(info.plnum_msl)
+ endif
+ return ind
+ endif
+
+ return -1
+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) 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
@@ -191,10 +728,9 @@ 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 msl_body = getline(msl)
let lnum = s:PrevNonBlankNonString(a:lnum - 1)
while lnum > 0
" If we have a continuation line, or we're in a string, use line as MSL.
@@ -291,14 +827,13 @@ function s:GetMSL(lnum)
endif
endif
- let msl_body = getline(msl)
let lnum = s:PrevNonBlankNonString(lnum - 1)
endwhile
return msl
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': []}
@@ -360,7 +895,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
@@ -380,7 +915,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',
@@ -396,297 +931,6 @@ function! s:FindContainingClass()
return 0
endfunction
-" 3. GetRubyIndent Function {{{1
-" =========================
-
-function GetRubyIndent(...)
- " 3.1. Setup {{{2
- " ----------
-
- " The value of a single shift-width
- let sw = shiftwidth()
-
- " For the current line, use the first argument if given, else v:lnum
- let clnum = a:0 ? a:1 : v:lnum
-
- " Set up variables for restoring position in file. Could use clnum here.
- let vcol = col('.')
-
- " 3.2. Work on the current line {{{2
- " -----------------------------
-
- " Get the current line.
- let line = getline(clnum)
- let ind = -1
-
- " If this line is an access modifier keyword, align according to the closest
- " class declaration.
- if g:ruby_indent_access_modifier_style == 'indent'
- if s:Match(clnum, s:access_modifier_regex)
- let class_line = s:FindContainingClass()
- if class_line > 0
- return indent(class_line) + sw
- endif
- endif
- elseif g:ruby_indent_access_modifier_style == 'outdent'
- if s:Match(clnum, s:access_modifier_regex)
- let class_line = s:FindContainingClass()
- if class_line > 0
- return indent(class_line)
- endif
- endif
- endif
-
- " If we got a closing bracket on an empty line, find its match and indent
- " according to it. For parentheses we indent to its column - 1, for the
- " others we indent to the containing line's MSL's level. Return -1 if fail.
- let col = matchend(line, '^\s*[]})]')
- if col > 0 && !s:IsInStringOrComment(clnum, col)
- call cursor(clnum, col)
- let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
- if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0
- if line[col-1]==')' && col('.') != col('$') - 1
- let ind = virtcol('.') - 1
- elseif g:ruby_indent_block_style == 'do'
- let ind = indent(line('.'))
- else " g:ruby_indent_block_style == 'expression'
- let ind = indent(s:GetMSL(line('.')))
- endif
- endif
- return ind
- endif
-
- " If we have a =begin or =end set indent to first column.
- if match(line, '^\s*\%(=begin\|=end\)$') != -1
- return 0
- endif
-
- " If we have a deindenting keyword, find its match and indent to its level.
- " TODO: this is messy
- if s:Match(clnum, s:ruby_deindent_keywords)
- call cursor(clnum, 1)
- if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW',
- \ s:end_skip_expr) > 0
- let msl = s:GetMSL(line('.'))
- let line = getline(line('.'))
-
- if strpart(line, 0, col('.') - 1) =~ '=\s*$' &&
- \ strpart(line, col('.') - 1, 2) !~ 'do'
- " assignment to case/begin/etc, on the same line, hanging indent
- let ind = virtcol('.') - 1
- elseif g:ruby_indent_block_style == 'do'
- " align to line of the "do", not to the MSL
- let ind = indent(line('.'))
- elseif getline(msl) =~ '=\s*\(#.*\)\=$'
- " in the case of assignment to the MSL, align to the starting line,
- " not to the MSL
- let ind = indent(line('.'))
- else
- " align to the MSL
- let ind = indent(msl)
- endif
- endif
- return ind
- endif
-
- " If we are in a multi-line string or line-comment, don't do anything to it.
- if s:IsInStringOrDocumentation(clnum, matchend(line, '^\s*') + 1)
- return indent('.')
- endif
-
- " If we are at the closing delimiter of a "<<" heredoc-style string, set the
- " indent to 0.
- if line =~ '^\k\+\s*$'
- \ && s:IsInStringDelimiter(clnum, 1)
- \ && search('\V<<'.line, 'nbW') > 0
- return 0
- endif
-
- " If the current line starts with a leading operator, add a level of indent.
- if s:Match(clnum, s:leading_operator_regex)
- return indent(s:GetMSL(clnum)) + sw
- endif
-
- " 3.3. Work on the previous line. {{{2
- " -------------------------------
-
- " Find a non-blank, non-multi-line string line above the current line.
- let lnum = s:PrevNonBlankNonString(clnum - 1)
-
- " If the line is empty and inside a string, use the previous line.
- if line =~ '^\s*$' && lnum != prevnonblank(clnum - 1)
- return indent(prevnonblank(clnum))
- endif
-
- " At the start of the file use zero indent.
- if lnum == 0
- return 0
- endif
-
- " Set up variables for the previous line.
- let line = getline(lnum)
- let ind = indent(lnum)
-
- if g:ruby_indent_access_modifier_style == 'indent'
- " If the previous line was a private/protected keyword, add a
- " level of indent.
- if s:Match(lnum, s:indent_access_modifier_regex)
- return indent(lnum) + sw
- endif
- elseif g:ruby_indent_access_modifier_style == 'outdent'
- " If the previous line was a private/protected/public keyword, add
- " a level of indent, since the keyword has been out-dented.
- if s:Match(lnum, s:access_modifier_regex)
- return indent(lnum) + sw
- endif
- endif
-
- if s:Match(lnum, s:continuable_regex) && s:Match(lnum, s:continuation_regex)
- return indent(s:GetMSL(lnum)) + sw + sw
- endif
-
- " If the previous line ended with a block opening, add a level of indent.
- if s:Match(lnum, s:block_regex)
- let msl = s:GetMSL(lnum)
-
- if g:ruby_indent_block_style == 'do'
- " don't align to the msl, align to the "do"
- let ind = indent(lnum) + sw
- elseif getline(msl) =~ '=\s*\(#.*\)\=$'
- " in the case of assignment to the msl, align to the starting line,
- " not to the msl
- let ind = indent(lnum) + sw
- else
- let ind = indent(msl) + sw
- endif
- return ind
- endif
-
- " If the previous line started with a leading operator, use its MSL's level
- " of indent
- if s:Match(lnum, s:leading_operator_regex)
- return indent(s:GetMSL(lnum))
- endif
-
- " If the previous line ended with the "*" of a splat, add a level of indent
- if line =~ s:splat_regex
- return indent(lnum) + sw
- endif
-
- " If the previous line contained unclosed opening brackets and we are still
- " in them, find the rightmost one and add indent depending on the bracket
- " type.
- "
- " If it contained hanging closing brackets, find the rightmost one, find its
- " match and indent according to that.
- if line =~ '[[({]' || line =~ '[])}]\s*\%(#.*\)\=$'
- let [opening, closing] = s:ExtraBrackets(lnum)
-
- if opening.pos != -1
- if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
- if col('.') + 1 == col('$')
- return ind + sw
- else
- return virtcol('.')
- endif
- else
- let nonspace = matchend(line, '\S', opening.pos + 1) - 1
- return nonspace > 0 ? nonspace : ind + sw
- endif
- elseif closing.pos != -1
- call cursor(lnum, closing.pos + 1)
- normal! %
-
- if s:Match(line('.'), s:ruby_indent_keywords)
- return indent('.') + sw
- else
- return indent(s:GetMSL(line('.')))
- endif
- else
- call cursor(clnum, vcol)
- end
- endif
-
- " If the previous line ended with an "end", match that "end"s beginning's
- " indent.
- let col = s:Match(lnum, '\%(^\|[^.:@$]\)\<end\>\s*\%(#.*\)\=$')
- if col > 0
- call cursor(lnum, col)
- if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW',
- \ s:end_skip_expr) > 0
- let n = line('.')
- let ind = indent('.')
- let msl = s:GetMSL(n)
- if msl != n
- let ind = indent(msl)
- end
- return ind
- endif
- end
-
- let col = s:Match(lnum, s:ruby_indent_keywords)
- if col > 0
- call cursor(lnum, col)
- let ind = virtcol('.') - 1 + sw
- " TODO: make this better (we need to count them) (or, if a searchpair
- " fails, we know that something is lacking an end and thus we indent a
- " level
- if s:Match(lnum, s:end_end_regex)
- let ind = indent('.')
- endif
- return ind
- endif
-
- " 3.4. Work on the MSL line. {{{2
- " --------------------------
-
- " Set up variables to use and search for MSL to the previous line.
- let p_lnum = lnum
- let lnum = s:GetMSL(lnum)
-
- " If the previous line wasn't a MSL.
- if p_lnum != lnum
- " If previous line ends bracket and begins non-bracket continuation decrease indent by 1.
- if s:Match(p_lnum, s:bracket_switch_continuation_regex)
- return ind - 1
- " If previous line is a continuation return its indent.
- " TODO: the || s:IsInString() thing worries me a bit.
- elseif s:Match(p_lnum, s:non_bracket_continuation_regex) || s:IsInString(p_lnum,strlen(line))
- return ind
- endif
- endif
-
- " Set up more variables, now that we know we wasn't continuation bound.
- let line = getline(lnum)
- let msl_ind = indent(lnum)
-
- " 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
- " module Foo; class Bar; end
- if s:Match(lnum, s:ruby_indent_keywords)
- let ind = msl_ind + sw
- if s:Match(lnum, s:end_end_regex)
- let ind = ind - sw
- endif
- return ind
- endif
-
- " If the previous line ended with [*+/.,-=], but wasn't a block ending or a
- " closing bracket, indent one extra level.
- if s:Match(lnum, s:non_bracket_continuation_regex) && !s:Match(lnum, '^\s*\([\])}]\|end\)')
- if lnum == p_lnum
- let ind = msl_ind + sw
- else
- let ind = msl_ind
- endif
- return ind
- endif
-
- " }}}2
-
- return ind
-endfunction
-
" }}}1
let &cpo = s:cpo_save
diff --git a/runtime/indent/sh.vim b/runtime/indent/sh.vim
index 32bc9f35bb..c93be31958 100644
--- a/runtime/indent/sh.vim
+++ b/runtime/indent/sh.vim
@@ -3,10 +3,11 @@
" Maintainer: Christian Brabandt <cb@256bit.org>
" Original Author: Nikolai Weibull <now@bitwi.se>
" Previous Maintainer: Peter Aronoff <telemachus@arpinum.org>
-" Latest Revision: 2018-03-26
+" Latest Revision: 2019-02-02
" License: Vim (see :h license)
" Repository: https://github.com/chrisbra/vim-sh-indent
" Changelog:
+" 20190201 - Better check for closing if sections
" 20180724 - make check for zsh syntax more rigid (needs word-boundaries)
" 20180326 - better support for line continuation
" 20180325 - better detection of function definitions
@@ -59,6 +60,7 @@ function! s:indent_value(option)
endfunction
function! GetShIndent()
+ let curline = getline(v:lnum)
let lnum = prevnonblank(v:lnum - 1)
if lnum == 0
return 0
@@ -72,7 +74,7 @@ function! GetShIndent()
" Check contents of previous lines
if line =~ '^\s*\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>' ||
\ (&ft is# 'zsh' && line =~ '\<\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>')
- if line !~ '\<\%(fi\|esac\|done\|end\)\>\s*\%(#.*\)\=$'
+ if !s:is_end_expression(line)
let ind += s:indent_value('default')
endif
elseif s:is_case_label(line, pnum)
@@ -90,7 +92,10 @@ function! GetShIndent()
endif
elseif s:end_block(line) && !s:start_block(line)
let ind -= s:indent_value('default')
- elseif pnum != 0 && s:is_continuation_line(pline) && !s:end_block(getline(v:lnum))
+ elseif pnum != 0 &&
+ \ s:is_continuation_line(pline) &&
+ \ !s:end_block(curline) &&
+ \ !s:is_end_expression(curline)
" only add indent, if line and pline is in the same block
let i = v:lnum
let ind2 = indent(s:find_continued_lnum(pnum))
@@ -106,8 +111,15 @@ function! GetShIndent()
let pine = line
" Check content of current line
- let line = getline(v:lnum)
- if line =~ '^\s*\%(then\|do\|else\|elif\|fi\|done\|end\)\>' || s:end_block(line)
+ let line = curline
+ " Current line is a endif line, so get indent from start of "if condition" line
+ " TODO: should we do the same for other "end" lines?
+ if curline =~ '^\s*\%(fi\)\s*\%(#.*\)\=$'
+ let previous_line = search('if.\{-\};\s*then\s*\%(#.*\)\=$', 'bnW')
+ if previous_line > 0
+ let ind = indent(previous_line)
+ endif
+ elseif line =~ '^\s*\%(then\|do\|else\|elif\|done\|end\)\>' || s:end_block(line)
let ind -= s:indent_value('default')
elseif line =~ '^\s*esac\>' && s:is_case_empty(getline(v:lnum - 1))
let ind -= s:indent_value('default')
@@ -210,8 +222,8 @@ endfunction
function! s:is_here_doc(line)
if a:line =~ '^\w\+$'
- let here_pat = '<<-\?'. s:escape(a:line). '\$'
- return search(here_pat, 'bnW') > 0
+ let here_pat = '<<-\?'. s:escape(a:line). '\$'
+ return search(here_pat, 'bnW') > 0
endif
return 0
endfunction
@@ -256,5 +268,9 @@ function! s:is_comment(line)
return a:line =~ '^\s*#'
endfunction
+function! s:is_end_expression(line)
+ return a:line =~ '\<\%(fi\|esac\|done\|end\)\>\s*\%(#.*\)\=$'
+endfunction
+
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/indent/tcl.vim b/runtime/indent/tcl.vim
index e9d61e4366..d77081841d 100644
--- a/runtime/indent/tcl.vim
+++ b/runtime/indent/tcl.vim
@@ -1,7 +1,8 @@
" Vim indent file
-" Language: Tcl
-" Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2006-12-20
+" Language: Tcl
+" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
+" Latest Update: Chris Heithoff <chrisheithoff@gmail.com>
+" Latest Revision: 2018-12-05
if exists("b:did_indent")
finish
@@ -28,6 +29,15 @@ function s:prevnonblanknoncomment(lnum)
return lnum
endfunction
+function s:ends_with_backslash(lnum)
+ let line = getline(a:lnum)
+ if line =~ '\\\s*$'
+ return 1
+ else
+ return 0
+ endif
+endfunction
+
function s:count_braces(lnum, count_open)
let n_open = 0
let n_close = 0
@@ -53,23 +63,39 @@ endfunction
function GetTclIndent()
let line = getline(v:lnum)
- if line =~ '^\s*\*'
- return cindent(v:lnum)
- elseif line =~ '^\s*}'
- return indent(v:lnum) - shiftwidth()
- endif
+ " Get the line number of the previous non-blank or non-comment line.
let pnum = s:prevnonblanknoncomment(v:lnum - 1)
if pnum == 0
return 0
endif
- let ind = indent(pnum) + s:count_braces(pnum, 1) * shiftwidth()
+ " ..and the previous line before the previous line.
+ let pnum2 = s:prevnonblanknoncomment(pnum-1)
- let pline = getline(pnum)
- if pline =~ '}\s*$'
- let ind -= (s:count_braces(pnum, 0) - (pline =~ '^\s*}' ? 1 : 0)) * shiftwidth()
+ " Default indentation is to preserve the previous indentation.
+ let ind = indent(pnum)
+
+ " ...but if previous line introduces an open brace, then increase current line's indentation
+ if s:count_braces(pnum, 1) > 0
+ let ind += shiftwidth()
+ else
+ " Look for backslash line continuation on the previous two lines.
+ let slash1 = s:ends_with_backslash(pnum)
+ let slash2 = s:ends_with_backslash(pnum2)
+ if slash1 && !slash2
+ " If the previous line begins a line continuation.
+ let ind += shiftwidth()
+ elseif !slash1 && slash2
+ " If two lines ago was the end of a line continuation group of lines.
+ let ind -= shiftwidth()
+ endif
endif
+ " If the current line begins with a closed brace, then decrease the indentation by one.
+ if line =~ '^\s*}'
+ let ind -= shiftwidth()
+ endif
+
return ind
endfunction
diff --git a/runtime/indent/testdir/html.in b/runtime/indent/testdir/html.in
new file mode 100644
index 0000000000..9c776d61c6
--- /dev/null
+++ b/runtime/indent/testdir/html.in
@@ -0,0 +1,26 @@
+" vim: set ft=html sw=4 :
+
+
+" START_INDENT
+<div>
+<div>
+text
+</div>
+</div>
+
+<div
+class="foo bar">
+text
+</div>
+
+<div class="foo bar"
+data="something">
+text
+</div>
+
+<div class="foo
+bar">
+text
+</div>
+
+" END_INDENT
diff --git a/runtime/indent/testdir/html.ok b/runtime/indent/testdir/html.ok
new file mode 100644
index 0000000000..524d57bb6c
--- /dev/null
+++ b/runtime/indent/testdir/html.ok
@@ -0,0 +1,26 @@
+" vim: set ft=html sw=4 :
+
+
+" START_INDENT
+<div>
+ <div>
+ text
+ </div>
+</div>
+
+<div
+ class="foo bar">
+ text
+</div>
+
+<div class="foo bar"
+ data="something">
+ text
+</div>
+
+<div class="foo
+ bar">
+ text
+</div>
+
+" END_INDENT
diff --git a/runtime/indent/testdir/matlab.in b/runtime/indent/testdir/matlab.in
new file mode 100644
index 0000000000..5bba1a56dd
--- /dev/null
+++ b/runtime/indent/testdir/matlab.in
@@ -0,0 +1,80 @@
+% vim: set ft=matlab sw=4 :
+
+% START_INDENT
+if true
+disp foo
+elseif false
+disp bar
+end
+% END_INDENT
+
+% START_INDENT
+try
+statements
+catch exception
+statements
+end
+% END_INDENT
+
+% START_INDENT
+if true, ...
+if true
+disp hello
+end
+end
+% END_INDENT
+
+% START_INDENT
+switch a
+case expr
+if true, foo; end
+disp hello
+otherwise
+disp bar
+end
+% END_INDENT
+
+% START_INDENT
+if true
+A(1:end - 1)
+disp foo
+end
+% END_INDENT
+
+% START_INDENT
+A = [{
+}
+] ...
+disp foo
+disp bar
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 0
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 1
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 2
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
diff --git a/runtime/indent/testdir/matlab.ok b/runtime/indent/testdir/matlab.ok
new file mode 100644
index 0000000000..b1112263b2
--- /dev/null
+++ b/runtime/indent/testdir/matlab.ok
@@ -0,0 +1,80 @@
+% vim: set ft=matlab sw=4 :
+
+% START_INDENT
+if true
+ disp foo
+elseif false
+ disp bar
+end
+% END_INDENT
+
+% START_INDENT
+try
+ statements
+catch exception
+ statements
+end
+% END_INDENT
+
+% START_INDENT
+if true, ...
+ if true
+ disp hello
+ end
+end
+% END_INDENT
+
+% START_INDENT
+switch a
+ case expr
+ if true, foo; end
+ disp hello
+ otherwise
+ disp bar
+end
+% END_INDENT
+
+% START_INDENT
+if true
+ A(1:end - 1)
+ disp foo
+end
+% END_INDENT
+
+% START_INDENT
+A = [{
+ }
+ ] ...
+ disp foo
+disp bar
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 0
+function foo
+disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 1
+function foo
+disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 2
+function foo
+ disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
diff --git a/runtime/indent/testdir/tcl.in b/runtime/indent/testdir/tcl.in
new file mode 100644
index 0000000000..c769d5bf5e
--- /dev/null
+++ b/runtime/indent/testdir/tcl.in
@@ -0,0 +1,19 @@
+# vim: set filetype=tcl shiftwidth=4 tabstop=8 expandtab :
+
+# START_INDENT
+proc abc {} {
+set a 5
+if {[some_cmd]==1} {
+foreach i [list {1 2 3}] {
+# Does this comment affect anything?
+puts $i
+}
+}
+}
+
+command_with_a_long_time -arg1 "First" \
+-arg2 "Second" \
+-arg3 "Third"
+
+puts "Move indent back after line continuation is complete"
+# END_INDENT \ No newline at end of file
diff --git a/runtime/indent/testdir/tcl.ok b/runtime/indent/testdir/tcl.ok
new file mode 100644
index 0000000000..77f24e9044
--- /dev/null
+++ b/runtime/indent/testdir/tcl.ok
@@ -0,0 +1,19 @@
+# vim: set filetype=tcl shiftwidth=4 tabstop=8 expandtab :
+
+# START_INDENT
+proc abc {} {
+ set a 5
+ if {[some_cmd]==1} {
+ foreach i [list {1 2 3}] {
+ # Does this comment affect anything?
+ puts $i
+ }
+ }
+}
+
+command_with_a_long_time -arg1 "First" \
+ -arg2 "Second" \
+ -arg3 "Third"
+
+puts "Move indent back after line continuation is complete"
+# END_INDENT
diff --git a/runtime/indent/testdir/xml.in b/runtime/indent/testdir/xml.in
new file mode 100644
index 0000000000..b6333340e2
--- /dev/null
+++ b/runtime/indent/testdir/xml.in
@@ -0,0 +1,32 @@
+<!-- vim: set ft=xml ts=8 sw=0 sts=-1 et : -->
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+<!-- comment -->
+<tag2>
+ <tag3/>
+</tag2>
+<!-- text comment -->
+
+<!--
+text comment
+-->
+</tag1>
+<!--
+text comment
+end coment -->
+</tag0>
+<!-- END_INDENT -->
+
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+<!-- comment -->
+<tag2>
+ <tag3/>
+</tag2>
+</tag1>
+</tag0>
+<!-- END_INDENT -->
diff --git a/runtime/indent/testdir/xml.ok b/runtime/indent/testdir/xml.ok
new file mode 100644
index 0000000000..529198572a
--- /dev/null
+++ b/runtime/indent/testdir/xml.ok
@@ -0,0 +1,32 @@
+<!-- vim: set ft=xml ts=8 sw=0 sts=-1 et : -->
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+ <!-- comment -->
+ <tag2>
+ <tag3/>
+ </tag2>
+ <!-- text comment -->
+
+ <!--
+ text comment
+ -->
+ </tag1>
+ <!--
+ text comment
+ end coment -->
+</tag0>
+<!-- END_INDENT -->
+
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+ <!-- comment -->
+ <tag2>
+ <tag3/>
+ </tag2>
+ </tag1>
+</tag0>
+<!-- END_INDENT -->
diff --git a/runtime/indent/xml.vim b/runtime/indent/xml.vim
index dcafb467a6..29069bab84 100644
--- a/runtime/indent/xml.vim
+++ b/runtime/indent/xml.vim
@@ -1,13 +1,23 @@
-" Language: xml
-" Repository: https://github.com/chrisbra/vim-xml-ftplugin
-" Maintainer: Christian Brabandt <cb@256bit.org>
-" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
-" Last Change: 20180724 - Correctly indent xml comments https://github.com/vim/vim/issues/3200
-" Notes: 1) does not indent pure non-xml code (e.g. embedded scripts)
-" 2) will be confused by unbalanced tags in comments
-" or CDATA sections.
-" 2009-05-26 patch by Nikolai Weibull
-" TODO: implement pre-like tags, see xml_indent_open / xml_indent_close
+" Language: xml
+" Repository: https://github.com/chrisbra/vim-xml-ftplugin
+" Last Changed: Jan 28, 2019
+" Maintainer: Christian Brabandt <cb@256bit.org>
+" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
+" Last Change:
+" 20190128 - Make sure to find previous tag
+" https://github.com/chrisbra/vim-xml-ftplugin/issues/4
+" 20181116 - Fix indentation when tags start with a colon or an underscore
+" https://github.com/vim/vim/pull/926
+" 20181022 - Do not overwrite indentkeys setting
+" https://github.com/chrisbra/vim-xml-ftplugin/issues/1
+" 20180724 - Correctly indent xml comments https://github.com/vim/vim/issues/3200
+"
+" Notes:
+" 1) does not indent pure non-xml code (e.g. embedded scripts)
+" 2) will be confused by unbalanced tags in comments
+" or CDATA sections.
+" 2009-05-26 patch by Nikolai Weibull
+" TODO: implement pre-like tags, see xml_indent_open / xml_indent_close
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
@@ -18,11 +28,12 @@ let s:keepcpo= &cpo
set cpo&vim
" [-- local settings (must come before aborting the script) --]
+" Attention: Parameter use_syntax_check is used by the docbk.vim indent script
setlocal indentexpr=XmlIndentGet(v:lnum,1)
-setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,}
+setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,},!^F
if !exists('b:xml_indent_open')
- let b:xml_indent_open = '.\{-}<\a'
+ let b:xml_indent_open = '.\{-}<[:A-Z_a-z]'
" pre tag, e.g. <address>
" let b:xml_indent_open = '.\{-}<[/]\@!\(address\)\@!'
endif
@@ -38,7 +49,7 @@ unlet s:keepcpo
" [-- finish, if the function already exists --]
if exists('*XmlIndentGet')
- finish
+ finish
endif
let s:keepcpo= &cpo
@@ -51,13 +62,13 @@ endfun
" [-- check if it's xml --]
fun! <SID>XmlIndentSynCheck(lnum)
- if '' != &syntax
- let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name')
- let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name')
- if '' != syn1 && syn1 !~ 'xml' && '' != syn2 && syn2 !~ 'xml'
- " don't indent pure non-xml code
- return 0
- endif
+ if &syntax != ''
+ let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name')
+ let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name')
+ if syn1 != '' && syn1 !~ 'xml' && syn2 != '' && syn2 !~ 'xml'
+ " don't indent pure non-xml code
+ return 0
+ endif
endif
return 1
endfun
@@ -66,41 +77,73 @@ endfun
fun! <SID>XmlIndentSum(lnum, style, add)
let line = getline(a:lnum)
if a:style == match(line, '^\s*</')
- return (shiftwidth() *
- \ (<SID>XmlIndentWithPattern(line, b:xml_indent_open)
- \ - <SID>XmlIndentWithPattern(line, b:xml_indent_close)
- \ - <SID>XmlIndentWithPattern(line, '.\{-}/>'))) + a:add
+ return (shiftwidth() *
+ \ (<SID>XmlIndentWithPattern(line, b:xml_indent_open)
+ \ - <SID>XmlIndentWithPattern(line, b:xml_indent_close)
+ \ - <SID>XmlIndentWithPattern(line, '.\{-}/>'))) + a:add
else
- return a:add
+ return a:add
endif
endfun
+" Main indent function
fun! XmlIndentGet(lnum, use_syntax_check)
" Find a non-empty line above the current line.
- let lnum = prevnonblank(a:lnum - 1)
-
+ let plnum = prevnonblank(a:lnum - 1)
" Hit the start of the file, use zero indent.
- if lnum == 0
- return 0
+ if plnum == 0
+ return 0
endif
+ " Find previous line with a tag (regardless whether open or closed,
+ " but always start restrict the match to a line before the current one
+ let ptag_pattern = '\%(.\{-}<[/:A-Z_a-z]\)'. '\%(\&\%<'. line('.').'l\)'
+ let ptag = search(ptag_pattern, 'bnw')
+ let syn_name = ''
if a:use_syntax_check
- let check_lnum = <SID>XmlIndentSynCheck(lnum)
- let check_alnum = <SID>XmlIndentSynCheck(a:lnum)
- if 0 == check_lnum || 0 == check_alnum
- return indent(a:lnum)
- elseif -1 == check_lnum || -1 == check_alnum
- return -1
- endif
+ let check_lnum = <SID>XmlIndentSynCheck(plnum)
+ let check_alnum = <SID>XmlIndentSynCheck(a:lnum)
+ if check_lnum == 0 || check_alnum == 0
+ return indent(a:lnum)
+ endif
+ let syn_name = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name')
endif
- let ind = <SID>XmlIndentSum(lnum, -1, indent(lnum))
- let ind = <SID>XmlIndentSum(a:lnum, 0, ind)
+ if syn_name =~ 'Comment'
+ return <SID>XmlIndentComment(a:lnum)
+ endif
+ " Get indent from previous tag line
+ let ind = <SID>XmlIndentSum(ptag, -1, indent(ptag))
+ " Determine indent from current line
+ let ind = <SID>XmlIndentSum(a:lnum, 0, ind)
return ind
endfun
+" return indent for a commented line,
+" the middle part might be indented on additional level
+func! <SID>XmlIndentComment(lnum)
+ let ptagopen = search(b:xml_indent_open, 'bnw')
+ let ptagclose = search(b:xml_indent_close, 'bnw')
+ if getline(a:lnum) =~ '<!--'
+ " if previous tag was a closing tag, do not add
+ " one additional level of indent
+ if ptagclose > ptagopen && a:lnum > ptagclose
+ return indent(ptagclose)
+ else
+ " start of comment, add one indentation level
+ return indent(ptagopen) + shiftwidth()
+ endif
+ elseif getline(a:lnum) =~ '-->'
+ " end of comment, same as start of comment
+ return indent(search('<!--', 'bnw'))
+ else
+ " middle part of comment, add one additional level
+ return indent(search('<!--', 'bnw')) + shiftwidth()
+ endif
+endfunc
+
let &cpo = s:keepcpo
unlet s:keepcpo
-" vim:ts=8
+" vim:ts=4 et sts=-1 sw=0