diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-01-25 18:31:31 +0000 |
commit | 9243becbedbb6a1592208051f8fa2b090dcc5e7d (patch) | |
tree | 607c2a862ec3f4399b8766383f6f8e04c4aa43b4 /runtime/indent | |
parent | 9e40b6e9e1bc67f2d856adb837ee64dd0e25b717 (diff) | |
parent | 3c48d3c83fc21dbc0841f9210f04bdb073d73cd1 (diff) | |
download | rneovim-usermarks.tar.gz rneovim-usermarks.tar.bz2 rneovim-usermarks.zip |
Merge remote-tracking branch 'upstream/master' into usermarksusermarks
Diffstat (limited to 'runtime/indent')
-rw-r--r-- | runtime/indent/chatito.vim | 32 | ||||
-rw-r--r-- | runtime/indent/erlang.vim | 143 | ||||
-rw-r--r-- | runtime/indent/gyp.vim | 7 | ||||
-rw-r--r-- | runtime/indent/hare.vim | 138 | ||||
-rw-r--r-- | runtime/indent/json.vim | 3 | ||||
-rw-r--r-- | runtime/indent/lua.vim | 3 | ||||
-rw-r--r-- | runtime/indent/nginx.vim | 77 | ||||
-rw-r--r-- | runtime/indent/obse.vim | 55 | ||||
-rw-r--r-- | runtime/indent/racket.vim | 60 | ||||
-rw-r--r-- | runtime/indent/solidity.vim | 442 | ||||
-rw-r--r-- | runtime/indent/testdir/python.in | 18 | ||||
-rw-r--r-- | runtime/indent/testdir/python.ok | 18 | ||||
-rw-r--r-- | runtime/indent/testdir/runtest.vim | 15 | ||||
-rw-r--r-- | runtime/indent/testdir/vb.in | 134 | ||||
-rw-r--r-- | runtime/indent/testdir/vb.ok | 134 | ||||
-rw-r--r-- | runtime/indent/testdir/vim.in | 7 | ||||
-rw-r--r-- | runtime/indent/testdir/vim.ok | 7 | ||||
-rw-r--r-- | runtime/indent/vb.vim | 105 | ||||
-rw-r--r-- | runtime/indent/vim.vim | 44 | ||||
-rw-r--r-- | runtime/indent/vue.vim | 14 | ||||
-rw-r--r-- | runtime/indent/yaml.vim | 10 | ||||
-rw-r--r-- | runtime/indent/zig.vim | 80 |
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 |