From 13305beedb0f9657081ecb893c48e23f09af4eb1 Mon Sep 17 00:00:00 2001 From: lacygoill Date: Sat, 28 Jan 2023 09:12:42 +0100 Subject: [PATCH 1/5] support new class/interface/enum syntaxes --- runtime/autoload/dist/vimindent.vim | 285 +++++++++++++++------------- runtime/indent/testdir/vim.in | 37 ++++ runtime/indent/testdir/vim.ok | 37 ++++ 3 files changed, 227 insertions(+), 132 deletions(-) diff --git a/runtime/autoload/dist/vimindent.vim b/runtime/autoload/dist/vimindent.vim index 898f22f65c2ae..fc3d6fc9ba0f3 100644 --- a/runtime/autoload/dist/vimindent.vim +++ b/runtime/autoload/dist/vimindent.vim @@ -2,7 +2,7 @@ vim9script # Language: Vim script # Maintainer: github user lacygoill -# Last Change: 2023 Jan 03 +# Last Change: 2023 Jan 28 # NOTE: Whenever you change the code, make sure the tests are still passing: # @@ -112,6 +112,10 @@ const DICT_KEY: string = '^\s*\%(' .. '\)' .. ':\%(\s\|$\)' +# NOT_A_DICT_KEY {{{3 + +const NOT_A_DICT_KEY: string = ':\@!' + # END_OF_COMMAND {{{3 const END_OF_COMMAND: string = $'\s*\%($\|||\@!\|{INLINE_COMMENT}\)' @@ -145,18 +149,36 @@ const HEREDOC_OPERATOR: string = '\s=<<\s\@=\%(\s\+\%(trim\|eval\)\)\{,2}' # 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}' +# BLOCKS {{{3 + +const BLOCKS: list> = [ + ['if', 'el\%[se]', 'elseif\=', 'en\%[dif]'], + ['for', 'endfor\='], + ['wh\%[ile]', 'endw\%[hile]'], + ['try', 'cat\%[ch]', 'fina\|finally\=', 'endt\%[ry]'], + ['def', 'enddef'], + ['fu\%[nction](\@!', 'endf\%[unction]'], + ['class', 'endclass'], + ['interface', 'endinterface'], + ['enum', 'endenum'], + ['aug\%[roup]\%(\s\+[eE][nN][dD]\)\@!\s\+\S\+', 'aug\%[roup]\s\+[eE][nN][dD]'], +] + +# MODIFIERS {{{3 + +# some keywords can be prefixed by modifiers (e.g. `def` can be prefixed by `export`) +const MODIFIERS: dict = { + def: ['export', 'static'], + class: ['export', 'abstract', 'export abstract'], + interface: ['export'], +} +->map((_, mods: list): string => + '\%(' .. mods + ->join('\|') + ->substitute('\s\+', '\\s\\+', 'g') + .. '\)\s\+') # HIGHER_ORDER_COMMAND {{{3 @@ -174,58 +196,98 @@ patterns =<< trim eval END g\%[lobal]!\={PATTERN_DELIMITER}.* v\%[global]!\={PATTERN_DELIMITER}.* END -const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%(' .. patterns->join('\|') .. '\):\@!' -# MAPPING_COMMAND {{{3 +const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%({patterns->join('\|')}\){NOT_A_DICT_KEY}' -const MAPPING_COMMAND: string = '\%(\> + +def BlockStartKeyword(line: string): string + var kwd: string = line->matchstr('\l\+') + return fullcommand(kwd, false) +enddef -const NORMAL_COMMAND: string = '\ in BLOCKS + var [start: string, middle: string, end: string] = [block[0], '', block[-1]] + if MODIFIERS->has_key(start->BlockStartKeyword()) + start = $'\%({MODIFIERS[start]}\)\={start}' + endif + START_MIDDLE_END->extend({[block[0]]: []}) + if block->len() > 2 + middle = block[1 : -2]->join('\|') + endif + for kwd: string in block + START_MIDDLE_END->extend({[kwd->BlockStartKeyword()]: [start, middle, end]}) + endfor + endfor +} -# PLUS_MINUS_COMMAND {{{3 +START_MIDDLE_END = START_MIDDLE_END + ->map((_, kwds: list) => + kwds->map((_, kwd: string) => kwd == '' + ? '' + : $'\%(^\|{BAR_SEPARATION}\|\\%(\s*{OPERATOR}\)\@!')) -# 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*$' +lockvar! START_MIDDLE_END # ENDS_BLOCK {{{3 const ENDS_BLOCK: string = '^\s*\%(' - .. 'en\%[dif]' - .. '\|' .. 'endfor\=' - .. '\|' .. 'endw\%[hile]' - .. '\|' .. 'endt\%[ry]' - .. '\|' .. 'enddef' - .. '\|' .. 'endclass' - .. '\|' .. 'endf\%[unction]' - .. '\|' .. 'aug\%[roup]\s\+[eE][nN][dD]' + .. BLOCKS + ->copy() + ->map((_, kwds: list): string => kwds[-1]) + ->join('\|') .. '\|' .. CLOSING_BRACKET .. $'\){END_OF_COMMAND}' # ENDS_BLOCK_OR_CLAUSE {{{3 -patterns =<< trim END - en\%[dif] - el\%[se] - endfor\= - endclass - endw\%[hile] - endt\%[ry] - fina\|finally\= - enddef - endf\%[unction] - aug\%[roup]\s\+[eE][nN][dD] -END +patterns = BLOCKS + ->copy() + ->map((_, kwds: list) => kwds[1 :]) + ->flattennew() + # `catch` and `elseif` need to be handled as special cases + ->filter((_, pat: string): bool => pat->BlockStartKeyword() !~ '^\%(catch\|elseif\)') const ENDS_BLOCK_OR_CLAUSE: string = '^\s*\%(' .. patterns->join('\|') .. $'\){END_OF_COMMAND}' .. $'\|^\s*cat\%[ch]\%(\s\+\({PATTERN_DELIMITER}\).*\1\)\={END_OF_COMMAND}' .. $'\|^\s*elseif\=\>\%({OPERATOR}\)\@!' +# STARTS_NAMED_BLOCK {{{3 + +patterns = [] +{ + for kwds: list in BLOCKS + for kwd: string in kwds[0 : -2] + if MODIFIERS->has_key(kwd->BlockStartKeyword()) + patterns += [$'\%({MODIFIERS[kwd]}\)\={kwd}'] + else + patterns += [kwd] + endif + endfor + endfor +} + +const STARTS_NAMED_BLOCK: string = $'^\s*\%(sil\%[ent]\s\+\)\=\%({patterns->join('\|')}\)\>{NOT_A_DICT_KEY}' + # STARTS_CURLY_BLOCK {{{3 # TODO: `{` alone on a line is not necessarily the start of a block. @@ -238,67 +300,47 @@ const STARTS_CURLY_BLOCK: string = '\%(' .. '\|' .. $'^\%(\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 - class - 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\>:\@!' +const STARTS_FUNCTION: string = $'^\s*\%({MODIFIERS.def}\)\=def\>{NOT_A_DICT_KEY}' # ENDS_FUNCTION {{{3 -const ENDS_FUNCTION: string = $'^\s*enddef\>:\@!{END_OF_COMMAND}' +const ENDS_FUNCTION: string = $'^\s*enddef\>{END_OF_COMMAND}' -# START_MIDDLE_END {{{3 +# ASSIGNS_HEREDOC {{{3 -const START_MIDDLE_END: dict> = { - 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\='], - class: ['class', '', 'endclass'], - endclass: ['class', '', 'endclass'], - 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) => - kwds->map((_, kwd: string) => kwd == '' - ? '' - : $'\%(^\|{BAR_SEPARATION}\|\:\@!\%%(\s*%s\)\@!', kwd, OPERATOR)}\)')) +const ASSIGNS_HEREDOC: string = $'^\%({COMMENT}\)\@!.*\%({HEREDOC_OPERATOR}\)\s\+\zs[A-Z]\+{END_OF_LINE}' + +# 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*$' + +# TRICKY_COMMANDS {{{3 + +# Some commands are tricky because they accept an argument which can be +# conflated with an operator. Examples: +# +# argdelete * +# cd - +# normal! == +# nunmap ( +# +# TODO: Other commands might accept operators as argument. Handle them too. +patterns =<< trim eval END + {'\'}join('\|') # }}}2 # EOL {{{2 # OPENING_BRACKET_AT_EOL {{{3 @@ -392,6 +434,7 @@ export def Expr(lnum = v:lnum): number # {{{2 endif if line_A->AtStartOf('FuncHeader') + && !IsInInterface() line_A.lnum->CacheFuncHeader() elseif line_A.lnum->IsInside('FuncHeader') return b:vimindent.startindent + 2 * shiftwidth() @@ -536,8 +579,13 @@ def Offset( # {{{2 line_B: dict, ): number + if line_B->AtStartOf('FuncHeader') + && IsInInterface() + return 0 + # increase indentation inside a block - if line_B.text =~ STARTS_NAMED_BLOCK || line_B->EndsWithCurlyBlock() + elseif 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 @@ -807,11 +855,6 @@ def Indent(lnum: number): number # {{{3 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): number # {{{3 var end: string = line.text->matchstr(CLOSING_BRACKET) var start: string = {']': '[', '}': '{', ')': '('}[end] @@ -908,7 +951,8 @@ def SearchPair( # {{{3 if end == '[' || end == ']' e = e->escape('[]') endif - return searchpair(s, middle, e, flags, (): bool => InCommentOrString(), stopline, TIMEOUT) + return searchpair('\C' .. s, (middle == '' ? '' : '\C' .. middle), '\C' .. e, + flags, (): bool => InCommentOrString(), stopline, TIMEOUT) enddef def SearchPairStart( # {{{3 @@ -1016,6 +1060,10 @@ def IsInThisBlock(line_A: dict, lnum: number): bool # {{{3 return line_A.lnum <= end enddef +def IsInInterface(): bool # {{{3 + return SearchPair('interface', '', 'endinterface', 'nW') > 0 +enddef + def IsFirstLineOfCommand(line_1: dict, line_2: dict): bool # {{{3 if line_1.text->Is_IN_KeywordForLoop(line_2.text) return false @@ -1103,16 +1151,6 @@ def NonCommentedMatch(line: dict, pat: string): bool # {{{3 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 =~ '\, pat: string): bool # {{{3 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 ( - # - # 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 + if line.text =~ TRICKY_COMMANDS return false endif diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in index 55acf6fde1f89..be7a6a070445e 100644 --- a/runtime/indent/testdir/vim.in +++ b/runtime/indent/testdir/vim.in @@ -887,3 +887,40 @@ if true elseif endif " END_INDENT + +" START_INDENT +abstract class Shape +this.color = Color.Black +this.thickness = 10 +endclass +" END_INDENT + +" START_INDENT +class OtherThing +this.size: number +static totalSize: number + +static def ClearTotalSize(): number +var prev = totalSize +totalSize = 0 +return prev +enddef +endclass +" END_INDENT + +" START_INDENT +interface HasSurface +this.size: number +def Surface(): number +endinterface +" END_INDENT + +" START_INDENT +enum Color +White +Red +Green +Blue +Black +endenum +" END_INDENT diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok index c6ba084305d8f..3b16ec3eb0e08 100644 --- a/runtime/indent/testdir/vim.ok +++ b/runtime/indent/testdir/vim.ok @@ -887,3 +887,40 @@ if true elseif endif " END_INDENT + +" START_INDENT +abstract class Shape + this.color = Color.Black + this.thickness = 10 +endclass +" END_INDENT + +" START_INDENT +class OtherThing + this.size: number + static totalSize: number + + static def ClearTotalSize(): number + var prev = totalSize + totalSize = 0 + return prev + enddef +endclass +" END_INDENT + +" START_INDENT +interface HasSurface + this.size: number + def Surface(): number +endinterface +" END_INDENT + +" START_INDENT +enum Color + White + Red + Green + Blue + Black +endenum +" END_INDENT From 13de3bdaf2055d06382b508da45dcc19254a9454 Mon Sep 17 00:00:00 2001 From: lacygoill Date: Sat, 28 Jan 2023 09:48:58 +0100 Subject: [PATCH 2/5] rename function; add comment --- runtime/autoload/dist/vimindent.vim | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/runtime/autoload/dist/vimindent.vim b/runtime/autoload/dist/vimindent.vim index fc3d6fc9ba0f3..ea94d8844e85b 100644 --- a/runtime/autoload/dist/vimindent.vim +++ b/runtime/autoload/dist/vimindent.vim @@ -148,7 +148,6 @@ const HEREDOC_OPERATOR: string = '\s=<<\s\@=\%(\s\+\%(trim\|eval\)\)\{,2}' # # But sometimes, it can be too costly and cause `E363` to be given. const PATTERN_DELIMITER: string = '[-+*/%]\%(=\s\)\@!' - # }}}2 # Syntaxes {{{2 # BLOCKS {{{3 @@ -174,6 +173,9 @@ const MODIFIERS: dict = { class: ['export', 'abstract', 'export abstract'], interface: ['export'], } +# class: ['export', 'abstract', 'export abstract'], +# → +# class: '\%(export\|abstract\|export\s\+abstract\)\s\+', ->map((_, mods: list): string => '\%(' .. mods ->join('\|') @@ -218,23 +220,26 @@ const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%({patterns # } var START_MIDDLE_END: dict> +def Unshorten(kwd: string): string + return BlockStartKeyword(kwd) +enddef + def BlockStartKeyword(line: string): string var kwd: string = line->matchstr('\l\+') return fullcommand(kwd, false) enddef { - for block: list in BLOCKS - var [start: string, middle: string, end: string] = [block[0], '', block[-1]] - if MODIFIERS->has_key(start->BlockStartKeyword()) + for kwds: list in BLOCKS + var [start: string, middle: string, end: string] = [kwds[0], '', kwds[-1]] + if MODIFIERS->has_key(start->Unshorten()) start = $'\%({MODIFIERS[start]}\)\={start}' endif - START_MIDDLE_END->extend({[block[0]]: []}) - if block->len() > 2 - middle = block[1 : -2]->join('\|') + if kwds->len() > 2 + middle = kwds[1 : -2]->join('\|') endif - for kwd: string in block - START_MIDDLE_END->extend({[kwd->BlockStartKeyword()]: [start, middle, end]}) + for kwd: string in kwds + START_MIDDLE_END->extend({[kwd->Unshorten()]: [start, middle, end]}) endfor endfor } @@ -265,7 +270,7 @@ patterns = BLOCKS ->map((_, kwds: list) => kwds[1 :]) ->flattennew() # `catch` and `elseif` need to be handled as special cases - ->filter((_, pat: string): bool => pat->BlockStartKeyword() !~ '^\%(catch\|elseif\)') + ->filter((_, pat: string): bool => pat->Unshorten() !~ '^\%(catch\|elseif\)') const ENDS_BLOCK_OR_CLAUSE: string = '^\s*\%(' .. patterns->join('\|') .. $'\){END_OF_COMMAND}' .. $'\|^\s*cat\%[ch]\%(\s\+\({PATTERN_DELIMITER}\).*\1\)\={END_OF_COMMAND}' @@ -277,7 +282,7 @@ patterns = [] { for kwds: list in BLOCKS for kwd: string in kwds[0 : -2] - if MODIFIERS->has_key(kwd->BlockStartKeyword()) + if MODIFIERS->has_key(kwd->Unshorten()) patterns += [$'\%({MODIFIERS[kwd]}\)\={kwd}'] else patterns += [kwd] From 0b0126314cb7b955a8212abacc62e84ff59e7004 Mon Sep 17 00:00:00 2001 From: lacygoill Date: Wed, 1 Feb 2023 12:15:14 +0100 Subject: [PATCH 3/5] fix: wrong indent in multiline bracket block after :if --- runtime/autoload/dist/vimindent.vim | 15 ++++++++++++++- runtime/indent/testdir/vim.in | 8 ++++++++ runtime/indent/testdir/vim.ok | 8 ++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/runtime/autoload/dist/vimindent.vim b/runtime/autoload/dist/vimindent.vim index ea94d8844e85b..5d2c8e8bd372f 100644 --- a/runtime/autoload/dist/vimindent.vim +++ b/runtime/autoload/dist/vimindent.vim @@ -7,7 +7,7 @@ vim9script # NOTE: Whenever you change the code, make sure the tests are still passing: # # $ cd runtime/indent/ -# $ make clean; make test || vimdiff testdir/vim.{fail,ok} +# $ make clean; make test || vimdiff testdir/vim.{ok,fail} # Config {{{1 @@ -173,9 +173,13 @@ const MODIFIERS: dict = { class: ['export', 'abstract', 'export abstract'], interface: ['export'], } +# ... # class: ['export', 'abstract', 'export abstract'], +# ... # → +# ... # class: '\%(export\|abstract\|export\s\+abstract\)\s\+', +# ... ->map((_, mods: list): string => '\%(' .. mods ->join('\|') @@ -352,6 +356,10 @@ const TRICKY_COMMANDS: string = patterns->join('\|') const OPENING_BRACKET_AT_EOL: string = OPENING_BRACKET .. END_OF_VIM9_LINE +# CLOSING_BRACKET_AT_EOL {{{3 + +const CLOSING_BRACKET_AT_EOL: string = CLOSING_BRACKET .. END_OF_VIM9_LINE + # COMMA_AT_EOL {{{3 const COMMA_AT_EOL: string = $',{END_OF_VIM9_LINE}' @@ -478,6 +486,7 @@ export def Expr(lnum = v:lnum): number # {{{2 if line_A.text->ContinuesBelowBracketBlock(line_B, past_bracket_block) && line_A.text !~ CLOSING_BRACKET_AT_SOL return past_bracket_block.startindent + + (past_bracket_block.startline =~ STARTS_NAMED_BLOCK ? 2 * shiftwidth() : 0) endif # Problem: If we press `==` on the line right below the start of a multiline @@ -1149,6 +1158,10 @@ def EndsWithOpeningBracket(line: dict): bool # {{{3 return NonCommentedMatch(line, OPENING_BRACKET_AT_EOL) enddef +def EndsWithClosingBracket(line: dict): bool # {{{3 + return NonCommentedMatch(line, CLOSING_BRACKET_AT_EOL) +enddef + def NonCommentedMatch(line: dict, 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: ''}`. diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in index be7a6a070445e..c0da413eefaa2 100644 --- a/runtime/indent/testdir/vim.in +++ b/runtime/indent/testdir/vim.in @@ -888,6 +888,14 @@ elseif endif " END_INDENT +" START_INDENT +if ( +true) +&& true +echo +endif +" END_INDENT + " START_INDENT abstract class Shape this.color = Color.Black diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok index 3b16ec3eb0e08..ce1c828700042 100644 --- a/runtime/indent/testdir/vim.ok +++ b/runtime/indent/testdir/vim.ok @@ -888,6 +888,14 @@ elseif endif " END_INDENT +" START_INDENT +if ( + true) + && true + echo +endif +" END_INDENT + " START_INDENT abstract class Shape this.color = Color.Black From fc04b9b85e598c27b9b4785e04e5cb15a6c9eadc Mon Sep 17 00:00:00 2001 From: lacygoill Date: Wed, 1 Feb 2023 12:57:06 +0100 Subject: [PATCH 4/5] update "Last Change" --- runtime/autoload/dist/vimindent.vim | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/runtime/autoload/dist/vimindent.vim b/runtime/autoload/dist/vimindent.vim index 5d2c8e8bd372f..8d86543cb4f12 100644 --- a/runtime/autoload/dist/vimindent.vim +++ b/runtime/autoload/dist/vimindent.vim @@ -2,7 +2,7 @@ vim9script # Language: Vim script # Maintainer: github user lacygoill -# Last Change: 2023 Jan 28 +# Last Change: 2023 Feb 01 # NOTE: Whenever you change the code, make sure the tests are still passing: # @@ -184,7 +184,7 @@ const MODIFIERS: dict = { '\%(' .. mods ->join('\|') ->substitute('\s\+', '\\s\\+', 'g') - .. '\)\s\+') + .. '\)' .. '\s\+') # HIGHER_ORDER_COMMAND {{{3 @@ -209,9 +209,10 @@ const HIGHER_ORDER_COMMAND: string = $'\%(^\|{BAR_SEPARATION}\)\s*\<\%({patterns # Let's derive this constant from `BLOCKS`: # -# [['for', 'endfor\='] -# ['if', 'el\%[se]', 'elseif\=', 'en\%[dif]'],, -# ...]] +# [['if', 'el\%[se]', 'elseif\=', 'en\%[dif]'], +# ['for', 'endfor\='], +# ..., +# [...]] # → # { # 'for': ['for', '', 'endfor\='], @@ -274,7 +275,7 @@ patterns = BLOCKS ->map((_, kwds: list) => kwds[1 :]) ->flattennew() # `catch` and `elseif` need to be handled as special cases - ->filter((_, pat: string): bool => pat->Unshorten() !~ '^\%(catch\|elseif\)') + ->filter((_, pat: string): bool => pat->Unshorten() !~ '^\%(catch\|elseif\)\>') const ENDS_BLOCK_OR_CLAUSE: string = '^\s*\%(' .. patterns->join('\|') .. $'\){END_OF_COMMAND}' .. $'\|^\s*cat\%[ch]\%(\s\+\({PATTERN_DELIMITER}\).*\1\)\={END_OF_COMMAND}' @@ -495,6 +496,18 @@ export def Expr(lnum = v:lnum): number # {{{2 if line_B->EndsWithLambdaArrow() return Indent(line_B.lnum) + shiftwidth() + IndentMoreInBracketBlock() endif + # FIXME: Similar issue here: + # + # var x = [] + # ->filter((_, _) => + # true) + # ->items() + # + # Press `==` on last line. + # Expected: The `->items()` line is indented like `->filter(...)`. + # Actual: It's indented like `true)`. + # Is it worth fixing? `=ip` gives the correct indentation, because then the + # cache is used. # Don't move this block before the heredoc one.{{{ # From da2fc75a748b6b8ad2e7497f155e2869228e9428 Mon Sep 17 00:00:00 2001 From: lacygoill Date: Wed, 1 Feb 2023 18:29:46 +0100 Subject: [PATCH 5/5] add test --- runtime/indent/testdir/vim.in | 7 +++++++ runtime/indent/testdir/vim.ok | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/runtime/indent/testdir/vim.in b/runtime/indent/testdir/vim.in index c0da413eefaa2..c60d2d1160651 100644 --- a/runtime/indent/testdir/vim.in +++ b/runtime/indent/testdir/vim.in @@ -923,6 +923,13 @@ def Surface(): number endinterface " END_INDENT +" START_INDENT +interface EnterExit +def Enter(): void +def Exit(): void +endinterface +" END_INDENT + " START_INDENT enum Color White diff --git a/runtime/indent/testdir/vim.ok b/runtime/indent/testdir/vim.ok index ce1c828700042..57f0dbf34d700 100644 --- a/runtime/indent/testdir/vim.ok +++ b/runtime/indent/testdir/vim.ok @@ -923,6 +923,13 @@ interface HasSurface endinterface " END_INDENT +" START_INDENT +interface EnterExit + def Enter(): void + def Exit(): void +endinterface +" END_INDENT + " START_INDENT enum Color White