Update runtime files
diff --git a/runtime/indent/chatito.vim b/runtime/indent/chatito.vim
new file mode 100644
index 0000000..1ff5e9e
--- /dev/null
+++ b/runtime/indent/chatito.vim
@@ -0,0 +1,32 @@
+" Vim indent file
+" Language: Chatito
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Last Change: 2022 Sep 20
+
+if exists('b:did_indent')
+ finish
+endif
+let b:did_indent = 1
+
+setlocal indentexpr=GetChatitoIndent()
+setlocal indentkeys=o,O,*<Return>,0#,!^F
+
+let b:undo_indent = 'setl inde< indk<'
+
+if exists('*GetChatitoIndent')
+ finish
+endif
+
+function GetChatitoIndent()
+ let l:prev = v:lnum - 1
+ if getline(prevnonblank(l:prev)) =~# '^[~%@]\['
+ " shift indent after definitions
+ return shiftwidth()
+ elseif getline(l:prev) !~# '^\s*$'
+ " maintain indent in sentences
+ return indent(l:prev)
+ else
+ " reset indent after a blank line
+ return 0
+ end
+endfunction
diff --git a/runtime/indent/gyp.vim b/runtime/indent/gyp.vim
new file mode 100644
index 0000000..c3980ac
--- /dev/null
+++ b/runtime/indent/gyp.vim
@@ -0,0 +1,7 @@
+" Vim indent file
+" Language: GYP
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Last Change: 2022 Sep 27
+
+" JSON indent works well
+runtime! indent/json.vim
diff --git a/runtime/indent/hare.vim b/runtime/indent/hare.vim
new file mode 100644
index 0000000..bc4fea4
--- /dev/null
+++ b/runtime/indent/hare.vim
@@ -0,0 +1,138 @@
+" Vim indent file
+" Language: Hare
+" Maintainer: Amelia Clarke <me@rsaihe.dev>
+" Last Change: 2022 Sep 22
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+if !has("cindent") || !has("eval")
+ finish
+endif
+
+setlocal cindent
+
+" L0 -> don't deindent labels
+" (s -> use one indent after a trailing (
+" m1 -> if ) starts a line, indent it the same as its matching (
+" ks -> add an extra indent to extra lines in an if expression or for expression
+" j1 -> indent code inside {} one level when in parentheses
+" J1 -> see j1
+" *0 -> don't search for unclosed block comments
+" #1 -> don't deindent lines that begin with #
+setlocal cinoptions=L0,(s,m1,ks,j1,J1,*0,#1
+
+" Controls which keys reindent the current line.
+" 0{ -> { at beginning of line
+" 0} -> } at beginning of line
+" 0) -> ) at beginning of line
+" 0] -> ] at beginning of line
+" !^F -> <C-f> (not inserted)
+" o -> <CR> or `o` command
+" O -> `O` command
+" e -> else
+" 0=case -> case
+setlocal indentkeys=0{,0},0),0],!^F,o,O,e,0=case
+
+setlocal cinwords=if,else,for,switch,match
+
+setlocal indentexpr=GetHareIndent()
+
+function! FloorCindent(lnum)
+ return cindent(a:lnum) / shiftwidth() * shiftwidth()
+endfunction
+
+function! GetHareIndent()
+ let line = getline(v:lnum)
+ let prevlnum = prevnonblank(v:lnum - 1)
+ let prevline = getline(prevlnum)
+ let prevprevline = getline(prevnonblank(prevlnum - 1))
+
+ " This is all very hacky and imperfect, but it's tough to do much better when
+ " working with regex-based indenting rules.
+
+ " If the previous line ended with =, indent by one shiftwidth.
+ if prevline =~# '\v\=\s*(//.*)?$'
+ return indent(prevlnum) + shiftwidth()
+ endif
+
+ " If the previous line ended in a semicolon and the line before that ended
+ " with =, deindent by one shiftwidth.
+ if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\s*(//.*)?$'
+ return indent(prevlnum) - shiftwidth()
+ endif
+
+ " TODO: The following edge-case is still indented incorrectly:
+ " case =>
+ " if (foo) {
+ " bar;
+ " };
+ " | // cursor is incorrectly deindented by one shiftwidth.
+ "
+ " This only happens if the {} block is the first statement in the case body.
+ " If `case` is typed, the case will also be incorrectly deindented by one
+ " shiftwidth. Are you having fun yet?
+
+ " Deindent cases.
+ if line =~# '\v^\s*case'
+ " If the previous line was also a case, don't do any special indenting.
+ if prevline =~# '\v^\s*case'
+ return indent(prevlnum)
+ end
+
+ " If the previous line was a multiline case, deindent by one shiftwidth.
+ if prevline =~# '\v\=\>\s*(//.*)?$'
+ return indent(prevlnum) - shiftwidth()
+ endif
+
+ " If the previous line started a block, deindent by one shiftwidth.
+ " This handles the first case in a switch/match block.
+ if prevline =~# '\v\{\s*(//.*)?$'
+ return FloorCindent(v:lnum) - shiftwidth()
+ end
+
+ " If the previous line ended in a semicolon and the line before that wasn't
+ " a case, deindent by one shiftwidth.
+ if prevline =~# '\v;\s*(//.*)?$' && prevprevline !~# '\v\=\>\s*(//.*)?$'
+ return FloorCindent(v:lnum) - shiftwidth()
+ end
+
+ let l:indent = FloorCindent(v:lnum)
+
+ " If a normal cindent would indent the same amount as the previous line,
+ " deindent by one shiftwidth. This fixes some issues with `case let` blocks.
+ if l:indent == indent(prevlnum)
+ return l:indent - shiftwidth()
+ endif
+
+ " Otherwise, do a normal cindent.
+ return l:indent
+ endif
+
+ " Don't indent an extra shiftwidth for cases which span multiple lines.
+ if prevline =~# '\v\=\>\s*(//.*)?$' && prevline !~# '\v^\s*case\W'
+ return indent(prevlnum)
+ endif
+
+ " Indent the body of a case.
+ " If the previous line ended in a semicolon and the line before that was a
+ " case, don't do any special indenting.
+ if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' && line !~# '\v^\s*}'
+ return indent(prevlnum)
+ endif
+
+ let l:indent = FloorCindent(v:lnum)
+
+ " If the previous line was a case and a normal cindent wouldn't indent, indent
+ " an extra shiftwidth.
+ if prevline =~# '\v\=\>\s*(//.*)?$' && l:indent == indent(prevlnum)
+ return l:indent + shiftwidth()
+ endif
+
+ " If everything above is false, do a normal cindent.
+ return l:indent
+endfunction
+
+" vim: tabstop=2 shiftwidth=2 expandtab
diff --git a/runtime/indent/solidity.vim b/runtime/indent/solidity.vim
new file mode 100644
index 0000000..caed726
--- /dev/null
+++ b/runtime/indent/solidity.vim
@@ -0,0 +1,442 @@
+" Vim indent file
+" Language: Solidity
+" Acknowledgement: Based off of vim-javascript
+" Maintainer: Cothi (jiungdev@gmail.com)
+" Original Author: tomlion (https://github.com/tomlion/vim-solidity)
+" Last Changed: 2022 Sep 27
+"
+" 0. Initialization {{{1
+" =================
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal nosmartindent
+
+" Now, set up our indentation expression and keys that trigger it.
+setlocal indentexpr=GetSolidityIndent()
+setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e
+
+" Only define the function once.
+if exists("*GetSolidityIndent")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" 1. Variables {{{1
+" ============
+
+let s:js_keywords = '^\s*\(break\|case\|catch\|continue\|debugger\|default\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)'
+
+" Regex of syntax group names that are or delimit string or are comments.
+let s:syng_strcom = 'string\|regex\|comment\c'
+
+" Regex of syntax group names that are strings.
+let s:syng_string = 'regex\c'
+
+" Regex of syntax group names that are strings or documentation.
+let s:syng_multiline = 'comment\c'
+
+" Regex of syntax group names that are line comment.
+let s:syng_linecom = 'linecomment\c'
+
+" 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."'"
+
+let s:line_term = '\s*\%(\%(\/\/\).*\)\=$'
+
+" Regex that defines continuation lines, not including (, {, or [.
+let s:continuation_regex = '\%([\\*+/.:]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)' . s:line_term
+
+" Regex that defines continuation lines.
+" TODO: this needs to deal with if ...: and so on
+let s:msl_regex = '\%([\\*+/.:([]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)' . s:line_term
+
+let s:one_line_scope_regex = '\<\%(if\|else\|for\|while\)\>[^{;]*' . s:line_term
+
+" Regex that defines blocks.
+let s:block_regex = '\%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term
+
+let s:var_stmt = '^\s*var'
+
+let s:comma_first = '^\s*,'
+let s:comma_last = ',\s*$'
+
+let s:ternary = '^\s\+[?|:]'
+let s:ternary_q = '^\s\+?'
+
+" 2. Auxiliary Functions {{{1
+" ======================
+
+" 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
+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
+endfunction
+
+" Check if the character at lnum:col is inside a multi-line comment.
+function s:IsInMultilineComment(lnum, col)
+ return !s:IsLineComment(a:lnum, a:col) && synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_multiline
+endfunction
+
+" Check if the character at lnum:col is a line comment.
+function s:IsLineComment(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_linecom
+endfunction
+
+" Find line above 'lnum' that isn't empty, in a comment, or in a string.
+function s:PrevNonBlankNonString(lnum)
+ let in_block = 0
+ let lnum = prevnonblank(a:lnum)
+ while lnum > 0
+ " Go in and out of blocks comments as necessary.
+ " If the line isn't empty (with opt. comment) or in a string, end search.
+ let line = getline(lnum)
+ if line =~ '/\*'
+ if in_block
+ let in_block = 0
+ else
+ break
+ endif
+ elseif !in_block && line =~ '\*/'
+ let in_block = 1
+ elseif !in_block && line !~ '^\s*\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line)))
+ break
+ endif
+ let lnum = prevnonblank(lnum - 1)
+ endwhile
+ return lnum
+endfunction
+
+" Find line above 'lnum' that started the continuation 'lnum' may be part of.
+function s:GetMSL(lnum, in_one_line_scope)
+ " Start on the line we're at and use its indent.
+ let msl = a:lnum
+ 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.
+ " Otherwise, terminate search as we have found our MSL already.
+ let line = getline(lnum)
+ let col = match(line, s:msl_regex) + 1
+ if (col > 0 && !s:IsInStringOrComment(lnum, col)) || s:IsInString(lnum, strlen(line))
+ let msl = lnum
+ else
+ " Don't use lines that are part of a one line scope as msl unless the
+ " flag in_one_line_scope is set to 1
+ "
+ if a:in_one_line_scope
+ break
+ end
+ let msl_one_line = s:Match(lnum, s:one_line_scope_regex)
+ if msl_one_line == 0
+ break
+ endif
+ endif
+ let lnum = s:PrevNonBlankNonString(lnum - 1)
+ endwhile
+ return msl
+endfunction
+
+function s:RemoveTrailingComments(content)
+ let single = '\/\/\(.*\)\s*$'
+ let multi = '\/\*\(.*\)\*\/\s*$'
+ return substitute(substitute(a:content, single, '', ''), multi, '', '')
+endfunction
+
+" Find if the string is inside var statement (but not the first string)
+function s:InMultiVarStatement(lnum)
+ let lnum = s:PrevNonBlankNonString(a:lnum - 1)
+
+" let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name')
+
+ " loop through previous expressions to find a var statement
+ while lnum > 0
+ let line = getline(lnum)
+
+ " if the line is a js keyword
+ if (line =~ s:js_keywords)
+ " check if the line is a var stmt
+ " if the line has a comma first or comma last then we can assume that we
+ " are in a multiple var statement
+ if (line =~ s:var_stmt)
+ return lnum
+ endif
+
+ " other js keywords, not a var
+ return 0
+ endif
+
+ let lnum = s:PrevNonBlankNonString(lnum - 1)
+ endwhile
+
+ " beginning of program, not a var
+ return 0
+endfunction
+
+" Find line above with beginning of the var statement or returns 0 if it's not
+" this statement
+function s:GetVarIndent(lnum)
+ let lvar = s:InMultiVarStatement(a:lnum)
+ let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1)
+
+ if lvar
+ let line = s:RemoveTrailingComments(getline(prev_lnum))
+
+ " if the previous line doesn't end in a comma, return to regular indent
+ if (line !~ s:comma_last)
+ return indent(prev_lnum) - &sw
+ else
+ return indent(lvar) + &sw
+ endif
+ endif
+
+ return -1
+endfunction
+
+
+" Check if line 'lnum' has more opening brackets than closing ones.
+function s:LineHasOpeningBrackets(lnum)
+ let open_0 = 0
+ let open_2 = 0
+ let open_4 = 0
+ let line = getline(a:lnum)
+ let pos = match(line, '[][(){}]', 0)
+ while pos != -1
+ if !s:IsInStringOrComment(a:lnum, pos + 1)
+ let idx = stridx('(){}[]', line[pos])
+ if idx % 2 == 0
+ let open_{idx} = open_{idx} + 1
+ else
+ let open_{idx - 1} = open_{idx - 1} - 1
+ endif
+ endif
+ let pos = match(line, '[][(){}]', pos + 1)
+ endwhile
+ return (open_0 > 0) . (open_2 > 0) . (open_4 > 0)
+endfunction
+
+function s:Match(lnum, regex)
+ let col = match(getline(a:lnum), a:regex) + 1
+ return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0
+endfunction
+
+function s:IndentWithContinuation(lnum, ind, width)
+ " Set up variables to use and search for MSL to the previous line.
+ let p_lnum = a:lnum
+ let lnum = s:GetMSL(a:lnum, 1)
+ let line = getline(lnum)
+
+ " If the previous line wasn't a MSL and is continuation return its indent.
+ " TODO: the || s:IsInString() thing worries me a bit.
+ if p_lnum != lnum
+ if s:Match(p_lnum,s:continuation_regex)||s:IsInString(p_lnum,strlen(line))
+ return a:ind
+ endif
+ endif
+
+ " Set up more variables now that we know we aren't continuation bound.
+ let msl_ind = indent(lnum)
+
+ " If the previous line ended with [*+/.-=], start a continuation that
+ " indents an extra level.
+ if s:Match(lnum, s:continuation_regex)
+ if lnum == p_lnum
+ return msl_ind + a:width
+ else
+ return msl_ind
+ endif
+ endif
+
+ return a:ind
+endfunction
+
+function s:InOneLineScope(lnum)
+ let msl = s:GetMSL(a:lnum, 1)
+ if msl > 0 && s:Match(msl, s:one_line_scope_regex)
+ return msl
+ endif
+ return 0
+endfunction
+
+function s:ExitingOneLineScope(lnum)
+ let msl = s:GetMSL(a:lnum, 1)
+ if msl > 0
+ " if the current line is in a one line scope ..
+ if s:Match(msl, s:one_line_scope_regex)
+ return 0
+ else
+ let prev_msl = s:GetMSL(msl - 1, 1)
+ if s:Match(prev_msl, s:one_line_scope_regex)
+ return prev_msl
+ endif
+ endif
+ endif
+ return 0
+endfunction
+
+" 3. GetSolidityIndent Function {{{1
+" =========================
+
+function GetSolidityIndent()
+ " 3.1. Setup {{{2
+ " ----------
+
+ " Set up variables for restoring position in file. Could use v:lnum here.
+ let vcol = col('.')
+
+ " 3.2. Work on the current line {{{2
+ " -----------------------------
+
+ let ind = -1
+ " Get the current line.
+ let line = getline(v:lnum)
+ " previous nonblank line number
+ let prevline = prevnonblank(v:lnum - 1)
+
+ " 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(v:lnum, col)
+ call cursor(v:lnum, col)
+
+ let lvar = s:InMultiVarStatement(v:lnum)
+ if lvar
+ let prevline_contents = s:RemoveTrailingComments(getline(prevline))
+
+ " check for comma first
+ if (line[col - 1] =~ ',')
+ " if the previous line ends in comma or semicolon don't indent
+ if (prevline_contents =~ '[;,]\s*$')
+ return indent(s:GetMSL(line('.'), 0))
+ " get previous line indent, if it's comma first return prevline indent
+ elseif (prevline_contents =~ s:comma_first)
+ return indent(prevline)
+ " otherwise we indent 1 level
+ else
+ return indent(lvar) + &sw
+ endif
+ endif
+ endif
+
+
+ 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
+ else
+ let ind = indent(s:GetMSL(line('.'), 0))
+ endif
+ endif
+ return ind
+ endif
+
+ " If the line is comma first, dedent 1 level
+ if (getline(prevline) =~ s:comma_first)
+ return indent(prevline) - &sw
+ endif
+
+ if (line =~ s:ternary)
+ if (getline(prevline) =~ s:ternary_q)
+ return indent(prevline)
+ else
+ return indent(prevline) + &sw
+ endif
+ endif
+
+ " If we are in a multi-line comment, cindent does the right thing.
+ if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1)
+ return cindent(v:lnum)
+ endif
+
+ " Check for multiple var assignments
+" let var_indent = s:GetVarIndent(v:lnum)
+" if var_indent >= 0
+" return var_indent
+" endif
+
+ " 3.3. Work on the previous line. {{{2
+ " -------------------------------
+
+ " If the line is empty and the previous nonblank line was a multi-line
+ " comment, use that comment's indent. Deduct one char to account for the
+ " space in ' */'.
+ if line =~ '^\s*$' && s:IsInMultilineComment(prevline, 1)
+ return indent(prevline) - 1
+ endif
+
+ " Find a non-blank, non-multi-line string line above the current line.
+ let lnum = s:PrevNonBlankNonString(v:lnum - 1)
+
+ " If the line is empty and inside a string, use the previous line.
+ if line =~ '^\s*$' && lnum != prevline
+ return indent(prevnonblank(v:lnum))
+ endif
+
+ " At the start of the file use zero indent.
+ if lnum == 0
+ return 0
+ endif
+
+ " Set up variables for current line.
+ let line = getline(lnum)
+ let ind = indent(lnum)
+
+ " If the previous line ended with a block opening, add a level of indent.
+ if s:Match(lnum, s:block_regex)
+ return indent(s:GetMSL(lnum, 0)) + &sw
+ endif
+
+ " If the previous line contained an opening bracket, and we are still in it,
+ " add indent depending on the bracket type.
+ if line =~ '[[({]'
+ let counts = s:LineHasOpeningBrackets(lnum)
+ if counts[0] == '1' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
+ if col('.') + 1 == col('$')
+ return ind + &sw
+ else
+ return virtcol('.')
+ endif
+ elseif counts[1] == '1' || counts[2] == '1'
+ return ind + &sw
+ else
+ call cursor(v:lnum, vcol)
+ end
+ endif
+
+ " 3.4. Work on the MSL line. {{{2
+ " --------------------------
+
+ let ind_con = ind
+ let ind = s:IndentWithContinuation(lnum, ind_con, &sw)
+
+ " }}}2
+ "
+ "
+ let ols = s:InOneLineScope(lnum)
+ if ols > 0
+ let ind = ind + &sw
+ else
+ let ols = s:ExitingOneLineScope(lnum)
+ while ols > 0 && ind > 0
+ let ind = ind - &sw
+ let ols = s:InOneLineScope(ols - 1)
+ endwhile
+ endif
+
+ return ind
+endfunction
+
+" }}}1
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in
index 5eb262f..0582a93 100644
--- a/runtime/indent/testdir/vim.in
+++ b/runtime/indent/testdir/vim.in
@@ -1,7 +1,6 @@
" vim: set ft=vim sw=4 :
" START_INDENT
-
func Some()
let x = 1
endfunc
@@ -15,15 +14,6 @@
\ ]
endif
-" TODO: add searchpair() to find matching {
-"for x in [
-"{
-"key: 'value'
-"},
-"]
-"eval 0
-"endfor
-
for x in [
{key: 'value'},
]
@@ -37,12 +27,11 @@
\ ]
def Func()
- var d = dd
- ->extend({
- })
- eval 0
+var d = dd
+->extend({
+})
+eval 0
enddef
-
" END_INDENT
" START_INDENT
@@ -84,7 +73,7 @@
" START_INDENT
" INDENT_NEXT next-line
func Some()
- " next-line
+ " next-line
let f = x
endfunc
" END_INDENT
@@ -104,6 +93,12 @@
" END_INDENT
" START_INDENT
+let a =<< trim END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
" INDENT_AT this-line
let a=<< trim END
blah
@@ -111,3 +106,754 @@
blah this-line
END
" END_INDENT
+
+" START_INDENT
+if v:true
+echo 0
+end
+" END_INDENT
+
+" START_INDENT
+var result = Func(
+arg1,
+arg2
+)
+" END_INDENT
+
+" START_INDENT
+var result = Func(arg1,
+arg2)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) =>
+v > 0)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) => {
+const x = get(list, k, 0)
+return x > 0
+})
+" END_INDENT
+
+" START_INDENT
+if x > 0
+filter(list, (k, v) => {
+const x = get(list, k, 1)
+return x > 0
+})
+endif
+" END_INDENT
+
+" START_INDENT
+{
+var temp = 'temp'
+}
+" END_INDENT
+
+" START_INDENT
+var text = lead
+.. middle
+.. end
+" END_INDENT
+
+" START_INDENT
+var text = lead ..
+middle ..
+end
+" END_INDENT
+
+" START_INDENT
+var total = start +
+end -
+correction
+" END_INDENT
+
+" START_INDENT
+var result = start
+:+ print
+" END_INDENT
+
+" START_INDENT
+var result = positive
+? PosFunc(arg)
+: NegFunc(arg)
+" END_INDENT
+
+" START_INDENT
+var result = GetBuilder()
+->BuilderSetWidth(333)
+->BuilderSetHeight(777)
+->BuilderBuild()
+" END_INDENT
+
+" START_INDENT
+var result = MyDict
+.member
+" END_INDENT
+
+" START_INDENT
+autocmd BufNewFile *.match if condition
+| echo 'match'
+| endif
+" END_INDENT
+
+" START_INDENT
+set cpo+=C
+var lines =<< trim END
+| this works
+END
+set cpo-=C
+" END_INDENT
+
+" START_INDENT
+syn region Text
+\ start='foo'
+#\ comment
+\ end='bar'
+" END_INDENT
+
+" START_INDENT
+au CursorHold * echom 'BEFORE bar'
+#\ some comment
+| echom 'AFTER bar'
+" END_INDENT
+
+" START_INDENT
+def MyFunc(text: string,
+separator = '-'
+): string
+enddef
+" END_INDENT
+
+" START_INDENT
+def MyFunc(
+text: string,
+separator = '-'
+): string
+enddef
+" END_INDENT
+
+" START_INDENT
+[var1, var2] =
+Func()
+" END_INDENT
+
+" START_INDENT
+const list = ['one',
+'two']
+" END_INDENT
+
+" START_INDENT
+const list = [
+'one',
+'two',
+]
+" END_INDENT
+
+" START_INDENT
+const dict = {one: 1,
+two: 2
+}
+" END_INDENT
+
+" START_INDENT
+const dict = {
+one: 1,
+two: 2
+}
+" END_INDENT
+
+" START_INDENT
+if true
+const dict =
+{
+one: 1,
+two: 2
+}
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+return {
+one: 1
+}
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+a: 0,
+# b
+# c
+}
+" END_INDENT
+
+" START_INDENT
+echo search(
+# comment
+'1'
+.. '2'
+)
+" END_INDENT
+
+" START_INDENT
+if true
+var v = ( # trailing "(" starts line continuation
+3 + 4 # nothing special
+) # end of expression indicates continued line
+var x: number # needs to align with previous "var"
+endif
+" END_INDENT
+
+" START_INDENT
+def Func() # {{{
+# comment
+if true
+return
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+key:
+'value',
+}
+" END_INDENT
+
+" START_INDENT
+var id = time
+->timer_start((_) => {
+n = 0
+})
+" END_INDENT
+
+" START_INDENT
+augroup Name
+autocmd!
+augroup END
+" END_INDENT
+
+" START_INDENT
+var n =
+# comment
+1
++ 2
+
+var s = ''
+" END_INDENT
+
+" START_INDENT
+var keys = {
+J: 'j',
+"\<Home>": '1G',
+"\<End>": 'G',
+z: 'zz'
+}
+" END_INDENT
+
+" START_INDENT
+export def Func(
+n: number,
+s: string,
+...l: list<bool>
+)
+enddef
+" END_INDENT
+
+" START_INDENT
+var heredoc =<< trim ENDD
+var nested_heredoc =<< trim END
+END
+ENDD
+" END_INDENT
+
+" START_INDENT
+if true
+else " comment
+endif
+" END_INDENT
+
+" START_INDENT
+if true | echo 'one' | endif
+if true | echo 'two' | endif
+if true | echo 'three' | endif
+" END_INDENT
+
+" START_INDENT
+if true
+:'<-1 mark <
+else
+echo ''
+endif
+" END_INDENT
+
+" START_INDENT
+substitute/pat /rep /
+echo
+" END_INDENT
+
+" START_INDENT
+try
+echo 1
+catch /pat / # comment
+echo 2
+endtry
+" END_INDENT
+
+" START_INDENT
+def Func()
+Cmd %
+enddef
+" END_INDENT
+
+" START_INDENT
+if end == 'xxx' || end == 'yyy'
+echo
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+popup_move(id, {col: 1,
+line: 2})
+endif
+setwinvar(id, 'name', 3)
+" END_INDENT
+
+" START_INDENT
+var d = [
+{a: 'x',
+b: 'y'},
+FuncA(),
+FuncB(),
+]
+" END_INDENT
+
+" START_INDENT
+var ll = [[
+1,
+2,
+3], [
+4,
+5,
+6], [
+7,
+8,
+9]]
+" END_INDENT
+
+" START_INDENT
+var ld = [{
+a: 'xxx',
+b: 'yyy'}, {
+c: 'xxx',
+d: 'yyy'}, {
+e: 'xxx',
+f: 'yyy'}, {
+}]
+" END_INDENT
+
+" START_INDENT
+var d = {
+a: {
+b: {
+c: [{
+d: 'e',
+f: 'g',
+h: 'i'
+}],
+j: 'k',
+},
+},
+}
+" END_INDENT
+
+" START_INDENT
+if true
+var end: any
+if true
+end = 0
+elseif true
+echo
+endif
+endif
+" END_INDENT
+
+" START_INDENT
+nunmap <buffer> (
+nunmap <buffer> )
+inoremap [ {
+inoremap ] }
+silent! xunmap i{
+silent! xunmap a{
+" END_INDENT
+
+" START_INDENT
+def Func(
+s: string,
+n = 1,
+m = 2
+)
+enddef
+" END_INDENT
+
+" START_INDENT
+var h =<< END
+text
+END
+
+def Func()
+echo
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+var h =<< END
+text
+END
+echo 'test'
+enddef
+" END_INDENT
+
+" START_INDENT
+def Foo()
+lcd -
+enddef
+def Bar()
+echo
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+n = Func(1, 2,
+3)
+endif
+" END_INDENT
+
+" START_INDENT
+def Func(s: string,
+n: number): bool
+if true
+return false
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func(
+n: number)
+#
+echo
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+def Func(
+ n: number)
+ #
+echo # this-line
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+if true
+normal! ==
+endif
+endif
+" END_INDENT
+
+" START_INDENT
+var d = {
+a: () => true,
+b: () => true
+&& true
+&& Foo(),
+c: () => Bar(),
+e: () => Baz(),
+}
+" END_INDENT
+
+" START_INDENT
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+return (Emit: func(any)) => {
+Cont((t: any) => {
+if Pred(t)
+Emit(t)
+endif
+})
+}
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:vim_indent = {'more_in_bracket_block': v:true}
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+return (Emit: func(any)) => {
+Cont((t: any) => {
+if Pred(t)
+Emit(t)
+endif
+})
+}
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE unlet! g:vim_indent
+" END_INDENT
+
+" START_INDENT
+g:lightline = {
+'active': {
+'left': [ [ 'mode', 'paste' ], [ 'readonly', 'relativepath', 'modified' ] ],
+},
+'inactive': {
+'left': [ [ 'readonly', 'relativepath', 'modified' ] ],
+}
+}
+" END_INDENT
+
+" START_INDENT
+if getline(1, 10)
+->map((_, v: string): number => strcharlen(v))
+->max() > 1'000
+&l:breakindent = false
+&l:linebreak = false
+else
+&l:breakindent = true
+&l:linebreak = true
+endif
+" END_INDENT
+
+" START_INDENT
+var ext2cmd: dict<string> = {
+doc: $'antiword {fname}',
+docx: $'pandoc --from=docx --to=markdown {fname}',
+epub: $'pandoc --from=epub --to=markdown {fname}',
+odp: $'odt2txt {fname}',
+odt: $'odt2txt {fname}',
+pdf: $'pdftotext -nopgbrk -layout -q -eol unix {fname} -',
+rtf: 'unrtf --text',
+}
+" END_INDENT
+
+" START_INDENT
+const ptybuf: number = term_start(&shell, {
+hidden: true,
+exit_cb: (_, _) => {
+if true
+close
+else
+help
+endif
+}
+})
+" END_INDENT
+
+" START_INDENT
+var d = {
+a: 0,
+# a ' quote {{{
+#}}}
+b: 0,
+}
+" END_INDENT
+
+" START_INDENT
+echo printf('%s () %s',
+1,
+2
+)
+" END_INDENT
+
+" START_INDENT
+prop_add(1, col('.'), {
+length: 2,
+type: 'test'
+})
+" END_INDENT
+
+" START_INDENT
+echo (() => " string starting with space")()
+echo
+" END_INDENT
+
+" START_INDENT
+var variables = deepcopy(g:)
+->filter((k: string, _): bool =>
+k =~ '\c\V' .. keyword->escape('\')
+&& k !~ '\%(loaded\|did_plugin_\)')
+->items()
+->map((_, v): string => v[0] .. ' = ' .. string(v[1]))
+new
+" END_INDENT
+
+" START_INDENT
+var d = freq
+->map((_, v) =>
+v * (
+1
++ 2
+))
+for item in d
+->items()
+->sort((a, b) => b[1] - a[1])
+echo
+endfor
+" END_INDENT
+
+" START_INDENT
+make_job = job_start([&shell, &shellcmdflag, make_cmd], {
+callback: function(MakeProcessOutput, [qfid]),
+close_cb: function(MakeCloseCb, [qfid]),
+exit_cb: MakeCompleted,
+in_io: 'null'
+})
+" END_INDENT
+
+" START_INDENT
+var matching_abbrev: list<dict<string>> = copy(ABBREV)
+->filter((_, v: dict<string>): bool =>
+stridx(v.lhs, word_to_complete) == 0)
+->map((_, v: dict<string>) => ({
+word: v.lhs,
+menu: AbbrevRhs(v.rhs)->stridx('expand_') >= 0
+? AbbrevRhs(v.rhs)->matchstr('.*,\s*''\zs.*\ze'')')
+: AbbrevRhs(v.rhs)
+}))
+" END_INDENT
+
+" START_INDENT
+def Func()
+if true
+vimgrep /^\C\s*\%(fu\%[nction]\|def\)\s\+/ file
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+setlocal iskeyword+=[
+cword = expand('<cword>')
+" END_INDENT
+
+" START_INDENT
+silent if true
+echo
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+sort :^.*[\/]:
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+d = {
+}
+hd =<< trim END
+['
+]'
+END
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+if true
+var hd =<< trim END
+if get(b:, 'current_syntax', '')
+endif
+END
+elseif true
+echo
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+# test for control-flow keyword followed by commented fold marker {{{
+if true
+echo
+endif #}}}
+" END_INDENT
+
+" START_INDENT
+if winsz == 0|let winsz= ""|endif
+exe "noswapfile ".winsz."wincmd s"
+" END_INDENT
+
+" START_INDENT
+if true
+if true
+windo if true | echo | endif
+augroup Name
+autocmd WinLeave * if true | eval 1 + 2 | endif
+augroup END
+endif
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+echo ' =<< trim END'
+->len()
+endif
+" END_INDENT
+
+" START_INDENT
+function Func()
+if true
+if true
+if true | echo com | endif
+if true | echo com | endif
+endif
+else
+endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+function Func()
+if v:true
++
+echo
+-
+endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+var matchpairs: string = &matchpairs
+var pairs: dict<list<string>>
+for [opening: string, closing: string]
+in matchpairs
+->split(',')
+->map((_, v: string): list<string> => split(v, ':'))
+pairs[opening] = [escape(opening, '[]'), escape(closing, '[]'), 'nW', 'w$']
+pairs[closing] = [escape(opening, '[]'), escape(closing, '[]'), 'bnW', 'w0']
+endfor
+" END_INDENT
+
+" START_INDENT
+{
+echo []
++ []
++ [{a: 1,
+b: 2}]
+}
+" END_INDENT
+
+" START_INDENT
+silent! argdel *
+edit file
+" END_INDENT
diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok
index 932eebe..39efdba 100644
--- a/runtime/indent/testdir/vim.ok
+++ b/runtime/indent/testdir/vim.ok
@@ -1,7 +1,6 @@
" vim: set ft=vim sw=4 :
" START_INDENT
-
func Some()
let x = 1
endfunc
@@ -15,15 +14,6 @@
\ ]
endif
-" TODO: add searchpair() to find matching {
-"for x in [
-"{
-"key: 'value'
-"},
-"]
-"eval 0
-"endfor
-
for x in [
{key: 'value'},
]
@@ -38,11 +28,10 @@
def Func()
var d = dd
- ->extend({
- })
+ ->extend({
+ })
eval 0
enddef
-
" END_INDENT
" START_INDENT
@@ -69,7 +58,7 @@
let list = [
'one',
'two',
- ]
+]
echo
" END_INDENT
@@ -84,8 +73,8 @@
" START_INDENT
" INDENT_NEXT next-line
func Some()
- " next-line
- let f = x
+ " next-line
+ let f = x
endfunc
" END_INDENT
@@ -99,6 +88,12 @@
" START_INDENT
let a =<< END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
+let a =<< trim END
nothing
END
" END_INDENT
@@ -111,3 +106,754 @@
blah this-line
END
" END_INDENT
+
+" START_INDENT
+if v:true
+ echo 0
+end
+" END_INDENT
+
+" START_INDENT
+var result = Func(
+ arg1,
+ arg2
+)
+" END_INDENT
+
+" START_INDENT
+var result = Func(arg1,
+ arg2)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) =>
+ v > 0)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) => {
+ const x = get(list, k, 0)
+ return x > 0
+})
+" END_INDENT
+
+" START_INDENT
+if x > 0
+ filter(list, (k, v) => {
+ const x = get(list, k, 1)
+ return x > 0
+ })
+endif
+" END_INDENT
+
+" START_INDENT
+{
+ var temp = 'temp'
+}
+" END_INDENT
+
+" START_INDENT
+var text = lead
+ .. middle
+ .. end
+" END_INDENT
+
+" START_INDENT
+var text = lead ..
+ middle ..
+ end
+" END_INDENT
+
+" START_INDENT
+var total = start +
+ end -
+ correction
+" END_INDENT
+
+" START_INDENT
+var result = start
+:+ print
+" END_INDENT
+
+" START_INDENT
+var result = positive
+ ? PosFunc(arg)
+ : NegFunc(arg)
+" END_INDENT
+
+" START_INDENT
+var result = GetBuilder()
+ ->BuilderSetWidth(333)
+ ->BuilderSetHeight(777)
+ ->BuilderBuild()
+" END_INDENT
+
+" START_INDENT
+var result = MyDict
+ .member
+" END_INDENT
+
+" START_INDENT
+autocmd BufNewFile *.match if condition
+ | echo 'match'
+ | endif
+" END_INDENT
+
+" START_INDENT
+set cpo+=C
+var lines =<< trim END
+ | this works
+END
+set cpo-=C
+" END_INDENT
+
+" START_INDENT
+syn region Text
+ \ start='foo'
+ #\ comment
+ \ end='bar'
+" END_INDENT
+
+" START_INDENT
+au CursorHold * echom 'BEFORE bar'
+ #\ some comment
+ | echom 'AFTER bar'
+" END_INDENT
+
+" START_INDENT
+def MyFunc(text: string,
+ separator = '-'
+ ): string
+enddef
+" END_INDENT
+
+" START_INDENT
+def MyFunc(
+ text: string,
+ separator = '-'
+ ): string
+enddef
+" END_INDENT
+
+" START_INDENT
+[var1, var2] =
+ Func()
+" END_INDENT
+
+" START_INDENT
+const list = ['one',
+ 'two']
+" END_INDENT
+
+" START_INDENT
+const list = [
+ 'one',
+ 'two',
+]
+" END_INDENT
+
+" START_INDENT
+const dict = {one: 1,
+ two: 2
+}
+" END_INDENT
+
+" START_INDENT
+const dict = {
+ one: 1,
+ two: 2
+}
+" END_INDENT
+
+" START_INDENT
+if true
+ const dict =
+ {
+ one: 1,
+ two: 2
+ }
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+ return {
+ one: 1
+ }
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+ a: 0,
+ # b
+ # c
+}
+" END_INDENT
+
+" START_INDENT
+echo search(
+ # comment
+ '1'
+ .. '2'
+)
+" END_INDENT
+
+" START_INDENT
+if true
+ var v = ( # trailing "(" starts line continuation
+ 3 + 4 # nothing special
+ ) # end of expression indicates continued line
+ var x: number # needs to align with previous "var"
+endif
+" END_INDENT
+
+" START_INDENT
+def Func() # {{{
+ # comment
+ if true
+ return
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+ key:
+ 'value',
+}
+" END_INDENT
+
+" START_INDENT
+var id = time
+ ->timer_start((_) => {
+ n = 0
+ })
+" END_INDENT
+
+" START_INDENT
+augroup Name
+ autocmd!
+augroup END
+" END_INDENT
+
+" START_INDENT
+var n =
+ # comment
+ 1
+ + 2
+
+var s = ''
+" END_INDENT
+
+" START_INDENT
+var keys = {
+ J: 'j',
+ "\<Home>": '1G',
+ "\<End>": 'G',
+ z: 'zz'
+}
+" END_INDENT
+
+" START_INDENT
+export def Func(
+ n: number,
+ s: string,
+ ...l: list<bool>
+ )
+enddef
+" END_INDENT
+
+" START_INDENT
+var heredoc =<< trim ENDD
+ var nested_heredoc =<< trim END
+ END
+ENDD
+" END_INDENT
+
+" START_INDENT
+if true
+else " comment
+endif
+" END_INDENT
+
+" START_INDENT
+if true | echo 'one' | endif
+if true | echo 'two' | endif
+if true | echo 'three' | endif
+" END_INDENT
+
+" START_INDENT
+if true
+ :'<-1 mark <
+else
+ echo ''
+endif
+" END_INDENT
+
+" START_INDENT
+substitute/pat /rep /
+echo
+" END_INDENT
+
+" START_INDENT
+try
+ echo 1
+catch /pat / # comment
+ echo 2
+endtry
+" END_INDENT
+
+" START_INDENT
+def Func()
+ Cmd %
+enddef
+" END_INDENT
+
+" START_INDENT
+if end == 'xxx' || end == 'yyy'
+ echo
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+ popup_move(id, {col: 1,
+ line: 2})
+endif
+setwinvar(id, 'name', 3)
+" END_INDENT
+
+" START_INDENT
+var d = [
+ {a: 'x',
+ b: 'y'},
+ FuncA(),
+ FuncB(),
+]
+" END_INDENT
+
+" START_INDENT
+var ll = [[
+ 1,
+ 2,
+ 3], [
+ 4,
+ 5,
+ 6], [
+ 7,
+ 8,
+ 9]]
+" END_INDENT
+
+" START_INDENT
+var ld = [{
+ a: 'xxx',
+ b: 'yyy'}, {
+ c: 'xxx',
+ d: 'yyy'}, {
+ e: 'xxx',
+ f: 'yyy'}, {
+ }]
+" END_INDENT
+
+" START_INDENT
+var d = {
+ a: {
+ b: {
+ c: [{
+ d: 'e',
+ f: 'g',
+ h: 'i'
+ }],
+ j: 'k',
+ },
+ },
+}
+" END_INDENT
+
+" START_INDENT
+if true
+ var end: any
+ if true
+ end = 0
+ elseif true
+ echo
+ endif
+endif
+" END_INDENT
+
+" START_INDENT
+nunmap <buffer> (
+nunmap <buffer> )
+inoremap [ {
+inoremap ] }
+silent! xunmap i{
+silent! xunmap a{
+" END_INDENT
+
+" START_INDENT
+def Func(
+ s: string,
+ n = 1,
+ m = 2
+ )
+enddef
+" END_INDENT
+
+" START_INDENT
+var h =<< END
+text
+END
+
+def Func()
+ echo
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+ var h =<< END
+text
+END
+ echo 'test'
+enddef
+" END_INDENT
+
+" START_INDENT
+def Foo()
+ lcd -
+enddef
+def Bar()
+ echo
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+ n = Func(1, 2,
+ 3)
+endif
+" END_INDENT
+
+" START_INDENT
+def Func(s: string,
+ n: number): bool
+ if true
+ return false
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func(
+ n: number)
+ #
+ echo
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+def Func(
+ n: number)
+ #
+ echo # this-line
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+ if true
+ normal! ==
+ endif
+endif
+" END_INDENT
+
+" START_INDENT
+var d = {
+ a: () => true,
+ b: () => true
+ && true
+ && Foo(),
+ c: () => Bar(),
+ e: () => Baz(),
+}
+" END_INDENT
+
+" START_INDENT
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+ return (Emit: func(any)) => {
+ Cont((t: any) => {
+ if Pred(t)
+ Emit(t)
+ endif
+ })
+ }
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:vim_indent = {'more_in_bracket_block': v:true}
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+ return (Emit: func(any)) => {
+ Cont((t: any) => {
+ if Pred(t)
+ Emit(t)
+ endif
+ })
+ }
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE unlet! g:vim_indent
+" END_INDENT
+
+" START_INDENT
+g:lightline = {
+ 'active': {
+ 'left': [ [ 'mode', 'paste' ], [ 'readonly', 'relativepath', 'modified' ] ],
+ },
+ 'inactive': {
+ 'left': [ [ 'readonly', 'relativepath', 'modified' ] ],
+ }
+}
+" END_INDENT
+
+" START_INDENT
+if getline(1, 10)
+ ->map((_, v: string): number => strcharlen(v))
+ ->max() > 1'000
+ &l:breakindent = false
+ &l:linebreak = false
+else
+ &l:breakindent = true
+ &l:linebreak = true
+endif
+" END_INDENT
+
+" START_INDENT
+var ext2cmd: dict<string> = {
+ doc: $'antiword {fname}',
+ docx: $'pandoc --from=docx --to=markdown {fname}',
+ epub: $'pandoc --from=epub --to=markdown {fname}',
+ odp: $'odt2txt {fname}',
+ odt: $'odt2txt {fname}',
+ pdf: $'pdftotext -nopgbrk -layout -q -eol unix {fname} -',
+ rtf: 'unrtf --text',
+}
+" END_INDENT
+
+" START_INDENT
+const ptybuf: number = term_start(&shell, {
+ hidden: true,
+ exit_cb: (_, _) => {
+ if true
+ close
+ else
+ help
+ endif
+ }
+})
+" END_INDENT
+
+" START_INDENT
+var d = {
+ a: 0,
+ # a ' quote {{{
+ #}}}
+ b: 0,
+}
+" END_INDENT
+
+" START_INDENT
+echo printf('%s () %s',
+ 1,
+ 2
+)
+" END_INDENT
+
+" START_INDENT
+prop_add(1, col('.'), {
+ length: 2,
+ type: 'test'
+})
+" END_INDENT
+
+" START_INDENT
+echo (() => " string starting with space")()
+echo
+" END_INDENT
+
+" START_INDENT
+var variables = deepcopy(g:)
+ ->filter((k: string, _): bool =>
+ k =~ '\c\V' .. keyword->escape('\')
+ && k !~ '\%(loaded\|did_plugin_\)')
+ ->items()
+ ->map((_, v): string => v[0] .. ' = ' .. string(v[1]))
+new
+" END_INDENT
+
+" START_INDENT
+var d = freq
+ ->map((_, v) =>
+ v * (
+ 1
+ + 2
+ ))
+for item in d
+ ->items()
+ ->sort((a, b) => b[1] - a[1])
+ echo
+endfor
+" END_INDENT
+
+" START_INDENT
+make_job = job_start([&shell, &shellcmdflag, make_cmd], {
+ callback: function(MakeProcessOutput, [qfid]),
+ close_cb: function(MakeCloseCb, [qfid]),
+ exit_cb: MakeCompleted,
+ in_io: 'null'
+})
+" END_INDENT
+
+" START_INDENT
+var matching_abbrev: list<dict<string>> = copy(ABBREV)
+ ->filter((_, v: dict<string>): bool =>
+ stridx(v.lhs, word_to_complete) == 0)
+ ->map((_, v: dict<string>) => ({
+ word: v.lhs,
+ menu: AbbrevRhs(v.rhs)->stridx('expand_') >= 0
+ ? AbbrevRhs(v.rhs)->matchstr('.*,\s*''\zs.*\ze'')')
+ : AbbrevRhs(v.rhs)
+ }))
+" END_INDENT
+
+" START_INDENT
+def Func()
+ if true
+ vimgrep /^\C\s*\%(fu\%[nction]\|def\)\s\+/ file
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+setlocal iskeyword+=[
+cword = expand('<cword>')
+" END_INDENT
+
+" START_INDENT
+silent if true
+ echo
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+ sort :^.*[\/]:
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+ d = {
+ }
+ hd =<< trim END
+ ['
+ ]'
+ END
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+ if true
+ var hd =<< trim END
+ if get(b:, 'current_syntax', '')
+ endif
+ END
+ elseif true
+ echo
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+# test for control-flow keyword followed by commented fold marker {{{
+if true
+ echo
+endif #}}}
+" END_INDENT
+
+" START_INDENT
+if winsz == 0|let winsz= ""|endif
+exe "noswapfile ".winsz."wincmd s"
+" END_INDENT
+
+" START_INDENT
+if true
+ if true
+ windo if true | echo | endif
+ augroup Name
+ autocmd WinLeave * if true | eval 1 + 2 | endif
+ augroup END
+ endif
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+ echo ' =<< trim END'
+ ->len()
+endif
+" END_INDENT
+
+" START_INDENT
+function Func()
+ if true
+ if true
+ if true | echo com | endif
+ if true | echo com | endif
+ endif
+ else
+ endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+function Func()
+ if v:true
+ +
+ echo
+ -
+ endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+var matchpairs: string = &matchpairs
+var pairs: dict<list<string>>
+for [opening: string, closing: string]
+ in matchpairs
+ ->split(',')
+ ->map((_, v: string): list<string> => split(v, ':'))
+ pairs[opening] = [escape(opening, '[]'), escape(closing, '[]'), 'nW', 'w$']
+ pairs[closing] = [escape(opening, '[]'), escape(closing, '[]'), 'bnW', 'w0']
+endfor
+" END_INDENT
+
+" START_INDENT
+{
+ echo []
+ + []
+ + [{a: 1,
+ b: 2}]
+}
+" END_INDENT
+
+" START_INDENT
+silent! argdel *
+edit file
+" END_INDENT
diff --git a/runtime/indent/vim.vim b/runtime/indent/vim.vim
index 2ae3658..2f59dfc 100644
--- a/runtime/indent/vim.vim
+++ b/runtime/indent/vim.vim
@@ -1,214 +1,22 @@
-" Vim indent file
-" Language: Vim script
-" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2022 Jun 24
+vim9script
-" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
- finish
+# Vim indent file
+# Language: Vim script
+# Maintainer: Bram Moolenaar <Bram@vim.org>
+# Last Change: 2022 Sep 27
+
+# Only load this indent file when no other was loaded.
+if exists('b:did_indent')
+ finish
endif
-let b:did_indent = 1
-setlocal indentexpr=GetVimIndent()
-setlocal indentkeys+==endif,=enddef,=endfu,=endfor,=endwh,=endtry,=},=else,=cat,=finall,=END,0\\,0=\"\\\
+b:did_indent = true
+b:undo_indent = 'setlocal indentkeys< indentexpr<'
+
+import autoload '../autoload/dist/vimindent.vim'
+
+setlocal indentexpr=vimindent.Expr(v:lnum)
+setlocal indentkeys+==endif,=enddef,=endfu,=endfor,=endwh,=endtry,=},=else,=cat,=finall,=END,0\\
+execute('setlocal indentkeys+=0=\"\\\ ,0=#\\\ ')
setlocal indentkeys-=0#
setlocal indentkeys-=:
-
-let b:undo_indent = "setl indentkeys< indentexpr<"
-
-" Only define the function once.
-if exists("*GetVimIndent")
- finish
-endif
-let s:keepcpo= &cpo
-set cpo&vim
-
-function GetVimIndent()
- let ignorecase_save = &ignorecase
- try
- let &ignorecase = 0
- return GetVimIndentIntern()
- finally
- let &ignorecase = ignorecase_save
- endtry
-endfunc
-
-" Legacy script line continuation and Vim9 script operators that must mean an
-" expression that continues from the previous line.
-let s:lineContPat = '^\s*\(\\\|"\\ \|->\)'
-
-function GetVimIndentIntern()
- " If the current line has line continuation and the previous one too, use
- " the same indent. This does not skip empty lines.
- let cur_text = getline(v:lnum)
- let cur_has_linecont = cur_text =~ s:lineContPat
- if cur_has_linecont && v:lnum > 1 && getline(v:lnum - 1) =~ s:lineContPat
- return indent(v:lnum - 1)
- endif
-
- " Find a non-blank line above the current line.
- let lnum = prevnonblank(v:lnum - 1)
-
- " The previous line, ignoring line continuation
- let prev_text_end = lnum > 0 ? getline(lnum) : ''
-
- " If the current line doesn't start with '\' or '"\ ' and below a line that
- " starts with '\' or '"\ ', use the indent of the line above it.
- if !cur_has_linecont
- while lnum > 0 && getline(lnum) =~ s:lineContPat
- let lnum = lnum - 1
- endwhile
- endif
-
- " At the start of the file use zero indent.
- if lnum == 0
- return 0
- endif
-
- " the start of the previous line, skipping over line continuation
- let prev_text = getline(lnum)
- let found_cont = 0
-
- " Add a 'shiftwidth' after :if, :while, :try, :catch, :finally, :function
- " and :else. Add it three times for a line that starts with '\' or '"\ '
- " after a line that doesn't (or g:vim_indent_cont if it exists).
- let ind = indent(lnum)
-
- " In heredoc indenting works completely differently.
- if has('syntax_items')
- let syn_here = synIDattr(synID(v:lnum, 1, 1), "name")
- if syn_here =~ 'vimLetHereDocStop'
- " End of heredoc: use indent of matching start line
- let lnum = v:lnum - 1
- while lnum > 0
- let attr = synIDattr(synID(lnum, 1, 1), "name")
- if attr != '' && attr !~ 'vimLetHereDoc'
- return indent(lnum)
- endif
- let lnum -= 1
- endwhile
- return 0
- endif
- if syn_here =~ 'vimLetHereDoc'
- if synIDattr(synID(lnum, 1, 1), "name") !~ 'vimLetHereDoc'
- " First line in heredoc: increase indent
- return ind + shiftwidth()
- endif
- " Heredoc continues: no change in indent
- return ind
- endif
- endif
-
- if cur_text =~ s:lineContPat && v:lnum > 1 && prev_text !~ s:lineContPat
- let found_cont = 1
- if exists("g:vim_indent_cont")
- let ind = ind + g:vim_indent_cont
- else
- let ind = ind + shiftwidth() * 3
- endif
- elseif prev_text =~ '^\s*aug\%[roup]\s\+' && prev_text !~ '^\s*aug\%[roup]\s\+[eE][nN][dD]\>'
- let ind = ind + shiftwidth()
- else
- " A line starting with :au does not increment/decrement indent.
- " A { may start a block or a dict. Assume that when a } follows it's a
- " terminated dict.
- " ":function" starts a block but "function(" doesn't.
- if prev_text !~ '^\s*au\%[tocmd]' && prev_text !~ '^\s*{.*}'
- let i = match(prev_text, '\(^\||\)\s*\(export\s\+\)\?\({\|\(if\|wh\%[ile]\|for\|try\|cat\%[ch]\|fina\|finall\%[y]\|def\|el\%[seif]\)\>\|fu\%[nction][! ]\)')
- if i >= 0
- let ind += shiftwidth()
- if strpart(prev_text, i, 1) == '|' && has('syntax_items')
- \ && synIDattr(synID(lnum, i, 1), "name") =~ '\(Comment\|String\|PatSep\)$'
- let ind -= shiftwidth()
- endif
- endif
- endif
- endif
-
- " If the previous line contains an "end" after a pipe, but not in an ":au"
- " command. And not when there is a backslash before the pipe.
- " And when syntax HL is enabled avoid a match inside a string.
- let i = match(prev_text, '[^\\]|\s*\(ene\@!\)')
- if i > 0 && prev_text !~ '^\s*au\%[tocmd]'
- if !has('syntax_items') || synIDattr(synID(lnum, i + 2, 1), "name") !~ '\(Comment\|String\)$'
- let ind = ind - shiftwidth()
- endif
- endif
-
- " For a line starting with "}" find the matching "{". Align with that line,
- " it is either the matching block start or dictionary start.
- " Use the mapped "%" from matchit to find the match, otherwise we may match
- " a { inside a comment or string.
- if cur_text =~ '^\s*}'
- if maparg('%') != ''
- exe v:lnum
- silent! normal %
- if line('.') < v:lnum
- let ind = indent('.')
- endif
- else
- " todo: use searchpair() to find a match
- endif
- endif
-
- " Look back for a line to align with
- while lnum > 1
- " Below a line starting with "}" find the matching "{".
- if prev_text =~ '^\s*}'
- if maparg('%') != ''
- exe lnum
- silent! normal %
- if line('.') < lnum
- let lnum = line('.')
- let ind = indent(lnum)
- let prev_text = getline(lnum)
- else
- break
- endif
- else
- " todo: use searchpair() to find a match
- break
- endif
- elseif prev_text =~ s:lineContPat
- " looks like a continuation like, go back one line
- let lnum = lnum - 1
- let ind = indent(lnum)
- let prev_text = getline(lnum)
- else
- break
- endif
- endwhile
-
- " Below a line starting with "]" we must be below the end of a list.
- " Include a "}" and "},} in case a dictionary ends too.
- if prev_text_end =~ '^\s*\(},\=\s*\)\=]'
- let ind = ind - shiftwidth()
- endif
-
- let ends_in_comment = has('syntax_items')
- \ && synIDattr(synID(lnum, len(getline(lnum)), 1), "name") =~ '\(Comment\|String\)$'
-
- " A line ending in "{" or "[" is most likely the start of a dict/list literal,
- " indent the next line more. Not for a continuation line or {{{.
- if !ends_in_comment && prev_text_end =~ '\s[{[]\s*$' && !found_cont
- let ind = ind + shiftwidth()
- endif
-
- " Subtract a 'shiftwidth' on a :endif, :endwhile, :endfor, :catch, :finally,
- " :endtry, :endfun, :enddef, :else and :augroup END.
- " Although ":en" would be enough only match short command names as in
- " 'indentkeys'.
- if cur_text =~ '^\s*\(endif\|endwh\|endfor\|endtry\|endfu\|enddef\|cat\|finall\|else\|aug\%[roup]\s\+[eE][nN][dD]\)'
- let ind = ind - shiftwidth()
- if ind < 0
- let ind = 0
- endif
- endif
-
- return ind
-endfunction
-
-let &cpo = s:keepcpo
-unlet s:keepcpo
-
-" vim:sw=2
diff --git a/runtime/indent/vue.vim b/runtime/indent/vue.vim
new file mode 100644
index 0000000..7ff623b
--- /dev/null
+++ b/runtime/indent/vue.vim
@@ -0,0 +1,12 @@
+" Vim indent file placeholder
+" Language: Vue
+" Maintainer: None, please volunteer if you have a real Vue indent script
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+" Html comes closest
+runtime! indent/html.vim