summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-09-27 17:30:34 +0100
committerBram Moolenaar <Bram@vim.org>2022-09-27 17:30:34 +0100
commit9fbdbb814f4ad67a14979aba4a6a49800c2f1a99 (patch)
treecbf6e2990b41ad67092e529497df96bd9199e353
parent26f09ea54b2c60abf21df42c60bdfc60eca17b0d (diff)
downloadvim-git-9fbdbb814f4ad67a14979aba4a6a49800c2f1a99.tar.gz
Update runtime files
-rw-r--r--.github/CODEOWNERS12
-rw-r--r--runtime/autoload/context.vim9
-rw-r--r--runtime/autoload/dist/vimindent.vim1200
-rw-r--r--runtime/compiler/hare.vim31
-rw-r--r--runtime/doc/cmdline.txt4
-rw-r--r--runtime/doc/develop.txt2
-rw-r--r--runtime/doc/ft_context.txt32
-rw-r--r--runtime/doc/indent.txt30
-rw-r--r--runtime/doc/map.txt16
-rw-r--r--runtime/doc/motion.txt4
-rw-r--r--runtime/doc/options.txt7
-rw-r--r--runtime/doc/pattern.txt7
-rw-r--r--runtime/doc/quickfix.txt8
-rw-r--r--runtime/doc/repeat.txt13
-rw-r--r--runtime/doc/syntax.txt4
-rw-r--r--runtime/doc/tags5
-rw-r--r--runtime/doc/textprop.txt39
-rw-r--r--runtime/doc/todo.txt43
-rw-r--r--runtime/doc/various.txt4
-rw-r--r--runtime/doc/vim9.txt4
-rw-r--r--runtime/filetype.vim2
-rw-r--r--runtime/ftplugin/chatito.vim15
-rw-r--r--runtime/ftplugin/elixir.vim6
-rw-r--r--runtime/ftplugin/gyp.vim14
-rw-r--r--runtime/ftplugin/hare.vim27
-rw-r--r--runtime/ftplugin/heex.vim16
-rw-r--r--runtime/ftplugin/vim.vim18
-rw-r--r--runtime/indent/chatito.vim32
-rw-r--r--runtime/indent/gyp.vim7
-rw-r--r--runtime/indent/hare.vim138
-rw-r--r--runtime/indent/solidity.vim442
-rw-r--r--runtime/indent/testdir/vim.in778
-rw-r--r--runtime/indent/testdir/vim.ok778
-rw-r--r--runtime/indent/vim.vim224
-rw-r--r--runtime/indent/vue.vim12
-rw-r--r--runtime/syntax/chatito.vim62
-rw-r--r--runtime/syntax/desktop.vim6
-rw-r--r--runtime/syntax/gyp.vim49
-rw-r--r--runtime/syntax/hare.vim133
-rw-r--r--runtime/syntax/help.vim3
-rw-r--r--runtime/syntax/hlsplaylist.vim120
-rw-r--r--runtime/syntax/plsql.vim68
-rw-r--r--runtime/syntax/solidity.vim173
-rw-r--r--runtime/syntax/vim.vim2
-rw-r--r--src/INSTALLpc.txt1
45 files changed, 4222 insertions, 378 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 2baadcbf6..b33c37bff 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -57,6 +57,7 @@ runtime/compiler/gawk.vim @dkearns
runtime/compiler/gjs.vim @dkearns
runtime/compiler/go.vim @dbarnett
runtime/compiler/haml.vim @tpope
+runtime/compiler/hare.vim @rsaihe
runtime/compiler/icon.vim @dkearns
runtime/compiler/javac.vim @dkearns
runtime/compiler/jest.vim @dkearns
@@ -107,6 +108,7 @@ runtime/ftplugin/awk.vim @dkearns
runtime/ftplugin/basic.vim @dkearns
runtime/ftplugin/bst.vim @tpope
runtime/ftplugin/cfg.vim @chrisbra
+runtime/ftplugin/chatito.vim @ObserverOfTime
runtime/ftplugin/clojure.vim @axvr
runtime/ftplugin/cs.vim @nickspoons
runtime/ftplugin/csh.vim @dkearns
@@ -116,9 +118,9 @@ runtime/ftplugin/desktop.vim @e-kwsm
runtime/ftplugin/dosbatch.vim @mrdubya
runtime/ftplugin/eiffel.vim @dkearns
runtime/ftplugin/elixir.vim @mhanberg
-runtime/ftplugin/expect.vim @dkearns
runtime/ftplugin/erlang.vim @hcs42
runtime/ftplugin/eruby.vim @tpope @dkearns
+runtime/ftplugin/expect.vim @dkearns
runtime/ftplugin/fennel.vim @gpanders
runtime/ftplugin/fetchmail.vim @dkearns
runtime/ftplugin/fpcmake.vim @dkearns
@@ -134,9 +136,11 @@ runtime/ftplugin/gitconfig.vim @tpope
runtime/ftplugin/gitignore.vim @ObserverOfTime
runtime/ftplugin/gitrebase.vim @tpope
runtime/ftplugin/gitsendemail.vim @tpope
+runtime/ftplugin/gyp.vim @ObserverOfTime
runtime/ftplugin/go.vim @dbarnett
runtime/ftplugin/gprof.vim @dpelle
runtime/ftplugin/haml.vim @tpope
+runtime/ftplugin/hare.vim @rsaihe
runtime/ftplugin/hgcommit.vim @k-takata
runtime/ftplugin/html.vim @dkearns
runtime/ftplugin/i3config.vim @hiqua
@@ -208,6 +212,7 @@ runtime/ftplugin/zsh.vim @chrisbra
runtime/indent/basic.vim @dkearns
runtime/indent/bst.vim @tpope
runtime/indent/cdl.vim @dkearns
+runtime/indent/chatito.vim @ObserverOfTime
runtime/indent/clojure.vim @axvr
runtime/indent/config.vim @dkearns
runtime/indent/cs.vim @nickspoons
@@ -229,7 +234,9 @@ runtime/indent/gdscript.vim @habamax
runtime/indent/gitconfig.vim @tpope
runtime/indent/gitolite.vim @sitaramc
runtime/indent/go.vim @dbarnett
+runtime/indent/gyp.vim @ObserverOfTime
runtime/indent/haml.vim @tpope
+runtime/indent/hare.vim @rsaihe
runtime/indent/idlang.vim @dkearns
runtime/indent/j.vim @glts
runtime/indent/java.vim @xuhdev
@@ -303,6 +310,7 @@ runtime/syntax/cabal.vim @coot
runtime/syntax/cabalconfig.vim @coot
runtime/syntax/cabalproject.vim @coot
runtime/syntax/cf.vim @ernstvanderlinden
+runtime/syntax/chatito.vim @ObserverOfTime
runtime/syntax/clojure.vim @axvr
runtime/syntax/cs.vim @nickspoons
runtime/syntax/csh.vim @cecamp
@@ -345,7 +353,9 @@ runtime/syntax/go.vim @bhcleek
runtime/syntax/godoc.vim @dbarnett
runtime/syntax/gprof.vim @dpelle
runtime/syntax/groff.vim @jmarshall
+runtime/syntax/gyp.vim @ObserverOfTime
runtime/syntax/haml.vim @tpope
+runtime/syntax/hare.vim @rsaihe
runtime/syntax/haskell.vim @coot
runtime/syntax/hgcommit.vim @k-takata
runtime/syntax/html.vim @dkearns
diff --git a/runtime/autoload/context.vim b/runtime/autoload/context.vim
index e42b99e2e..fc5930976 100644
--- a/runtime/autoload/context.vim
+++ b/runtime/autoload/context.vim
@@ -3,13 +3,18 @@ vim9script
# Language: ConTeXt typesetting engine
# Maintainer: Nicola Vitacolonna <nvitacolonna@gmail.com>
# Former Maintainers: Nikolai Weibull <now@bitwi.se>
-# Latest Revision: 2022 Aug 12
+# Latest Revision: 2022 Sep 19
# Typesetting {{{
import autoload './typeset.vim'
export def ConTeXtCmd(path: string): list<string>
- return ['mtxrun', '--script', 'context', '--nonstopmode', '--autogenerate', path]
+ var cmd = ['mtxrun', '--script', 'context', '--nonstopmode', '--autogenerate']
+ if !empty(get(g:, 'context_extra_options', ''))
+ cmd += g:context_extra_options
+ endif
+ cmd->add(path)
+ return cmd
enddef
export def Typeset(bufname: string, env = {}, Cmd = ConTeXtCmd): bool
diff --git a/runtime/autoload/dist/vimindent.vim b/runtime/autoload/dist/vimindent.vim
new file mode 100644
index 000000000..572fc7c6c
--- /dev/null
+++ b/runtime/autoload/dist/vimindent.vim
@@ -0,0 +1,1200 @@
+vim9script
+
+# Language: Vim script
+# Maintainer: github user lacygoill
+# Last Change: 2022 Sep 24
+
+# Config {{{1
+
+const TIMEOUT: number = get(g:, 'vim_indent', {})
+ ->get('searchpair_timeout', 100)
+
+def IndentMoreInBracketBlock(): number # {{{2
+ if get(g:, 'vim_indent', {})
+ ->get('more_in_bracket_block', false)
+ return shiftwidth()
+ else
+ return 0
+ endif
+enddef
+
+def IndentMoreLineContinuation(): number # {{{2
+ var n: any = get(g:, 'vim_indent', {})
+ # We inspect `g:vim_indent_cont` to stay backward compatible.
+ ->get('line_continuation', get(g:, 'vim_indent_cont', shiftwidth() * 3))
+
+ if n->typename() == 'string'
+ return n->eval()
+ else
+ return n
+ endif
+enddef
+# }}}2
+
+# Init {{{1
+var patterns: list<string>
+# Tokens {{{2
+# BAR_SEPARATION {{{3
+
+const BAR_SEPARATION: string = '[^|\\]\@1<=|'
+
+# OPENING_BRACKET {{{3
+
+const OPENING_BRACKET: string = '[[{(]'
+
+# CLOSING_BRACKET {{{3
+
+const CLOSING_BRACKET: string = '[]})]'
+
+# NON_BRACKET {{{3
+
+const NON_BRACKET: string = '[^[\]{}()]'
+
+# LIST_OR_DICT_CLOSING_BRACKET {{{3
+
+const LIST_OR_DICT_CLOSING_BRACKET: string = '[]}]'
+
+# LIST_OR_DICT_OPENING_BRACKET {{{3
+
+const LIST_OR_DICT_OPENING_BRACKET: string = '[[{]'
+
+# CHARACTER_UNDER_CURSOR {{{3
+
+const CHARACTER_UNDER_CURSOR: string = '\%.c.'
+
+# INLINE_COMMENT {{{3
+
+# TODO: It is not required for an inline comment to be surrounded by whitespace.
+# But it might help against false positives.
+# To be more reliable, we should inspect the syntax, and only require whitespace
+# before the `#` comment leader. But that might be too costly (because of
+# `synstack()`).
+const INLINE_COMMENT: string = '\s[#"]\%(\s\|[{}]\{3}\)'
+
+# INLINE_VIM9_COMMENT {{{3
+
+const INLINE_VIM9_COMMENT: string = '\s#'
+
+# COMMENT {{{3
+
+# TODO: Technically, `"\s` is wrong.
+#
+# First, whitespace is not required.
+# Second, in Vim9, a string might appear at the start of the line.
+# To be sure, we should also inspect the syntax.
+# We can't use `INLINE_COMMENT` here. {{{
+#
+# const COMMENT: string = $'^\s*{INLINE_COMMENT}'
+# ^------------^
+# ✘
+#
+# Because `INLINE_COMMENT` asserts the presence of a whitespace before the
+# comment leader. This assertion is not satisfied for a comment starting at the
+# start of the line.
+#}}}
+const COMMENT: string = '^\s*\%(#\|"\\\=\s\).*$'
+
+# DICT_KEY {{{3
+
+const DICT_KEY: string = '^\s*\%('
+ .. '\%(\w\|-\)\+'
+ .. '\|'
+ .. '"[^"]*"'
+ .. '\|'
+ .. "'[^']*'"
+ .. '\|'
+ .. '\[[^]]\+\]'
+ .. '\)'
+ .. ':\%(\s\|$\)'
+
+# END_OF_COMMAND {{{3
+
+const END_OF_COMMAND: string = $'\s*\%($\|||\@!\|{INLINE_COMMENT}\)'
+
+# END_OF_LINE {{{3
+
+const END_OF_LINE: string = $'\s*\%($\|{INLINE_COMMENT}\)'
+
+# END_OF_VIM9_LINE {{{3
+
+const END_OF_VIM9_LINE: string = $'\s*\%($\|{INLINE_VIM9_COMMENT}\)'
+
+# OPERATOR {{{3
+
+const OPERATOR: string = '\%(^\|\s\)\%([-+*/%]\|\.\.\|||\|&&\|??\|?\|<<\|>>\|\%([=!]=\|[<>]=\=\|[=!]\~\|is\|isnot\)[?#]\=\)\%(\s\|$\)\@=\%(\s*[|<]\)\@!'
+ # assignment operators
+ .. '\|' .. '\s\%([-+*/%]\|\.\.\)\==\%(\s\|$\)\@='
+ # support `:` when used inside conditional operator `?:`
+ .. '\|' .. '\%(\s\|^\):\%(\s\|$\)'
+
+# HEREDOC_OPERATOR {{{3
+
+const HEREDOC_OPERATOR: string = '\s=<<\s\@=\%(\s\+\%(trim\|eval\)\)\{,2}'
+
+# PATTERN_DELIMITER {{{3
+
+# A better regex would be:
+#
+# [^-+*/%.:# \t[:alnum:]\"|]\@=.\|->\@!\%(=\s\)\@!\|[+*/%]\%(=\s\)\@!
+#
+# But sometimes, it can be too costly and cause `E363` to be given.
+const PATTERN_DELIMITER: string = '[-+*/%]\%(=\s\)\@!'
+
+# QUOTE {{{3
+
+const QUOTE: string = '["'']'
+# }}}2
+# Syntaxes {{{2
+# ASSIGNS_HEREDOC {{{3
+
+const ASSIGNS_HEREDOC: string = $'^\%({COMMENT}\)\@!.*\%({HEREDOC_OPERATOR}\)\s\+\zs[A-Z]\+{END_OF_LINE}'
+
+# CD_COMMAND {{{3
+
+const CD_COMMAND: string = $'[lt]\=cd!\=\s\+-{END_OF_COMMAND}'
+
+# HIGHER_ORDER_COMMAND {{{3
+
+patterns =<< trim eval END
+ argdo\>!\=
+ bufdo\>!\=
+ cdo\>!\=
+ folddoc\%[losed]\>
+ foldd\%[oopen]\>
+ ldo\=\>!\=
+ tabdo\=\>
+ windo\>
+ au\%[tocmd]\>.*
+ com\%[mand]\>.*
+ g\%[lobal]!\={PATTERN_DELIMITER}.*
+ v\%[global]!\={PATTERN_DELIMITER}.*
+END
+const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%(' .. patterns->join('\|') .. '\):\@!'
+
+# MAPPING_COMMAND {{{3
+
+const MAPPING_COMMAND: string = '\%(\<sil\%[ent]!\=\s\+\)\=[nvxsoilct]\=\%(nore\|un\)map!\=\s'
+
+# NORMAL_COMMAND {{{3
+
+const NORMAL_COMMAND: string = '\<norm\%[al]!\=\s*\S\+$'
+
+# PLUS_MINUS_COMMAND {{{3
+
+# In legacy, the `:+` and `:-` commands are not required to be preceded by a colon.
+# As a result, when `+` or `-` is alone on a line, there is ambiguity.
+# It might be an operator or a command.
+# To not break the indentation in legacy scripts, we might need to consider such
+# lines as commands.
+const PLUS_MINUS_COMMAND: string = '^\s*[+-]\s*$'
+
+# ENDS_BLOCK {{{3
+
+const ENDS_BLOCK: string = '^\s*\%('
+ .. 'en\%[dif]'
+ .. '\|' .. 'endfor\='
+ .. '\|' .. 'endw\%[hile]'
+ .. '\|' .. 'endt\%[ry]'
+ .. '\|' .. 'enddef'
+ .. '\|' .. 'endf\%[unction]'
+ .. '\|' .. 'aug\%[roup]\s\+[eE][nN][dD]'
+ .. '\|' .. CLOSING_BRACKET
+ .. $'\){END_OF_COMMAND}'
+
+# ENDS_BLOCK_OR_CLAUSE {{{3
+
+patterns =<< trim END
+ en\%[dif]
+ el\%[se]
+ endfor\=
+ endw\%[hile]
+ endt\%[ry]
+ fina\|finally\=
+ enddef
+ endf\%[unction]
+ aug\%[roup]\s\+[eE][nN][dD]
+END
+
+const ENDS_BLOCK_OR_CLAUSE: string = '^\s*\%(' .. patterns->join('\|') .. $'\){END_OF_COMMAND}'
+ .. $'\|^\s*cat\%[ch]\%(\s\+\({PATTERN_DELIMITER}\).*\1\)\={END_OF_COMMAND}'
+ .. $'\|^\s*elseif\=\s\+\%({OPERATOR}\)\@!'
+
+# STARTS_CURLY_BLOCK {{{3
+
+# TODO: `{` alone on a line is not necessarily the start of a block.
+# It could be a dictionary if the previous line ends with a binary/ternary
+# operator. This can cause an issue whenever we use `STARTS_CURLY_BLOCK` or
+# `LINE_CONTINUATION_AT_EOL`.
+const STARTS_CURLY_BLOCK: string = '\%('
+ .. '^\s*{'
+ .. '\|' .. '^.*\zs\s=>\s\+{'
+ .. '\|' .. $'^\%(\s*\|.*{BAR_SEPARATION}\s*\)\%(com\%[mand]\|au\%[tocmd]\).*\zs\s{{'
+ .. '\)' .. END_OF_COMMAND
+
+# STARTS_NAMED_BLOCK {{{3
+
+# All of these will be used at the start of a line (or after a bar).
+# NOTE: Don't replace `\%x28` with `(`.{{{
+#
+# Otherwise, the paren would be unbalanced which might cause syntax highlighting
+# issues much later in the code of the current script (sometimes, the syntax
+# highlighting plugin fails to correctly recognize a heredoc which is far away
+# and/or not displayed because inside a fold).
+# }}}
+patterns =<< trim END
+ if
+ el\%[se]
+ elseif\=
+ for
+ wh\%[ile]
+ try
+ cat\%[ch]
+ fina\|finally\=
+ fu\%[nction]\%x28\@!
+ \%(export\s\+\)\=def
+ aug\%[roup]\%(\s\+[eE][nN][dD]\)\@!\s\+\S\+
+END
+const STARTS_NAMED_BLOCK: string = '^\s*\%(sil\%[ent]\s\+\)\=\%(' .. patterns->join('\|') .. '\)\>:\@!'
+
+# STARTS_FUNCTION {{{3
+
+const STARTS_FUNCTION: string = '^\s*\%(export\s\+\)\=def\>:\@!'
+
+# ENDS_FUNCTION {{{3
+
+const ENDS_FUNCTION: string = $'^\s*enddef\>:\@!{END_OF_COMMAND}'
+
+# START_MIDDLE_END {{{3
+
+const START_MIDDLE_END: dict<list<string>> = {
+ if: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
+ else: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
+ elseif: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
+ endif: ['if', 'el\%[se]\|elseif\=', 'en\%[dif]'],
+ for: ['for', '', 'endfor\='],
+ endfor: ['for', '', 'endfor\='],
+ while: ['wh\%[ile]', '', 'endw\%[hile]'],
+ endwhile: ['wh\%[ile]', '', 'endw\%[hile]'],
+ try: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
+ catch: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
+ finally: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
+ endtry: ['try', 'cat\%[ch]\|fina\|finally\=', 'endt\%[ry]'],
+ def: ['\%(export\s\+\)\=def', '', 'enddef'],
+ enddef: ['\%(export\s\+\)\=def', '', 'enddef'],
+ function: ['fu\%[nction]', '', 'endf\%[unction]'],
+ endfunction: ['fu\%[nction]', '', 'endf\%[unction]'],
+ augroup: ['aug\%[roup]\%(\s\+[eE][nN][dD]\)\@!\s\+\S\+', '', 'aug\%[roup]\s\+[eE][nN][dD]'],
+}->map((_, kwds: list<string>) =>
+ kwds->map((_, kwd: string) => kwd == ''
+ ? ''
+ : $'\%(^\|{BAR_SEPARATION}\|\<sil\%[ent]\|{HIGHER_ORDER_COMMAND}\)\s*'
+ .. $'\%({printf('\C\<\%%(%s\)\>:\@!\%%(\s*%s\)\@!', kwd, OPERATOR)}\)'))
+# }}}2
+# EOL {{{2
+# OPENING_BRACKET_AT_EOL {{{3
+
+const OPENING_BRACKET_AT_EOL: string = $'{OPENING_BRACKET}{END_OF_VIM9_LINE}'
+
+# COMMA_AT_EOL {{{3
+
+const COMMA_AT_EOL: string = $',{END_OF_VIM9_LINE}'
+
+# COMMA_OR_DICT_KEY_AT_EOL {{{3
+
+const COMMA_OR_DICT_KEY_AT_EOL: string = $'\%(,\|{DICT_KEY}\){END_OF_VIM9_LINE}'
+
+# LAMBDA_ARROW_AT_EOL {{{3
+
+const LAMBDA_ARROW_AT_EOL: string = $'\s=>{END_OF_VIM9_LINE}'
+
+# LINE_CONTINUATION_AT_EOL {{{3
+
+const LINE_CONTINUATION_AT_EOL: string = '\%('
+ .. ','
+ .. '\|' .. OPERATOR
+ .. '\|' .. '\s=>'
+ .. '\|' .. '[^=]\zs[[(]'
+ .. '\|' .. DICT_KEY
+ # `{` is ambiguous.
+ # It can be the start of a dictionary or a block.
+ # We only want to match the former.
+ .. '\|' .. $'^\%({STARTS_CURLY_BLOCK}\)\@!.*\zs{{'
+ .. '\)\s*\%(\s#.*\)\=$'
+# }}}2
+# SOL {{{2
+# BACKSLASH_AT_SOL {{{3
+
+const BACKSLASH_AT_SOL: string = '^\s*\%(\\\|[#"]\\ \)'
+
+# CLOSING_BRACKET_AT_SOL {{{3
+
+const CLOSING_BRACKET_AT_SOL: string = $'^\s*{CLOSING_BRACKET}'
+
+# LINE_CONTINUATION_AT_SOL {{{3
+
+const LINE_CONTINUATION_AT_SOL: string = '^\s*\%('
+ .. '\\'
+ .. '\|' .. '[#"]\\ '
+ .. '\|' .. OPERATOR
+ .. '\|' .. '->\s*\h'
+ .. '\|' .. '\.\h' # dict member
+ .. '\|' .. '|'
+ # TODO: `}` at the start of a line is not necessarily a line continuation.
+ # Could be the end of a block.
+ .. '\|' .. CLOSING_BRACKET
+ .. '\)'
+
+# RANGE_AT_SOL {{{3
+
+const RANGE_AT_SOL: string = '^\s*:\S'
+# }}}1
+# Interface {{{1
+export def Expr(lnum: number): number # {{{2
+ # line which is indented
+ var line_A: dict<any> = {text: getline(lnum), lnum: lnum}
+ # line above, on which we'll base the indent of line A
+ var line_B: dict<any>
+
+ if line_A->AtStartOf('HereDoc')
+ line_A->CacheHeredoc()
+ elseif line_A.lnum->IsInside('HereDoc')
+ return line_A.text->HereDocIndent()
+ elseif line_A.lnum->IsRightBelow('HereDoc')
+ var ind: number = b:vimindent.startindent
+ unlet! b:vimindent
+ return ind
+ endif
+
+ # Don't move this block after the function header one.
+ # Otherwise, we might clear the cache too early if the line following the
+ # header is a comment.
+ if line_A.text =~ COMMENT
+ return CommentIndent()
+ endif
+
+ line_B = PrevCodeLine(line_A.lnum)
+ if line_A.text =~ BACKSLASH_AT_SOL
+ if line_B.text =~ BACKSLASH_AT_SOL
+ return Indent(line_B.lnum)
+ else
+ return Indent(line_B.lnum) + IndentMoreLineContinuation()
+ endif
+ endif
+
+ if line_A->AtStartOf('FuncHeader')
+ line_A.lnum->CacheFuncHeader()
+ elseif line_A.lnum->IsInside('FuncHeader')
+ return b:vimindent.startindent + 2 * shiftwidth()
+ elseif line_A.lnum->IsRightBelow('FuncHeader')
+ var startindent: number = b:vimindent.startindent
+ unlet! b:vimindent
+ if line_A.text =~ ENDS_FUNCTION
+ return startindent
+ else
+ return startindent + shiftwidth()
+ endif
+ endif
+
+ var past_bracket_block: dict<any>
+ if exists('b:vimindent')
+ && b:vimindent->has_key('is_BracketBlock')
+ past_bracket_block = RemovePastBracketBlock(line_A)
+ endif
+ if line_A->AtStartOf('BracketBlock')
+ line_A->CacheBracketBlock()
+ endif
+ if line_A.lnum->IsInside('BracketBlock')
+ && !b:vimindent.block_stack[0].is_curly_block
+ for block: dict<any> in b:vimindent.block_stack
+ # Can't call `BracketBlockIndent()` before we're indenting a line *after* the start of the block.{{{
+ #
+ # That's because it might need the correct indentation of the start
+ # of the block. But if we're still *on* the start, we haven't yet
+ # computed that indentation.
+ #}}}
+ if line_A.lnum > block.startlnum
+ && !block.is_curly_block
+ return BracketBlockIndent(line_A, block)
+ endif
+ endfor
+ endif
+ if line_A.text->ContinuesBelowBracketBlock(line_B, past_bracket_block)
+ && line_A.text !~ CLOSING_BRACKET_AT_SOL
+ return past_bracket_block.startindent
+ endif
+
+ # Problem: If we press `==` on the line right below the start of a multiline
+ # lambda (split after its arrow `=>`), the indent is not correct.
+ # Solution: Indent relative to the line above.
+ if line_B->EndsWithLambdaArrow()
+ return Indent(line_B.lnum) + shiftwidth() + IndentMoreInBracketBlock()
+ endif
+
+ # Don't move this block before the heredoc one.{{{
+ #
+ # A heredoc might be assigned on the very first line.
+ # And if it is, we need to cache some info.
+ #}}}
+ # Don't move it before the function header and bracket block ones either.{{{
+ #
+ # You could, because these blocks of code deal with construct which can only
+ # appear in a Vim9 script. And in a Vim9 script, the first line is
+ # `vim9script`. Or maybe some legacy code/comment (see `:help vim9-mix`).
+ # But you can't find a Vim9 function header or Vim9 bracket block on the
+ # first line.
+ #
+ # Anyway, even if you could, don't. First, it would be inconsistent.
+ # Second, it could give unexpected results while we're trying to fix some
+ # failing test.
+ #}}}
+ if line_A.lnum == 1
+ return 0
+ endif
+
+ # Don't do that:
+ # if line_A.text !~ '\S'
+ # return -1
+ # endif
+ # It would prevent a line from being automatically indented when using the
+ # normal command `o`.
+ # TODO: Can we write a test for this?
+
+ if line_B.text =~ STARTS_CURLY_BLOCK
+ return Indent(line_B.lnum) + shiftwidth() + IndentMoreInBracketBlock()
+
+ elseif line_A.text =~ CLOSING_BRACKET_AT_SOL
+ var start: number = MatchingOpenBracket(line_A)
+ if start <= 0
+ return -1
+ endif
+ return Indent(start) + IndentMoreInBracketBlock()
+
+ elseif line_A.text =~ ENDS_BLOCK_OR_CLAUSE
+ && !line_B->EndsWithLineContinuation()
+ var kwd: string = BlockStartKeyword(line_A.text)
+ if !START_MIDDLE_END->has_key(kwd)
+ return -1
+ endif
+
+ # If the cursor is after the match for the end pattern, we won't find
+ # the start of the block. Let's make sure that doesn't happen.
+ cursor(line_A.lnum, 1)
+
+ var [start: string, middle: string, end: string] = START_MIDDLE_END[kwd]
+ var block_start = SearchPairStart(start, middle, end)
+ if block_start > 0
+ return Indent(block_start)
+ else
+ return -1
+ endif
+ endif
+
+ var base_ind: number
+ if line_A->IsFirstLineOfCommand(line_B)
+ line_A.isfirst = true
+ line_B = line_B->FirstLinePreviousCommand()
+ base_ind = Indent(line_B.lnum)
+
+ if line_B->EndsWithCurlyBlock()
+ && !line_A->IsInThisBlock(line_B.lnum)
+ return base_ind
+ endif
+
+ else
+ line_A.isfirst = false
+ base_ind = Indent(line_B.lnum)
+
+ var line_C: dict<any> = PrevCodeLine(line_B.lnum)
+ if !line_B->IsFirstLineOfCommand(line_C) || line_C.lnum <= 0
+ return base_ind
+ endif
+ endif
+
+ var ind: number = base_ind + Offset(line_A, line_B)
+ return [ind, 0]->max()
+enddef
+
+def g:GetVimIndent(): number # {{{2
+ # for backward compatibility
+ return Expr(v:lnum)
+enddef
+# }}}1
+# Core {{{1
+def Offset( # {{{2
+ # we indent this line ...
+ line_A: dict<any>,
+ # ... relatively to this line
+ line_B: dict<any>,
+ ): number
+
+ # increase indentation inside a block
+ if line_B.text =~ STARTS_NAMED_BLOCK || line_B->EndsWithCurlyBlock()
+ # But don't indent if the line starting the block also closes it.
+ if line_B->AlsoClosesBlock()
+ return 0
+ # Indent twice for a line continuation in the block header itself, so that
+ # we can easily distinguish the end of the block header from the start of
+ # the block body.
+ elseif line_B->EndsWithLineContinuation()
+ && !line_A.isfirst
+ || line_A.text =~ LINE_CONTINUATION_AT_SOL
+ && line_A.text !~ PLUS_MINUS_COMMAND
+ || line_A.text->Is_IN_KeywordForLoop(line_B.text)
+ return 2 * shiftwidth()
+ else
+ return shiftwidth()
+ endif
+
+ # increase indentation of a line if it's the continuation of a command which
+ # started on a previous line
+ elseif !line_A.isfirst
+ && (line_B->EndsWithLineContinuation()
+ || line_A.text =~ LINE_CONTINUATION_AT_SOL)
+ return shiftwidth()
+ endif
+
+ return 0
+enddef
+
+def HereDocIndent(line_A: string): number # {{{2
+ # at the end of a heredoc
+ if line_A =~ $'^\s*{b:vimindent.endmarker}$'
+ # `END` must be at the very start of the line if the heredoc is not trimmed
+ if !b:vimindent.is_trimmed
+ # We can't invalidate the cache just yet.
+ # The indent of `END` is meaningless; it's always 0. The next line
+ # will need to be indented relative to the start of the heredoc. It
+ # must know where it starts; it needs the cache.
+ return 0
+ else
+ var ind: number = b:vimindent.startindent
+ # invalidate the cache so that it's not used for the next heredoc
+ unlet! b:vimindent
+ return ind
+ endif
+ endif
+
+ # In a non-trimmed heredoc, all of leading whitespace is semantic.
+ # Leave it alone.
+ if !b:vimindent.is_trimmed
+ # But do save the indent of the assignment line.
+ if !b:vimindent->has_key('startindent')
+ b:vimindent.startindent = b:vimindent.startlnum->Indent()
+ endif
+ return -1
+ endif
+
+ # In a trimmed heredoc, *some* of the leading whitespace is semantic.
+ # We want to preserve it, so we can't just indent relative to the assignment
+ # line. That's because we're dealing with data, not with code.
+ # Instead, we need to compute by how much the indent of the assignment line
+ # was increased or decreased. Then, we need to apply that same change to
+ # every line inside the body.
+ var offset: number
+ if !b:vimindent->has_key('offset')
+ var old_startindent: number = b:vimindent.startindent
+ var new_startindent: number = b:vimindent.startlnum->Indent()
+ offset = new_startindent - old_startindent
+
+ # If all the non-empty lines in the body have a higher indentation relative
+ # to the assignment, there is no need to indent them more.
+ # But if at least one of them does have the same indentation level (or a
+ # lower one), then we want to indent it further (and the whole block with it).
+ # This way, we can clearly distinguish the heredoc block from the rest of
+ # the code.
+ var end: number = search($'^\s*{b:vimindent.endmarker}$', 'nW')
+ var should_indent_more: bool = range(v:lnum, end - 1)
+ ->indexof((_, lnum: number): bool => Indent(lnum) <= old_startindent && getline(lnum) != '') >= 0
+ if should_indent_more
+ offset += shiftwidth()
+ endif
+
+ b:vimindent.offset = offset
+ b:vimindent.startindent = new_startindent
+ endif
+
+ return [0, Indent(v:lnum) + b:vimindent.offset]->max()
+enddef
+
+def CommentIndent(): number # {{{2
+ var line_B: dict<any>
+ line_B.lnum = prevnonblank(v:lnum - 1)
+ line_B.text = getline(line_B.lnum)
+ if line_B.text =~ COMMENT
+ return Indent(line_B.lnum)
+ endif
+
+ var next: number = NextCodeLine()
+ if next == 0
+ return 0
+ endif
+ var vimindent_save: dict<any> = get(b:, 'vimindent', {})->deepcopy()
+ var ind: number = next->Expr()
+ # The previous `Expr()` might have set or deleted `b:vimindent`.
+ # This could cause issues (e.g. when indenting 2 commented lines above a
+ # heredoc). Let's make sure the state of the variable is not altered.
+ if vimindent_save->empty()
+ unlet! b:vimindent
+ else
+ b:vimindent = vimindent_save
+ endif
+ if getline(next) =~ ENDS_BLOCK
+ return ind + shiftwidth()
+ else
+ return ind
+ endif
+enddef
+
+def BracketBlockIndent(line_A: dict<any>, block: dict<any>): number # {{{2
+ if !block->has_key('startindent')
+ block.startindent = block.startlnum->Indent()
+ endif
+
+ var ind: number = block.startindent
+
+ if line_A.text =~ CLOSING_BRACKET_AT_SOL
+ if b:vimindent.is_on_named_block_line
+ ind += 2 * shiftwidth()
+ endif
+ return ind + IndentMoreInBracketBlock()
+ endif
+
+ var startline: dict<any> = {
+ text: block.startline,
+ lnum: block.startlnum
+ }
+ if startline->EndsWithComma()
+ || startline->EndsWithLambdaArrow()
+ || (startline->EndsWithOpeningBracket()
+ # TODO: Is that reliable?
+ && block.startline !~
+ $'^\s*{NON_BRACKET}\+{LIST_OR_DICT_CLOSING_BRACKET},\s\+{LIST_OR_DICT_OPENING_BRACKET}')
+ ind += shiftwidth() + IndentMoreInBracketBlock()
+ endif
+
+ if b:vimindent.is_on_named_block_line
+ ind += shiftwidth()
+ endif
+
+ if block.is_dict
+ && line_A.text !~ DICT_KEY
+ ind += shiftwidth()
+ endif
+
+ return ind
+enddef
+
+def CacheHeredoc(line_A: dict<any>) # {{{2
+ var endmarker: string = line_A.text->matchstr(ASSIGNS_HEREDOC)
+ var endlnum: number = search($'^\s*{endmarker}$', 'nW')
+ var is_trimmed: bool = line_A.text =~ $'.*\s\%(trim\%(\s\+eval\)\=\)\s\+[A-Z]\+{END_OF_LINE}'
+ b:vimindent = {
+ is_HereDoc: true,
+ startlnum: line_A.lnum,
+ endlnum: endlnum,
+ endmarker: endmarker,
+ is_trimmed: is_trimmed,
+ }
+ if is_trimmed
+ b:vimindent.startindent = Indent(line_A.lnum)
+ endif
+ RegisterCacheInvalidation()
+enddef
+
+def CacheFuncHeader(startlnum: number) # {{{2
+ var pos: list<number> = getcurpos()
+ cursor(startlnum, 1)
+ if search('(', 'W', startlnum) <= 0
+ return
+ endif
+ var endlnum: number = SearchPair('(', '', ')', 'nW')
+ setpos('.', pos)
+ if endlnum == startlnum
+ return
+ endif
+
+ b:vimindent = {
+ is_FuncHeader: true,
+ startindent: startlnum->Indent(),
+ endlnum: endlnum,
+ }
+ RegisterCacheInvalidation()
+enddef
+
+def CacheBracketBlock(line_A: dict<any>) # {{{2
+ var pos: list<number> = getcurpos()
+ var opening: string = line_A.text->matchstr(CHARACTER_UNDER_CURSOR)
+ var closing: string = {'[': ']', '{': '}', '(': ')'}[opening]
+ var endlnum: number = SearchPair(opening, '', closing, 'nW')
+ setpos('.', pos)
+ if endlnum <= line_A.lnum
+ return
+ endif
+
+ if !exists('b:vimindent')
+ b:vimindent = {
+ is_BracketBlock: true,
+ is_on_named_block_line: line_A.text =~ STARTS_NAMED_BLOCK,
+ block_stack: [],
+ }
+ endif
+
+ var is_dict: bool
+ var is_curly_block: bool
+ if opening == '{'
+ if line_A.text =~ STARTS_CURLY_BLOCK
+ [is_dict, is_curly_block] = [false, true]
+ else
+ [is_dict, is_curly_block] = [true, false]
+ endif
+ endif
+ b:vimindent.block_stack->insert({
+ is_dict: is_dict,
+ is_curly_block: is_curly_block,
+ startline: line_A.text,
+ startlnum: line_A.lnum,
+ endlnum: endlnum,
+ })
+
+ RegisterCacheInvalidation()
+enddef
+
+def RegisterCacheInvalidation() # {{{2
+ # invalidate the cache so that it's not used for the next `=` normal command
+ autocmd_add([{
+ cmd: 'unlet! b:vimindent',
+ event: 'ModeChanged',
+ group: '__VimIndent__',
+ once: true,
+ pattern: '*:n',
+ replace: true,
+ }])
+enddef
+
+def RemovePastBracketBlock(line_A: dict<any>): dict<any> # {{{2
+ var stack: list<dict<any>> = b:vimindent.block_stack
+
+ var removed: dict<any>
+ if line_A.lnum > stack[0].endlnum
+ removed = stack[0]
+ endif
+
+ stack->filter((_, block: dict<any>): bool => line_A.lnum <= block.endlnum)
+ if stack->empty()
+ unlet! b:vimindent
+ endif
+ return removed
+enddef
+# }}}1
+# Util {{{1
+# Get {{{2
+def Indent(lnum: number): number # {{{3
+ if lnum <= 0
+ # Don't return `-1`. It could cause `Expr()` to return a non-multiple of `'shiftwidth'`.{{{
+ #
+ # It would be OK if we were always returning `Indent()` directly. But
+ # we don't. Most of the time, we include it in some computation
+ # like `Indent(...) + shiftwidth()`. If `'shiftwidth'` is `4`, and
+ # `Indent()` returns `-1`, `Expr()` will end up returning `3`.
+ #}}}
+ return 0
+ endif
+ return indent(lnum)
+enddef
+
+def BlockStartKeyword(line: string): string # {{{3
+ var kwd: string = line->matchstr('\l\+')
+ return fullcommand(kwd, false)
+enddef
+
+def MatchingOpenBracket(line: dict<any>): number # {{{3
+ var end: string = line.text->matchstr(CLOSING_BRACKET)
+ var start: string = {']': '[', '}': '{', ')': '('}[end]
+ cursor(line.lnum, 1)
+ return SearchPairStart(start, '', end)
+enddef
+
+def FirstLinePreviousCommand(line: dict<any>): dict<any> # {{{3
+ var line_B: dict<any> = line
+
+ while line_B.lnum > 1
+ var code_line_above: dict<any> = PrevCodeLine(line_B.lnum)
+
+ if line_B.text =~ CLOSING_BRACKET_AT_SOL
+ var n: number = MatchingOpenBracket(line_B)
+
+ if n <= 0
+ break
+ endif
+
+ line_B.lnum = n
+ line_B.text = getline(line_B.lnum)
+ continue
+
+ elseif line_B->IsFirstLineOfCommand(code_line_above)
+ break
+ endif
+
+ line_B = code_line_above
+ endwhile
+
+ return line_B
+enddef
+
+def PrevCodeLine(lnum: number): dict<any> # {{{3
+ var line: string = getline(lnum)
+ if line =~ '^\s*[A-Z]\+$'
+ var endmarker: string = line->matchstr('[A-Z]\+')
+ var pos: list<number> = getcurpos()
+ cursor(lnum, 1)
+ var n: number = search(ASSIGNS_HEREDOC, 'bnW')
+ setpos('.', pos)
+ if n > 0
+ line = getline(n)
+ if line =~ $'{HEREDOC_OPERATOR}\s\+{endmarker}'
+ return {lnum: n, text: line}
+ endif
+ endif
+ endif
+
+ var n: number = prevnonblank(lnum - 1)
+ line = getline(n)
+ while line =~ COMMENT && n > 1
+ n = prevnonblank(n - 1)
+ line = getline(n)
+ endwhile
+ # If we get back to the first line, we return 1 no matter what; even if it's a
+ # commented line. That should not cause an issue though. We just want to
+ # avoid a commented line above which there is a line of code which is more
+ # relevant. There is nothing above the first line.
+ return {lnum: n, text: line}
+enddef
+
+def NextCodeLine(): number # {{{3
+ var last: number = line('$')
+ if v:lnum == last
+ return 0
+ endif
+
+ var lnum: number = v:lnum + 1
+ while lnum <= last
+ var line: string = getline(lnum)
+ if line != '' && line !~ COMMENT
+ return lnum
+ endif
+ ++lnum
+ endwhile
+ return 0
+enddef
+
+def SearchPair( # {{{3
+ start: string,
+ middle: string,
+ end: string,
+ flags: string,
+ stopline = 0,
+ ): number
+
+ var s: string = start
+ var e: string = end
+ if start == '[' || start == ']'
+ s = s->escape('[]')
+ endif
+ if end == '[' || end == ']'
+ e = e->escape('[]')
+ endif
+ return searchpair(s, middle, e, flags, (): bool => InCommentOrString(), stopline, TIMEOUT)
+enddef
+
+def SearchPairStart( # {{{3
+ start: string,
+ middle: string,
+ end: string,
+ ): number
+ return SearchPair(start, middle, end, 'bnW')
+enddef
+
+def SearchPairEnd( # {{{3
+ start: string,
+ middle: string,
+ end: string,
+ stopline = 0,
+ ): number
+ return SearchPair(start, middle, end, 'nW', stopline)
+enddef
+# }}}2
+# Test {{{2
+def AtStartOf(line_A: dict<any>, syntax: string): bool # {{{3
+ if syntax == 'BracketBlock'
+ return AtStartOfBracketBlock(line_A)
+ endif
+
+ var pat: string = {
+ HereDoc: ASSIGNS_HEREDOC,
+ FuncHeader: STARTS_FUNCTION
+ }[syntax]
+ return line_A.text =~ pat
+ && (!exists('b:vimindent') || !b:vimindent->has_key('is_HereDoc'))
+enddef
+
+def AtStartOfBracketBlock(line_A: dict<any>): bool # {{{3
+ # We ignore bracket blocks while we're indenting a function header
+ # because it makes the logic simpler. It might mean that we don't
+ # indent correctly a multiline bracket block inside a function header,
+ # but that's a corner case for which it doesn't seem worth making the
+ # code more complex.
+ if exists('b:vimindent')
+ && !b:vimindent->has_key('is_BracketBlock')
+ return false
+ endif
+
+ var pos: list<number> = getcurpos()
+ cursor(line_A.lnum, [line_A.lnum, '$']->col())
+
+ if SearchPair(OPENING_BRACKET, '', CLOSING_BRACKET, 'bcW', line_A.lnum) <= 0
+ setpos('.', pos)
+ return false
+ endif
+ # Don't restore the cursor position.
+ # It needs to be on a bracket for `CacheBracketBlock()` to work as intended.
+
+ return line_A->EndsWithOpeningBracket()
+ || line_A->EndsWithCommaOrDictKey()
+ || line_A->EndsWithLambdaArrow()
+enddef
+
+def ContinuesBelowBracketBlock( # {{{3
+ line_A: string,
+ line_B: dict<any>,
+ block: dict<any>
+ ): bool
+
+ return !block->empty()
+ && (line_A =~ LINE_CONTINUATION_AT_SOL
+ || line_B->EndsWithLineContinuation())
+enddef
+
+def IsInside(lnum: number, syntax: string): bool # {{{3
+ if !exists('b:vimindent')
+ || !b:vimindent->has_key($'is_{syntax}')
+ return false
+ endif
+
+ if syntax == 'BracketBlock'
+ if !b:vimindent->has_key('block_stack')
+ || b:vimindent.block_stack->empty()
+ return false
+ endif
+ return lnum <= b:vimindent.block_stack[0].endlnum
+ endif
+
+ return lnum <= b:vimindent.endlnum
+enddef
+
+def IsRightBelow(lnum: number, syntax: string): bool # {{{3
+ return exists('b:vimindent')
+ && b:vimindent->has_key($'is_{syntax}')
+ && lnum > b:vimindent.endlnum
+enddef
+
+def IsInThisBlock(line_A: dict<any>, lnum: number): bool # {{{3
+ var pos: list<number> = getcurpos()
+ cursor(lnum, [lnum, '$']->col())
+ var end: number = SearchPairEnd('{', '', '}')
+ setpos('.', pos)
+
+ return line_A.lnum <= end
+enddef
+
+def IsFirstLineOfCommand(line_1: dict<any>, line_2: dict<any>): bool # {{{3
+ if line_1.text->Is_IN_KeywordForLoop(line_2.text)
+ return false
+ endif
+
+ if line_1.text =~ RANGE_AT_SOL
+ || line_1.text =~ PLUS_MINUS_COMMAND
+ return true
+ endif
+
+ if line_2.text =~ DICT_KEY
+ && !line_1->IsInThisBlock(line_2.lnum)
+ return true
+ endif
+
+ var line_1_is_good: bool = line_1.text !~ COMMENT
+ && line_1.text !~ DICT_KEY
+ && line_1.text !~ LINE_CONTINUATION_AT_SOL
+
+ var line_2_is_good: bool = !line_2->EndsWithLineContinuation()
+
+ return line_1_is_good && line_2_is_good
+enddef
+
+def Is_IN_KeywordForLoop(line_1: string, line_2: string): bool # {{{3
+ return line_2 =~ '^\s*for\s'
+ && line_1 =~ '^\s*in\s'
+enddef
+
+def InCommentOrString(): bool # {{{3
+ for synID: number in synstack('.', col('.'))
+ if synIDattr(synID, 'name') =~ '\ccomment\|string\|heredoc'
+ return true
+ endif
+ endfor
+
+ return false
+enddef
+
+def AlsoClosesBlock(line_B: dict<any>): bool # {{{3
+ # We know that `line_B` opens a block.
+ # Let's see if it also closes that block.
+ var kwd: string = BlockStartKeyword(line_B.text)
+ if !START_MIDDLE_END->has_key(kwd)
+ return false
+ endif
+
+ var [start: string, middle: string, end: string] = START_MIDDLE_END[kwd]
+ var pos: list<number> = getcurpos()
+ cursor(line_B.lnum, 1)
+ var block_end: number = SearchPairEnd(start, middle, end, line_B.lnum)
+ setpos('.', pos)
+
+ return block_end > 0
+enddef
+
+def EndsWithComma(line: dict<any>): bool # {{{3
+ return NonCommentedMatch(line, COMMA_AT_EOL)
+enddef
+
+def EndsWithCommaOrDictKey(line_A: dict<any>): bool # {{{3
+ return NonCommentedMatch(line_A, COMMA_OR_DICT_KEY_AT_EOL)
+enddef
+
+def EndsWithCurlyBlock(line_B: dict<any>): bool # {{{3
+ return NonCommentedMatch(line_B, STARTS_CURLY_BLOCK)
+enddef
+
+def EndsWithLambdaArrow(line_A: dict<any>): bool # {{{3
+ return NonCommentedMatch(line_A, LAMBDA_ARROW_AT_EOL)
+enddef
+
+def EndsWithLineContinuation(line_B: dict<any>): bool # {{{3
+ return NonCommentedMatch(line_B, LINE_CONTINUATION_AT_EOL)
+enddef
+
+def EndsWithOpeningBracket(line: dict<any>): bool # {{{3
+ return NonCommentedMatch(line, OPENING_BRACKET_AT_EOL)
+enddef
+
+def NonCommentedMatch(line: dict<any>, pat: string): bool # {{{3
+ # Could happen if there is no code above us, and we're not on the 1st line.
+ # In that case, `PrevCodeLine()` returns `{lnum: 0, line: ''}`.
+ if line.lnum == 0
+ return false
+ endif
+
+ if line.text =~ PLUS_MINUS_COMMAND
+ return false
+ endif
+
+ # In `argdelete *`, `*` is not a multiplication operator.
+ # TODO: Other commands can accept `*` as an argument. Handle them too.
+ if line.text =~ '\<argd\%[elete]\s\+\*\s*$'
+ return false
+ endif
+
+ # Technically, that's wrong. A line might start with a range and end with a
+ # line continuation symbol. But it's unlikely. And it's useful to assume the
+ # opposite because it prevents us from conflating a mark with an operator or
+ # the start of a list:
+ #
+ # not a comparison operator
+ # v
+ # :'< mark <
+ # :'< mark [
+ # ^
+ # not the start of a list
+ if line.text =~ RANGE_AT_SOL
+ return false
+ endif
+
+ # that's not an arithmetic operator
+ # v
+ # catch /pattern /
+ #
+ # When `/` is used as a pattern delimiter, it's always present twice.
+ # And usually, the first occurrence is in the middle of a sequence of
+ # non-whitespace characters. If we can find such a `/`, we assume that the
+ # trailing `/` is not an operator.
+ # Warning: Here, don't use a too complex pattern.{{{
+ #
+ # In particular, avoid backreferences.
+ # For example, this would be too costly:
+ #
+ # if line.text =~ $'\%(\S*\({PATTERN_DELIMITER}\)\S\+\|\S\+\({PATTERN_DELIMITER}\)\S*\)'
+ # .. $'\s\+\1{END_OF_COMMAND}'
+ #
+ # Sometimes, it could even give `E363`.
+ #}}}
+ var delim: string = line.text
+ ->matchstr($'\s\+\zs{PATTERN_DELIMITER}\ze{END_OF_COMMAND}')
+ if !delim->empty()
+ delim = $'\V{delim}\m'
+ if line.text =~ $'\%(\S*{delim}\S\+\|\S\+{delim}\S*\)\s\+{delim}{END_OF_COMMAND}'
+ return false
+ endif
+ endif
+ # TODO: We might still miss some corner cases:{{{
+ #
+ # conflated with arithmetic division
+ # v
+ # substitute/pat / rep /
+ # echo
+ # ^--^
+ # ✘
+ #
+ # A better way to handle all these corner cases, would be to inspect the top
+ # of the syntax stack:
+ #
+ # :echo synID('.', col('.'), v:false)->synIDattr('name')
+ #
+ # Unfortunately, the legacy syntax plugin is not accurate enough.
+ # For example, it doesn't highlight a slash as an operator.
+ # }}}
+
+ # `%` at the end of a line is tricky.
+ # It might be the modulo operator or the current file (e.g. `edit %`).
+ # Let's assume it's the latter.
+ if line.text =~ $'%{END_OF_COMMAND}'
+ return false
+ endif
+
+ # `:help cd-`
+ if line.text =~ CD_COMMAND
+ return false
+ endif
+
+ # At the end of a mapping, any character might appear; e.g. a paren:
+ #
+ # nunmap <buffer> (
+ #
+ # Don't conflate this with a line continuation symbol.
+ if line.text =~ MAPPING_COMMAND
+ return false
+ endif
+
+ # not a comparison operator
+ # vv
+ # normal! ==
+ if line.text =~ NORMAL_COMMAND
+ return false
+ endif
+
+ var pos: list<number> = getcurpos()
+ cursor(line.lnum, 1)
+ var match_lnum: number = search(pat, 'cnW', line.lnum, TIMEOUT, (): bool => InCommentOrString())
+ setpos('.', pos)
+ return match_lnum > 0
+enddef
+# }}}1
+# vim:sw=4
diff --git a/runtime/compiler/hare.vim b/runtime/compiler/hare.vim
new file mode 100644
index 000000000..c0fa68cc0
--- /dev/null
+++ b/runtime/compiler/hare.vim
@@ -0,0 +1,31 @@
+" Vim compiler file
+" Compiler: Hare Compiler
+" Maintainer: Amelia Clarke <me@rsaihe.dev>
+" Last Change: 2022-09-21
+
+if exists("g:current_compiler")
+ finish
+endif
+let g:current_compiler = "hare"
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+if exists(':CompilerSet') != 2
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+if filereadable("Makefile") || filereadable("makefile")
+ CompilerSet makeprg=make
+else
+ CompilerSet makeprg=hare\ build
+endif
+
+CompilerSet errorformat=
+ \Error\ %f:%l:%c:\ %m,
+ \Syntax\ error:\ %.%#\ at\ %f:%l:%c\\,\ %m,
+ \%-G%.%#
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+" vim: tabstop=2 shiftwidth=2 expandtab
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index e29369cb6..a9d3b3642 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -1,4 +1,4 @@
-*cmdline.txt* For Vim version 9.0. Last change: 2022 Jun 16
+*cmdline.txt* For Vim version 9.0. Last change: 2022 Sep 26
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -806,7 +806,7 @@ Count and Range *N:*
When giving a count before entering ":", this is translated into:
:.,.+(count - 1)
-In words: The 'count' lines at and after the cursor. Example: To delete
+In words: The "count" lines at and after the cursor. Example: To delete
three lines: >
3:d<CR> is translated into: .,.+2d<CR>
<
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index f76a9456e..932569475 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -1,4 +1,4 @@
-*develop.txt* For Vim version 9.0. Last change: 2020 Aug 15
+*develop.txt* For Vim version 9.0. Last change: 2022 Sep 20
VIM REFERENCE MANUAL by Bram Moolenaar
diff --git a/runtime/doc/ft_context.txt b/runtime/doc/ft_context.txt
index ba6bd0d81..e608c5b84 100644
--- a/runtime/doc/ft_context.txt
+++ b/runtime/doc/ft_context.txt
@@ -1,4 +1,4 @@
-*ft_context.txt* For Vim version 9.0. Last change: 2022 Aug 12
+*ft_context.txt* For Vim version 9.0. Last change: 2022 Sep 27
This is the documentation for the ConTeXt filetype plugin.
@@ -23,13 +23,12 @@ ConTeXt, similarly to LaTeX, is a macro-based typesetting system built on TeX:
<
The ConTeXt plugin provides syntax highlighting, completion and support for
typesetting ConTeXt documents. The recommended way to typeset a document is to
-use |:ConTeXt|. This will invoke the `mtxrun` script that is found in $PATH.
+use |:ConTeXt|. This will invoke the `mtxrun` script that is found in `$PATH`.
-For more fine grained control over the command and its environment, you may
-invoke `context.Typeset()` directly (or `context#Typeset()` from legacy Vim
-script). For instance, if you have installed a version of ConTeXt in
-`~/context`, you may define a function to use it (you may put the following
-code in `~/.vim/after/ftplugin/context.vim`) similar to the following:
+For more fine grained control over the command and its environment,
+`context.Typeset()` can be used directly (or `context#Typeset()` from legacy
+Vim script). For instance, if a version of ConTeXt is installed in
+`~/context`, you may define a function to use it similar to the following:
>
import autoload 'context.vim'
@@ -38,14 +37,15 @@ code in `~/.vim/after/ftplugin/context.vim`) similar to the following:
printf("%s/context/tex/texmf-<os>-<arch>/bin:%s", $HOME, $PATH)}
context.Typeset("%", env)
enddef
-<
-and perhaps use it with a mapping:
+
+This code may go in `~/.vim/after/ftplugin/context.vim`. A mapping can then be
+defined to invoke the custom command:
>
nnoremap <silent><buffer><leader>t <scriptcmd>MyConTeXt()<cr>
<
`context.Typeset()` accepts a third optional argument to specify a custom
-typesetting command. Such argument must be a function that takes a path and
-returns the command as a List. For example:
+typesetting command. That must be a function that takes a path and returns the
+command as a List. For example:
>
def ConTeXtCustomCommand(path: string): list<string>
return ['mtxrun', '--script', 'context', '--nonstopmode, path]
@@ -103,14 +103,20 @@ Stop all the ConTeXt jobs currently running in the background.
Settings ~
*'b:context_ignore_makefile'*
*'g:context_ignore_makefile'*
-`make` can be used to (synchronously) typeset a document. If a Makefile exists
+`:make` can be used to (synchronously) typeset a document. If a Makefile exists
and this option is not set, standard `make` is used. If this option is set,
`mtxrun` is invoked instead, even if a Makefile exists.
>
g:context_ignore_makefile = 0
<
-NOTE: before using `make`, set the working directory of the buffer to the
+NOTE: before using `:make`, set the working directory of the buffer to the
directory of the file to be typeset.
+
+ *'g:context_extra_options'*
+A list of additional options to pass to `mtxrun`.
+>
+ g:context_extra_options = []
+<
*'b:context_include'*
*'g:context_include'*
Dictionary of filetype/GROUP pairs for which syntax highlighting should be
diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt
index 2ebbadbf8..38c173bce 100644
--- a/runtime/doc/indent.txt
+++ b/runtime/doc/indent.txt
@@ -1227,13 +1227,31 @@ comments will be indented according to the correctly indented code.
VIM *ft-vim-indent*
- *g:vim_indent_cont*
-For indenting Vim scripts there is one variable that specifies the amount of
-indent for a continuation line, a line that starts with a backslash: >
-
- :let g:vim_indent_cont = shiftwidth() * 3
+ *g:vim_indent*
+Vim scripts indentation can be configured with the `g:vim_indent` dictionary
+variable. It supports 3 keys, `line_continuation`, `more_in_bracket_block`,
+and `searchpair_timeout`.
+`line_continuation` expects a number which will be added to the indent level of
+a continuation line starting with a backslash, and defaults to
+`shiftwidth() * 3`. It also accepts a string, which is evaluated at runtime.
+`more_in_bracket_block` expects a boolean value; when on, an extra
+`shiftwidth()` is added inside blocks surrounded with brackets. It defaults to
+`v:false`.
+`searchpair_timeout` expects a number which will be passed to `searchpair()` as
+a timeout. Increasing the value might give more accurate results, but also
+causes the indentation to take more time. It defaults to 100 (milliseconds).
+
+Example of configuration:
+
+ let g:vim_indent = #{
+ \ line_continuation: shiftwidth() * 3,
+ \ more_in_bracket_block: v:false,
+ \ searchpair_timeout: 100,
+ \ }
-Three times shiftwidth is the default value.
+ *g:vim_indent_cont*
+This variable is equivalent to `g:vim_indent.line_continuation`.
+It's supported for backward compatibility.
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index f1bfd75de..bd1381a37 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1,4 +1,4 @@
-*map.txt* For Vim version 9.0. Last change: 2022 Sep 12
+*map.txt* For Vim version 9.0. Last change: 2022 Sep 26
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1761,7 +1761,8 @@ The valid escape sequences are
If the first two characters of an escape sequence are "q-" (for example,
<q-args>) then the value is quoted in such a way as to make it a valid value
for use in an expression. This uses the argument as one single value.
-When there is no argument <q-args> is an empty string.
+When there is no argument <q-args> is an empty string. See the
+|q-args-example| below.
*<f-args>*
To allow commands to pass their arguments on to a user-defined function, there
is a special form <f-args> ("function args"). This splits the command
@@ -1771,7 +1772,7 @@ See the Mycmd example below. If no arguments are given <f-args> is removed.
To embed whitespace into an argument of <f-args>, prepend a backslash.
<f-args> replaces every pair of backslashes (\\) with one backslash. A
backslash followed by a character other than white space or a backslash
-remains unmodified. Overview:
+remains unmodified. Also see |f-args-example| below. Overview:
command <f-args> ~
XX ab 'ab'
@@ -1785,7 +1786,8 @@ remains unmodified. Overview:
XX a\\\\b 'a\\b'
XX a\\\\ b 'a\\', 'b'
-Examples >
+
+Examples for user commands: >
" Delete everything after here to the end
:com Ddel +,$d
@@ -1801,7 +1803,8 @@ Examples >
" Count the number of lines in the range
:com! -range -nargs=0 Lines echo <line2> - <line1> + 1 "lines"
- " Call a user function (example of <f-args>)
+< *f-args-example*
+Call a user function (example of <f-args>) >
:com -nargs=* Mycmd call Myfunc(<f-args>)
When executed as: >
@@ -1809,7 +1812,8 @@ When executed as: >
This will invoke: >
:call Myfunc("arg1","arg2")
- :" A more substantial example
+< *q-args-example*
+A more substantial example: >
:function Allargs(command)
: let i = 0
: while i < argc()
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 4253684d1..263c4f3ac 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -1,4 +1,4 @@
-*motion.txt* For Vim version 9.0. Last change: 2022 Apr 18
+*motion.txt* For Vim version 9.0. Last change: 2022 Sep 26
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1145,7 +1145,7 @@ g; Go to [count] older position in change list.
(not a motion command)
*g,* *E663*
-g, Go to [count] newer cursor position in change list.
+g, Go to [count] newer position in change list.
Just like |g;| but in the opposite direction.
(not a motion command)
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 336d4497d..4ea75ba2d 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt* For Vim version 9.0. Last change: 2022 Sep 09
+*options.txt* For Vim version 9.0. Last change: 2022 Sep 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1702,7 +1702,8 @@ A jump table for the options with a short description can be found at |Q_op|.
after that. Therefore do not append an item with += but use ^= to
prepend, e.g.: >
set clipboard^=unnamed
-< These names are recognized:
+< When using the GUI see |'go-A'|.
+ These names are recognized:
*clipboard-unnamed*
unnamed When included, Vim will use the clipboard register '*'
@@ -3978,6 +3979,8 @@ A jump table for the options with a short description can be found at |Q_op|.
"A" - yes
"aA" yes yes
+ When using a terminal see the 'clipboard' option.
+
*'go-c'*
'c' Use console dialogs instead of popup dialogs for simple
choices.
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 7700d26e1..a9452c5c3 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -1,4 +1,4 @@
-*pattern.txt* For Vim version 9.0. Last change: 2022 Mar 04
+*pattern.txt* For Vim version 9.0. Last change: 2022 Sep 24
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -134,6 +134,11 @@ gD Goto global Declaration. When the cursor is on a
CTRL-C Interrupt current (search) command. Use CTRL-Break on
MS-Windows |dos-CTRL-Break|.
In Normal mode, any pending command is aborted.
+ When Vim was started with output redirected and there
+ are no changed buffers CTRL-C exits Vim. That is to
+ help users who use "vim file | grep word" and don't
+ know how to get out (blindly typing :qa<CR> would
+ work).
*:noh* *:nohlsearch*
:noh[lsearch] Stop the highlighting for the 'hlsearch' option. It
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 67947854d..032e9a796 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1,4 +1,4 @@
-*quickfix.txt* For Vim version 9.0. Last change: 2022 Feb 22
+*quickfix.txt* For Vim version 9.0. Last change: 2022 Sep 26
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -478,7 +478,7 @@ You can parse a list of lines using 'errorformat' without creating or
modifying a quickfix list using the |getqflist()| function. Examples: >
echo getqflist({'lines' : ["F1:10:Line10", "F2:20:Line20"]})
echo getqflist({'lines' : systemlist('grep -Hn quickfix *')})
-This returns a dictionary where the 'items' key contains the list of quickfix
+This returns a dictionary where the "items" key contains the list of quickfix
entries parsed from lines. The following shows how to use a custom
'errorformat' to parse the lines without modifying the 'errorformat' option: >
echo getqflist({'efm' : '%f#%l#%m', 'lines' : ['F1#10#Line']})
@@ -597,7 +597,7 @@ can go back to the unfiltered list using the |:colder|/|:lolder| command.
quickfix command or function, the |b:changedtick|
variable is incremented. You can get the number of
this buffer using the getqflist() and getloclist()
- functions by passing the 'qfbufnr' item. For a
+ functions by passing the "qfbufnr" item. For a
location list, this buffer is wiped out when the
location list is removed.
@@ -2011,7 +2011,7 @@ The function should return a single line of text to display in the quickfix
window for each entry from start_idx to end_idx. The function can obtain
information about the entries using the |getqflist()| function and specifying
the quickfix list identifier "id". For a location list, getloclist() function
-can be used with the 'winid' argument. If an empty list is returned, then the
+can be used with the "winid" argument. If an empty list is returned, then the
default format is used to display all the entries. If an item in the returned
list is an empty string, then the default format is used to display the
corresponding entry.
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index f8602ba8c..059c6393d 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -1,4 +1,4 @@
-*repeat.txt* For Vim version 9.0. Last change: 2022 Jun 18
+*repeat.txt* For Vim version 9.0. Last change: 2022 Sep 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -92,7 +92,8 @@ pattern and do not match another pattern: >
This first finds all lines containing "found", but only executes {cmd} when
there is no match for "notfound".
-To execute a non-Ex command, you can use the `:normal` command: >
+Any Ex command can be used, see |ex-cmd-index|. To execute a Normal mode
+command, you can use the `:normal` command: >
:g/pat/normal {commands}
Make sure that {commands} ends with a whole command, otherwise Vim will wait
for you to type the rest of the command for each match. The screen will not
@@ -200,7 +201,8 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
*:source-range*
:[range]so[urce] [++clear]
Read Ex commands from the [range] of lines in the
- current buffer.
+ current buffer. When [range] is omitted read all
+ lines.
When sourcing commands from the current buffer, the
same script-ID |<SID>| is used even if the buffer is
@@ -904,6 +906,11 @@ executed like a normal Ex command, "step" will stop once in the compiled
context, where local variables can be inspected, and once just before
executing the command.
+In a :def function variables that haven't been declared yet cannot be
+inspected. Variables that have been declared can be inspected, also when the
+block they were declared in has finished. In commands this would not be
+possible, thus is slightly misleading (but can be useful).
+
The backtrace shows the hierarchy of function calls, e.g.:
>bt ~
3 function One[3] ~
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index adc1d5695..1587df5e7 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -1,4 +1,4 @@
-*syntax.txt* For Vim version 9.0. Last change: 2022 Jun 10
+*syntax.txt* For Vim version 9.0. Last change: 2022 Sep 26
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -3153,7 +3153,7 @@ The default is to use the twice sh_minlines. Set it to a smaller number to
speed up displaying. The disadvantage is that highlight errors may appear.
syntax/sh.vim tries to flag certain problems as errors; usually things like
-extra ']'s, 'done's, 'fi's, etc. If you find the error handling problematic
+unmatched "]", "done", "fi", etc. If you find the error handling problematic
for your purposes, you may suppress such error highlighting by putting
the following line in your .vimrc: >
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 1fdc74fc9..2c4a550de 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -302,6 +302,7 @@ $quote eval.txt /*$quote*
'fs' options.txt /*'fs'*
'fsync' options.txt /*'fsync'*
'ft' options.txt /*'ft'*
+'g:context_extra_options' ft_context.txt /*'g:context_extra_options'*
'g:context_ignore_makefile' ft_context.txt /*'g:context_ignore_makefile'*
'g:context_include' ft_context.txt /*'g:context_include'*
'g:mf_other_macros' ft_mp.txt /*'g:mf_other_macros'*
@@ -4343,6 +4344,7 @@ E1302 eval.txt /*E1302*
E1303 map.txt /*E1303*
E1304 vim9.txt /*E1304*
E1305 textprop.txt /*E1305*
+E1306 vim9.txt /*E1306*
E131 userfunc.txt /*E131*
E132 userfunc.txt /*E132*
E133 userfunc.txt /*E133*
@@ -6802,6 +6804,7 @@ extendnew() builtin.txt /*extendnew()*
extension-removal cmdline.txt /*extension-removal*
extensions-improvements todo.txt /*extensions-improvements*
f motion.txt /*f*
+f-args-example map.txt /*f-args-example*
false vim9.txt /*false*
false-variable eval.txt /*false-variable*
falsy eval.txt /*falsy*
@@ -7399,6 +7402,7 @@ g:tex_subscripts syntax.txt /*g:tex_subscripts*
g:tex_superscripts syntax.txt /*g:tex_superscripts*
g:tex_verbspell syntax.txt /*g:tex_verbspell*
g:var eval.txt /*g:var*
+g:vim_indent indent.txt /*g:vim_indent*
g:vim_indent_cont indent.txt /*g:vim_indent_cont*
g:vimball_home pi_vimball.txt /*g:vimball_home*
g:vimball_mkdir pi_vimball.txt /*g:vimball_mkdir*
@@ -9173,6 +9177,7 @@ pythonx if_pyth.txt /*pythonx*
pythonx-directory if_pyth.txt /*pythonx-directory*
pyxeval() builtin.txt /*pyxeval()*
q repeat.txt /*q*
+q-args-example map.txt /*q-args-example*
q/ cmdline.txt /*q\/*
q: cmdline.txt /*q:*
q? cmdline.txt /*q?*
diff --git a/runtime/doc/textprop.txt b/runtime/doc/textprop.txt
index 5fb53aff1..5a849fed6 100644
--- a/runtime/doc/textprop.txt
+++ b/runtime/doc/textprop.txt
@@ -1,4 +1,4 @@
-*textprop.txt* For Vim version 9.0. Last change: 2022 Sep 17
+*textprop.txt* For Vim version 9.0. Last change: 2022 Sep 21
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -143,10 +143,11 @@ prop_add({lnum}, {col}, {props})
automatically to a negative number; otherwise
zero is used
*E1305*
- text text to be displayed before {col}, or after the
- line if {col} is zero; prepend and/or append
- spaces for padding with highlighting; cannot
- be used with "length", "end_lnum" and "end_col"
+ text text to be displayed before {col}, or
+ above/below the line if {col} is zero; prepend
+ and/or append spaces for padding with
+ highlighting; cannot be used with "length",
+ "end_lnum" and "end_col" |virtual-text|
*E1294*
text_align when "text" is present and {col} is zero;
specifies where to display the text:
@@ -191,12 +192,23 @@ prop_add({lnum}, {col}, {props})
If not found an error is given.
*virtual-text*
When "text" is used and the column is non-zero then this text
- will be displayed at the start location of the text property
- after the text. The text of the buffer line will be shifted
- to make room. This is called "virtual text".
- When the column is zero the virtual text will appear after the
- buffer text. The "text_align" and "text_wrap" arguments
- determine how it is displayed.
+ will be displayed at the specified start location of the text
+ property. The text of the buffer line will be shifted to make
+ room. This is called "virtual text".
+ When the column is zero the virtual text will appear above,
+ after or below the buffer text. The "text_align" and
+ "text_wrap" arguments determine how it is displayed.
+ To separate the virtual text from the buffer text prepend
+ and/or append spaces to the "text" field or use the
+ "text_padding_left" value.
+
+ Make sure to use a highlight that makes clear to the user that
+ this is virtual text, otherwise it will be very confusing that
+ the text cannot be edited. When using "above" you need to
+ make clear this text belongs to the text line below it, when
+ using "below" you need to make sure it belongs to the text
+ line above it.
+
The text will be displayed but it is not part of the actual
buffer line, the cursor cannot be placed on it. A mouse click
in the text will move the cursor to the first character after
@@ -208,11 +220,6 @@ prop_add({lnum}, {col}, {props})
property with "text" has been added for a buffer then using a
negative "id" for any other property will give an error:
*E1293*
- Make sure to use a highlight that makes clear to the user that
- this is virtual text, otherwise it will be very confusing that
- the text cannot be edited.
- To separate the virtual text from the buffer text prepend
- and/or append spaces to the "text" field.
Can also be used as a |method|: >
GetLnum()->prop_add(col, props)
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 864f0b2cf..75aef3101 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 9.0. Last change: 2022 Sep 18
+*todo.txt* For Vim version 9.0. Last change: 2022 Sep 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -38,49 +38,21 @@ browser use: https://github.com/vim/vim/issues/1234
*known-bugs*
-------------------- Known bugs and current work -----------------------
-Closure created in for loop can use loop variable? #11094
- Nested loops do not work correctly yet.
- Would need to save vars for each block separately.
-
-Virtual text:
-- Virtual text below: padding is highlighted when 'number' is set #11138
-- Virtual text above: do not highlight until end of line? #11138
-- 'number' should be below "above" virtual text? Might be difficult to
- implement.
-- Add highlight for the gap before/after virtual text above/below?
-- option to hide virtual text?
-
-Fail with valgrind: test_edit
-Found errors in Test_edit_insertmode_ex_edit():
- Run 1, 01:19:51 - 01:20:01:
- command line..script /home/mool/vim/vim90/src/testdir/runtest.vim[469]..function RunTheTest[44]..Test_edit_insertmode_ex_edit[13]..WaitForAssert[2]..<SNR>6_WaitForCommon[11]..<lambda>4 line 1: Pattern '^-- INSERT --\\s*$' does not match ''
-
From test_global
Found errors in Test_interrupt_global():
Run 1, 02:16:22 - 02:16:27:
command line..script /home/mool/vim/vim90/src/testdir/runtest.vim[469]..function RunTheTest[44]..Test_interrupt_global[13]..WaitForAssert[2]..<SNR>7_WaitForCommon[11]..<lambda>20 line 1: Pattern 'Interrupted' does not match 'Type :qa! and press...l changes and exit Vim 1,1 All'
command line..script /home/mool/vim/vim90/src/testdir/runtest.vim[469]..function RunTheTest[44]..Test_interrupt_global[20]..WaitForAssert[2]..<SNR>7_WaitForCommon[11]..<lambda>21 line 1: Pattern 'Interrupted' does not match 'Entering Ex mode. Type "visual" to go to Normal mode.'
-test_terminal3:
-Conditional jump or move depends on uninitialised value(s)
-==2819005== at 0x2E9134: jump_to_mouse (mouse.c:2015)
-==2819005== by 0x2E69E6: do_mouse (mouse.c:702)
-==2819005== by 0x2E95C2: nv_mouse (mouse.c:2166)
-
-option_set(): "get a bit too much"
- - refactor to separate function
- - check for empty result
-
Use :defer command:
- Use "D" flag of writefile() and mkdir() in tests.
- (testdir/test_c*.vim done)
-
-When using :echomessage do use msg_row and msg_col, but save and restore.
-How to test any failure? If nothing fails perhaps it's OK alrady.
+ (testdir/test_e*.vim done)
-New Vim indent script: #11079 Not done yet.
+New Vim indent script: #11079 OK?
Further Vim9 improvements, possibly after launch:
+- For map(), reduce() and filter() use a specific implementation if the second
+ argument is a compiled function. #11163
- Use Vim9 for more runtime files.
- Check performance with callgrind and kcachegrind.
getline()/substitute()/setline() in #5632
@@ -228,6 +200,9 @@ reduced?
Add BufDeletePost. #11041
+Test property disappears when using CR twice in a row. OK when some text was
+entered. (#11151)
+
Add a string to the 'display' option ("smoothscroll" ?) to make CTRL-E and
CTRL-Y scroll one screen line, also if this means the first line doesn't start
with the first character (like what happens with a last line that doesn't
@@ -312,7 +287,9 @@ Adding "10" to 'spellsuggest' causes spell suggestions to become very slow.
Also, z= in German on a long word can take a very long time, but CTRL-C to
interrupt does not work. Where to add ui_breakcheck()?
New English spell files also have very slow suggestions.
+
French spell files don't work correctly. #4916
+ Make Vim understand the format somehow?
Make "g>" and "g<" in Visual mode move the text right or left.
Also for a block selection. #8558
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index fa4ad07d0..448091ec4 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -1,4 +1,4 @@
-*various.txt* For Vim version 9.0. Last change: 2022 Sep 17
+*various.txt* For Vim version 9.0. Last change: 2022 Sep 19
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -29,6 +29,8 @@ CTRL-L Clear and redraw the screen. The redraw may happen
Useful to update the status line(s) when 'statusline'
includes an item that doesn't cause automatic
updating.
+ If the command line is being edited the redraw is
+ postponed until later.
*:redrawt* *:redrawtabline*
:redrawt[abline] Redraw the tabline. Useful to update the tabline when
diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt
index 2a953eedf..b73011a09 100644
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -1,4 +1,4 @@
-*vim9.txt* For Vim version 9.0. Last change: 2022 Sep 15
+*vim9.txt* For Vim version 9.0. Last change: 2022 Sep 19
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -962,6 +962,8 @@ In compiled Vim9 script you get:
3
Generally, you should not change the list that is iterated over. Make a copy
first if needed.
+ *E1306*
+The depth of loops, :for and :while loops added together, cannot exceed 10.
Conditions and expressions ~
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 519ea330f..e192534bb 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1,7 +1,7 @@
" Vim support file to detect file types
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2022 Sep 11
+" Last Change: 2022 Sep 27
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
diff --git a/runtime/ftplugin/chatito.vim b/runtime/ftplugin/chatito.vim
new file mode 100644
index 000000000..af212e958
--- /dev/null
+++ b/runtime/ftplugin/chatito.vim
@@ -0,0 +1,15 @@
+" Vim filetype plugin
+" Language: Chatito
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Last Change: 2022 Sep 19
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal comments=:#,:// commentstring=#\ %s
+" indent of 4 spaces is mandated by the spec
+setlocal expandtab softtabstop=4 shiftwidth=4
+
+let b:undo_ftplugin = 'setl com< cms< et< sts< sw<'
diff --git a/runtime/ftplugin/elixir.vim b/runtime/ftplugin/elixir.vim
index c423c2acb..50f63673d 100644
--- a/runtime/ftplugin/elixir.vim
+++ b/runtime/ftplugin/elixir.vim
@@ -1,7 +1,7 @@
" Elixir filetype plugin
" Language: Elixir
" Maintainer: Mitchell Hanberg <vimNOSPAM@mitchellhanberg.com>
-" Last Change: 2022 August 10
+" Last Change: 2022 Sep 20
if exists("b:did_ftplugin")
finish
@@ -23,7 +23,11 @@ if exists('loaded_matchit') && !exists('b:match_words')
\ ',{:},\[:\],(:)'
endif
+setlocal shiftwidth=2 softtabstop=2 expandtab iskeyword+=!,?
+setlocal comments=:#
setlocal commentstring=#\ %s
+let b:undo_ftplugin = 'setlocal sw< sts< et< isk< com< cms<'
+
let &cpo = s:save_cpo
unlet s:save_cpo
diff --git a/runtime/ftplugin/gyp.vim b/runtime/ftplugin/gyp.vim
new file mode 100644
index 000000000..becfcadb6
--- /dev/null
+++ b/runtime/ftplugin/gyp.vim
@@ -0,0 +1,14 @@
+" Vim filetype plugin
+" Language: GYP
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Last Change: 2022 Sep 27
+
+if exists('b:did_ftplugin')
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal formatoptions-=t
+setlocal commentstring=#\ %s comments=b:#,fb:-
+
+let b:undo_ftplugin = 'setlocal fo< cms< com<'
diff --git a/runtime/ftplugin/hare.vim b/runtime/ftplugin/hare.vim
new file mode 100644
index 000000000..bb10daf38
--- /dev/null
+++ b/runtime/ftplugin/hare.vim
@@ -0,0 +1,27 @@
+" Vim filetype plugin
+" Language: Hare
+" Maintainer: Amelia Clarke <me@rsaihe.dev>
+" Previous Maintainer: Drew DeVault <sir@cmpwn.com>
+" Last Updated: 2022-09-21
+
+" Only do this when not done yet for this buffer
+if exists('b:did_ftplugin')
+ finish
+endif
+
+" Don't load another plugin for this buffer
+let b:did_ftplugin = 1
+
+setlocal noexpandtab
+setlocal tabstop=8
+setlocal shiftwidth=0
+setlocal softtabstop=0
+setlocal textwidth=80
+setlocal commentstring=//\ %s
+
+" Set 'formatoptions' to break comment lines but not other lines,
+" and insert the comment leader when hitting <CR> or using "o".
+setlocal fo-=t fo+=croql
+
+compiler hare
+" vim: tabstop=2 shiftwidth=2 expandtab
diff --git a/runtime/ftplugin/heex.vim b/runtime/ftplugin/heex.vim
new file mode 100644
index 000000000..5274d59fb
--- /dev/null
+++ b/runtime/ftplugin/heex.vim
@@ -0,0 +1,16 @@
+" Elixir filetype plugin
+" Language: HEEx
+" Maintainer: Mitchell Hanberg <vimNOSPAM@mitchellhanberg.com>
+" Last Change: 2022 Sep 21
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal shiftwidth=2 softtabstop=2 expandtab
+
+setlocal comments=:<%!--
+setlocal commentstring=<%!--\ %s\ --%>
+
+let b:undo_ftplugin = 'set sw< sts< et< com< cms<'
diff --git a/runtime/ftplugin/vim.vim b/runtime/ftplugin/vim.vim
index 60934d731..6a8370fdf 100644
--- a/runtime/ftplugin/vim.vim
+++ b/runtime/ftplugin/vim.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin
" Language: Vim
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2022 Sep 09
+" Last Change: 2022 Sep 20
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -74,14 +74,14 @@ if !exists("no_plugin_maps") && !exists("no_vim_maps")
let b:did_add_maps = 1
" Move around functions.
- nnoremap <silent><buffer> [[ m':call search('^\s*\(fu\%[nction]\\|def\)\>', "bW")<CR>
- vnoremap <silent><buffer> [[ m':<C-U>exe "normal! gv"<Bar>call search('^\s*\(fu\%[nction]\\|def\)\>', "bW")<CR>
- nnoremap <silent><buffer> ]] m':call search('^\s*\(fu\%[nction]\\|def\)\>', "W")<CR>
- vnoremap <silent><buffer> ]] m':<C-U>exe "normal! gv"<Bar>call search('^\s*\(fu\%[nction]\\|def\)\>', "W")<CR>
- nnoremap <silent><buffer> [] m':call search('^\s*end\(f\%[unction]\\|def\)\>', "bW")<CR>
- vnoremap <silent><buffer> [] m':<C-U>exe "normal! gv"<Bar>call search('^\s*end\(f\%[unction]\\|def\)\>', "bW")<CR>
- nnoremap <silent><buffer> ][ m':call search('^\s*end\(f\%[unction]\\|def\)\>', "W")<CR>
- vnoremap <silent><buffer> ][ m':<C-U>exe "normal! gv"<Bar>call search('^\s*end\(f\%[unction]\\|def\)\>', "W")<CR>
+ nnoremap <silent><buffer> [[ m':call search('^\s*\(fu\%[nction]\\|\(export\s\+\)\?def\)\>', "bW")<CR>
+ vnoremap <silent><buffer> [[ m':<C-U>exe "normal! gv"<Bar>call search('^\s*\(fu\%[nction]\\|\(export\s\+\)\?def\)\>', "bW")<CR>
+ nnoremap <silent><buffer> ]] m':call search('^\s*\(fu\%[nction]\\|\(export\s\+\)\?def\)\>', "W")<CR>
+ vnoremap <silent><buffer> ]] m':<C-U>exe "normal! gv"<Bar>call search('^\s*\(fu\%[nction]\\|\(export\s\+\)\?def\)\>', "W")<CR>
+ nnoremap <silent><buffer> [] m':call search('^\s*end\(f\%[unction]\\|\(export\s\+\)\?def\)\>', "bW")<CR>
+ vnoremap <silent><buffer> [] m':<C-U>exe "normal! gv"<Bar>call search('^\s*end\(f\%[unction]\\|\(export\s\+\)\?def\)\>', "bW")<CR>
+ nnoremap <silent><buffer> ][ m':call search('^\s*end\(f\%[unction]\\|\(export\s\+\)\?def\)\>', "W")<CR>
+ vnoremap <silent><buffer> ][ m':<C-U>exe "normal! gv"<Bar>call search('^\s*end\(f\%[unction]\\|\(export\s\+\)\?def\)\>', "W")<CR>
" Move around comments
nnoremap <silent><buffer> ]" :call search('^\(\s*".*\n\)\@<!\(\s*"\)', "W")<CR>
diff --git a/runtime/indent/chatito.vim b/runtime/indent/chatito.vim
new file mode 100644
index 000000000..1ff5e9e3f
--- /dev/null
+++ b/runtime/indent/chatito.vim
@@ -0,0 +1,32 @@
+" Vim indent file
+" Language: Chatito
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Last Change: 2022 Sep 20
+
+if exists('b:did_indent')
+ finish
+endif
+let b:did_indent = 1
+
+setlocal indentexpr=GetChatitoIndent()
+setlocal indentkeys=o,O,*<Return>,0#,!^F
+
+let b:undo_indent = 'setl inde< indk<'
+
+if exists('*GetChatitoIndent')
+ finish
+endif
+
+function GetChatitoIndent()
+ let l:prev = v:lnum - 1
+ if getline(prevnonblank(l:prev)) =~# '^[~%@]\['
+ " shift indent after definitions
+ return shiftwidth()
+ elseif getline(l:prev) !~# '^\s*$'
+ " maintain indent in sentences
+ return indent(l:prev)
+ else
+ " reset indent after a blank line
+ return 0
+ end
+endfunction
diff --git a/runtime/indent/gyp.vim b/runtime/indent/gyp.vim
new file mode 100644
index 000000000..c3980ac56
--- /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 000000000..bc4fea4e6
--- /dev/null
+++ b/runtime/indent/hare.vim
@@ -0,0 +1,138 @@
+" Vim indent file
+" Language: Hare
+" Maintainer: Amelia Clarke <me@rsaihe.dev>
+" Last Change: 2022 Sep 22
+
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+if !has("cindent") || !has("eval")
+ finish
+endif
+
+setlocal cindent
+
+" L0 -> don't deindent labels
+" (s -> use one indent after a trailing (
+" m1 -> if ) starts a line, indent it the same as its matching (
+" ks -> add an extra indent to extra lines in an if expression or for expression
+" j1 -> indent code inside {} one level when in parentheses
+" J1 -> see j1
+" *0 -> don't search for unclosed block comments
+" #1 -> don't deindent lines that begin with #
+setlocal cinoptions=L0,(s,m1,ks,j1,J1,*0,#1
+
+" Controls which keys reindent the current line.
+" 0{ -> { at beginning of line
+" 0} -> } at beginning of line
+" 0) -> ) at beginning of line
+" 0] -> ] at beginning of line
+" !^F -> <C-f> (not inserted)
+" o -> <CR> or `o` command
+" O -> `O` command
+" e -> else
+" 0=case -> case
+setlocal indentkeys=0{,0},0),0],!^F,o,O,e,0=case
+
+setlocal cinwords=if,else,for,switch,match
+
+setlocal indentexpr=GetHareIndent()
+
+function! FloorCindent(lnum)
+ return cindent(a:lnum) / shiftwidth() * shiftwidth()
+endfunction
+
+function! GetHareIndent()
+ let line = getline(v:lnum)
+ let prevlnum = prevnonblank(v:lnum - 1)
+ let prevline = getline(prevlnum)
+ let prevprevline = getline(prevnonblank(prevlnum - 1))
+
+ " This is all very hacky and imperfect, but it's tough to do much better when
+ " working with regex-based indenting rules.
+
+ " If the previous line ended with =, indent by one shiftwidth.
+ if prevline =~# '\v\=\s*(//.*)?$'
+ return indent(prevlnum) + shiftwidth()
+ endif
+
+ " If the previous line ended in a semicolon and the line before that ended
+ " with =, deindent by one shiftwidth.
+ if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\s*(//.*)?$'
+ return indent(prevlnum) - shiftwidth()
+ endif
+
+ " TODO: The following edge-case is still indented incorrectly:
+ " case =>
+ " if (foo) {
+ " bar;
+ " };
+ " | // cursor is incorrectly deindented by one shiftwidth.
+ "
+ " This only happens if the {} block is the first statement in the case body.
+ " If `case` is typed, the case will also be incorrectly deindented by one
+ " shiftwidth. Are you having fun yet?
+
+ " Deindent cases.
+ if line =~# '\v^\s*case'
+ " If the previous line was also a case, don't do any special indenting.
+ if prevline =~# '\v^\s*case'
+ return indent(prevlnum)
+ end
+
+ " If the previous line was a multiline case, deindent by one shiftwidth.
+ if prevline =~# '\v\=\>\s*(//.*)?$'
+ return indent(prevlnum) - shiftwidth()
+ endif
+
+ " If the previous line started a block, deindent by one shiftwidth.
+ " This handles the first case in a switch/match block.
+ if prevline =~# '\v\{\s*(//.*)?$'
+ return FloorCindent(v:lnum) - shiftwidth()
+ end
+
+ " If the previous line ended in a semicolon and the line before that wasn't
+ " a case, deindent by one shiftwidth.
+ if prevline =~# '\v;\s*(//.*)?$' && prevprevline !~# '\v\=\>\s*(//.*)?$'
+ return FloorCindent(v:lnum) - shiftwidth()
+ end
+
+ let l:indent = FloorCindent(v:lnum)
+
+ " If a normal cindent would indent the same amount as the previous line,
+ " deindent by one shiftwidth. This fixes some issues with `case let` blocks.
+ if l:indent == indent(prevlnum)
+ return l:indent - shiftwidth()
+ endif
+
+ " Otherwise, do a normal cindent.
+ return l:indent
+ endif
+
+ " Don't indent an extra shiftwidth for cases which span multiple lines.
+ if prevline =~# '\v\=\>\s*(//.*)?$' && prevline !~# '\v^\s*case\W'
+ return indent(prevlnum)
+ endif
+
+ " Indent the body of a case.
+ " If the previous line ended in a semicolon and the line before that was a
+ " case, don't do any special indenting.
+ if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' && line !~# '\v^\s*}'
+ return indent(prevlnum)
+ endif
+
+ let l:indent = FloorCindent(v:lnum)
+
+ " If the previous line was a case and a normal cindent wouldn't indent, indent
+ " an extra shiftwidth.
+ if prevline =~# '\v\=\>\s*(//.*)?$' && l:indent == indent(prevlnum)
+ return l:indent + shiftwidth()
+ endif
+
+ " If everything above is false, do a normal cindent.
+ return l:indent
+endfunction
+
+" vim: tabstop=2 shiftwidth=2 expandtab
diff --git a/runtime/indent/solidity.vim b/runtime/indent/solidity.vim
new file mode 100644
index 000000000..caed726c0
--- /dev/null
+++ b/runtime/indent/solidity.vim
@@ -0,0 +1,442 @@
+" Vim indent file
+" Language: Solidity
+" Acknowledgement: Based off of vim-javascript
+" Maintainer: Cothi (jiungdev@gmail.com)
+" Original Author: tomlion (https://github.com/tomlion/vim-solidity)
+" Last Changed: 2022 Sep 27
+"
+" 0. Initialization {{{1
+" =================
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal nosmartindent
+
+" Now, set up our indentation expression and keys that trigger it.
+setlocal indentexpr=GetSolidityIndent()
+setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e
+
+" Only define the function once.
+if exists("*GetSolidityIndent")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" 1. Variables {{{1
+" ============
+
+let s:js_keywords = '^\s*\(break\|case\|catch\|continue\|debugger\|default\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)'
+
+" Regex of syntax group names that are or delimit string or are comments.
+let s:syng_strcom = 'string\|regex\|comment\c'
+
+" Regex of syntax group names that are strings.
+let s:syng_string = 'regex\c'
+
+" Regex of syntax group names that are strings or documentation.
+let s:syng_multiline = 'comment\c'
+
+" Regex of syntax group names that are line comment.
+let s:syng_linecom = 'linecomment\c'
+
+" Expression used to check whether we should skip a match with searchpair().
+let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'"
+
+let s:line_term = '\s*\%(\%(\/\/\).*\)\=$'
+
+" Regex that defines continuation lines, not including (, {, or [.
+let s:continuation_regex = '\%([\\*+/.:]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)' . s:line_term
+
+" Regex that defines continuation lines.
+" TODO: this needs to deal with if ...: and so on
+let s:msl_regex = '\%([\\*+/.:([]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)' . s:line_term
+
+let s:one_line_scope_regex = '\<\%(if\|else\|for\|while\)\>[^{;]*' . s:line_term
+
+" Regex that defines blocks.
+let s:block_regex = '\%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term
+
+let s:var_stmt = '^\s*var'
+
+let s:comma_first = '^\s*,'
+let s:comma_last = ',\s*$'
+
+let s:ternary = '^\s\+[?|:]'
+let s:ternary_q = '^\s\+?'
+
+" 2. Auxiliary Functions {{{1
+" ======================
+
+" Check if the character at lnum:col is inside a string, comment, or is ascii.
+function s:IsInStringOrComment(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom
+endfunction
+
+" Check if the character at lnum:col is inside a string.
+function s:IsInString(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_string
+endfunction
+
+" Check if the character at lnum:col is inside a multi-line comment.
+function s:IsInMultilineComment(lnum, col)
+ return !s:IsLineComment(a:lnum, a:col) && synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_multiline
+endfunction
+
+" Check if the character at lnum:col is a line comment.
+function s:IsLineComment(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_linecom
+endfunction
+
+" Find line above 'lnum' that isn't empty, in a comment, or in a string.
+function s:PrevNonBlankNonString(lnum)
+ let in_block = 0
+ let lnum = prevnonblank(a:lnum)
+ while lnum > 0
+ " Go in and out of blocks comments as necessary.
+ " If the line isn't empty (with opt. comment) or in a string, end search.
+ let line = getline(lnum)
+ if line =~ '/\*'
+ if in_block
+ let in_block = 0
+ else
+ break
+ endif
+ elseif !in_block && line =~ '\*/'
+ let in_block = 1
+ elseif !in_block && line !~ '^\s*\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line)))
+ break
+ endif
+ let lnum = prevnonblank(lnum - 1)
+ endwhile
+ return lnum
+endfunction
+
+" Find line above 'lnum' that started the continuation 'lnum' may be part of.
+function s:GetMSL(lnum, in_one_line_scope)
+ " Start on the line we're at and use its indent.
+ let msl = a:lnum
+ let lnum = s:PrevNonBlankNonString(a:lnum - 1)
+ while lnum > 0
+ " If we have a continuation line, or we're in a string, use line as MSL.
+ " Otherwise, terminate search as we have found our MSL already.
+ let line = getline(lnum)
+ let col = match(line, s:msl_regex) + 1
+ if (col > 0 && !s:IsInStringOrComment(lnum, col)) || s:IsInString(lnum, strlen(line))
+ let msl = lnum
+ else
+ " Don't use lines that are part of a one line scope as msl unless the
+ " flag in_one_line_scope is set to 1
+ "
+ if a:in_one_line_scope
+ break
+ end
+ let msl_one_line = s:Match(lnum, s:one_line_scope_regex)
+ if msl_one_line == 0
+ break
+ endif
+ endif
+ let lnum = s:PrevNonBlankNonString(lnum - 1)
+ endwhile
+ return msl
+endfunction
+
+function s:RemoveTrailingComments(content)
+ let single = '\/\/\(.*\)\s*$'
+ let multi = '\/\*\(.*\)\*\/\s*$'
+ return substitute(substitute(a:content, single, '', ''), multi, '', '')
+endfunction
+
+" Find if the string is inside var statement (but not the first string)
+function s:InMultiVarStatement(lnum)
+ let lnum = s:PrevNonBlankNonString(a:lnum - 1)
+
+" let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name')
+
+ " loop through previous expressions to find a var statement
+ while lnum > 0
+ let line = getline(lnum)
+
+ " if the line is a js keyword
+ if (line =~ s:js_keywords)
+ " check if the line is a var stmt
+ " if the line has a comma first or comma last then we can assume that we
+ " are in a multiple var statement
+ if (line =~ s:var_stmt)
+ return lnum
+ endif
+
+ " other js keywords, not a var
+ return 0
+ endif
+
+ let lnum = s:PrevNonBlankNonString(lnum - 1)
+ endwhile
+
+ " beginning of program, not a var
+ return 0
+endfunction
+
+" Find line above with beginning of the var statement or returns 0 if it's not
+" this statement
+function s:GetVarIndent(lnum)
+ let lvar = s:InMultiVarStatement(a:lnum)
+ let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1)
+
+ if lvar
+ let line = s:RemoveTrailingComments(getline(prev_lnum))
+
+ " if the previous line doesn't end in a comma, return to regular indent
+ if (line !~ s:comma_last)
+ return indent(prev_lnum) - &sw
+ else
+ return indent(lvar) + &sw
+ endif
+ endif
+
+ return -1
+endfunction
+
+
+" Check if line 'lnum' has more opening brackets than closing ones.
+function s:LineHasOpeningBrackets(lnum)
+ let open_0 = 0
+ let open_2 = 0
+ let open_4 = 0
+ let line = getline(a:lnum)
+ let pos = match(line, '[][(){}]', 0)
+ while pos != -1
+ if !s:IsInStringOrComment(a:lnum, pos + 1)
+ let idx = stridx('(){}[]', line[pos])
+ if idx % 2 == 0
+ let open_{idx} = open_{idx} + 1
+ else
+ let open_{idx - 1} = open_{idx - 1} - 1
+ endif
+ endif
+ let pos = match(line, '[][(){}]', pos + 1)
+ endwhile
+ return (open_0 > 0) . (open_2 > 0) . (open_4 > 0)
+endfunction
+
+function s:Match(lnum, regex)
+ let col = match(getline(a:lnum), a:regex) + 1
+ return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0
+endfunction
+
+function s:IndentWithContinuation(lnum, ind, width)
+ " Set up variables to use and search for MSL to the previous line.
+ let p_lnum = a:lnum
+ let lnum = s:GetMSL(a:lnum, 1)
+ let line = getline(lnum)
+
+ " If the previous line wasn't a MSL and is continuation return its indent.
+ " TODO: the || s:IsInString() thing worries me a bit.
+ if p_lnum != lnum
+ if s:Match(p_lnum,s:continuation_regex)||s:IsInString(p_lnum,strlen(line))
+ return a:ind
+ endif
+ endif
+
+ " Set up more variables now that we know we aren't continuation bound.
+ let msl_ind = indent(lnum)
+
+ " If the previous line ended with [*+/.-=], start a continuation that
+ " indents an extra level.
+ if s:Match(lnum, s:continuation_regex)
+ if lnum == p_lnum
+ return msl_ind + a:width
+ else
+ return msl_ind
+ endif
+ endif
+
+ return a:ind
+endfunction
+
+function s:InOneLineScope(lnum)
+ let msl = s:GetMSL(a:lnum, 1)
+ if msl > 0 && s:Match(msl, s:one_line_scope_regex)
+ return msl
+ endif
+ return 0
+endfunction
+
+function s:ExitingOneLineScope(lnum)
+ let msl = s:GetMSL(a:lnum, 1)
+ if msl > 0
+ " if the current line is in a one line scope ..
+ if s:Match(msl, s:one_line_scope_regex)
+ return 0
+ else
+ let prev_msl = s:GetMSL(msl - 1, 1)
+ if s:Match(prev_msl, s:one_line_scope_regex)
+ return prev_msl
+ endif
+ endif
+ endif
+ return 0
+endfunction
+
+" 3. GetSolidityIndent Function {{{1
+" =========================
+
+function GetSolidityIndent()
+ " 3.1. Setup {{{2
+ " ----------
+
+ " Set up variables for restoring position in file. Could use v:lnum here.
+ let vcol = col('.')
+
+ " 3.2. Work on the current line {{{2
+ " -----------------------------
+
+ let ind = -1
+ " Get the current line.
+ let line = getline(v:lnum)
+ " previous nonblank line number
+ let prevline = prevnonblank(v:lnum - 1)
+
+ " If we got a closing bracket on an empty line, find its match and indent
+ " according to it. For parentheses we indent to its column - 1, for the
+ " others we indent to the containing line's MSL's level. Return -1 if fail.
+ let col = matchend(line, '^\s*[],})]')
+ if col > 0 && !s:IsInStringOrComment(v:lnum, col)
+ call cursor(v:lnum, col)
+
+ let lvar = s:InMultiVarStatement(v:lnum)
+ if lvar
+ let prevline_contents = s:RemoveTrailingComments(getline(prevline))
+
+ " check for comma first
+ if (line[col - 1] =~ ',')
+ " if the previous line ends in comma or semicolon don't indent
+ if (prevline_contents =~ '[;,]\s*$')
+ return indent(s:GetMSL(line('.'), 0))
+ " get previous line indent, if it's comma first return prevline indent
+ elseif (prevline_contents =~ s:comma_first)
+ return indent(prevline)
+ " otherwise we indent 1 level
+ else
+ return indent(lvar) + &sw
+ endif
+ endif
+ endif
+
+
+ let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
+ if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0
+ if line[col-1]==')' && col('.') != col('$') - 1
+ let ind = virtcol('.')-1
+ else
+ let ind = indent(s:GetMSL(line('.'), 0))
+ endif
+ endif
+ return ind
+ endif
+
+ " If the line is comma first, dedent 1 level
+ if (getline(prevline) =~ s:comma_first)
+ return indent(prevline) - &sw
+ endif
+
+ if (line =~ s:ternary)
+ if (getline(prevline) =~ s:ternary_q)
+ return indent(prevline)
+ else
+ return indent(prevline) + &sw
+ endif
+ endif
+
+ " If we are in a multi-line comment, cindent does the right thing.
+ if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1)
+ return cindent(v:lnum)
+ endif
+
+ " Check for multiple var assignments
+" let var_indent = s:GetVarIndent(v:lnum)
+" if var_indent >= 0
+" return var_indent
+" endif
+
+ " 3.3. Work on the previous line. {{{2
+ " -------------------------------
+
+ " If the line is empty and the previous nonblank line was a multi-line
+ " comment, use that comment's indent. Deduct one char to account for the
+ " space in ' */'.
+ if line =~ '^\s*$' && s:IsInMultilineComment(prevline, 1)
+ return indent(prevline) - 1
+ endif
+
+ " Find a non-blank, non-multi-line string line above the current line.
+ let lnum = s:PrevNonBlankNonString(v:lnum - 1)
+
+ " If the line is empty and inside a string, use the previous line.
+ if line =~ '^\s*$' && lnum != prevline
+ return indent(prevnonblank(v:lnum))
+ endif
+
+ " At the start of the file use zero indent.
+ if lnum == 0
+ return 0
+ endif
+
+ " Set up variables for current line.
+ let line = getline(lnum)
+ let ind = indent(lnum)
+
+ " If the previous line ended with a block opening, add a level of indent.
+ if s:Match(lnum, s:block_regex)
+ return indent(s:GetMSL(lnum, 0)) + &sw
+ endif
+
+ " If the previous line contained an opening bracket, and we are still in it,
+ " add indent depending on the bracket type.
+ if line =~ '[[({]'
+ let counts = s:LineHasOpeningBrackets(lnum)
+ if counts[0] == '1' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
+ if col('.') + 1 == col('$')
+ return ind + &sw
+ else
+ return virtcol('.')
+ endif
+ elseif counts[1] == '1' || counts[2] == '1'
+ return ind + &sw
+ else
+ call cursor(v:lnum, vcol)
+ end
+ endif
+
+ " 3.4. Work on the MSL line. {{{2
+ " --------------------------
+
+ let ind_con = ind
+ let ind = s:IndentWithContinuation(lnum, ind_con, &sw)
+
+ " }}}2
+ "
+ "
+ let ols = s:InOneLineScope(lnum)
+ if ols > 0
+ let ind = ind + &sw
+ else
+ let ols = s:ExitingOneLineScope(lnum)
+ while ols > 0 && ind > 0
+ let ind = ind - &sw
+ let ols = s:InOneLineScope(ols - 1)
+ endwhile
+ endif
+
+ return ind
+endfunction
+
+" }}}1
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in
index 5eb262f50..0582a930e 100644
--- a/runtime/indent/testdir/vim.in
+++ b/runtime/indent/testdir/vim.in
@@ -1,7 +1,6 @@
" vim: set ft=vim sw=4 :
" START_INDENT
-
func Some()
let x = 1
endfunc
@@ -15,15 +14,6 @@ let x = [
\ ]
endif
-" TODO: add searchpair() to find matching {
-"for x in [
-"{
-"key: 'value'
-"},
-"]
-"eval 0
-"endfor
-
for x in [
{key: 'value'},
]
@@ -37,12 +27,11 @@ let t = [
\ ]
def Func()
- var d = dd
- ->extend({
- })
- eval 0
+var d = dd
+->extend({
+})
+eval 0
enddef
-
" END_INDENT
" START_INDENT
@@ -84,7 +73,7 @@ endfunc
" START_INDENT
" INDENT_NEXT next-line
func Some()
- " next-line
+ " next-line
let f = x
endfunc
" END_INDENT
@@ -104,6 +93,12 @@ END
" END_INDENT
" START_INDENT
+let a =<< trim END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
" INDENT_AT this-line
let a=<< trim END
blah
@@ -111,3 +106,754 @@ let a=<< trim END
blah this-line
END
" END_INDENT
+
+" START_INDENT
+if v:true
+echo 0
+end
+" END_INDENT
+
+" START_INDENT
+var result = Func(
+arg1,
+arg2
+)
+" END_INDENT
+
+" START_INDENT
+var result = Func(arg1,
+arg2)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) =>
+v > 0)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) => {
+const x = get(list, k, 0)
+return x > 0
+})
+" END_INDENT
+
+" START_INDENT
+if x > 0
+filter(list, (k, v) => {
+const x = get(list, k, 1)
+return x > 0
+})
+endif
+" END_INDENT
+
+" START_INDENT
+{
+var temp = 'temp'
+}
+" END_INDENT
+
+" START_INDENT
+var text = lead
+.. middle
+.. end
+" END_INDENT
+
+" START_INDENT
+var text = lead ..
+middle ..
+end
+" END_INDENT
+
+" START_INDENT
+var total = start +
+end -
+correction
+" END_INDENT
+
+" START_INDENT
+var result = start
+:+ print
+" END_INDENT
+
+" START_INDENT
+var result = positive
+? PosFunc(arg)
+: NegFunc(arg)
+" END_INDENT
+
+" START_INDENT
+var result = GetBuilder()
+->BuilderSetWidth(333)
+->BuilderSetHeight(777)
+->BuilderBuild()
+" END_INDENT
+
+" START_INDENT
+var result = MyDict
+.member
+" END_INDENT
+
+" START_INDENT
+autocmd BufNewFile *.match if condition
+| echo 'match'
+| endif
+" END_INDENT
+
+" START_INDENT
+set cpo+=C
+var lines =<< trim END
+| this works
+END
+set cpo-=C
+" END_INDENT
+
+" START_INDENT
+syn region Text
+\ start='foo'
+#\ comment
+\ end='bar'
+" END_INDENT
+
+" START_INDENT
+au CursorHold * echom 'BEFORE bar'
+#\ some comment
+| echom 'AFTER bar'
+" END_INDENT
+
+" START_INDENT
+def MyFunc(text: string,
+separator = '-'
+): string
+enddef
+" END_INDENT
+
+" START_INDENT
+def MyFunc(
+text: string,
+separator = '-'
+): string
+enddef
+" END_INDENT
+
+" START_INDENT
+[var1, var2] =
+Func()
+" END_INDENT
+
+" START_INDENT
+const list = ['one',
+'two']
+" END_INDENT
+
+" START_INDENT
+const list = [
+'one',
+'two',
+]
+" END_INDENT
+
+" START_INDENT
+const dict = {one: 1,
+two: 2
+}
+" END_INDENT
+
+" START_INDENT
+const dict = {
+one: 1,
+two: 2
+}
+" END_INDENT
+
+" START_INDENT
+if true
+const dict =
+{
+one: 1,
+two: 2
+}
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+return {
+one: 1
+}
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+a: 0,
+# b
+# c
+}
+" END_INDENT
+
+" START_INDENT
+echo search(
+# comment
+'1'
+.. '2'
+)
+" END_INDENT
+
+" START_INDENT
+if true
+var v = ( # trailing "(" starts line continuation
+3 + 4 # nothing special
+) # end of expression indicates continued line
+var x: number # needs to align with previous "var"
+endif
+" END_INDENT
+
+" START_INDENT
+def Func() # {{{
+# comment
+if true
+return
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+key:
+'value',
+}
+" END_INDENT
+
+" START_INDENT
+var id = time
+->timer_start((_) => {
+n = 0
+})
+" END_INDENT
+
+" START_INDENT
+augroup Name
+autocmd!
+augroup END
+" END_INDENT
+
+" START_INDENT
+var n =
+# comment
+1
++ 2
+
+var s = ''
+" END_INDENT
+
+" START_INDENT
+var keys = {
+J: 'j',
+"\<Home>": '1G',
+"\<End>": 'G',
+z: 'zz'
+}
+" END_INDENT
+
+" START_INDENT
+export def Func(
+n: number,
+s: string,
+...l: list<bool>
+)
+enddef
+" END_INDENT
+
+" START_INDENT
+var heredoc =<< trim ENDD
+var nested_heredoc =<< trim END
+END
+ENDD
+" END_INDENT
+
+" START_INDENT
+if true
+else " comment
+endif
+" END_INDENT
+
+" START_INDENT
+if true | echo 'one' | endif
+if true | echo 'two' | endif
+if true | echo 'three' | endif
+" END_INDENT
+
+" START_INDENT
+if true
+:'<-1 mark <
+else
+echo ''
+endif
+" END_INDENT
+
+" START_INDENT
+substitute/pat /rep /
+echo
+" END_INDENT
+
+" START_INDENT
+try
+echo 1
+catch /pat / # comment
+echo 2
+endtry
+" END_INDENT
+
+" START_INDENT
+def Func()
+Cmd %
+enddef
+" END_INDENT
+
+" START_INDENT
+if end == 'xxx' || end == 'yyy'
+echo
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+popup_move(id, {col: 1,
+line: 2})
+endif
+setwinvar(id, 'name', 3)
+" END_INDENT
+
+" START_INDENT
+var d = [
+{a: 'x',
+b: 'y'},
+FuncA(),
+FuncB(),
+]
+" END_INDENT
+
+" START_INDENT
+var ll = [[
+1,
+2,
+3], [
+4,
+5,
+6], [
+7,
+8,
+9]]
+" END_INDENT
+
+" START_INDENT
+var ld = [{
+a: 'xxx',
+b: 'yyy'}, {
+c: 'xxx',
+d: 'yyy'}, {
+e: 'xxx',
+f: 'yyy'}, {
+}]
+" END_INDENT
+
+" START_INDENT
+var d = {
+a: {
+b: {
+c: [{
+d: 'e',
+f: 'g',
+h: 'i'
+}],
+j: 'k',
+},
+},
+}
+" END_INDENT
+
+" START_INDENT
+if true
+var end: any
+if true
+end = 0
+elseif true
+echo
+endif
+endif
+" END_INDENT
+
+" START_INDENT
+nunmap <buffer> (
+nunmap <buffer> )
+inoremap [ {
+inoremap ] }
+silent! xunmap i{
+silent! xunmap a{
+" END_INDENT
+
+" START_INDENT
+def Func(
+s: string,
+n = 1,
+m = 2
+)
+enddef
+" END_INDENT
+
+" START_INDENT
+var h =<< END
+text
+END
+
+def Func()
+echo
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+var h =<< END
+text
+END
+echo 'test'
+enddef
+" END_INDENT
+
+" START_INDENT
+def Foo()
+lcd -
+enddef
+def Bar()
+echo
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+n = Func(1, 2,
+3)
+endif
+" END_INDENT
+
+" START_INDENT
+def Func(s: string,
+n: number): bool
+if true
+return false
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func(
+n: number)
+#
+echo
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+def Func(
+ n: number)
+ #
+echo # this-line
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+if true
+normal! ==
+endif
+endif
+" END_INDENT
+
+" START_INDENT
+var d = {
+a: () => true,
+b: () => true
+&& true
+&& Foo(),
+c: () => Bar(),
+e: () => Baz(),
+}
+" END_INDENT
+
+" START_INDENT
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+return (Emit: func(any)) => {
+Cont((t: any) => {
+if Pred(t)
+Emit(t)
+endif
+})
+}
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:vim_indent = {'more_in_bracket_block': v:true}
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+return (Emit: func(any)) => {
+Cont((t: any) => {
+if Pred(t)
+Emit(t)
+endif
+})
+}
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE unlet! g:vim_indent
+" END_INDENT
+
+" START_INDENT
+g:lightline = {
+'active': {
+'left': [ [ 'mode', 'paste' ], [ 'readonly', 'relativepath', 'modified' ] ],
+},
+'inactive': {
+'left': [ [ 'readonly', 'relativepath', 'modified' ] ],
+}
+}
+" END_INDENT
+
+" START_INDENT
+if getline(1, 10)
+->map((_, v: string): number => strcharlen(v))
+->max() > 1'000
+&l:breakindent = false
+&l:linebreak = false
+else
+&l:breakindent = true
+&l:linebreak = true
+endif
+" END_INDENT
+
+" START_INDENT
+var ext2cmd: dict<string> = {
+doc: $'antiword {fname}',
+docx: $'pandoc --from=docx --to=markdown {fname}',
+epub: $'pandoc --from=epub --to=markdown {fname}',
+odp: $'odt2txt {fname}',
+odt: $'odt2txt {fname}',
+pdf: $'pdftotext -nopgbrk -layout -q -eol unix {fname} -',
+rtf: 'unrtf --text',
+}
+" END_INDENT
+
+" START_INDENT
+const ptybuf: number = term_start(&shell, {
+hidden: true,
+exit_cb: (_, _) => {
+if true
+close
+else
+help
+endif
+}
+})
+" END_INDENT
+
+" START_INDENT
+var d = {
+a: 0,
+# a ' quote {{{
+#}}}
+b: 0,
+}
+" END_INDENT
+
+" START_INDENT
+echo printf('%s () %s',
+1,
+2
+)
+" END_INDENT
+
+" START_INDENT
+prop_add(1, col('.'), {
+length: 2,
+type: 'test'
+})
+" END_INDENT
+
+" START_INDENT
+echo (() => " string starting with space")()
+echo
+" END_INDENT
+
+" START_INDENT
+var variables = deepcopy(g:)
+->filter((k: string, _): bool =>
+k =~ '\c\V' .. keyword->escape('\')
+&& k !~ '\%(loaded\|did_plugin_\)')
+->items()
+->map((_, v): string => v[0] .. ' = ' .. string(v[1]))
+new
+" END_INDENT
+
+" START_INDENT
+var d = freq
+->map((_, v) =>
+v * (
+1
++ 2
+))
+for item in d
+->items()
+->sort((a, b) => b[1] - a[1])
+echo
+endfor
+" END_INDENT
+
+" START_INDENT
+make_job = job_start([&shell, &shellcmdflag, make_cmd], {
+callback: function(MakeProcessOutput, [qfid]),
+close_cb: function(MakeCloseCb, [qfid]),
+exit_cb: MakeCompleted,
+in_io: 'null'
+})
+" END_INDENT
+
+" START_INDENT
+var matching_abbrev: list<dict<string>> = copy(ABBREV)
+->filter((_, v: dict<string>): bool =>
+stridx(v.lhs, word_to_complete) == 0)
+->map((_, v: dict<string>) => ({
+word: v.lhs,
+menu: AbbrevRhs(v.rhs)->stridx('expand_') >= 0
+? AbbrevRhs(v.rhs)->matchstr('.*,\s*''\zs.*\ze'')')
+: AbbrevRhs(v.rhs)
+}))
+" END_INDENT
+
+" START_INDENT
+def Func()
+if true
+vimgrep /^\C\s*\%(fu\%[nction]\|def\)\s\+/ file
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+setlocal iskeyword+=[
+cword = expand('<cword>')
+" END_INDENT
+
+" START_INDENT
+silent if true
+echo
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+sort :^.*[\/]:
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+d = {
+}
+hd =<< trim END
+['
+]'
+END
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+if true
+var hd =<< trim END
+if get(b:, 'current_syntax', '')
+endif
+END
+elseif true
+echo
+endif
+enddef
+" END_INDENT
+
+" START_INDENT
+# test for control-flow keyword followed by commented fold marker {{{
+if true
+echo
+endif #}}}
+" END_INDENT
+
+" START_INDENT
+if winsz == 0|let winsz= ""|endif
+exe "noswapfile ".winsz."wincmd s"
+" END_INDENT
+
+" START_INDENT
+if true
+if true
+windo if true | echo | endif
+augroup Name
+autocmd WinLeave * if true | eval 1 + 2 | endif
+augroup END
+endif
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+echo ' =<< trim END'
+->len()
+endif
+" END_INDENT
+
+" START_INDENT
+function Func()
+if true
+if true
+if true | echo com | endif
+if true | echo com | endif
+endif
+else
+endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+function Func()
+if v:true
++
+echo
+-
+endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+var matchpairs: string = &matchpairs
+var pairs: dict<list<string>>
+for [opening: string, closing: string]
+in matchpairs
+->split(',')
+->map((_, v: string): list<string> => split(v, ':'))
+pairs[opening] = [escape(opening, '[]'), escape(closing, '[]'), 'nW', 'w$']
+pairs[closing] = [escape(opening, '[]'), escape(closing, '[]'), 'bnW', 'w0']
+endfor
+" END_INDENT
+
+" START_INDENT
+{
+echo []
++ []
++ [{a: 1,
+b: 2}]
+}
+" END_INDENT
+
+" START_INDENT
+silent! argdel *
+edit file
+" END_INDENT
diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok
index 932eebef4..39efdbaac 100644
--- a/runtime/indent/testdir/vim.ok
+++ b/runtime/indent/testdir/vim.ok
@@ -1,7 +1,6 @@
" vim: set ft=vim sw=4 :
" START_INDENT
-
func Some()
let x = 1
endfunc
@@ -15,15 +14,6 @@ if 1
\ ]
endif
-" TODO: add searchpair() to find matching {
-"for x in [
-"{
-"key: 'value'
-"},
-"]
-"eval 0
-"endfor
-
for x in [
{key: 'value'},
]
@@ -38,11 +28,10 @@ let t = [
def Func()
var d = dd
- ->extend({
- })
+ ->extend({
+ })
eval 0
enddef
-
" END_INDENT
" START_INDENT
@@ -69,7 +58,7 @@ let list = [
let list = [
'one',
'two',
- ]
+]
echo
" END_INDENT
@@ -84,8 +73,8 @@ endfunc
" START_INDENT
" INDENT_NEXT next-line
func Some()
- " next-line
- let f = x
+ " next-line
+ let f = x
endfunc
" END_INDENT
@@ -99,6 +88,12 @@ endfunc
" START_INDENT
let a =<< END
+nothing
+END
+" END_INDENT
+
+" START_INDENT
+let a =<< trim END
nothing
END
" END_INDENT
@@ -111,3 +106,754 @@ let a=<< trim END
blah this-line
END
" END_INDENT
+
+" START_INDENT
+if v:true
+ echo 0
+end
+" END_INDENT
+
+" START_INDENT
+var result = Func(
+ arg1,
+ arg2
+)
+" END_INDENT
+
+" START_INDENT
+var result = Func(arg1,
+ arg2)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) =>
+ v > 0)
+" END_INDENT
+
+" START_INDENT
+filter(list, (k, v) => {
+ const x = get(list, k, 0)
+ return x > 0
+})
+" END_INDENT
+
+" START_INDENT
+if x > 0
+ filter(list, (k, v) => {
+ const x = get(list, k, 1)
+ return x > 0
+ })
+endif
+" END_INDENT
+
+" START_INDENT
+{
+ var temp = 'temp'
+}
+" END_INDENT
+
+" START_INDENT
+var text = lead
+ .. middle
+ .. end
+" END_INDENT
+
+" START_INDENT
+var text = lead ..
+ middle ..
+ end
+" END_INDENT
+
+" START_INDENT
+var total = start +
+ end -
+ correction
+" END_INDENT
+
+" START_INDENT
+var result = start
+:+ print
+" END_INDENT
+
+" START_INDENT
+var result = positive
+ ? PosFunc(arg)
+ : NegFunc(arg)
+" END_INDENT
+
+" START_INDENT
+var result = GetBuilder()
+ ->BuilderSetWidth(333)
+ ->BuilderSetHeight(777)
+ ->BuilderBuild()
+" END_INDENT
+
+" START_INDENT
+var result = MyDict
+ .member
+" END_INDENT
+
+" START_INDENT
+autocmd BufNewFile *.match if condition
+ | echo 'match'
+ | endif
+" END_INDENT
+
+" START_INDENT
+set cpo+=C
+var lines =<< trim END
+ | this works
+END
+set cpo-=C
+" END_INDENT
+
+" START_INDENT
+syn region Text
+ \ start='foo'
+ #\ comment
+ \ end='bar'
+" END_INDENT
+
+" START_INDENT
+au CursorHold * echom 'BEFORE bar'
+ #\ some comment
+ | echom 'AFTER bar'
+" END_INDENT
+
+" START_INDENT
+def MyFunc(text: string,
+ separator = '-'
+ ): string
+enddef
+" END_INDENT
+
+" START_INDENT
+def MyFunc(
+ text: string,
+ separator = '-'
+ ): string
+enddef
+" END_INDENT
+
+" START_INDENT
+[var1, var2] =
+ Func()
+" END_INDENT
+
+" START_INDENT
+const list = ['one',
+ 'two']
+" END_INDENT
+
+" START_INDENT
+const list = [
+ 'one',
+ 'two',
+]
+" END_INDENT
+
+" START_INDENT
+const dict = {one: 1,
+ two: 2
+}
+" END_INDENT
+
+" START_INDENT
+const dict = {
+ one: 1,
+ two: 2
+}
+" END_INDENT
+
+" START_INDENT
+if true
+ const dict =
+ {
+ one: 1,
+ two: 2
+ }
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+ return {
+ one: 1
+ }
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+ a: 0,
+ # b
+ # c
+}
+" END_INDENT
+
+" START_INDENT
+echo search(
+ # comment
+ '1'
+ .. '2'
+)
+" END_INDENT
+
+" START_INDENT
+if true
+ var v = ( # trailing "(" starts line continuation
+ 3 + 4 # nothing special
+ ) # end of expression indicates continued line
+ var x: number # needs to align with previous "var"
+endif
+" END_INDENT
+
+" START_INDENT
+def Func() # {{{
+ # comment
+ if true
+ return
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+echo {
+ key:
+ 'value',
+}
+" END_INDENT
+
+" START_INDENT
+var id = time
+ ->timer_start((_) => {
+ n = 0
+ })
+" END_INDENT
+
+" START_INDENT
+augroup Name
+ autocmd!
+augroup END
+" END_INDENT
+
+" START_INDENT
+var n =
+ # comment
+ 1
+ + 2
+
+var s = ''
+" END_INDENT
+
+" START_INDENT
+var keys = {
+ J: 'j',
+ "\<Home>": '1G',
+ "\<End>": 'G',
+ z: 'zz'
+}
+" END_INDENT
+
+" START_INDENT
+export def Func(
+ n: number,
+ s: string,
+ ...l: list<bool>
+ )
+enddef
+" END_INDENT
+
+" START_INDENT
+var heredoc =<< trim ENDD
+ var nested_heredoc =<< trim END
+ END
+ENDD
+" END_INDENT
+
+" START_INDENT
+if true
+else " comment
+endif
+" END_INDENT
+
+" START_INDENT
+if true | echo 'one' | endif
+if true | echo 'two' | endif
+if true | echo 'three' | endif
+" END_INDENT
+
+" START_INDENT
+if true
+ :'<-1 mark <
+else
+ echo ''
+endif
+" END_INDENT
+
+" START_INDENT
+substitute/pat /rep /
+echo
+" END_INDENT
+
+" START_INDENT
+try
+ echo 1
+catch /pat / # comment
+ echo 2
+endtry
+" END_INDENT
+
+" START_INDENT
+def Func()
+ Cmd %
+enddef
+" END_INDENT
+
+" START_INDENT
+if end == 'xxx' || end == 'yyy'
+ echo
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+ popup_move(id, {col: 1,
+ line: 2})
+endif
+setwinvar(id, 'name', 3)
+" END_INDENT
+
+" START_INDENT
+var d = [
+ {a: 'x',
+ b: 'y'},
+ FuncA(),
+ FuncB(),
+]
+" END_INDENT
+
+" START_INDENT
+var ll = [[
+ 1,
+ 2,
+ 3], [
+ 4,
+ 5,
+ 6], [
+ 7,
+ 8,
+ 9]]
+" END_INDENT
+
+" START_INDENT
+var ld = [{
+ a: 'xxx',
+ b: 'yyy'}, {
+ c: 'xxx',
+ d: 'yyy'}, {
+ e: 'xxx',
+ f: 'yyy'}, {
+ }]
+" END_INDENT
+
+" START_INDENT
+var d = {
+ a: {
+ b: {
+ c: [{
+ d: 'e',
+ f: 'g',
+ h: 'i'
+ }],
+ j: 'k',
+ },
+ },
+}
+" END_INDENT
+
+" START_INDENT
+if true
+ var end: any
+ if true
+ end = 0
+ elseif true
+ echo
+ endif
+endif
+" END_INDENT
+
+" START_INDENT
+nunmap <buffer> (
+nunmap <buffer> )
+inoremap [ {
+inoremap ] }
+silent! xunmap i{
+silent! xunmap a{
+" END_INDENT
+
+" START_INDENT
+def Func(
+ s: string,
+ n = 1,
+ m = 2
+ )
+enddef
+" END_INDENT
+
+" START_INDENT
+var h =<< END
+text
+END
+
+def Func()
+ echo
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+ var h =<< END
+text
+END
+ echo 'test'
+enddef
+" END_INDENT
+
+" START_INDENT
+def Foo()
+ lcd -
+enddef
+def Bar()
+ echo
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+ n = Func(1, 2,
+ 3)
+endif
+" END_INDENT
+
+" START_INDENT
+def Func(s: string,
+ n: number): bool
+ if true
+ return false
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func(
+ n: number)
+ #
+ echo
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_AT this-line
+def Func(
+ n: number)
+ #
+ echo # this-line
+enddef
+" END_INDENT
+
+" START_INDENT
+if true
+ if true
+ normal! ==
+ endif
+endif
+" END_INDENT
+
+" START_INDENT
+var d = {
+ a: () => true,
+ b: () => true
+ && true
+ && Foo(),
+ c: () => Bar(),
+ e: () => Baz(),
+}
+" END_INDENT
+
+" START_INDENT
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+ return (Emit: func(any)) => {
+ Cont((t: any) => {
+ if Pred(t)
+ Emit(t)
+ endif
+ })
+ }
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE let g:vim_indent = {'more_in_bracket_block': v:true}
+def Select(Cont: func(func(any)), Pred: func(any): bool): func(func(any))
+ return (Emit: func(any)) => {
+ Cont((t: any) => {
+ if Pred(t)
+ Emit(t)
+ endif
+ })
+ }
+enddef
+" END_INDENT
+
+" START_INDENT
+" INDENT_EXE unlet! g:vim_indent
+" END_INDENT
+
+" START_INDENT
+g:lightline = {
+ 'active': {
+ 'left': [ [ 'mode', 'paste' ], [ 'readonly', 'relativepath', 'modified' ] ],
+ },
+ 'inactive': {
+ 'left': [ [ 'readonly', 'relativepath', 'modified' ] ],
+ }
+}
+" END_INDENT
+
+" START_INDENT
+if getline(1, 10)
+ ->map((_, v: string): number => strcharlen(v))
+ ->max() > 1'000
+ &l:breakindent = false
+ &l:linebreak = false
+else
+ &l:breakindent = true
+ &l:linebreak = true
+endif
+" END_INDENT
+
+" START_INDENT
+var ext2cmd: dict<string> = {
+ doc: $'antiword {fname}',
+ docx: $'pandoc --from=docx --to=markdown {fname}',
+ epub: $'pandoc --from=epub --to=markdown {fname}',
+ odp: $'odt2txt {fname}',
+ odt: $'odt2txt {fname}',
+ pdf: $'pdftotext -nopgbrk -layout -q -eol unix {fname} -',
+ rtf: 'unrtf --text',
+}
+" END_INDENT
+
+" START_INDENT
+const ptybuf: number = term_start(&shell, {
+ hidden: true,
+ exit_cb: (_, _) => {
+ if true
+ close
+ else
+ help
+ endif
+ }
+})
+" END_INDENT
+
+" START_INDENT
+var d = {
+ a: 0,
+ # a ' quote {{{
+ #}}}
+ b: 0,
+}
+" END_INDENT
+
+" START_INDENT
+echo printf('%s () %s',
+ 1,
+ 2
+)
+" END_INDENT
+
+" START_INDENT
+prop_add(1, col('.'), {
+ length: 2,
+ type: 'test'
+})
+" END_INDENT
+
+" START_INDENT
+echo (() => " string starting with space")()
+echo
+" END_INDENT
+
+" START_INDENT
+var variables = deepcopy(g:)
+ ->filter((k: string, _): bool =>
+ k =~ '\c\V' .. keyword->escape('\')
+ && k !~ '\%(loaded\|did_plugin_\)')
+ ->items()
+ ->map((_, v): string => v[0] .. ' = ' .. string(v[1]))
+new
+" END_INDENT
+
+" START_INDENT
+var d = freq
+ ->map((_, v) =>
+ v * (
+ 1
+ + 2
+ ))
+for item in d
+ ->items()
+ ->sort((a, b) => b[1] - a[1])
+ echo
+endfor
+" END_INDENT
+
+" START_INDENT
+make_job = job_start([&shell, &shellcmdflag, make_cmd], {
+ callback: function(MakeProcessOutput, [qfid]),
+ close_cb: function(MakeCloseCb, [qfid]),
+ exit_cb: MakeCompleted,
+ in_io: 'null'
+})
+" END_INDENT
+
+" START_INDENT
+var matching_abbrev: list<dict<string>> = copy(ABBREV)
+ ->filter((_, v: dict<string>): bool =>
+ stridx(v.lhs, word_to_complete) == 0)
+ ->map((_, v: dict<string>) => ({
+ word: v.lhs,
+ menu: AbbrevRhs(v.rhs)->stridx('expand_') >= 0
+ ? AbbrevRhs(v.rhs)->matchstr('.*,\s*''\zs.*\ze'')')
+ : AbbrevRhs(v.rhs)
+ }))
+" END_INDENT
+
+" START_INDENT
+def Func()
+ if true
+ vimgrep /^\C\s*\%(fu\%[nction]\|def\)\s\+/ file
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+setlocal iskeyword+=[
+cword = expand('<cword>')
+" END_INDENT
+
+" START_INDENT
+silent if true
+ echo
+endif
+" END_INDENT
+
+" START_INDENT
+def Func()
+ sort :^.*[\/]:
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+ d = {
+ }
+ hd =<< trim END
+ ['
+ ]'
+ END
+enddef
+" END_INDENT
+
+" START_INDENT
+def Func()
+ if true
+ var hd =<< trim END
+ if get(b:, 'current_syntax', '')
+ endif
+ END
+ elseif true
+ echo
+ endif
+enddef
+" END_INDENT
+
+" START_INDENT
+# test for control-flow keyword followed by commented fold marker {{{
+if true
+ echo
+endif #}}}
+" END_INDENT
+
+" START_INDENT
+if winsz == 0|let winsz= ""|endif
+exe "noswapfile ".winsz."wincmd s"
+" END_INDENT
+
+" START_INDENT
+if true
+ if true
+ windo if true | echo | endif
+ augroup Name
+ autocmd WinLeave * if true | eval 1 + 2 | endif
+ augroup END
+ endif
+endif
+" END_INDENT
+
+" START_INDENT
+if true
+ echo ' =<< trim END'
+ ->len()
+endif
+" END_INDENT
+
+" START_INDENT
+function Func()
+ if true
+ if true
+ if true | echo com | endif
+ if true | echo com | endif
+ endif
+ else
+ endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+function Func()
+ if v:true
+ +
+ echo
+ -
+ endif
+endfunction
+" END_INDENT
+
+" START_INDENT
+var matchpairs: string = &matchpairs
+var pairs: dict<list<string>>
+for [opening: string, closing: string]
+ in matchpairs
+ ->split(',')
+ ->map((_, v: string): list<string> => split(v, ':'))
+ pairs[opening] = [escape(opening, '[]'), escape(closing, '[]'), 'nW', 'w$']
+ pairs[closing] = [escape(opening, '[]'), escape(closing, '[]'), 'bnW', 'w0']
+endfor
+" END_INDENT
+
+" START_INDENT
+{
+ echo []
+ + []
+ + [{a: 1,
+ b: 2}]
+}
+" END_INDENT
+
+" START_INDENT
+silent! argdel *
+edit file
+" END_INDENT
diff --git a/runtime/indent/vim.vim b/runtime/indent/vim.vim
index 2ae3658a4..2f59dfc86 100644
--- a/runtime/indent/vim.vim
+++ b/runtime/indent/vim.vim
@@ -1,214 +1,22 @@
-" Vim indent file
-" Language: Vim script
-" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2022 Jun 24
+vim9script
-" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
- finish
-endif
-let b:did_indent = 1
-
-setlocal indentexpr=GetVimIndent()
-setlocal indentkeys+==endif,=enddef,=endfu,=endfor,=endwh,=endtry,=},=else,=cat,=finall,=END,0\\,0=\"\\\
-setlocal indentkeys-=0#
-setlocal indentkeys-=:
+# Vim indent file
+# Language: Vim script
+# Maintainer: Bram Moolenaar <Bram@vim.org>
+# Last Change: 2022 Sep 27
-let b:undo_indent = "setl indentkeys< indentexpr<"
-
-" Only define the function once.
-if exists("*GetVimIndent")
- finish
+# Only load this indent file when no other was loaded.
+if exists('b:did_indent')
+ finish
endif
-let s:keepcpo= &cpo
-set cpo&vim
-
-function GetVimIndent()
- let ignorecase_save = &ignorecase
- try
- let &ignorecase = 0
- return GetVimIndentIntern()
- finally
- let &ignorecase = ignorecase_save
- endtry
-endfunc
-
-" Legacy script line continuation and Vim9 script operators that must mean an
-" expression that continues from the previous line.
-let s:lineContPat = '^\s*\(\\\|"\\ \|->\)'
-
-function GetVimIndentIntern()
- " If the current line has line continuation and the previous one too, use
- " the same indent. This does not skip empty lines.
- let cur_text = getline(v:lnum)
- let cur_has_linecont = cur_text =~ s:lineContPat
- if cur_has_linecont && v:lnum > 1 && getline(v:lnum - 1) =~ s:lineContPat
- return indent(v:lnum - 1)
- endif
-
- " Find a non-blank line above the current line.
- let lnum = prevnonblank(v:lnum - 1)
-
- " The previous line, ignoring line continuation
- let prev_text_end = lnum > 0 ? getline(lnum) : ''
-
- " If the current line doesn't start with '\' or '"\ ' and below a line that
- " starts with '\' or '"\ ', use the indent of the line above it.
- if !cur_has_linecont
- while lnum > 0 && getline(lnum) =~ s:lineContPat
- let lnum = lnum - 1
- endwhile
- endif
-
- " At the start of the file use zero indent.
- if lnum == 0
- return 0
- endif
-
- " the start of the previous line, skipping over line continuation
- let prev_text = getline(lnum)
- let found_cont = 0
- " Add a 'shiftwidth' after :if, :while, :try, :catch, :finally, :function
- " and :else. Add it three times for a line that starts with '\' or '"\ '
- " after a line that doesn't (or g:vim_indent_cont if it exists).
- let ind = indent(lnum)
+b:did_indent = true
+b:undo_indent = 'setlocal indentkeys< indentexpr<'
- " In heredoc indenting works completely differently.
- if has('syntax_items')
- let syn_here = synIDattr(synID(v:lnum, 1, 1), "name")
- if syn_here =~ 'vimLetHereDocStop'
- " End of heredoc: use indent of matching start line
- let lnum = v:lnum - 1
- while lnum > 0
- let attr = synIDattr(synID(lnum, 1, 1), "name")
- if attr != '' && attr !~ 'vimLetHereDoc'
- return indent(lnum)
- endif
- let lnum -= 1
- endwhile
- return 0
- endif
- if syn_here =~ 'vimLetHereDoc'
- if synIDattr(synID(lnum, 1, 1), "name") !~ 'vimLetHereDoc'
- " First line in heredoc: increase indent
- return ind + shiftwidth()
- endif
- " Heredoc continues: no change in indent
- return ind
- endif
- endif
+import autoload '../autoload/dist/vimindent.vim'
- if cur_text =~ s:lineContPat && v:lnum > 1 && prev_text !~ s:lineContPat
- let found_cont = 1
- if exists("g:vim_indent_cont")
- let ind = ind + g:vim_indent_cont
- else
- let ind = ind + shiftwidth() * 3
- endif
- elseif prev_text =~ '^\s*aug\%[roup]\s\+' && prev_text !~ '^\s*aug\%[roup]\s\+[eE][nN][dD]\>'
- let ind = ind + shiftwidth()
- else
- " A line starting with :au does not increment/decrement indent.
- " A { may start a block or a dict. Assume that when a } follows it's a
- " terminated dict.
- " ":function" starts a block but "function(" doesn't.
- if prev_text !~ '^\s*au\%[tocmd]' && prev_text !~ '^\s*{.*}'
- let i = match(prev_text, '\(^\||\)\s*\(export\s\+\)\?\({\|\(if\|wh\%[ile]\|for\|try\|cat\%[ch]\|fina\|finall\%[y]\|def\|el\%[seif]\)\>\|fu\%[nction][! ]\)')
- if i >= 0
- let ind += shiftwidth()
- if strpart(prev_text, i, 1) == '|' && has('syntax_items')
- \ && synIDattr(synID(lnum, i, 1), "name") =~ '\(Comment\|String\|PatSep\)$'
- let ind -= shiftwidth()
- endif
- endif
- endif
- endif
-
- " If the previous line contains an "end" after a pipe, but not in an ":au"
- " command. And not when there is a backslash before the pipe.
- " And when syntax HL is enabled avoid a match inside a string.
- let i = match(prev_text, '[^\\]|\s*\(ene\@!\)')
- if i > 0 && prev_text !~ '^\s*au\%[tocmd]'
- if !has('syntax_items') || synIDattr(synID(lnum, i + 2, 1), "name") !~ '\(Comment\|String\)$'
- let ind = ind - shiftwidth()
- endif
- endif
-
- " For a line starting with "}" find the matching "{". Align with that line,
- " it is either the matching block start or dictionary start.
- " Use the mapped "%" from matchit to find the match, otherwise we may match
- " a { inside a comment or string.
- if cur_text =~ '^\s*}'
- if maparg('%') != ''
- exe v:lnum
- silent! normal %
- if line('.') < v:lnum
- let ind = indent('.')
- endif
- else
- " todo: use searchpair() to find a match
- endif
- endif
-
- " Look back for a line to align with
- while lnum > 1
- " Below a line starting with "}" find the matching "{".
- if prev_text =~ '^\s*}'
- if maparg('%') != ''
- exe lnum
- silent! normal %
- if line('.') < lnum
- let lnum = line('.')
- let ind = indent(lnum)
- let prev_text = getline(lnum)
- else
- break
- endif
- else
- " todo: use searchpair() to find a match
- break
- endif
- elseif prev_text =~ s:lineContPat
- " looks like a continuation like, go back one line
- let lnum = lnum - 1
- let ind = indent(lnum)
- let prev_text = getline(lnum)
- else
- break
- endif
- endwhile
-
- " Below a line starting with "]" we must be below the end of a list.
- " Include a "}" and "},} in case a dictionary ends too.
- if prev_text_end =~ '^\s*\(},\=\s*\)\=]'
- let ind = ind - shiftwidth()
- endif
-
- let ends_in_comment = has('syntax_items')
- \ && synIDattr(synID(lnum, len(getline(lnum)), 1), "name") =~ '\(Comment\|String\)$'
-
- " A line ending in "{" or "[" is most likely the start of a dict/list literal,
- " indent the next line more. Not for a continuation line or {{{.
- if !ends_in_comment && prev_text_end =~ '\s[{[]\s*$' && !found_cont
- let ind = ind + shiftwidth()
- endif
-
- " Subtract a 'shiftwidth' on a :endif, :endwhile, :endfor, :catch, :finally,
- " :endtry, :endfun, :enddef, :else and :augroup END.
- " Although ":en" would be enough only match short command names as in
- " 'indentkeys'.
- if cur_text =~ '^\s*\(endif\|endwh\|endfor\|endtry\|endfu\|enddef\|cat\|finall\|else\|aug\%[roup]\s\+[eE][nN][dD]\)'
- let ind = ind - shiftwidth()
- if ind < 0
- let ind = 0
- endif
- endif
-
- return ind
-endfunction
-
-let &cpo = s:keepcpo
-unlet s:keepcpo
-
-" vim:sw=2
+setlocal indentexpr=vimindent.Expr(v:lnum)
+setlocal indentkeys+==endif,=enddef,=endfu,=endfor,=endwh,=endtry,=},=else,=cat,=finall,=END,0\\
+execute('setlocal indentkeys+=0=\"\\\ ,0=#\\\ ')
+setlocal indentkeys-=0#
+setlocal indentkeys-=:
diff --git a/runtime/indent/vue.vim b/runtime/indent/vue.vim
new file mode 100644
index 000000000..7ff623b3d
--- /dev/null
+++ b/runtime/indent/vue.vim
@@ -0,0 +1,12 @@
+" Vim indent file placeholder
+" Language: Vue
+" Maintainer: None, please volunteer if you have a real Vue indent script
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+" Html comes closest
+runtime! indent/html.vim
diff --git a/runtime/syntax/chatito.vim b/runtime/syntax/chatito.vim
new file mode 100644
index 000000000..d89307cf0
--- /dev/null
+++ b/runtime/syntax/chatito.vim
@@ -0,0 +1,62 @@
+" Vim syntax file
+" Language: Chatito
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Filenames: *.chatito
+" Last Change: 2022 Sep 19
+
+if exists('b:current_syntax')
+ finish
+endif
+
+" Comment
+syn keyword chatitoTodo contained TODO FIXME XXX
+syn match chatitoComment /^#.*/ contains=chatitoTodo,@Spell
+syn match chatitoComment +^//.*+ contains=chatitoTodo,@Spell
+
+" Import
+syn match chatitoImport /^import \+.*$/ transparent contains=chatitoImportKeyword,chatitoImportFile
+syn keyword chatitoImportKeyword import contained nextgroup=chatitoImportFile
+syn match chatitoImportFile /.*$/ contained skipwhite
+
+" Intent
+syn match chatitoIntent /^%\[[^\]?]\+\]\((.\+)\)\=$/ contains=chatitoArgs
+
+" Slot
+syn match chatitoSlot /^@\[[^\]?#]\+\(#[^\]?#]\+\)\=\]\((.\+)\)\=$/ contains=chatitoArgs,chatitoVariation
+syn match chatitoSlot /@\[[^\]?#]\+\(#[^\]?#]\+\)\=?\=\]/ contained contains=chatitoOpt,chatitoVariation
+
+" Alias
+syn match chatitoAlias /^\~\[[^\]?]\+\]\=$/
+syn match chatitoAlias /\~\[[^\]?]\+?\=\]/ contained contains=chatitoOpt
+
+" Probability
+syn match chatitoProbability /\*\[\d\+\(\.\d\+\)\=%\=\]/ contained
+
+" Optional
+syn match chatitoOpt '?' contained
+
+" Arguments
+syn match chatitoArgs /(.\+)/ contained
+
+" Variation
+syn match chatitoVariation /#[^\]?#]\+/ contained
+
+" Value
+syn match chatitoValue /^ \{4\}\zs.\+$/ contains=chatitoProbability,chatitoSlot,chatitoAlias,@Spell
+
+" Errors
+syn match chatitoError /^\t/
+
+hi def link chatitoAlias String
+hi def link chatitoArgs Special
+hi def link chatitoComment Comment
+hi def link chatitoError Error
+hi def link chatitoImportKeyword Include
+hi def link chatitoIntent Statement
+hi def link chatitoOpt SpecialChar
+hi def link chatitoProbability Number
+hi def link chatitoSlot Identifier
+hi def link chatitoTodo Todo
+hi def link chatitoVariation Special
+
+let b:current_syntax = 'chatito'
diff --git a/runtime/syntax/desktop.vim b/runtime/syntax/desktop.vim
index 2c1102238..461ba855b 100644
--- a/runtime/syntax/desktop.vim
+++ b/runtime/syntax/desktop.vim
@@ -3,7 +3,7 @@
" Filenames: *.desktop, *.directory
" Maintainer: Eisuke Kawashima ( e.kawaschima+vim AT gmail.com )
" Previous Maintainer: Mikolaj Machowski ( mikmach AT wp DOT pl )
-" Last Change: 2020-06-11
+" Last Change: 2022 Sep 22
" Version Info: desktop.vim 1.5
" References:
" - https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.5.html (2020-04-27)
@@ -60,10 +60,10 @@ syn match dtLocaleSuffix
" Boolean Value {{{2
syn match dtBoolean
- \ /^\%(DBusActivatable\|Hidden\|NoDisplay\|PrefersNonDefaultGPU\|StartupNotify\|Terminal\)\s*=\s*\%(true\|false\)/
+ \ /^\%(DBusActivatable\|Hidden\|NoDisplay\|PrefersNonDefaultGPU\|SingleMainWindow\|StartupNotify\|Terminal\)\s*=\s*\%(true\|false\)/
\ contains=dtBooleanKey,dtDelim,dtBooleanValue transparent
syn keyword dtBooleanKey
- \ DBusActivatable Hidden NoDisplay PrefersNonDefaultGPU StartupNotify Terminal
+ \ DBusActivatable Hidden NoDisplay PrefersNonDefaultGPU SingleMainWindow StartupNotify Terminal
\ contained nextgroup=dtDelim
if s:desktop_enable_kde
diff --git a/runtime/syntax/gyp.vim b/runtime/syntax/gyp.vim
new file mode 100644
index 000000000..14c07b872
--- /dev/null
+++ b/runtime/syntax/gyp.vim
@@ -0,0 +1,49 @@
+" Vim syntax file
+" Language: GYP
+" Maintainer: ObserverOfTime <chronobserver@disroot.org>
+" Filenames: *.gyp,*.gypi
+" Last Change: 2022 Sep 27
+
+if !exists('g:main_syntax')
+ if exists('b:current_syntax') && b:current_syntax ==# 'gyp'
+ finish
+ endif
+ let g:main_syntax = 'gyp'
+endif
+
+" Based on JSON syntax
+runtime! syntax/json.vim
+
+" Single quotes are allowed
+syn clear jsonStringSQError
+
+syn match jsonKeywordMatch /'\([^']\|\\\'\)\+'[[:blank:]\r\n]*\:/ contains=jsonKeyword
+if has('conceal') && (!exists('g:vim_json_conceal') || g:vim_json_conceal==1)
+ syn region jsonKeyword matchgroup=jsonQuote start=/'/ end=/'\ze[[:blank:]\r\n]*\:/ concealends contained
+else
+ syn region jsonKeyword matchgroup=jsonQuote start=/'/ end=/'\ze[[:blank:]\r\n]*\:/ contained
+endif
+
+syn match jsonStringMatch /'\([^']\|\\\'\)\+'\ze[[:blank:]\r\n]*[,}\]]/ contains=jsonString
+if has('conceal') && (!exists('g:vim_json_conceal') || g:vim_json_conceal==1)
+ syn region jsonString oneline matchgroup=jsonQuote start=/'/ skip=/\\\\\|\\'/ end=/'/ concealends contains=jsonEscape contained
+else
+ syn region jsonString oneline matchgroup=jsonQuote start=/'/ skip=/\\\\\|\\'/ end=/'/ contains=jsonEscape contained
+endif
+
+" Trailing commas are allowed
+if !exists('g:vim_json_warnings') || g:vim_json_warnings==1
+ syn clear jsonTrailingCommaError
+endif
+
+" Python-style comments are allowed
+syn match jsonComment /#.*$/ contains=jsonTodo,@Spell
+syn keyword jsonTodo FIXME NOTE TODO XXX TBD contained
+
+hi def link jsonComment Comment
+hi def link jsonTodo Todo
+
+let b:current_syntax = 'gyp'
+if g:main_syntax ==# 'gyp'
+ unlet g:main_syntax
+endif
diff --git a/runtime/syntax/hare.vim b/runtime/syntax/hare.vim
new file mode 100644
index 000000000..07cf33fb1
--- /dev/null
+++ b/runtime/syntax/hare.vim
@@ -0,0 +1,133 @@
+" PRELUDE {{{1
+" Vim syntax file
+" Language: Hare
+" Maintainer: Amelia Clarke <me@rsaihe.dev>
+" Last Change: 2022-09-21
+
+if exists("b:current_syntax")
+ finish
+endif
+let b:current_syntax = "hare"
+
+" SYNTAX {{{1
+syn case match
+
+" KEYWORDS {{{2
+syn keyword hareConditional if else match switch
+syn keyword hareKeyword break continue return yield
+syn keyword hareKeyword defer
+syn keyword hareKeyword fn
+syn keyword hareKeyword let
+syn keyword hareLabel case
+syn keyword hareOperator as is
+syn keyword hareRepeat for
+syn keyword hareStorageClass const def export nullable static
+syn keyword hareStructure enum struct union
+syn keyword hareTypedef type
+
+" C ABI.
+syn keyword hareKeyword vastart vaarg vaend
+
+" BUILTINS {{{2
+syn keyword hareBuiltin abort
+syn keyword hareBuiltin alloc free
+syn keyword hareBuiltin append delete insert
+syn keyword hareBuiltin assert
+syn keyword hareBuiltin len offset
+
+" TYPES {{{2
+syn keyword hareType bool
+syn keyword hareType char str
+syn keyword hareType f32 f64
+syn keyword hareType u8 u16 u32 u64 i8 i16 i32 i64
+syn keyword hareType uint int
+syn keyword hareType rune
+syn keyword hareType uintptr
+syn keyword hareType void
+
+" C ABI.
+syn keyword hareType valist
+
+" LITERALS {{{2
+syn keyword hareBoolean true false
+syn keyword hareNull null
+
+" Number literals.
+syn match hareNumber "\v(\.@1<!|\.\.)\zs<\d+([Ee][+-]?\d+)?(z|[iu](8|16|32|64)?)?>" display
+syn match hareNumber "\v(\.@1<!|\.\.)\zs<0b[01]+(z|[iu](8|16|32|64)?)?>" display
+syn match hareNumber "\v(\.@1<!|\.\.)\zs<0o\o+(z|[iu](8|16|32|64)?)?>" display
+syn match hareNumber "\v(\.@1<!|\.\.)\zs<0x\x+(z|[iu](8|16|32|64)?)?>" display
+
+" Floating-point number literals.
+syn match hareFloat "\v<\d+\.\d+([Ee][+-]?\d+)?(f32|f64)?>" display
+syn match hareFloat "\v<\d+([Ee][+-]?\d+)?(f32|f64)>" display
+
+" String and rune literals.
+syn match hareEscape "\\[\\'"0abfnrtv]" contained display
+syn match hareEscape "\v\\(x\x{2}|u\x{4}|U\x{8})" contained display
+syn match hareFormat "\v\{\d*(\%\d*|(:[ 0+-]?\d*(\.\d+)?[Xbox]?))?}" contained display
+syn match hareFormat "\({{\|}}\)" contained display
+syn region hareRune start="'" end="'\|$" skip="\\'" contains=hareEscape display extend
+syn region hareString start=+"+ end=+"\|$+ skip=+\\"+ contains=hareEscape,hareFormat display extend
+syn region hareString start="`" end="`\|$" contains=hareFormat display
+
+" MISCELLANEOUS {{{2
+syn keyword hareTodo FIXME TODO XXX contained
+
+" Attributes.
+syn match hareAttribute "@[a-z]*"
+
+" Blocks.
+syn region hareBlock start="{" end="}" fold transparent
+
+" Comments.
+syn region hareComment start="//" end="$" contains=hareCommentDoc,hareTodo,@Spell display keepend
+syn region hareCommentDoc start="\[\[" end="]]\|\ze\_s" contained display
+
+" The size keyword can be either a builtin or a type.
+syn match hareBuiltin "\v<size>\ze(\_s*//.*\_$)*\_s*\(" contains=hareComment
+syn match hareType "\v<size>((\_s*//.*\_$)*\_s*\()@!" contains=hareComment
+
+" Trailing whitespace.
+syn match hareSpaceError "\v\s+$" display excludenl
+syn match hareSpaceError "\v\zs +\ze\t" display
+
+" Use statement.
+syn region hareUse start="\v^\s*\zsuse>" end=";" contains=hareComment display
+
+syn match hareErrorAssertion "\v(^([^/]|//@!)*\)\_s*)@<=!\=@!"
+syn match hareQuestionMark "?"
+
+" DEFAULT HIGHLIGHTING {{{1
+hi def link hareAttribute Keyword
+hi def link hareBoolean Boolean
+hi def link hareBuiltin Function
+hi def link hareComment Comment
+hi def link hareCommentDoc SpecialComment
+hi def link hareConditional Conditional
+hi def link hareEscape SpecialChar
+hi def link hareFloat Float
+hi def link hareFormat SpecialChar
+hi def link hareKeyword Keyword
+hi def link hareLabel Label
+hi def link hareNull Constant
+hi def link hareNumber Number
+hi def link hareOperator Operator
+hi def link hareQuestionMark Special
+hi def link hareRepeat Repeat
+hi def link hareRune Character
+hi def link hareStorageClass StorageClass
+hi def link hareString String
+hi def link hareStructure Structure
+hi def link hareTodo Todo
+hi def link hareType Type
+hi def link hareTypedef Typedef
+hi def link hareUse PreProc
+
+hi def link hareSpaceError Error
+autocmd InsertEnter * hi link hareSpaceError NONE
+autocmd InsertLeave * hi link hareSpaceError Error
+
+hi def hareErrorAssertion ctermfg=red cterm=bold guifg=red gui=bold
+
+" vim: tabstop=8 shiftwidth=2 expandtab
diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim
index aa76906d7..e38c90db7 100644
--- a/runtime/syntax/help.vim
+++ b/runtime/syntax/help.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Vim help file
" Maintainer: Bram Moolenaar (Bram@vim.org)
-" Last Change: 2022 May 15
+" Last Change: 2022 Sep 26
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
@@ -44,6 +44,7 @@ syn match helpVim "\<Vim version [0-9][0-9.a-z]*"
syn match helpVim "VIM REFERENCE.*"
syn match helpOption "'[a-z]\{2,\}'"
syn match helpOption "'t_..'"
+syn match helpNormal "'ab'"
syn match helpCommand "`[^` \t]\+`"hs=s+1,he=e-1 contains=helpBacktick
syn match helpCommand "\(^\|[^a-z"[]\)\zs`[^`]\+`\ze\([^a-z\t."']\|$\)"hs=s+1,he=e-1 contains=helpBacktick
syn match helpHeader "\s*\zs.\{-}\ze\s\=\~$" nextgroup=helpIgnore
diff --git a/runtime/syntax/hlsplaylist.vim b/runtime/syntax/hlsplaylist.vim
new file mode 100644
index 000000000..245eee213
--- /dev/null
+++ b/runtime/syntax/hlsplaylist.vim
@@ -0,0 +1,120 @@
+" Vim syntax file
+" Language: HLS Playlist
+" Maintainer: Benoît Ryder <benoit@ryder.fr>
+" Latest Revision: 2022-09-23
+
+if exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" Comment line
+syn match hlsplaylistComment "^#\(EXT\)\@!.*$"
+" Segment URL
+syn match hlsplaylistUrl "^[^#].*$"
+
+" Unknown tags, assume an attribute list or nothing
+syn match hlsplaylistTagUnknown "^#EXT[^:]*$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagUnknown start="^#EXT[^:]*\ze:" end="$" keepend contains=hlsplaylistAttributeList
+
+" Basic Tags
+syn match hlsplaylistTagHeader "^#EXTM3U$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-VERSION\ze:" end="$" keepend contains=hlsplaylistValueInt
+
+" Media or Multivariant Playlist Tags
+syn match hlsplaylistTagHeader "^#EXT-X-INDEPENDENT-SEGMENTS$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagDelimiter start="^#EXT-X-START\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-DEFINE\ze:" end="$" keepend contains=hlsplaylistAttributeList
+
+" Media Playlist Tags
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-TARGETDURATION\ze:" end="$" keepend contains=hlsplaylistValueFloat
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-MEDIA-SEQUENCE\ze:" end="$" keepend contains=hlsplaylistValueInt
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-DISCONTINUITY-SEQUENCE\ze:" end="$" keepend contains=hlsplaylistValueInt
+syn match hlsplaylistTagDelimiter "^#EXT-X-ENDLIST$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-PLAYLIST-TYPE\ze:" end="$" keepend contains=hlsplaylistAttributeEnum
+syn match hlsplaylistTagStandard "^#EXT-X-I-FRAME-ONLY$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-PART-INF\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagHeader start="^#EXT-X-SERVER-CONTROL\ze:" end="$" keepend contains=hlsplaylistAttributeList
+
+" Media Segment Tags
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStatement start="^#EXTINF\ze:" end="$" keepend contains=hlsplaylistValueFloat,hlsplaylistExtInfDesc
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-BYTERANGE\ze:" end="$" keepend contains=hlsplaylistValueInt
+syn match hlsplaylistTagDelimiter "^#EXT-X-DISCONTINUITY$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-KEY\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-MAP\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-PROGRAM-DATE-TIME\ze:" end="$" keepend contains=hlsplaylistValueDateTime
+syn match hlsplaylistTagDelimiter "^#EXT-X-GAP$"
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-BITRATE\ze:" end="$" keepend contains=hlsplaylistValueFloat
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStatement start="^#EXT-X-PART\ze:" end="$" keepend contains=hlsplaylistAttributeList
+
+" Media Metadata Tags
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-DATERANGE\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-SKIP\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStatement start="^#EXT-X-PRELOAD-HINT\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStatement start="^#EXT-X-RENDITION-REPORT\ze:" end="$" keepend contains=hlsplaylistAttributeList
+
+" Multivariant Playlist Tags
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-MEDIA\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStatement start="^#EXT-X-STREAM-INF\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStatement start="^#EXT-X-I-FRAME-STREAM-INF\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-SESSION-DATA\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-SESSION-KEY\ze:" end="$" keepend contains=hlsplaylistAttributeList
+syn region hlsplaylistTagLine matchgroup=hlsplaylistTagStandard start="^#EXT-X-CONTENT-STEERING\ze:" end="$" keepend contains=hlsplaylistAttributeList
+
+" Attributes
+syn region hlsplaylistAttributeList start=":" end="$" keepend contained
+ \ contains=hlsplaylistAttributeName,hlsplaylistAttributeInt,hlsplaylistAttributeHex,hlsplaylistAttributeFloat,hlsplaylistAttributeString,hlsplaylistAttributeEnum,hlsplaylistAttributeResolution,hlsplaylistAttributeUri
+" Common attributes
+syn match hlsplaylistAttributeName "[A-Za-z-]\+\ze=" contained
+syn match hlsplaylistAttributeEnum "=\zs[A-Za-z][A-Za-z0-9-_]*" contained
+syn match hlsplaylistAttributeString +=\zs"[^"]*"+ contained
+syn match hlsplaylistAttributeInt "=\zs\d\+" contained
+syn match hlsplaylistAttributeFloat "=\zs-\?\d*\.\d*" contained
+syn match hlsplaylistAttributeHex "=\zs0[xX]\d*" contained
+syn match hlsplaylistAttributeResolution "=\zs\d\+x\d\+" contained
+" Allow different highligting for URI attributes
+syn region hlsplaylistAttributeUri matchgroup=hlsplaylistAttributeName start="\zsURI\ze" end="\(,\|$\)" contained contains=hlsplaylistUriQuotes
+syn region hlsplaylistUriQuotes matchgroup=hlsplaylistAttributeString start=+"+ end=+"+ keepend contained contains=hlsplaylistUriValue
+syn match hlsplaylistUriValue /[^" ]\+/ contained
+" Individual values
+syn match hlsplaylistValueInt "[0-9]\+" contained
+syn match hlsplaylistValueFloat "\(\d\+\|\d*\.\d*\)" contained
+syn match hlsplaylistExtInfDesc ",\zs.*$" contained
+syn match hlsplaylistValueDateTime "\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\(\.\d*\)\?\(Z\|\d\d:\?\d\d\)$" contained
+
+
+" Define default highlighting
+
+hi def link hlsplaylistComment Comment
+hi def link hlsplaylistUrl NONE
+
+hi def link hlsplaylistTagHeader Special
+hi def link hlsplaylistTagStandard Define
+hi def link hlsplaylistTagDelimiter Delimiter
+hi def link hlsplaylistTagStatement Statement
+hi def link hlsplaylistTagUnknown Special
+
+hi def link hlsplaylistUriQuotes String
+hi def link hlsplaylistUriValue Underlined
+hi def link hlsplaylistAttributeQuotes String
+hi def link hlsplaylistAttributeName Identifier
+hi def link hlsplaylistAttributeInt Number
+hi def link hlsplaylistAttributeHex Number
+hi def link hlsplaylistAttributeFloat Float
+hi def link hlsplaylistAttributeString String
+hi def link hlsplaylistAttributeEnum Constant
+hi def link hlsplaylistAttributeResolution Constant
+hi def link hlsplaylistValueInt Number
+hi def link hlsplaylistValueFloat Float
+hi def link hlsplaylistExtInfDesc String
+hi def link hlsplaylistValueDateTime Constant
+
+
+let b:current_syntax = "hlsplaylist"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: sts=2 sw=2 et
diff --git a/runtime/syntax/plsql.vim b/runtime/syntax/plsql.vim
index 21681d59e..9b4df09ac 100644
--- a/runtime/syntax/plsql.vim
+++ b/runtime/syntax/plsql.vim
@@ -4,8 +4,11 @@
" Previous Maintainer: Jeff Lanzarotta (jefflanzarotta at yahoo dot com)
" Previous Maintainer: C. Laurence Gonsalves (clgonsal@kami.com)
" URL: https://github.com/lee-lindley/vim_plsql_syntax
-" Last Change: Aug 21, 2022
-" History Lee Lindley (lee dot lindley at gmail dot com)
+" Last Change: Sep 19, 2022
+" History Carsten Czarski (carsten dot czarski at oracle com)
+" add handling for typical SQL*Plus commands (rem, start, host, set, etc)
+" add error highlight for non-breaking space
+" Lee Lindley (lee dot lindley at gmail dot com)
" use get with default 0 instead of exists per Bram suggestion
" make procedure folding optional
" updated to 19c keywords. refined quoting.
@@ -54,8 +57,13 @@ syn case ignore
syn match plsqlGarbage "[^ \t()]"
syn match plsqlIdentifier "[a-z][a-z0-9$_#]*"
+syn match plsqlSqlPlusDefine "&&\?[a-z][a-z0-9$_#]*\.\?"
syn match plsqlHostIdentifier ":[a-z][a-z0-9$_#]*"
+" The Non-Breaking is often accidentally typed (Mac User: Opt+Space, after typing the "|", Opt+7);
+" error highlight for these avoids running into annoying compiler errors.
+syn match plsqlIllegalSpace "[\xa0]"
+
" When wanted, highlight the trailing whitespace.
if get(g:,"plsql_space_errors",0) == 1
if get(g:,"plsql_no_trail_space_error",0) == 0
@@ -79,7 +87,6 @@ syn match plsqlOperator "\<IS\\_s\+\(NOT\_s\+\)\?NULL\>"
"
" conditional compilation Preprocessor directives and sqlplus define sigil
syn match plsqlPseudo "$[$a-z][a-z0-9$_#]*"
-syn match plsqlPseudo "&"
syn match plsqlReserved "\<\(CREATE\|THEN\|UPDATE\|INSERT\|SET\)\>"
syn match plsqlKeyword "\<\(REPLACE\|PACKAGE\|FUNCTION\|PROCEDURE\|TYPE|BODY\|WHEN\|MATCHED\)\>"
@@ -150,7 +157,7 @@ syn keyword plsqlKeyword DATA_SECURITY_REWRITE_LIMIT DATA_VALIDATE DATE_MODE DAY
syn keyword plsqlKeyword DBMS_STATS DBSTR2UTF8 DBTIMEZONE DB_ROLE_CHANGE DB_UNIQUE_NAME DB_VERSION
syn keyword plsqlKeyword DDL DEALLOCATE DEBUG DEBUGGER DECLARE DECODE DECOMPOSE DECOMPRESS DECORRELATE
syn keyword plsqlKeyword DECR DECREMENT DECRYPT DEDUPLICATE DEFAULTS DEFAULT_COLLATION DEFAULT_PDB_HINT
-syn keyword plsqlKeyword DEFERRABLE DEFERRED DEFINE DEFINED DEFINER DEFINITION DEGREE DELAY DELEGATE
+syn keyword plsqlKeyword DEFERRABLE DEFERRED DEFINED DEFINER DEFINITION DEGREE DELAY DELEGATE
syn keyword plsqlKeyword DELETEXML DELETE_ALL DEMAND DENORM_AV DENSE_RANK DENSE_RANKM DEPENDENT DEPTH
syn keyword plsqlKeyword DEQUEUE DEREF DEREF_NO_REWRITE DESCENDANT DESCRIPTION DESTROY DETACHED DETERMINED
syn keyword plsqlKeyword DETERMINES DETERMINISTIC DG_GATHER_STATS DIAGNOSTICS DICTIONARY DIGEST DIMENSION
@@ -189,7 +196,7 @@ syn keyword plsqlKeyword HELP HEXTORAW HEXTOREF HIDDEN HIDE HIERARCHICAL HIERARC
syn keyword plsqlKeyword HIER_CAPTION HIER_CHILDREN HIER_CHILD_COUNT HIER_COLUMN HIER_CONDITION HIER_DEPTH
syn keyword plsqlKeyword HIER_DESCRIPTION HIER_HAS_CHILDREN HIER_LAG HIER_LEAD HIER_LEVEL HIER_MEMBER_NAME
syn keyword plsqlKeyword HIER_MEMBER_UNIQUE_NAME HIER_ORDER HIER_PARENT HIER_WINDOW HIGH HINTSET_BEGIN
-syn keyword plsqlKeyword HINTSET_END HOST HOT HOUR HOURS HTTP HWM_BROKERED HYBRID ID IDENTIFIER IDENTITY
+syn keyword plsqlKeyword HINTSET_END HOT HOUR HOURS HTTP HWM_BROKERED HYBRID ID IDENTIFIER IDENTITY
syn keyword plsqlKeyword IDGENERATORS IDLE IDLE_TIME IGNORE IGNORE_OPTIM_EMBEDDED_HINTS IGNORE_ROW_ON_DUPKEY_INDEX
syn keyword plsqlKeyword IGNORE_WHERE_CLAUSE ILM IMMEDIATE IMMUTABLE IMPACT IMPORT INACTIVE INACTIVE_ACCOUNT_TIME
syn keyword plsqlKeyword INCLUDE INCLUDES INCLUDE_VERSION INCLUDING INCOMING INCR INCREMENT INCREMENTAL
@@ -342,7 +349,7 @@ syn keyword plsqlKeyword SELF SEMIJOIN SEMIJOIN_DRIVER SEMI_TO_INNER SENSITIVE S
syn keyword plsqlKeyword SERIAL SERIALIZABLE SERVERERROR SERVICE SERVICES SERVICE_NAME_CONVERT SESSION
syn keyword plsqlKeyword SESSIONS_PER_USER SESSIONTIMEZONE SESSIONTZNAME SESSION_CACHED_CURSORS SETS
syn keyword plsqlKeyword SETTINGS SET_GBY_PUSHDOWN SET_TO_JOIN SEVERE SHARD SHARDED SHARDS SHARDSPACE
-syn keyword plsqlKeyword SHARD_CHUNK_ID SHARED SHARED_POOL SHARE_OF SHARING SHD$COL$MAP SHELFLIFE SHOW
+syn keyword plsqlKeyword SHARD_CHUNK_ID SHARED SHARED_POOL SHARE_OF SHARING SHD$COL$MAP SHELFLIFE
syn keyword plsqlKeyword SHRINK SHUTDOWN SIBLING SIBLINGS SID SIGN SIGNAL_COMPONENT SIGNAL_FUNCTION
syn keyword plsqlKeyword SIGNATURE SIMPLE SIN SINGLE SINGLETASK SINH SITE SKEWNESS_POP SKEWNESS_SAMP
syn keyword plsqlKeyword SKIP SKIP_EXT_OPTIMIZER SKIP_PROXY SKIP_UNQ_UNUSABLE_IDX SKIP_UNUSABLE_INDEXES
@@ -445,7 +452,7 @@ syn keyword plsqlKeyword VECTOR_READ_TRACE VECTOR_TRANSFORM VECTOR_TRANSFORM_DIM
syn keyword plsqlKeyword VERIFIER VERIFY VERSION VERSIONING VERSIONS VERSIONS_ENDSCN VERSIONS_ENDTIME
syn keyword plsqlKeyword VERSIONS_OPERATION VERSIONS_STARTSCN VERSIONS_STARTTIME VERSIONS_XID VIEWS
syn keyword plsqlKeyword VIOLATION VIRTUAL VISIBILITY VISIBLE VOLUME VSIZE WAIT WALLET WEEK WEEKS WELLFORMED
-syn keyword plsqlKeyword WHENEVER WHITESPACE WIDTH_BUCKET WINDOW WITHIN WITHOUT WITH_EXPRESSION
+syn keyword plsqlKeyword WHITESPACE WIDTH_BUCKET WINDOW WITHIN WITHOUT WITH_EXPRESSION
syn keyword plsqlKeyword WITH_PLSQL WORK WRAPPED WRAPPER WRITE XDB_FASTPATH_INSERT XID XML XML2OBJECT
syn keyword plsqlKeyword XMLATTRIBUTES XMLCAST XMLCDATA XMLCOLATTVAL XMLCOMMENT XMLCONCAT XMLDIFF XMLELEMENT
syn keyword plsqlKeyword XMLEXISTS XMLEXISTS2 XMLFOREST XMLINDEX_REWRITE XMLINDEX_REWRITE_IN_SELECT
@@ -468,13 +475,13 @@ syn keyword plsqlReserved MINUS MODE NOCOMPRESS NOWAIT NUMBER_BASE OCICOLL OCIDA
syn keyword plsqlReserved OCIDURATION OCIINTERVAL OCILOBLOCATOR OCINUMBER OCIRAW OCIREF OCIREFCURSOR
syn keyword plsqlReserved OCIROWID OCISTRING OCITYPE OF ON OPTION ORACLE ORADATA ORDER ORLANY ORLVARY
syn keyword plsqlReserved OUT OVERRIDING PARALLEL_ENABLE PARAMETER PASCAL PCTFREE PIPE PIPELINED POLYMORPHIC
-syn keyword plsqlReserved PRAGMA PRIOR PUBLIC RAISE RECORD RELIES_ON REM RENAME RESOURCE RESULT REVOKE ROWID
+syn keyword plsqlReserved PRAGMA PRIOR PUBLIC RAISE RECORD RELIES_ON RENAME RESOURCE RESULT REVOKE ROWID
syn keyword plsqlReserved SB1 SB2
syn match plsqlReserved "\<SELECT\>"
syn keyword plsqlReserved SEPARATE SHARE SHORT SIZE SIZE_T SPARSE SQLCODE SQLDATA
syn keyword plsqlReserved SQLNAME SQLSTATE STANDARD START STORED STRUCT STYLE SYNONYM TABLE TDO
syn keyword plsqlReserved TRANSACTIONAL TRIGGER UB1 UB4 UNION UNIQUE UNSIGNED UNTRUSTED VALIST
-syn keyword plsqlReserved VALUES VARIABLE VIEW VOID WHERE WITH
+syn keyword plsqlReserved VALUES VIEW VOID WHERE WITH
" PL/SQL and SQL functions.
syn keyword plsqlFunction ABS ACOS ADD_MONTHS APPROX_COUNT APPROX_COUNT_DISTINCT APPROX_COUNT_DISTINCT_AGG
@@ -584,18 +591,18 @@ syn match plsqlEND "\<END\>"
syn match plsqlISAS "\<\(IS\|AS\)\>"
" Various types of comments.
-syntax region plsqlCommentL start="--" skip="\\$" end="$" keepend extend contains=@plsqlCommentGroup,plsqlSpaceError
+syntax region plsqlCommentL start="--" skip="\\$" end="$" keepend extend contains=@plsqlCommentGroup,plsqlSpaceError,plsqlIllegalSpace,plsqlSqlplusDefine
if get(g:,"plsql_fold",0) == 1
syntax region plsqlComment
\ start="/\*" end="\*/"
\ extend
- \ contains=@plsqlCommentGroup,plsqlSpaceError
+ \ contains=@plsqlCommentGroup,plsqlSpaceError,plsqlIllegalSpace,plsqlSqlplusDefine
\ fold
else
syntax region plsqlComment
\ start="/\*" end="\*/"
\ extend
- \ contains=@plsqlCommentGroup,plsqlSpaceError
+ \ contains=@plsqlCommentGroup,plsqlSpaceError,plsqlIllegalSpace,plsqlSqlplusDefine
endif
syn cluster plsqlCommentAll contains=plsqlCommentL,plsqlComment
@@ -618,23 +625,23 @@ syn match plsqlFloatLiteral contained "\.\(\d\+\([eE][+-]\?\d\+\)\?\)[fd]\?"
" double quoted strings in SQL are database object names. Should be a subgroup of Normal.
" We will use Character group as a proxy for that so color can be chosen close to Normal
syn region plsqlQuotedIdentifier matchgroup=plsqlOperator start=+n\?"+ end=+"+ keepend extend
-syn cluster plsqlIdentifiers contains=plsqlIdentifier,plsqlQuotedIdentifier
+syn cluster plsqlIdentifiers contains=plsqlIdentifier,plsqlQuotedIdentifier,plsqlSqlPlusDefine
" quoted string literals
if get(g:,"plsql_fold",0) == 1
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?'+ skip=+''+ end=+'+ fold keepend extend
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\z([^[(<{]\)+ end=+\z1'+ fold keepend extend
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'<+ end=+>'+ fold keepend extend
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'{+ end=+}'+ fold keepend extend
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'(+ end=+)'+ fold keepend extend
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\[+ end=+]'+ fold keepend extend
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?'+ skip=+''+ end=+'+ contains=plsqlSqlplusDefine fold keepend extend
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\z([^[(<{]\)+ end=+\z1'+ contains=plsqlSqlplusDefine fold keepend extend
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'<+ end=+>'+ contains=plsqlSqlplusDefine fold keepend extend
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'{+ end=+}'+ contains=plsqlSqlplusDefine fold keepend extend
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'(+ end=+)'+ contains=plsqlSqlplusDefine fold keepend extend
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\[+ end=+]'+ contains=plsqlSqlplusDefine fold keepend extend
else
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?'+ skip=+''+ end=+'+
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\z([^[(<{]\)+ end=+\z1'+
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'<+ end=+>'+
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'{+ end=+}'+
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'(+ end=+)'+
- syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\[+ end=+]'+
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?'+ skip=+''+ end=+'+ contains=plsqlSqlplusDefine
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\z([^[(<{]\)+ end=+\z1'+ contains=plsqlSqlplusDefine
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'<+ end=+>'+ contains=plsqlSqlplusDefine
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'{+ end=+}'+ contains=plsqlSqlplusDefine
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'(+ end=+)'+ contains=plsqlSqlplusDefine
+ syn region plsqlStringLiteral matchgroup=plsqlOperator start=+n\?q'\[+ end=+]'+ contains=plsqlSqlplusDefine
endif
syn keyword plsqlBooleanLiteral TRUE FALSE
@@ -682,6 +689,10 @@ syn match plsqlConditional "\<END\>\_s\+\<IF\>"
syn match plsqlCase "\<END\>\_s\+\<CASE\>"
syn match plsqlCase "\<CASE\>"
+syn region plsqlSqlPlusCommentL start="^\(REM\)\( \|$\)" skip="\\$" end="$" keepend extend contains=@plsqlCommentGroup,plsqlSpaceError,plsqlIllegalSpace
+syn region plsqlSqlPlusCommand start="^\(SET\|DEFINE\|PROMPT\|ACCEPT\|EXEC\|HOST\|SHOW\|VAR\|VARIABLE\|COL\|WHENEVER\|TIMING\)\( \|$\)" skip="\\$" end="$" keepend extend
+syn region plsqlSqlPlusRunFile start="^\(@\|@@\)" skip="\\$" end="$" keepend extend
+
if get(g:,"plsql_fold",0) == 1
setlocal foldmethod=syntax
syn sync fromstart
@@ -826,6 +837,13 @@ hi def link plsqlComment2String String
hi def link plsqlTrigger Function
hi def link plsqlTypeAttribute StorageClass
hi def link plsqlTodo Todo
+
+hi def link plsqlIllegalSpace Error
+hi def link plsqlSqlPlusDefine PreProc
+hi def link plsqlSqlPlusCommand PreProc
+hi def link plsqlSqlPlusRunFile Include
+hi def link plsqlSqlPlusCommentL Comment
+
" to be able to change them after loading, need override whether defined or not
if get(g:,"plsql_legacy_sql_keywords",0) == 1
hi link plsqlSQLKeyword Function
diff --git a/runtime/syntax/solidity.vim b/runtime/syntax/solidity.vim
new file mode 100644
index 000000000..e552446e1
--- /dev/null
+++ b/runtime/syntax/solidity.vim
@@ -0,0 +1,173 @@
+" Vim syntax file
+" Language: Solidity
+" Maintainer: Cothi (jiungdev@gmail.com)
+" Original Author: tomlion (https://github.com/tomlion/vim-solidity/blob/master/syntax/solidity.vim)
+" Last Changed: 2022 Sep 27
+"
+" Additional contributors:
+" Modified by thesis (https://github.com/thesis/vim-solidity/blob/main/indent/solidity.vim)
+
+if exists("b:current_syntax")
+ finish
+endif
+
+" keyword
+syn keyword solKeyword abstract anonymous as break calldata case catch constant constructor continue default switch revert require
+syn keyword solKeyword ecrecover addmod mulmod keccak256
+syn keyword solKeyword delete do else emit enum external final for function if immutable import in indexed inline
+syn keyword solKeyword interface internal is let match memory modifier new of payable pragma private public pure override virtual
+syn keyword solKeyword relocatable return returns static storage struct throw try type typeof using
+syn keyword solKeyword var view while
+
+syn keyword solConstant true false wei szabo finney ether seconds minutes hours days weeks years now
+syn keyword solConstant abi block blockhash msg tx this super selfdestruct
+
+syn keyword solBuiltinType mapping address bool
+syn keyword solBuiltinType int int8 int16 int24 int32 int40 int48 int56 int64 int72 int80 int88 int96 int104 int112 int120 int128 int136 int144 int152 int160 int168 int178 int184 int192 int200 int208 int216 int224 int232 int240 int248 int256
+syn keyword solBuiltinType uint uint8 uint16 uint24 uint32 uint40 uint48 uint56 uint64 uint72 uint80 uint88 uint96 uint104 uint112 uint120 uint128 uint136 uint144 uint152 uint160 uint168 uint178 uint184 uint192 uint200 uint208 uint216 uint224 uint232 uint240 uint248 uint256
+syn keyword solBuiltinType fixed
+syn keyword solBuiltinType fixed0x8 fixed0x16 fixed0x24 fixed0x32 fixed0x40 fixed0x48 fixed0x56 fixed0x64 fixed0x72 fixed0x80 fixed0x88 fixed0x96 fixed0x104 fixed0x112 fixed0x120 fixed0x128 fixed0x136 fixed0x144 fixed0x152 fixed0x160 fixed0x168 fixed0x178 fixed0x184 fixed0x192 fixed0x200 fixed0x208 fixed0x216 fixed0x224 fixed0x232 fixed0x240 fixed0x248 fixed0x256
+syn keyword solBuiltinType fixed8x8 fixed8x16 fixed8x24 fixed8x32 fixed8x40 fixed8x48 fixed8x56 fixed8x64 fixed8x72 fixed8x80 fixed8x88 fixed8x96 fixed8x104 fixed8x112 fixed8x120 fixed8x128 fixed8x136 fixed8x144 fixed8x152 fixed8x160 fixed8x168 fixed8x178 fixed8x184 fixed8x192 fixed8x200 fixed8x208 fixed8x216 fixed8x224 fixed8x232 fixed8x240 fixed8x248
+syn keyword solBuiltinType fixed16x8 fixed16x16 fixed16x24 fixed16x32 fixed16x40 fixed16x48 fixed16x56 fixed16x64 fixed16x72 fixed16x80 fixed16x88 fixed16x96 fixed16x104 fixed16x112 fixed16x120 fixed16x128 fixed16x136 fixed16x144 fixed16x152 fixed16x160 fixed16x168 fixed16x178 fixed16x184 fixed16x192 fixed16x200 fixed16x208 fixed16x216 fixed16x224 fixed16x232 fixed16x240
+syn keyword solBuiltinType fixed24x8 fixed24x16 fixed24x24 fixed24x32 fixed24x40 fixed24x48 fixed24x56 fixed24x64 fixed24x72 fixed24x80 fixed24x88 fixed24x96 fixed24x104 fixed24x112 fixed24x120 fixed24x128 fixed24x136 fixed24x144 fixed24x152 fixed24x160 fixed24x168 fixed24x178 fixed24x184 fixed24x192 fixed24x200 fixed24x208 fixed24x216 fixed24x224 fixed24x232
+syn keyword solBuiltinType fixed32x8 fixed32x16 fixed32x24 fixed32x32 fixed32x40 fixed32x48 fixed32x56 fixed32x64 fixed32x72 fixed32x80 fixed32x88 fixed32x96 fixed32x104 fixed32x112 fixed32x120 fixed32x128 fixed32x136 fixed32x144 fixed32x152 fixed32x160 fixed32x168 fixed32x178 fixed32x184 fixed32x192 fixed32x200 fixed32x208 fixed32x216 fixed32x224
+syn keyword solBuiltinType fixed40x8 fixed40x16 fixed40x24 fixed40x32 fixed40x40 fixed40x48 fixed40x56 fixed40x64 fixed40x72 fixed40x80 fixed40x88 fixed40x96 fixed40x104 fixed40x112 fixed40x120 fixed40x128 fixed40x136 fixed40x144 fixed40x152 fixed40x160 fixed40x168 fixed40x178 fixed40x184 fixed40x192 fixed40x200 fixed40x208 fixed40x216
+syn keyword solBuiltinType fixed48x8 fixed48x16 fixed48x24 fixed48x32 fixed48x40 fixed48x48 fixed48x56 fixed48x64 fixed48x72 fixed48x80 fixed48x88 fixed48x96 fixed48x104 fixed48x112 fixed48x120 fixed48x128 fixed48x136 fixed48x144 fixed48x152 fixed48x160 fixed48x168 fixed48x178 fixed48x184 fixed48x192 fixed48x200 fixed48x208
+syn keyword solBuiltinType fixed56x8 fixed56x16 fixed56x24 fixed56x32 fixed56x40 fixed56x48 fixed56x56 fixed56x64 fixed56x72 fixed56x80 fixed56x88 fixed56x96 fixed56x104 fixed56x112 fixed56x120 fixed56x128 fixed56x136 fixed56x144 fixed56x152 fixed56x160 fixed56x168 fixed56x178 fixed56x184 fixed56x192 fixed56x200
+syn keyword solBuiltinType fixed64x8 fixed64x16 fixed64x24 fixed64x32 fixed64x40 fixed64x48 fixed64x56 fixed64x64 fixed64x72 fixed64x80 fixed64x88 fixed64x96 fixed64x104 fixed64x112 fixed64x120 fixed64x128 fixed64x136 fixed64x144 fixed64x152 fixed64x160 fixed64x168 fixed64x178 fixed64x184 fixed64x192
+syn keyword solBuiltinType fixed72x8 fixed72x16 fixed72x24 fixed72x32 fixed72x40 fixed72x48 fixed72x56 fixed72x64 fixed72x72 fixed72x80 fixed72x88 fixed72x96 fixed72x104 fixed72x112 fixed72x120 fixed72x128 fixed72x136 fixed72x144 fixed72x152 fixed72x160 fixed72x168 fixed72x178 fixed72x184
+syn keyword solBuiltinType fixed80x8 fixed80x16 fixed80x24 fixed80x32 fixed80x40 fixed80x48 fixed80x56 fixed80x64 fixed80x72 fixed80x80 fixed80x88 fixed80x96 fixed80x104 fixed80x112 fixed80x120 fixed80x128 fixed80x136 fixed80x144 fixed80x152 fixed80x160 fixed80x168 fixed80x178
+syn keyword solBuiltinType fixed88x8 fixed88x16 fixed88x24 fixed88x32 fixed88x40 fixed88x48 fixed88x56 fixed88x64 fixed88x72 fixed88x80 fixed88x88 fixed88x96 fixed88x104 fixed88x112 fixed88x120 fixed88x128 fixed88x136 fixed88x144 fixed88x152 fixed88x160 fixed88x168
+syn keyword solBuiltinType fixed96x8 fixed96x16 fixed96x24 fixed96x32 fixed96x40 fixed96x48 fixed96x56 fixed96x64 fixed96x72 fixed96x80 fixed96x88 fixed96x96 fixed96x104 fixed96x112 fixed96x120 fixed96x128 fixed96x136 fixed96x144 fixed96x152 fixed96x160
+syn keyword solBuiltinType fixed104x8 fixed104x16 fixed104x24 fixed104x32 fixed104x40 fixed104x48 fixed104x56 fixed104x64 fixed104x72 fixed104x80 fixed104x88 fixed104x96 fixed104x104 fixed104x112 fixed104x120 fixed104x128 fixed104x136 fixed104x144 fixed104x152
+syn keyword solBuiltinType fixed112x8 fixed112x16 fixed112x24 fixed112x32 fixed112x40 fixed112x48 fixed112x56 fixed112x64 fixed112x72 fixed112x80 fixed112x88 fixed112x96 fixed112x104 fixed112x112 fixed112x120 fixed112x128 fixed112x136 fixed112x144
+syn keyword solBuiltinType fixed120x8 fixed120x16 fixed120x24 fixed120x32 fixed120x40 fixed120x48 fixed120x56 fixed120x64 fixed120x72 fixed120x80 fixed120x88 fixed120x96 fixed120x104 fixed120x112 fixed120x120 fixed120x128 fixed120x136
+syn keyword solBuiltinType fixed128x8 fixed128x16 fixed128x24 fixed128x32 fixed128x40 fixed128x48 fixed128x56 fixed128x64 fixed128x72 fixed128x80 fixed128x88 fixed128x96 fixed128x104 fixed128x112 fixed128x120 fixed128x128
+syn keyword solBuiltinType fixed136x8 fixed136x16 fixed136x24 fixed136x32 fixed136x40 fixed136x48 fixed136x56 fixed136x64 fixed136x72 fixed136x80 fixed136x88 fixed136x96 fixed136x104 fixed136x112 fixed136x120
+syn keyword solBuiltinType fixed144x8 fixed144x16 fixed144x24 fixed144x32 fixed144x40 fixed144x48 fixed144x56 fixed144x64 fixed144x72 fixed144x80 fixed144x88 fixed144x96 fixed144x104 fixed144x112
+syn keyword solBuiltinType fixed152x8 fixed152x16 fixed152x24 fixed152x32 fixed152x40 fixed152x48 fixed152x56 fixed152x64 fixed152x72 fixed152x80 fixed152x88 fixed152x96 fixed152x104
+syn keyword solBuiltinType fixed160x8 fixed160x16 fixed160x24 fixed160x32 fixed160x40 fixed160x48 fixed160x56 fixed160x64 fixed160x72 fixed160x80 fixed160x88 fixed160x96
+syn keyword solBuiltinType fixed168x8 fixed168x16 fixed168x24 fixed168x32 fixed168x40 fixed168x48 fixed168x56 fixed168x64 fixed168x72 fixed168x80 fixed168x88
+syn keyword solBuiltinType fixed176x8 fixed176x16 fixed176x24 fixed176x32 fixed176x40 fixed176x48 fixed176x56 fixed176x64 fixed176x72 fixed176x80
+syn keyword solBuiltinType fixed184x8 fixed184x16 fixed184x24 fixed184x32 fixed184x40 fixed184x48 fixed184x56 fixed184x64 fixed184x72
+syn keyword solBuiltinType fixed192x8 fixed192x16 fixed192x24 fixed192x32 fixed192x40 fixed192x48 fixed192x56 fixed192x64
+syn keyword solBuiltinType fixed200x8 fixed200x16 fixed200x24 fixed200x32 fixed200x40 fixed200x48 fixed200x56
+syn keyword solBuiltinType fixed208x8 fixed208x16 fixed208x24 fixed208x32 fixed208x40 fixed208x48
+syn keyword solBuiltinType fixed216x8 fixed216x16 fixed216x24 fixed216x32 fixed216x40
+syn keyword solBuiltinType fixed224x8 fixed224x16 fixed224x24 fixed224x32
+syn keyword solBuiltinType fixed232x8 fixed232x16 fixed232x24
+syn keyword solBuiltinType fixed240x8 fixed240x16
+syn keyword solBuiltinType fixed248x8
+syn keyword solBuiltinType ufixed
+syn keyword solBuiltinType ufixed0x8 ufixed0x16 ufixed0x24 ufixed0x32 ufixed0x40 ufixed0x48 ufixed0x56 ufixed0x64 ufixed0x72 ufixed0x80 ufixed0x88 ufixed0x96 ufixed0x104 ufixed0x112 ufixed0x120 ufixed0x128 ufixed0x136 ufixed0x144 ufixed0x152 ufixed0x160 ufixed0x168 ufixed0x178 ufixed0x184 ufixed0x192 ufixed0x200 ufixed0x208 ufixed0x216 ufixed0x224 ufixed0x232 ufixed0x240 ufixed0x248 ufixed0x256
+syn keyword solBuiltinType ufixed8x8 ufixed8x16 ufixed8x24 ufixed8x32 ufixed8x40 ufixed8x48 ufixed8x56 ufixed8x64 ufixed8x72 ufixed8x80 ufixed8x88 ufixed8x96 ufixed8x104 ufixed8x112 ufixed8x120 ufixed8x128 ufixed8x136 ufixed8x144 ufixed8x152 ufixed8x160 ufixed8x168 ufixed8x178 ufixed8x184 ufixed8x192 ufixed8x200 ufixed8x208 ufixed8x216 ufixed8x224 ufixed8x232 ufixed8x240 ufixed8x248
+syn keyword solBuiltinType ufixed16x8 ufixed16x16 ufixed16x24 ufixed16x32 ufixed16x40 ufixed16x48 ufixed16x56 ufixed16x64 ufixed16x72 ufixed16x80 ufixed16x88 ufixed16x96 ufixed16x104 ufixed16x112 ufixed16x120 ufixed16x128 ufixed16x136 ufixed16x144 ufixed16x152 ufixed16x160 ufixed16x168 ufixed16x178 ufixed16x184 ufixed16x192 ufixed16x200 ufixed16x208 ufixed16x216 ufixed16x224 ufixed16x232 ufixed16x240
+syn keyword solBuiltinType ufixed24x8 ufixed24x16 ufixed24x24 ufixed24x32 ufixed24x40 ufixed24x48 ufixed24x56 ufixed24x64 ufixed24x72 ufixed24x80 ufixed24x88 ufixed24x96 ufixed24x104 ufixed24x112 ufixed24x120 ufixed24x128 ufixed24x136 ufixed24x144 ufixed24x152 ufixed24x160 ufixed24x168 ufixed24x178 ufixed24x184 ufixed24x192 ufixed24x200 ufixed24x208 ufixed24x216 ufixed24x224 ufixed24x232
+syn keyword solBuiltinType ufixed32x8 ufixed32x16 ufixed32x24 ufixed32x32 ufixed32x40 ufixed32x48 ufixed32x56 ufixed32x64 ufixed32x72 ufixed32x80 ufixed32x88 ufixed32x96 ufixed32x104 ufixed32x112 ufixed32x120 ufixed32x128 ufixed32x136 ufixed32x144 ufixed32x152 ufixed32x160 ufixed32x168 ufixed32x178 ufixed32x184 ufixed32x192 ufixed32x200 ufixed32x208 ufixed32x216 ufixed32x224
+syn keyword solBuiltinType ufixed40x8 ufixed40x16 ufixed40x24 ufixed40x32 ufixed40x40 ufixed40x48 ufixed40x56 ufixed40x64 ufixed40x72 ufixed40x80 ufixed40x88 ufixed40x96 ufixed40x104 ufixed40x112 ufixed40x120 ufixed40x128 ufixed40x136 ufixed40x144 ufixed40x152 ufixed40x160 ufixed40x168 ufixed40x178 ufixed40x184 ufixed40x192 ufixed40x200 ufixed40x208 ufixed40x216
+syn keyword solBuiltinType ufixed48x8 ufixed48x16 ufixed48x24 ufixed48x32 ufixed48x40 ufixed48x48 ufixed48x56 ufixed48x64 ufixed48x72 ufixed48x80 ufixed48x88 ufixed48x96 ufixed48x104 ufixed48x112 ufixed48x120 ufixed48x128 ufixed48x136 ufixed48x144 ufixed48x152 ufixed48x160 ufixed48x168 ufixed48x178 ufixed48x184 ufixed48x192 ufixed48x200 ufixed48x208
+syn keyword solBuiltinType ufixed56x8 ufixed56x16 ufixed56x24 ufixed56x32 ufixed56x40 ufixed56x48 ufixed56x56 ufixed56x64 ufixed56x72 ufixed56x80 ufixed56x88 ufixed56x96 ufixed56x104 ufixed56x112 ufixed56x120 ufixed56x128 ufixed56x136 ufixed56x144 ufixed56x152 ufixed56x160 ufixed56x168 ufixed56x178 ufixed56x184 ufixed56x192 ufixed56x200
+syn keyword solBuiltinType ufixed64x8 ufixed64x16 ufixed64x24 ufixed64x32 ufixed64x40 ufixed64x48 ufixed64x56 ufixed64x64 ufixed64x72 ufixed64x80 ufixed64x88 ufixed64x96 ufixed64x104 ufixed64x112 ufixed64x120 ufixed64x128 ufixed64x136 ufixed64x144 ufixed64x152 ufixed64x160 ufixed64x168 ufixed64x178 ufixed64x184 ufixed64x192
+syn keyword solBuiltinType ufixed72x8 ufixed72x16 ufixed72x24 ufixed72x32 ufixed72x40 ufixed72x48 ufixed72x56 ufixed72x64 ufixed72x72 ufixed72x80 ufixed72x88 ufixed72x96 ufixed72x104 ufixed72x112 ufixed72x120 ufixed72x128 ufixed72x136 ufixed72x144 ufixed72x152 ufixed72x160 ufixed72x168 ufixed72x178 ufixed72x184
+syn keyword solBuiltinType ufixed80x8 ufixed80x16 ufixed80x24 ufixed80x32 ufixed80x40 ufixed80x48 ufixed80x56 ufixed80x64 ufixed80x72 ufixed80x80 ufixed80x88 ufixed80x96 ufixed80x104 ufixed80x112 ufixed80x120 ufixed80x128 ufixed80x136 ufixed80x144 ufixed80x152 ufixed80x160 ufixed80x168 ufixed80x178
+syn keyword solBuiltinType ufixed88x8 ufixed88x16 ufixed88x24 ufixed88x32 ufixed88x40 ufixed88x48 ufixed88x56 ufixed88x64 ufixed88x72 ufixed88x80 ufixed88x88 ufixed88x96 ufixed88x104 ufixed88x112 ufixed88x120 ufixed88x128 ufixed88x136 ufixed88x144 ufixed88x152 ufixed88x160 ufixed88x168
+syn keyword solBuiltinType ufixed96x8 ufixed96x16 ufixed96x24 ufixed96x32 ufixed96x40 ufixed96x48 ufixed96x56 ufixed96x64 ufixed96x72 ufixed96x80 ufixed96x88 ufixed96x96 ufixed96x104 ufixed96x112 ufixed96x120 ufixed96x128 ufixed96x136 ufixed96x144 ufixed96x152 ufixed96x160
+syn keyword solBuiltinType ufixed104x8 ufixed104x16 ufixed104x24 ufixed104x32 ufixed104x40 ufixed104x48 ufixed104x56 ufixed104x64 ufixed104x72 ufixed104x80 ufixed104x88 ufixed104x96 ufixed104x104 ufixed104x112 ufixed104x120 ufixed104x128 ufixed104x136 ufixed104x144 ufixed104x152
+syn keyword solBuiltinType ufixed112x8 ufixed112x16 ufixed112x24 ufixed112x32 ufixed112x40 ufixed112x48 ufixed112x56 ufixed112x64 ufixed112x72 ufixed112x80 ufixed112x88 ufixed112x96 ufixed112x104 ufixed112x112 ufixed112x120 ufixed112x128 ufixed112x136 ufixed112x144
+syn keyword solBuiltinType ufixed120x8 ufixed120x16 ufixed120x24 ufixed120x32 ufixed120x40 ufixed120x48 ufixed120x56 ufixed120x64 ufixed120x72 ufixed120x80 ufixed120x88 ufixed120x96 ufixed120x104 ufixed120x112 ufixed120x120 ufixed120x128 ufixed120x136
+syn keyword solBuiltinType ufixed128x8 ufixed128x16 ufixed128x24 ufixed128x32 ufixed128x40 ufixed128x48 ufixed128x56 ufixed128x64 ufixed128x72 ufixed128x80 ufixed128x88 ufixed128x96 ufixed128x104 ufixed128x112 ufixed128x120 ufixed128x128
+syn keyword solBuiltinType ufixed136x8 ufixed136x16 ufixed136x24 ufixed136x32 ufixed136x40 ufixed136x48 ufixed136x56 ufixed136x64 ufixed136x72 ufixed136x80 ufixed136x88 ufixed136x96 ufixed136x104 ufixed136x112 ufixed136x120
+syn keyword solBuiltinType ufixed144x8 ufixed144x16 ufixed144x24 ufixed144x32 ufixed144x40 ufixed144x48 ufixed144x56 ufixed144x64 ufixed144x72 ufixed144x80 ufixed144x88 ufixed144x96 ufixed144x104 ufixed144x112
+syn keyword solBuiltinType ufixed152x8 ufixed152x16 ufixed152x24 ufixed152x32 ufixed152x40 ufixed152x48 ufixed152x56 ufixed152x64 ufixed152x72 ufixed152x80 ufixed152x88 ufixed152x96 ufixed152x104
+syn keyword solBuiltinType ufixed160x8 ufixed160x16 ufixed160x24 ufixed160x32 ufixed160x40 ufixed160x48 ufixed160x56 ufixed160x64 ufixed160x72 ufixed160x80 ufixed160x88 ufixed160x96
+syn keyword solBuiltinType ufixed168x8 ufixed168x16 ufixed168x24 ufixed168x32 ufixed168x40 ufixed168x48 ufixed168x56 ufixed168x64 ufixed168x72 ufixed168x80 ufixed168x88
+syn keyword solBuiltinType ufixed176x8 ufixed176x16 ufixed176x24 ufixed176x32 ufixed176x40 ufixed176x48 ufixed176x56 ufixed176x64 ufixed176x72 ufixed176x80
+syn keyword solBuiltinType ufixed184x8 ufixed184x16 ufixed184x24 ufixed184x32 ufixed184x40 ufixed184x48 ufixed184x56 ufixed184x64 ufixed184x72
+syn keyword solBuiltinType ufixed192x8 ufixed192x16 ufixed192x24 ufixed192x32 ufixed192x40 ufixed192x48 ufixed192x56 ufixed192x64
+syn keyword solBuiltinType ufixed200x8 ufixed200x16 ufixed200x24 ufixed200x32 ufixed200x40 ufixed200x48 ufixed200x56
+syn keyword solBuiltinType ufixed208x8 ufixed208x16 ufixed208x24 ufixed208x32 ufixed208x40 ufixed208x48
+syn keyword solBuiltinType ufixed216x8 ufixed216x16 ufixed216x24 ufixed216x32 ufixed216x40
+syn keyword solBuiltinType ufixed224x8 ufixed224x16 ufixed224x24 ufixed224x32
+syn keyword solBuiltinType ufixed232x8 ufixed232x16 ufixed232x24
+syn keyword solBuiltinType ufixed240x8 ufixed240x16
+syn keyword solBuiltinType ufixed248x8
+syn keyword solBuiltinType string string1 string2 string3 string4 string5 string6 string7 string8 string9 string10 string11 string12 string13 string14 string15 string16 string17 string18 string19 string20 string21 string22 string23 string24 string25 string26 string27 string28 string29 string30 string31 string32
+syn keyword solBuiltinType byte bytes bytes1 bytes2 bytes3 bytes4 bytes5 bytes6 bytes7 bytes8 bytes9 bytes10 bytes11 bytes12 bytes13 bytes14 bytes15 bytes16 bytes17 bytes18 bytes19 bytes20 bytes21 bytes22 bytes23 bytes24 bytes25 bytes26 bytes27 bytes28 bytes29 bytes30 bytes31 bytes32
+
+hi def link solKeyword Keyword
+hi def link solConstant Constant
+hi def link solBuiltinType Type
+hi def link solBuiltinFunction Keyword
+
+syn match solOperator /\(!\||\|&\|+\|-\|<\|>\|=\|%\|\/\|*\|\~\|\^\)/
+syn match solNumber /\<-\=\d\+L\=\>\|\<0[xX]\x\+\>/
+syn match solFloat /\<-\=\%(\d\+\.\d\+\|\d\+\.\|\.\d\+\)\%([eE][+-]\=\d\+\)\=\>/
+
+syn region solString start=+"+ skip=+\\\\\|\\$"\|\\"+ end=+"+
+syn region solString start=+'+ skip=+\\\\\|\\$'\|\\'+ end=+'+
+
+hi def link solOperator Operator
+hi def link solNumber Number
+hi def link solFloat Float
+hi def link solString String
+
+" Function
+syn match solFunction /\<function\>/ nextgroup=solFuncName,solFuncArgs skipwhite
+syn match solFuncName contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*/ nextgroup=solFuncArgs skipwhite
+
+syn region solFuncArgs contained matchgroup=solFuncParens start='(' end=')' contains=solFuncArgCommas,solBuiltinType nextgroup=solModifierName,solFuncReturns,solFuncBody keepend skipwhite skipempty
+syn match solModifierName contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*/ nextgroup=solModifierArgs,solModifierName skipwhite
+syn region solModifierArgs contained matchgroup=solFuncParens start='(' end=')' contains=solFuncArgCommas nextgroup=solModifierName,solFuncReturns,solFuncBody skipwhite
+syn region solFuncReturns contained matchgroup=solFuncParens nextgroup=solFuncBody start='(' end=')' contains=solFuncArgCommas,solBuiltinType skipwhite
+
+syn match solFuncArgCommas contained ','
+syn region solFuncBody start="{" end="}" fold transparent
+
+hi def link solFunction Type
+hi def link solFuncName Function
+hi def link solModifierName Function
+
+" Yul blocks
+syn match yul /\<assembly\>/ skipwhite skipempty nextgroup=yulBody
+syn region yulBody contained start='{' end='}' fold contains=yulAssemblyOp,solNumber,yulVarDeclaration,solLineComment,solComment skipwhite skipempty
+syn keyword yulAssemblyOp contained stop add sub mul div sdiv mod smod exp not lt gt slt sgt eq iszero and or xor byte shl shr sar addmod mulmod signextend keccak256 pc pop mload mstore mstore8 sload sstore msize gas address balance selfbalance caller callvalue calldataload calldatasize calldatacopy codesize codecopy extcodesize extcodecopy returndatasize returndatacopy extcodehash create create2 call callcode delegatecall staticcall return revert selfdestruct invalid log0 log1 log2 log3 log4 chainid basefee origin gasprice blockhash coinbase timestamp number difficulty gaslimit
+syn keyword yulVarDeclaration contained let
+
+hi def link yul Keyword
+hi def link yulVarDeclaration Keyword
+hi def link yulAssemblyOp Keyword
+
+" Contract
+syn match solContract /\<\%(contract\|library\|interface\)\>/ nextgroup=solContractName skipwhite
+syn match solContractName contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*/ nextgroup=solContractParent skipwhite
+syn region solContractParent contained start='is' end='{' contains=solContractName,solContractNoise,solContractCommas skipwhite skipempty
+syn match solContractNoise contained 'is' containedin=solContractParent
+syn match solContractCommas contained ','
+
+hi def link solContract Type
+hi def link solContractName Function
+
+" Event
+syn match solEvent /\<event\>/ nextgroup=solEventName,solEventArgs skipwhite
+syn match solEventName contained /\<[a-zA-Z_$][0-9a-zA-Z_$]*/ nextgroup=solEventArgs skipwhite
+syn region solEventArgs contained matchgroup=solFuncParens start='(' end=')' contains=solEventArgCommas,solBuiltinType,solEventArgSpecial skipwhite skipempty
+syn match solEventArgCommas contained ','
+syn match solEventArgSpecial contained 'indexed'
+
+hi def link solEvent Type
+hi def link solEventName Function
+hi def link solEventArgSpecial Label
+
+" Comment
+syn keyword solCommentTodo TODO FIXME XXX TBD contained
+syn match solNatSpec contained /@title\|@author\|@notice\|@dev\|@param\|@inheritdoc\|@return/
+syn region solLineComment start=+\/\/+ end=+$+ contains=solCommentTodo,solNatSpec,@Spell
+syn region solLineComment start=+^\s*\/\/+ skip=+\n\s*\/\/+ end=+$+ contains=solCommentTodo,solNatSpec,@Spell fold
+syn region solComment start="/\*" end="\*/" contains=solCommentTodo,solNatSpec,@Spell fold
+
+hi def link solCommentTodo Todo
+hi def link solNatSpec Label
+hi def link solLineComment Comment
+hi def link solComment Comment
+
+let b:current_syntax = "solidity"
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index df5c888f2..25b0f4cd9 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -401,7 +401,7 @@ syn match vimSetMod contained "&vim\=\|[!&?<]\|all&"
" Let: {{{2
" ===
syn keyword vimLet let unl[et] skipwhite nextgroup=vimVar,vimFuncVar,vimLetHereDoc
-VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s\+\%(trim\|eval\>\)\=\s*\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$'
+VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s\+\%(trim\s\+\)\=\%(eval\s\+\)\=\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$'
" Abbreviations: {{{2
" =============
diff --git a/src/INSTALLpc.txt b/src/INSTALLpc.txt
index 9a286447c..50f9c780a 100644
--- a/src/INSTALLpc.txt
+++ b/src/INSTALLpc.txt
@@ -686,7 +686,6 @@ Ruby version vs. Ruby API version:
Ruby ver. | Ruby API ver.
=========================
- 1.8.X | 1.8
1.9.[1-3] | 1.9.1
2.0.0 | 2.0.0
2.X.Y | 2.X.0