aboutsummaryrefslogtreecommitdiff
path: root/runtime/indent
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/indent')
-rw-r--r--runtime/indent/chatito.vim32
-rw-r--r--runtime/indent/erlang.vim143
-rw-r--r--runtime/indent/gyp.vim7
-rw-r--r--runtime/indent/hare.vim138
-rw-r--r--runtime/indent/json.vim3
-rw-r--r--runtime/indent/lua.vim3
-rw-r--r--runtime/indent/nginx.vim77
-rw-r--r--runtime/indent/obse.vim55
-rw-r--r--runtime/indent/racket.vim60
-rw-r--r--runtime/indent/solidity.vim442
-rw-r--r--runtime/indent/testdir/python.in18
-rw-r--r--runtime/indent/testdir/python.ok18
-rw-r--r--runtime/indent/testdir/runtest.vim15
-rw-r--r--runtime/indent/testdir/vb.in134
-rw-r--r--runtime/indent/testdir/vb.ok134
-rw-r--r--runtime/indent/testdir/vim.in7
-rw-r--r--runtime/indent/testdir/vim.ok7
-rw-r--r--runtime/indent/vb.vim105
-rw-r--r--runtime/indent/vim.vim44
-rw-r--r--runtime/indent/vue.vim14
-rw-r--r--runtime/indent/yaml.vim10
-rw-r--r--runtime/indent/zig.vim80
22 files changed, 1457 insertions, 89 deletions
diff --git a/runtime/indent/chatito.vim b/runtime/indent/chatito.vim
new file mode 100644
index 0000000000..1ff5e9e3f1
--- /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/erlang.vim b/runtime/indent/erlang.vim
index 4e7bf4ef4d..7aa38587a6 100644
--- a/runtime/indent/erlang.vim
+++ b/runtime/indent/erlang.vim
@@ -4,7 +4,7 @@
" Contributors: Edwin Fine <efine145_nospam01 at usa dot net>
" Pawel 'kTT' Salata <rockplayer.pl@gmail.com>
" Ricardo Catalinas Jiménez <jimenezrick@gmail.com>
-" Last Update: 2020-Jun-11
+" Last Update: 2022-Sep-06
" License: Vim license
" URL: https://github.com/vim-erlang/vim-erlang-runtime
@@ -30,7 +30,9 @@ else
endif
setlocal indentexpr=ErlangIndent()
-setlocal indentkeys+=0=end,0=of,0=catch,0=after,0=when,0=),0=],0=},0=>>
+setlocal indentkeys+=0=end,0=of,0=catch,0=after,0=else,0=when,0=),0=],0=},0=>>
+
+let b:undo_indent = "setl inde< indk<"
" Only define the functions once
if exists("*ErlangIndent")
@@ -235,8 +237,8 @@ function! s:GetTokensFromLine(line, string_continuation, atom_continuation,
" Two-character tokens
elseif i + 1 < linelen &&
- \ index(['->', '<<', '>>', '||', '==', '/=', '=<', '>=', '++', '--',
- \ '::'],
+ \ index(['->', '<<', '>>', '||', '==', '/=', '=<', '>=', '?=', '++',
+ \ '--', '::'],
\ a:line[i : i + 1]) != -1
call add(indtokens, [a:line[i : i + 1], vcol, i])
let next_i = i + 2
@@ -558,8 +560,8 @@ function! s:IsCatchStandalone(lnum, i)
let is_standalone = 0
elseif prev_token =~# '[a-z]'
if index(['after', 'and', 'andalso', 'band', 'begin', 'bnot', 'bor', 'bsl',
- \ 'bsr', 'bxor', 'case', 'catch', 'div', 'not', 'or', 'orelse',
- \ 'rem', 'try', 'xor'], prev_token) != -1
+ \ 'bsr', 'bxor', 'case', 'catch', 'div', 'maybe', 'not', 'or',
+ \ 'orelse', 'rem', 'try', 'xor'], prev_token) != -1
" If catch is after these keywords, it is standalone
let is_standalone = 1
else
@@ -568,7 +570,7 @@ function! s:IsCatchStandalone(lnum, i)
"
" Keywords:
" - may precede 'catch': end
- " - may not precede 'catch': fun if of receive when
+ " - may not precede 'catch': else fun if of receive when
" - unused: cond let query
let is_standalone = 0
endif
@@ -577,7 +579,7 @@ function! s:IsCatchStandalone(lnum, i)
let is_standalone = 0
else
" This 'else' branch includes the following tokens:
- " -> == /= =< < >= > =:= =/= + - * / ++ -- :: < > ; ( [ { ? = ! . |
+ " -> == /= =< < >= > ?= =:= =/= + - * / ++ -- :: < > ; ( [ { ? = ! . |
let is_standalone = 1
endif
@@ -590,6 +592,7 @@ endfunction
" Purpose:
" This function is called when a begin-type element ('begin', 'case',
" '[', '<<', etc.) is found. It asks the caller to return if the stack
+" if already empty.
" Parameters:
" stack: [token]
" token: string
@@ -758,7 +761,7 @@ endfunction
function! s:SearchEndPair(lnum, curr_col)
return s:SearchPair(
\ a:lnum, a:curr_col,
- \ '\C\<\%(case\|try\|begin\|receive\|if\)\>\|' .
+ \ '\C\<\%(case\|try\|begin\|receive\|if\|maybe\)\>\|' .
\ '\<fun\>\%(\s\|\n\|%.*$\|[A-Z_@][a-zA-Z_@]*\)*(',
\ '',
\ '\<end\>')
@@ -847,6 +850,7 @@ function! s:ErlangCalcIndent2(lnum, stack)
if ret | return res | endif
" case EXPR of BRANCHES end
+ " if BRANCHES end
" try EXPR catch BRANCHES end
" try EXPR after BODY end
" try EXPR catch BRANCHES after BODY end
@@ -855,15 +859,17 @@ function! s:ErlangCalcIndent2(lnum, stack)
" try EXPR of BRANCHES catch BRANCHES after BODY end
" receive BRANCHES end
" receive BRANCHES after BRANCHES end
+ " maybe EXPR end
+ " maybe EXPR else BRANCHES end
" This branch is not Emacs-compatible
- elseif (index(['of', 'receive', 'after', 'if'], token) != -1 ||
+ elseif (index(['of', 'receive', 'after', 'if', 'else'], token) != -1 ||
\ (token ==# 'catch' && !s:IsCatchStandalone(lnum, i))) &&
\ !last_token_of_line &&
\ (empty(stack) || stack ==# ['when'] || stack ==# ['->'] ||
\ stack ==# ['->', ';'])
- " If we are after of/receive, but these are not the last
+ " If we are after of/receive/etc, but these are not the last
" tokens of the line, we want to indent like this:
"
" % stack == []
@@ -889,21 +895,21 @@ function! s:ErlangCalcIndent2(lnum, stack)
" stack = ['when'] => LTI is a guard
if empty(stack) || stack == ['->', ';']
call s:Log(' LTI is in a condition after ' .
- \'"of/receive/after/if/catch" -> return')
+ \'"of/receive/after/if/else/catch" -> return')
return stored_vcol
elseif stack == ['->']
call s:Log(' LTI is in a branch after ' .
- \'"of/receive/after/if/catch" -> return')
+ \'"of/receive/after/if/else/catch" -> return')
return stored_vcol + shiftwidth()
elseif stack == ['when']
call s:Log(' LTI is in a guard after ' .
- \'"of/receive/after/if/catch" -> return')
+ \'"of/receive/after/if/else/catch" -> return')
return stored_vcol + shiftwidth()
else
return s:UnexpectedToken(token, stack)
endif
- elseif index(['case', 'if', 'try', 'receive'], token) != -1
+ elseif index(['case', 'if', 'try', 'receive', 'maybe'], token) != -1
" stack = [] => LTI is a condition
" stack = ['->'] => LTI is a branch
@@ -913,45 +919,47 @@ function! s:ErlangCalcIndent2(lnum, stack)
" pass
elseif (token ==# 'case' && stack[0] ==# 'of') ||
\ (token ==# 'if') ||
+ \ (token ==# 'maybe' && stack[0] ==# 'else') ||
\ (token ==# 'try' && (stack[0] ==# 'of' ||
\ stack[0] ==# 'catch' ||
\ stack[0] ==# 'after')) ||
\ (token ==# 'receive')
" From the indentation point of view, the keyword
- " (of/catch/after/end) before the LTI is what counts, so
+ " (of/catch/after/else/end) before the LTI is what counts, so
" when we reached these tokens, and the stack already had
- " a catch/after/end, we didn't modify it.
+ " a catch/after/else/end, we didn't modify it.
"
- " This way when we reach case/try/receive (i.e. now),
- " there is at most one of/catch/after/end token in the
+ " This way when we reach case/try/receive/maybe (i.e. now),
+ " there is at most one of/catch/after/else/end token in the
" stack.
if token ==# 'case' || token ==# 'try' ||
- \ (token ==# 'receive' && stack[0] ==# 'after')
+ \ (token ==# 'receive' && stack[0] ==# 'after') ||
+ \ (token ==# 'maybe' && stack[0] ==# 'else')
call s:Pop(stack)
endif
if empty(stack)
call s:Log(' LTI is in a condition; matching ' .
- \'"case/if/try/receive" found')
+ \'"case/if/try/receive/maybe" found')
let stored_vcol = curr_vcol + shiftwidth()
elseif stack[0] ==# 'align_to_begin_element'
call s:Pop(stack)
let stored_vcol = curr_vcol
elseif len(stack) > 1 && stack[0] ==# '->' && stack[1] ==# ';'
call s:Log(' LTI is in a condition; matching ' .
- \'"case/if/try/receive" found')
+ \'"case/if/try/receive/maybe" found')
call s:Pop(stack)
call s:Pop(stack)
let stored_vcol = curr_vcol + shiftwidth()
elseif stack[0] ==# '->'
call s:Log(' LTI is in a branch; matching ' .
- \'"case/if/try/receive" found')
+ \'"case/if/try/receive/maybe" found')
call s:Pop(stack)
let stored_vcol = curr_vcol + 2 * shiftwidth()
elseif stack[0] ==# 'when'
call s:Log(' LTI is in a guard; matching ' .
- \'"case/if/try/receive" found')
+ \'"case/if/try/receive/maybe" found')
call s:Pop(stack)
let stored_vcol = curr_vcol + 2 * shiftwidth() + 2
endif
@@ -1213,7 +1221,7 @@ function! s:ErlangCalcIndent2(lnum, stack)
if empty(stack)
call s:Push(stack, ';')
- elseif index([';', '->', 'when', 'end', 'after', 'catch'],
+ elseif index([';', '->', 'when', 'end', 'after', 'catch', 'else'],
\stack[0]) != -1
" Pass:
"
@@ -1223,10 +1231,10 @@ function! s:ErlangCalcIndent2(lnum, stack)
" should keep that, because they signify the type of the
" LTI (branch, condition or guard).
" - From the indentation point of view, the keyword
- " (of/catch/after/end) before the LTI is what counts, so
- " if the stack already has a catch/after/end, we don't
- " modify it. This way when we reach case/try/receive,
- " there will be at most one of/catch/after/end token in
+ " (of/catch/after/else/end) before the LTI is what counts, so
+ " if the stack already has a catch/after/else/end, we don't
+ " modify it. This way when we reach case/try/receive/maybe,
+ " there will be at most one of/catch/after/else/end token in
" the stack.
else
return s:UnexpectedToken(token, stack)
@@ -1242,7 +1250,8 @@ function! s:ErlangCalcIndent2(lnum, stack)
" stack = ['->'] -> LTI is a condition
" stack = ['->', ';'] -> LTI is a branch
call s:Push(stack, '->')
- elseif index(['->', 'when', 'end', 'after', 'catch'], stack[0]) != -1
+ elseif index(['->', 'when', 'end', 'after', 'catch', 'else'],
+ \stack[0]) != -1
" Pass:
"
" - If the stack top is another '->', then one '->' is
@@ -1250,10 +1259,10 @@ function! s:ErlangCalcIndent2(lnum, stack)
" - If the stack top is a 'when', then we should keep
" that, because this signifies that LTI is a in a guard.
" - From the indentation point of view, the keyword
- " (of/catch/after/end) before the LTI is what counts, so
- " if the stack already has a catch/after/end, we don't
- " modify it. This way when we reach case/try/receive,
- " there will be at most one of/catch/after/end token in
+ " (of/catch/after/else/end) before the LTI is what counts, so
+ " if the stack already has a catch/after/else/end, we don't
+ " modify it. This way when we reach case/try/receive/maybe,
+ " there will be at most one of/catch/after/else/end token in
" the stack.
else
return s:UnexpectedToken(token, stack)
@@ -1283,7 +1292,8 @@ function! s:ErlangCalcIndent2(lnum, stack)
" LTI
call s:Push(stack, token)
endif
- elseif index(['->', 'when', 'end', 'after', 'catch'], stack[0]) != -1
+ elseif index(['->', 'when', 'end', 'after', 'catch', 'else'],
+ \stack[0]) != -1
" Pass:
" - If the stack top is another 'when', then one 'when' is
" enough.
@@ -1291,21 +1301,63 @@ function! s:ErlangCalcIndent2(lnum, stack)
" should keep that, because they signify the type of the
" LTI (branch, condition or guard).
" - From the indentation point of view, the keyword
- " (of/catch/after/end) before the LTI is what counts, so
- " if the stack already has a catch/after/end, we don't
- " modify it. This way when we reach case/try/receive,
- " there will be at most one of/catch/after/end token in
+ " (of/catch/after/else/end) before the LTI is what counts, so
+ " if the stack already has a catch/after/else/end, we don't
+ " modify it. This way when we reach case/try/receive/maybe,
+ " there will be at most one of/catch/after/else/end token in
" the stack.
else
return s:UnexpectedToken(token, stack)
endif
- elseif token ==# 'of' || token ==# 'after' ||
+ elseif token ==# 'of' || token ==# 'after' || token ==# 'else' ||
\ (token ==# 'catch' && !s:IsCatchStandalone(lnum, i))
- if token ==# 'after'
- " If LTI is between an 'after' and the corresponding
- " 'end', then let's return
+ if token ==# 'after' || token ==# 'else'
+ " If LTI is between an after/else and the corresponding 'end', then
+ " let's return because calculating the indentation based on
+ " after/else is enough.
+ "
+ " Example:
+ " receive A after
+ " LTI
+ " maybe A else
+ " LTI
+ "
+ " Note about Emacs compabitility {{{
+ "
+ " It would be fine to indent the examples above the following way:
+ "
+ " receive A after
+ " LTI
+ " maybe A else
+ " LTI
+ "
+ " We intend it the way above because that is how Emacs does it.
+ " Also, this is a bit faster.
+ "
+ " We are still not 100% Emacs compatible because of placing the
+ " 'end' after the indented blocks.
+ "
+ " Emacs example:
+ "
+ " receive A after
+ " LTI
+ " end,
+ " maybe A else
+ " LTI
+ " end % Yes, it's here (in OTP 25.0, might change
+ " % later)
+ "
+ " vim-erlang example:
+ "
+ " receive A after
+ " LTI
+ " end,
+ " maybe A else
+ " LTI
+ " end
+ " }}}
let [ret, res] = s:BeginElementFoundIfEmpty(stack, token, curr_vcol,
\stored_vcol, shiftwidth())
if ret | return res | endif
@@ -1313,7 +1365,8 @@ function! s:ErlangCalcIndent2(lnum, stack)
if empty(stack) || stack[0] ==# '->' || stack[0] ==# 'when'
call s:Push(stack, token)
- elseif stack[0] ==# 'catch' || stack[0] ==# 'after' || stack[0] ==# 'end'
+ elseif stack[0] ==# 'catch' || stack[0] ==# 'after' ||
+ \stack[0] ==# 'else' || stack[0] ==# 'end'
" Pass: From the indentation point of view, the keyword
" (of/catch/after/end) before the LTI is what counts, so
" if the stack already has a catch/after/end, we don't
@@ -1403,7 +1456,7 @@ function! ErlangIndent()
endif
let ml = matchlist(currline,
- \'^\(\s*\)\(\%(end\|of\|catch\|after\)\>\|[)\]}]\|>>\)')
+ \'^\(\s*\)\(\%(end\|of\|catch\|after\|else\)\>\|[)\]}]\|>>\)')
" If the line has a special beginning, but not a standalone catch
if !empty(ml) && !(ml[2] ==# 'catch' && s:IsCatchStandalone(v:lnum, 0))
diff --git a/runtime/indent/gyp.vim b/runtime/indent/gyp.vim
new file mode 100644
index 0000000000..c3980ac568
--- /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 0000000000..bc4fea4e61
--- /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/json.vim b/runtime/indent/json.vim
index 09c7d7a85a..510f7e8f42 100644
--- a/runtime/indent/json.vim
+++ b/runtime/indent/json.vim
@@ -3,6 +3,7 @@
" Maintainer: Eli Parra <eli@elzr.com> https://github.com/elzr/vim-json
" Last Change: 2020 Aug 30
" https://github.com/jakar/vim-json/commit/20b650e22aa750c4ab6a66aa646bdd95d7cd548a#diff-e81fc111b2052e306d126bd9989f7b7c
+" 2022 Sep 07: b:undo_indent added by Doug Kearns
" Original Author: Rogerz Zhang <rogerz.zhang at gmail.com> http://github.com/rogerz/vim-json
" Acknowledgement: Based off of vim-javascript maintained by Darrick Wiebe
" http://www.vim.org/scripts/script.php?script_id=2765
@@ -22,6 +23,8 @@ setlocal nosmartindent
setlocal indentexpr=GetJSONIndent(v:lnum)
setlocal indentkeys=0{,0},0),0[,0],!^F,o,O,e
+let b:undo_indent = "setl inde< indk< si<"
+
" Only define the function once.
if exists("*GetJSONIndent")
finish
diff --git a/runtime/indent/lua.vim b/runtime/indent/lua.vim
index 604cd333c9..0d1f934a03 100644
--- a/runtime/indent/lua.vim
+++ b/runtime/indent/lua.vim
@@ -3,6 +3,7 @@
" Maintainer: Marcus Aurelius Farias <marcus.cf 'at' bol.com.br>
" First Author: Max Ischenko <mfi 'at' ukr.net>
" Last Change: 2017 Jun 13
+" 2022 Sep 07: b:undo_indent added by Doug Kearns
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
@@ -18,6 +19,8 @@ setlocal indentkeys+=0=end,0=until
setlocal autoindent
+let b:undo_indent = "setlocal autoindent< indentexpr< indentkeys<"
+
" Only define the function once.
if exists("*GetLuaIndent")
finish
diff --git a/runtime/indent/nginx.vim b/runtime/indent/nginx.vim
index 8cef7662e0..65506099f4 100644
--- a/runtime/indent/nginx.vim
+++ b/runtime/indent/nginx.vim
@@ -1,19 +1,78 @@
" Vim indent file
" Language: nginx.conf
" Maintainer: Chris Aumann <me@chr4.org>
-" Last Change: 2022 Apr 06
+" Last Change: 2022 Dec 01
-if exists("b:did_indent")
- finish
+" Only load this indent file when no other was loaded.
+if exists('b:did_indent')
+ finish
endif
let b:did_indent = 1
-setlocal indentexpr=
+setlocal indentexpr=GetNginxIndent()
-" cindent actually works for nginx' simple file structure
-setlocal cindent
+setlocal indentkeys=0{,0},0#,!^F,o,O
-" Just make sure that the comments are not reset as defs would be.
-setlocal cinkeys-=0#
+let b:undo_indent = 'setl inde< indk<'
-let b:undo_indent = "setl inde< cin< cink<"
+" Only define the function once.
+if exists('*GetNginxIndent')
+ finish
+endif
+
+function GetNginxIndent() abort
+ let plnum = s:PrevNotAsBlank(v:lnum - 1)
+
+ " Hit the start of the file, use zero indent.
+ if plnum == 0
+ return 0
+ endif
+
+ let ind = indent(plnum)
+
+ " Add a 'shiftwidth' after '{'
+ if s:AsEndWith(getline(plnum), '{')
+ let ind = ind + shiftwidth()
+ end
+
+ " Subtract a 'shiftwidth' on '}'
+ " This is the part that requires 'indentkeys'.
+ if getline(v:lnum) =~ '^\s*}'
+ let ind = ind - shiftwidth()
+ endif
+
+ let pplnum = s:PrevNotAsBlank(plnum - 1)
+
+ if s:IsLineContinuation(plnum)
+ if !s:IsLineContinuation(pplnum)
+ let ind = ind + shiftwidth()
+ end
+ else
+ if s:IsLineContinuation(pplnum)
+ let ind = ind - shiftwidth()
+ end
+ endif
+
+ return ind
+endfunction
+
+" Find the first line at or above {lnum} that is non-blank and not a comment.
+function s:PrevNotAsBlank(lnum) abort
+ let lnum = prevnonblank(a:lnum)
+ while lnum > 0
+ if getline(lnum) !~ '^\s*#'
+ break
+ endif
+ let lnum = prevnonblank(lnum - 1)
+ endwhile
+ return lnum
+endfunction
+
+" Check whether {line} ends with {pat}, ignoring trailing comments.
+function s:AsEndWith(line, pat) abort
+ return a:line =~ a:pat . '\m\s*\%(#.*\)\?$'
+endfunction
+
+function s:IsLineContinuation(lnum) abort
+ return a:lnum > 0 && !s:AsEndWith(getline(a:lnum), '[;{}]')
+endfunction
diff --git a/runtime/indent/obse.vim b/runtime/indent/obse.vim
new file mode 100644
index 0000000000..6603723dba
--- /dev/null
+++ b/runtime/indent/obse.vim
@@ -0,0 +1,55 @@
+" Vim indent file
+" Language: Oblivion Language (obl)
+" Original Creator: Kat <katisntgood@gmail.com>
+" Maintainer: Kat <katisntgood@gmail.com>
+" Created: 01 November 2021
+" Last Change: 13 November 2022
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+let b:undo_indent = 'setlocal indentkeys< indentexpr<'
+
+setlocal indentexpr=GetOblIndent()
+setlocal indentkeys+==~endif,=~else,=~loop,=~end
+
+if exists("*GetOblIndent")
+ finish
+endif
+let s:keepcpo = &cpo
+set cpo&vim
+
+let s:SKIP_LINES = '^\s*\(;.*\)'
+function! GetOblIndent()
+
+ let lnum = prevnonblank(v:lnum - 1)
+ let cur_text = getline(v:lnum)
+ if lnum == 0
+ return 0
+ endif
+ let prev_text = getline(lnum)
+ let found_cont = 0
+ let ind = indent(lnum)
+
+ " indent next line on start terms
+ let i = match(prev_text, '\c^\s*\(\s\+\)\?\(\(if\|while\|foreach\|begin\|else\%[if]\)\>\)')
+ if i >= 0
+ let ind += shiftwidth()
+ if strpart(prev_text, i, 1) == '|' && has('syntax_items')
+ \ && synIDattr(synID(lnum, i, 1), "name") =~ '\(Comment\|String\)$'
+ let ind -= shiftwidth()
+ endif
+ endif
+ " indent current line on end/else terms
+ if cur_text =~ '\c^\s*\(\s\+\)\?\(\(loop\|endif\|else\%[if]\)\>\)'
+ let ind = ind - shiftwidth()
+ " if we are at a begin block just go to column 0
+ elseif cur_text =~ '\c^\s*\(\s\+\)\?\(\(begin\|end\)\>\)'
+ let ind = 0
+ endif
+ return ind
+endfunction
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
diff --git a/runtime/indent/racket.vim b/runtime/indent/racket.vim
new file mode 100644
index 0000000000..93bd38fbff
--- /dev/null
+++ b/runtime/indent/racket.vim
@@ -0,0 +1,60 @@
+" Vim indent file
+" Language: Racket
+" Maintainer: D. Ben Knoble <ben.knoble+github@gmail.com>
+" Previous Maintainer: Will Langstroth <will@langstroth.com>
+" URL: https://github.com/benknoble/vim-racket
+" Last Change: 2022 Aug 12
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal lisp autoindent nosmartindent
+
+setlocal lispwords+=module,module*,module+,parameterize,let-values,let*-values,letrec-values,local
+setlocal lispwords+=define/contract
+setlocal lispwords+=λ
+setlocal lispwords+=with-handlers
+setlocal lispwords+=define-values,opt-lambda,case-lambda,syntax-rules,with-syntax,syntax-case,syntax-parse
+setlocal lispwords+=define-for-syntax,define-syntax-parser,define-syntax-parse-rule,define-syntax-class,define-splicing-syntax-class
+setlocal lispwords+=define-signature,unit,unit/sig,compund-unit/sig,define-values/invoke-unit/sig
+setlocal lispwords+=define-opt/c,define-syntax-rule
+setlocal lispwords+=define-test-suite
+setlocal lispwords+=struct
+setlocal lispwords+=with-input-from-file,with-output-to-file
+
+" Racket OOP
+" TODO missing a lot of define-like forms here (e.g., define/augment, etc.)
+setlocal lispwords+=class,class*,mixin,interface,class/derived
+setlocal lispwords+=define/public,define/pubment,define/public-final
+setlocal lispwords+=define/override,define/overment,define/override-final
+setlocal lispwords+=define/augment,define/augride,define/augment-final
+setlocal lispwords+=define/private
+
+" kanren
+setlocal lispwords+=fresh,run,run*,project,conde,condu
+
+" loops
+setlocal lispwords+=for,for/list,for/fold,for*,for*/list,for*/fold,for/or,for/and,for*/or,for*/and
+setlocal lispwords+=for/hash,for/hasheq,for/hasheqv,for/sum,for/flvector,for*/flvector,for/vector,for*/vector,for*/sum,for*/hash,for*/hasheq,for*/hasheqv
+setlocal lispwords+=for/async
+setlocal lispwords+=for/set,for*/set
+setlocal lispwords+=for/first,for*/first
+
+setlocal lispwords+=match,match*,match/values,define/match,match-lambda,match-lambda*,match-lambda**
+setlocal lispwords+=match-let,match-let*,match-let-values,match-let*-values
+setlocal lispwords+=match-letrec,match-define,match-define-values
+
+setlocal lispwords+=let/cc,let/ec
+
+" qi
+setlocal lispwords+=define-flow,define-switch,flow-lambda,switch-lambda,on,switch,π,λ01
+setlocal lispwords+=define-qi-syntax,define-qi-syntax-parser,define-qi-syntax-rule
+
+" gui-easy
+setlocal lispwords+=if-view,case-view,cond-view,list-view,dyn-view
+setlocal lispwords+=case/dep
+setlocal lispwords+=define/obs
+
+let b:undo_indent = "setlocal lisp< ai< si< lw<"
diff --git a/runtime/indent/solidity.vim b/runtime/indent/solidity.vim
new file mode 100644
index 0000000000..caed726c0a
--- /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/python.in b/runtime/indent/testdir/python.in
index e6f05f22bc..57719ee430 100644
--- a/runtime/indent/testdir/python.in
+++ b/runtime/indent/testdir/python.in
@@ -1,6 +1,24 @@
# vim: set ft=python sw=4 et:
# START_INDENT
+dict = {
+'a': 1,
+'b': 2,
+'c': 3,
+}
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let [g:python_indent.open_paren, g:python_indent.closed_paren_align_last_line] = ['shiftwidth()', v:false]
+dict = {
+'a': 1,
+'b': 2,
+'c': 3,
+}
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:python_indent.open_paren = 'shiftwidth() * 2'
# INDENT_EXE syntax match pythonFoldMarkers /{{{\d*/ contained containedin=pythonComment
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {{{1
diff --git a/runtime/indent/testdir/python.ok b/runtime/indent/testdir/python.ok
index df3de8f186..f5ebbc2285 100644
--- a/runtime/indent/testdir/python.ok
+++ b/runtime/indent/testdir/python.ok
@@ -1,6 +1,24 @@
# vim: set ft=python sw=4 et:
# START_INDENT
+dict = {
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+ }
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let [g:python_indent.open_paren, g:python_indent.closed_paren_align_last_line] = ['shiftwidth()', v:false]
+dict = {
+ 'a': 1,
+ 'b': 2,
+ 'c': 3,
+}
+# END_INDENT
+
+# START_INDENT
+# INDENT_EXE let g:python_indent.open_paren = 'shiftwidth() * 2'
# INDENT_EXE syntax match pythonFoldMarkers /{{{\d*/ contained containedin=pythonComment
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx {{{1
diff --git a/runtime/indent/testdir/runtest.vim b/runtime/indent/testdir/runtest.vim
index 6bbd33cacd..fa4e16e381 100644
--- a/runtime/indent/testdir/runtest.vim
+++ b/runtime/indent/testdir/runtest.vim
@@ -11,6 +11,7 @@ syn on
set nowrapscan
set report=9999
set modeline
+set debug=throw
au! SwapExists * call HandleSwapExists()
func HandleSwapExists()
@@ -84,7 +85,12 @@ for fname in glob('testdir/*.in', 1, 1)
exe start + 1
if pattern == ''
- exe 'normal =' . (end - 1) . 'G'
+ try
+ exe 'normal =' . (end - 1) . 'G'
+ catch
+ call append(indent_at, 'ERROR: ' . v:exception)
+ let failed = 1
+ endtry
else
let lnum = search(pattern)
if lnum <= 0
@@ -99,7 +105,12 @@ for fname in glob('testdir/*.in', 1, 1)
else
exe lnum - 1
endif
- normal ==
+ try
+ normal ==
+ catch
+ call append(indent_at, 'ERROR: ' . v:exception)
+ let failed = 1
+ endtry
endif
endif
endwhile
diff --git a/runtime/indent/testdir/vb.in b/runtime/indent/testdir/vb.in
new file mode 100644
index 0000000000..1653ae6f80
--- /dev/null
+++ b/runtime/indent/testdir/vb.in
@@ -0,0 +1,134 @@
+' vim: filetype=vb shiftwidth=4 expandtab
+'
+' START_INDENT
+Public Type GEmployeeRecord ' Create user-defined type.
+ID As Integer ' Define elements of data type.
+Name As String * 20
+Address As String * 30
+Phone As Long
+HireDate As Date
+End Type
+
+Public Enum InterfaceColors
+icMistyRose = &HE1E4FF&
+icSlateGray = &H908070&
+icDodgerBlue = &HFF901E&
+icDeepSkyBlue = &HFFBF00&
+icSpringGreen = &H7FFF00&
+icForestGreen = &H228B22&
+icGoldenrod = &H20A5DA&
+icFirebrick = &H2222B2&
+End Enum
+
+Enum SecurityLevel
+IllegalEntry = -1
+SecurityLevel1 = 0
+SecurityLevel2 = 1
+End Enum
+
+Public Function TestConditional (number As Integer, ext As String) As Boolean
+Dim inRange As Boolean
+
+Select Case number
+Case <= 0
+inRange = False
+Case > 10
+inRange = False
+Case Else
+inRange = True
+End Select
+
+' This is a special case identified in the indent script.
+Select Case number
+End Select
+
+If ext = ".xlm" Then
+If inRange Then
+TestConditional = True
+Else
+TestConditional = False
+End If
+ElseIf ext = ".xlsx" Then
+If inRange Then
+TestConditional = False
+Else
+TestConditional = True
+End If
+Else
+TestConditional = False
+End If
+End Function
+
+Private Sub TestIterators (lLimit As Integer, uLimit As Integer)
+Dim a() As Variant
+Dim elmt As Variant
+Dim found As Boolean
+Dim indx As Integer
+Const specialValue As Integer = 5
+
+If uLimit < lLimit Then
+Exit Sub
+End If
+
+ReDim a(lLimit To uLimit)
+For indx=lLimit To Ulimit
+a(indx) = 2 * indx
+Next indx
+
+found = False
+For Each elmt in a
+If elmt = specialValue Then
+found = True
+End If
+Next elmt
+
+If found then
+indx = uLimit
+Do While indx >= lLimit
+indx = indx - 1
+Loop
+End If
+
+End Sub
+
+Public Sub TestMultiline (cellAddr As String, rowNbr As Long)
+Dim rng As Range
+
+Set rng = Range(cellAddr)
+With rng
+.Cells(1,1).Value = _
+"Line 1 of multiline string; " & _
+"Line 2 of multiline string; " & _
+"Line 3 of multiline string"
+End With
+
+' The following lines have whitespace after the underscore character
+' and therefore do not form a valid multiline statement. The indent
+' script correctly treats them as four single line statements contrary
+' to the author's obvious indent.
+rng..Cells(1,1).Value = _
+"Line 1 of multiline string; " & _
+"Line 2 of multiline string; " & _
+"Line 3 of multiline string"
+
+End Sub
+
+Private Sub TestStmtLabel()
+GoTo stmtLabel
+
+' Statement labels are never indented
+stmtLabel:
+
+End Sub
+
+Sub TestTypeKeyword()
+Type EmployeeRecord ' Create user-defined type.
+ID As Integer ' Define elements of data type.
+Name As String * 20
+Address As String * 30
+Phone As Long
+HireDate As Date
+End Type
+Dim varType As EmployeeRecord
+End Sub
+' END_INDENT
diff --git a/runtime/indent/testdir/vb.ok b/runtime/indent/testdir/vb.ok
new file mode 100644
index 0000000000..143c688708
--- /dev/null
+++ b/runtime/indent/testdir/vb.ok
@@ -0,0 +1,134 @@
+' vim: filetype=vb shiftwidth=4 expandtab
+'
+' START_INDENT
+Public Type GEmployeeRecord ' Create user-defined type.
+ ID As Integer ' Define elements of data type.
+ Name As String * 20
+ Address As String * 30
+ Phone As Long
+ HireDate As Date
+End Type
+
+Public Enum InterfaceColors
+ icMistyRose = &HE1E4FF&
+ icSlateGray = &H908070&
+ icDodgerBlue = &HFF901E&
+ icDeepSkyBlue = &HFFBF00&
+ icSpringGreen = &H7FFF00&
+ icForestGreen = &H228B22&
+ icGoldenrod = &H20A5DA&
+ icFirebrick = &H2222B2&
+End Enum
+
+Enum SecurityLevel
+ IllegalEntry = -1
+ SecurityLevel1 = 0
+ SecurityLevel2 = 1
+End Enum
+
+Public Function TestConditional (number As Integer, ext As String) As Boolean
+ Dim inRange As Boolean
+
+ Select Case number
+ Case <= 0
+ inRange = False
+ Case > 10
+ inRange = False
+ Case Else
+ inRange = True
+ End Select
+
+ ' This is a special case identified in the indent script.
+ Select Case number
+ End Select
+
+ If ext = ".xlm" Then
+ If inRange Then
+ TestConditional = True
+ Else
+ TestConditional = False
+ End If
+ ElseIf ext = ".xlsx" Then
+ If inRange Then
+ TestConditional = False
+ Else
+ TestConditional = True
+ End If
+ Else
+ TestConditional = False
+ End If
+End Function
+
+Private Sub TestIterators (lLimit As Integer, uLimit As Integer)
+ Dim a() As Variant
+ Dim elmt As Variant
+ Dim found As Boolean
+ Dim indx As Integer
+ Const specialValue As Integer = 5
+
+ If uLimit < lLimit Then
+ Exit Sub
+ End If
+
+ ReDim a(lLimit To uLimit)
+ For indx=lLimit To Ulimit
+ a(indx) = 2 * indx
+ Next indx
+
+ found = False
+ For Each elmt in a
+ If elmt = specialValue Then
+ found = True
+ End If
+ Next elmt
+
+ If found then
+ indx = uLimit
+ Do While indx >= lLimit
+ indx = indx - 1
+ Loop
+ End If
+
+End Sub
+
+Public Sub TestMultiline (cellAddr As String, rowNbr As Long)
+ Dim rng As Range
+
+ Set rng = Range(cellAddr)
+ With rng
+ .Cells(1,1).Value = _
+ "Line 1 of multiline string; " & _
+ "Line 2 of multiline string; " & _
+ "Line 3 of multiline string"
+ End With
+
+ ' The following lines have whitespace after the underscore character
+ ' and therefore do not form a valid multiline statement. The indent
+ ' script correctly treats them as four single line statements contrary
+ ' to the author's obvious indent.
+ rng..Cells(1,1).Value = _
+ "Line 1 of multiline string; " & _
+ "Line 2 of multiline string; " & _
+ "Line 3 of multiline string"
+
+End Sub
+
+Private Sub TestStmtLabel()
+ GoTo stmtLabel
+
+ ' Statement labels are never indented
+stmtLabel:
+
+End Sub
+
+Sub TestTypeKeyword()
+ Type EmployeeRecord ' Create user-defined type.
+ ID As Integer ' Define elements of data type.
+ Name As String * 20
+ Address As String * 30
+ Phone As Long
+ HireDate As Date
+ End Type
+ Dim varType As EmployeeRecord
+End Sub
+' END_INDENT
diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in
index 873045bc2c..5eb262f50a 100644
--- a/runtime/indent/testdir/vim.in
+++ b/runtime/indent/testdir/vim.in
@@ -36,6 +36,13 @@ let t = [
\ },
\ ]
+def Func()
+ var d = dd
+ ->extend({
+ })
+ eval 0
+enddef
+
" END_INDENT
" START_INDENT
diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok
index 8e70abe619..932eebef43 100644
--- a/runtime/indent/testdir/vim.ok
+++ b/runtime/indent/testdir/vim.ok
@@ -36,6 +36,13 @@ let t = [
\ },
\ ]
+def Func()
+ var d = dd
+ ->extend({
+ })
+ eval 0
+enddef
+
" END_INDENT
" START_INDENT
diff --git a/runtime/indent/vb.vim b/runtime/indent/vb.vim
index 4d05345565..bc7142f428 100644
--- a/runtime/indent/vb.vim
+++ b/runtime/indent/vb.vim
@@ -1,8 +1,12 @@
" Vim indent file
" Language: VisualBasic (ft=vb) / Basic (ft=basic) / SaxBasic (ft=vb)
" Author: Johannes Zellner <johannes@zellner.org>
+" Maintainer: Michael Soyka (mssr953@gmail.com)
" Last Change: Fri, 18 Jun 2004 07:22:42 CEST
" Small update 2010 Jul 28 by Maxim Kim
+" 2022/12/15: add support for multiline statements.
+" 2022/12/21: move VbGetIndent from global to script-local scope
+" 2022/12/26: recognize "Type" keyword
if exists("b:did_indent")
finish
@@ -10,28 +14,33 @@ endif
let b:did_indent = 1
setlocal autoindent
-setlocal indentexpr=VbGetIndent(v:lnum)
+setlocal indentexpr=s:VbGetIndent(v:lnum)
setlocal indentkeys&
-setlocal indentkeys+==~else,=~elseif,=~end,=~wend,=~case,=~next,=~select,=~loop,<:>
+setlocal indentkeys+==~else,=~elseif,=~end,=~wend,=~case,=~next,=~select,=~loop
let b:undo_indent = "set ai< indentexpr< indentkeys<"
" Only define the function once.
-if exists("*VbGetIndent")
+if exists("*s:VbGetIndent")
finish
endif
-fun! VbGetIndent(lnum)
+function s:VbGetIndent(lnum)
+ let this_lnum = a:lnum
+ let this_line = getline(this_lnum)
+
" labels and preprocessor get zero indent immediately
- let this_line = getline(a:lnum)
let LABELS_OR_PREPROC = '^\s*\(\<\k\+\>:\s*$\|#.*\)'
if this_line =~? LABELS_OR_PREPROC
return 0
endif
+
+ " Get the current value of "shiftwidth"
+ let bShiftwidth = shiftwidth()
" Find a non-blank line above the current line.
" Skip over labels and preprocessor directives.
- let lnum = a:lnum
+ let lnum = this_lnum
while lnum > 0
let lnum = prevnonblank(lnum - 1)
let previous_line = getline(lnum)
@@ -45,34 +54,102 @@ fun! VbGetIndent(lnum)
return 0
endif
- let ind = indent(lnum)
+ " Variable "previous_line" now contains the text in buffer line "lnum".
+
+ " Multi-line statements have the underscore character at end-of-line:
+ "
+ " object.method(arguments, _
+ " arguments, _
+ " arguments)
+ "
+ " and require extra logic to determine the correct indentation.
+ "
+ " Case 1: Line "lnum" is the first line of a multiline statement.
+ " Line "lnum" will have a trailing underscore character
+ " but the preceding non-blank line does not.
+ " Line "this_lnum" will be indented relative to "lnum".
+ "
+ " Case 2: Line "lnum" is the last line of a multiline statement.
+ " Line "lnum" will not have a trailing underscore character
+ " but the preceding non-blank line will.
+ " Line "this_lnum" will have the same indentation as the starting
+ " line of the multiline statement.
+ "
+ " Case 3: Line "lnum" is neither the first nor last line.
+ " Lines "lnum" and "lnum-1" will have a trailing underscore
+ " character.
+ " Line "this_lnum" will have the same indentation as the preceding
+ " line.
+ "
+ " No matter which case it is, the starting line of the statement must be
+ " found. It will be assumed that multiline statements cannot have
+ " intermingled comments, statement labels, preprocessor directives or
+ " blank lines.
+ "
+ let lnum_is_continued = (previous_line =~ '_$')
+ if lnum > 1
+ let before_lnum = prevnonblank(lnum-1)
+ let before_previous_line = getline(before_lnum)
+ else
+ let before_lnum = 0
+ let before_previous_line = ""
+ endif
+
+ if before_previous_line !~ '_$'
+ " Variable "previous_line" contains the start of a statement.
+ "
+ let ind = indent(lnum)
+ if lnum_is_continued
+ let ind += bShiftwidth
+ endif
+ elseif ! lnum_is_continued
+ " Line "lnum" contains the last line of a multiline statement.
+ " Need to find where this multiline statement begins
+ "
+ while before_lnum > 0
+ let before_lnum -= 1
+ if getline(before_lnum) !~ '_$'
+ let before_lnum += 1
+ break
+ endif
+ endwhile
+ if before_lnum == 0
+ let before_lnum = 1
+ endif
+ let previous_line = getline(before_lnum)
+ let ind = indent(before_lnum)
+ else
+ " Line "lnum" is not the first or last line of a multiline statement.
+ "
+ let ind = indent(lnum)
+ endif
" Add
- if previous_line =~? '^\s*\<\(begin\|\%(\%(private\|public\|friend\)\s\+\)\=\%(function\|sub\|property\)\|select\|case\|default\|if\|else\|elseif\|do\|for\|while\|enum\|with\)\>'
- let ind = ind + shiftwidth()
+ if previous_line =~? '^\s*\<\(begin\|\%(\%(private\|public\|friend\)\s\+\)\=\%(function\|sub\|property\|enum\|type\)\|select\|case\|default\|if\|else\|elseif\|do\|for\|while\|with\)\>'
+ let ind = ind + bShiftwidth
endif
" Subtract
if this_line =~? '^\s*\<end\>\s\+\<select\>'
if previous_line !~? '^\s*\<select\>'
- let ind = ind - 2 * shiftwidth()
+ let ind = ind - 2 * bShiftwidth
else
" this case is for an empty 'select' -- 'end select'
" (w/o any case statements) like:
"
" select case readwrite
" end select
- let ind = ind - shiftwidth()
+ let ind = ind - bShiftwidth
endif
elseif this_line =~? '^\s*\<\(end\|else\|elseif\|until\|loop\|next\|wend\)\>'
- let ind = ind - shiftwidth()
+ let ind = ind - bShiftwidth
elseif this_line =~? '^\s*\<\(case\|default\)\>'
if previous_line !~? '^\s*\<select\>'
- let ind = ind - shiftwidth()
+ let ind = ind - bShiftwidth
endif
endif
return ind
-endfun
+endfunction
" vim:sw=4
diff --git a/runtime/indent/vim.vim b/runtime/indent/vim.vim
index 8076b2df07..3beb70d255 100644
--- a/runtime/indent/vim.vim
+++ b/runtime/indent/vim.vim
@@ -33,7 +33,9 @@ function GetVimIndent()
endtry
endfunc
-let s:lineContPat = '^\s*\(\\\|"\\ \)'
+" 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
@@ -133,15 +135,15 @@ function GetVimIndentIntern()
endif
endif
- " For a line starting with "}" find the matching "{". If it is at the start
- " of the line align with it, probably end of a block.
+ " 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 && getline('.') =~ '^\s*{'
+ if line('.') < v:lnum
let ind = indent('.')
endif
else
@@ -149,19 +151,33 @@ function GetVimIndentIntern()
endif
endif
- " Below a line starting with "}" find the matching "{". If it is at the
- " end of the line we must be below the end of a dictionary.
- if prev_text =~ '^\s*}'
- if maparg('%') != ''
- exe lnum
- silent! normal %
- if line('.') == lnum || getline('.') !~ '^\s*{'
- let ind = ind - shiftwidth()
+ " 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
- " todo: use searchpair() to find a match
+ break
endif
- 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.
diff --git a/runtime/indent/vue.vim b/runtime/indent/vue.vim
new file mode 100644
index 0000000000..f6fe350a8f
--- /dev/null
+++ b/runtime/indent/vue.vim
@@ -0,0 +1,14 @@
+" Vim indent file placeholder
+" Language: Vue
+" Maintainer: None, please volunteer if you have a real Vue indent script
+" Last Change: 2022 Dec 24
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+" don't set b:did_indent, otherwise html indenting won't be activated
+" let b:did_indent = 1
+
+" Html comes closest
+runtime! indent/html.vim
diff --git a/runtime/indent/yaml.vim b/runtime/indent/yaml.vim
index d732c37c05..93fd8ea6f6 100644
--- a/runtime/indent/yaml.vim
+++ b/runtime/indent/yaml.vim
@@ -1,7 +1,7 @@
" Vim indent file
" Language: YAML
" Maintainer: Nikolai Pavlov <zyx.vim@gmail.com>
-" Last Update: Lukas Reineke
+" Last Updates: Lukas Reineke, "lacygoill"
" Last Change: 2022 Jun 17
" Only load this indent file when no other was loaded.
@@ -29,8 +29,8 @@ function s:FindPrevLessIndentedLine(lnum, ...)
let prevlnum = prevnonblank(a:lnum-1)
let curindent = a:0 ? a:1 : indent(a:lnum)
while prevlnum
- \&& indent(prevlnum) >= curindent
- \&& getline(prevlnum) !~# '^\s*#'
+ \ && indent(prevlnum) >= curindent
+ \ && getline(prevlnum) !~# '^\s*#'
let prevlnum = prevnonblank(prevlnum-1)
endwhile
return prevlnum
@@ -54,7 +54,7 @@ let s:c_ns_anchor_name = s:c_ns_anchor_char .. '+'
let s:c_ns_anchor_property = '\v\&' .. s:c_ns_anchor_name
let s:ns_word_char = '\v[[:alnum:]_\-]'
-let s:ns_tag_char = '\v%(%\x\x|' .. s:ns_word_char .. '|[#/;?:@&=+$.~*''()])'
+let s:ns_tag_char = '\v%(\x\x|' .. s:ns_word_char .. '|[#/;?:@&=+$.~*''()])'
let s:c_named_tag_handle = '\v\!' .. s:ns_word_char .. '+\!'
let s:c_secondary_tag_handle = '\v\!\!'
let s:c_primary_tag_handle = '\v\!'
@@ -63,7 +63,7 @@ let s:c_tag_handle = '\v%(' .. s:c_named_tag_handle.
\ '|' .. s:c_primary_tag_handle .. ')'
let s:c_ns_shorthand_tag = '\v' .. s:c_tag_handle .. s:ns_tag_char .. '+'
let s:c_non_specific_tag = '\v\!'
-let s:ns_uri_char = '\v%(%\x\x|' .. s:ns_word_char .. '\v|[#/;?:@&=+$,.!~*''()[\]])'
+let s:ns_uri_char = '\v%(\x\x|' .. s:ns_word_char .. '\v|[#/;?:@&=+$,.!~*''()[\]])'
let s:c_verbatim_tag = '\v\!\<' .. s:ns_uri_char.. '+\>'
let s:c_ns_tag_property = '\v' .. s:c_verbatim_tag.
\ '\v|' .. s:c_ns_shorthand_tag.
diff --git a/runtime/indent/zig.vim b/runtime/indent/zig.vim
new file mode 100644
index 0000000000..e3ce8aa410
--- /dev/null
+++ b/runtime/indent/zig.vim
@@ -0,0 +1,80 @@
+" Vim filetype indent file
+" Language: Zig
+" Upstream: https://github.com/ziglang/zig.vim
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+if (!has("cindent") || !has("eval"))
+ finish
+endif
+
+setlocal cindent
+
+" L0 -> 0 indent for jump labels (i.e. case statement in c).
+" j1 -> indenting for "javascript object declarations"
+" J1 -> see j1
+" w1 -> starting a new line with `(` at the same indent as `(`
+" m1 -> if `)` starts a line, match its indent with the first char of its
+" matching `(` line
+" (s -> use one indent, when starting a new line after a trailing `(`
+setlocal cinoptions=L0,m1,(s,j1,J1,l1
+
+" cinkeys: controls what keys trigger indent formatting
+" 0{ -> {
+" 0} -> }
+" 0) -> )
+" 0] -> ]
+" !^F -> make CTRL-F (^F) reindent the current line when typed
+" o -> when <CR> or `o` is used
+" O -> when the `O` command is used
+setlocal cinkeys=0{,0},0),0],!^F,o,O
+
+setlocal indentexpr=GetZigIndent(v:lnum)
+
+let b:undo_indent = "setlocal cindent< cinkeys< cinoptions< indentexpr<"
+
+function! GetZigIndent(lnum)
+ let curretLineNum = a:lnum
+ let currentLine = getline(a:lnum)
+
+ " cindent doesn't handle multi-line strings properly, so force no indent
+ if currentLine =~ '^\s*\\\\.*'
+ return -1
+ endif
+
+ let prevLineNum = prevnonblank(a:lnum-1)
+ let prevLine = getline(prevLineNum)
+
+ " for lines that look like
+ " },
+ " };
+ " try treating them the same as a }
+ if prevLine =~ '\v^\s*},$'
+ if currentLine =~ '\v^\s*};$' || currentLine =~ '\v^\s*}$'
+ return indent(prevLineNum) - 4
+ endif
+ return indent(prevLineNum-1) - 4
+ endif
+ if currentLine =~ '\v^\s*},$'
+ return indent(prevLineNum) - 4
+ endif
+ if currentLine =~ '\v^\s*};$'
+ return indent(prevLineNum) - 4
+ endif
+
+
+ " cindent doesn't handle this case correctly:
+ " switch (1): {
+ " 1 => true,
+ " ~
+ " ^---- indents to here
+ if prevLine =~ '.*=>.*,$' && currentLine !~ '.*}$'
+ return indent(prevLineNum)
+ endif
+
+ return cindent(a:lnum)
+endfunction