aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--runtime/ftplugin/nroff.vim19
-rw-r--r--runtime/lua/vim/lsp/completion.lua18
-rw-r--r--runtime/syntax/vim.vim255
-rw-r--r--src/nvim/memline.c10
-rw-r--r--test/functional/lua/buffer_updates_spec.lua18
-rw-r--r--test/functional/plugin/lsp/completion_spec.lua77
7 files changed, 318 insertions, 81 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index bb98430763..d2262d44c0 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -6,7 +6,7 @@ freebsd_task:
name: FreeBSD
only_if: $BRANCH != "master"
freebsd_instance:
- image_family: freebsd-14-0
+ image_family: freebsd-14-2
timeout_in: 30m
install_script:
- pkg install -y cmake gmake ninja unzip wget gettext python git
diff --git a/runtime/ftplugin/nroff.vim b/runtime/ftplugin/nroff.vim
index ed0b32f5f3..7d3d2a597f 100644
--- a/runtime/ftplugin/nroff.vim
+++ b/runtime/ftplugin/nroff.vim
@@ -2,8 +2,11 @@
" Language: roff(7)
" Maintainer: Aman Verma
" Homepage: https://github.com/a-vrma/vim-nroff-ftplugin
+" Document: https://www.gnu.org/software/groff/manual/groff.html
" Previous Maintainer: Chris Spiegel <cspiegel@gmail.com>
-" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring')
+" Last Changes:
+" 2024 May 24 by Riley Bruins <ribru17@gmail.com> ('commentstring' #14843)
+" 2025 Feb 12 by Wu, Zhenyu <wuzhenyu@ustc.edu> (matchit configuration #16619)
if exists("b:did_ftplugin")
finish
@@ -13,5 +16,17 @@ let b:did_ftplugin = 1
setlocal commentstring=.\\\"\ %s
setlocal comments=:.\\\"
setlocal sections+=Sh
+setlocal define=.\s*de
-let b:undo_ftplugin = 'setlocal commentstring< comments< sections<'
+let b:undo_ftplugin = 'setlocal commentstring< comments< sections< define<'
+
+if exists('loaded_matchit')
+ let b:match_words = '^\.\s*ie\>:^\.\s*el\>'
+ \ . ',^\.\s*LB\>:^\.\s*LI\>:^\.\s*LE\>'
+ \ . ',^\.\s*TS\>:^\.\s*TE\>'
+ \ . ',^\.\s*PS\>:^\.\s*P[EF]\>'
+ \ . ',^\.\s*EQ\>:^\.\s*EN\>'
+ \ . ',^\.\s*[\>:^\.\s*]\>'
+ \ . ',^\.\s*FS\>:^\.\s*FE\>'
+ let b:undo_ftplugin .= "| unlet b:match_words"
+endif
diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua
index cf6d07745f..f287304508 100644
--- a/runtime/lua/vim/lsp/completion.lua
+++ b/runtime/lua/vim/lsp/completion.lua
@@ -493,6 +493,7 @@ local function trigger(bufnr, clients)
end
end
local start_col = (server_start_boundary or word_boundary) + 1
+ Context.cursor = { cursor_row, start_col }
vim.fn.complete(start_col, matches)
end)
@@ -518,11 +519,14 @@ local function on_insert_char_pre(handle)
end
local char = api.nvim_get_vvar('char')
- if not completion_timer and handle.triggers[char] then
+ local matched_clients = handle.triggers[char]
+ if not completion_timer and matched_clients then
completion_timer = assert(vim.uv.new_timer())
completion_timer:start(25, 0, function()
reset_timer()
- vim.schedule(M.trigger)
+ vim.schedule(function()
+ trigger(api.nvim_get_current_buf(), matched_clients)
+ end)
end)
end
end
@@ -569,8 +573,14 @@ local function on_complete_done()
end
-- Remove the already inserted word.
- local start_char = cursor_col - #completed_item.word
- api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, cursor_col, { '' })
+ api.nvim_buf_set_text(
+ bufnr,
+ Context.cursor[1] - 1,
+ Context.cursor[2] - 1,
+ cursor_row,
+ cursor_col,
+ { '' }
+ )
end
local function apply_snippet_and_command()
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index c4e231d145..9b128265de 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -185,31 +185,51 @@ Vim9 syn keyword vim9Boolean true false
" Numbers {{{2
" =======
syn case ignore
-syn match vimNumber '\<\d\+\%(\.\d\+\%(e[+-]\=\d\+\)\=\)\=' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
-syn match vimNumber '\<0b[01]\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
-syn match vimNumber '\<0o\=\o\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
-syn match vimNumber '\<0x\x\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
+syn match vimNumber '\<\d\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment,vimSubscript
+syn match vimNumber '\<\d\+\.\d\+\%(e[+-]\=\d\+\)\=' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
+syn match vimNumber '\<0b[01]\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment,vimSubscript
+syn match vimNumber '\<0o\=\o\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment,vimSubscript
+syn match vimNumber '\<0x\x\+' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment,vimSubscript
syn match vimNumber '\<0z\>' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
-syn match vimNumber '\<0z\%(\x\x\)\+\%(\.\%(\x\x\)\+\)*' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
+syn match vimNumber '\<0z\%(\x\x\)\+\%(\.\%(\x\x\)\+\)*' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment,vimSubscript
syn match vimNumber '\%(^\|\A\)\zs#\x\{6}' skipwhite nextgroup=vimGlobal,vimSubst1,@vimComment
syn case match
" All vimCommands are contained by vimIsCommand. {{{2
-syn cluster vimCmdList contains=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimCall,vimCatch,vimConst,vimDef,vimDefFold,vimDelcommand,@vimEcho,vimEnddef,vimEndfunction,vimExecute,vimIsCommand,vimExtCmd,vimFor,vimFunction,vimFuncFold,vimGlobal,vimHighlight,vimLet,vimLoadkeymap,vimMap,vimMark,vimMatch,vimNotFunc,vimNormal,vimSet,vimSleep,vimSyntax,vimThrow,vimUnlet,vimUnmap,vimUserCmd,vimMenu,vimMenutranslate,@vim9CmdList
+syn cluster vimCmdList contains=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimCall,vimCatch,vimConst,vimDebuggreedy,vimDef,vimDefFold,vimDelcommand,@vimEcho,vimEnddef,vimEndfunction,vimExecute,vimIsCommand,vimExtCmd,vimFor,vimFunction,vimFuncFold,vimGlobal,vimHighlight,vimLet,vimLoadkeymap,vimLockvar,vimMap,vimMark,vimMatch,vimNotFunc,vimNormal,vimSet,vimSleep,vimSyntax,vimThrow,vimUnlet,vimUnlockvar,vimUnmap,vimUserCmd,vimMenu,vimMenutranslate,@vim9CmdList
syn cluster vim9CmdList contains=vim9Abstract,vim9Class,vim9Const,vim9Enum,vim9Export,vim9Final,vim9For,vim9Interface,vim9Type,vim9Var
syn match vimCmdSep "[:|]\+" skipwhite nextgroup=@vimCmdList,vimSubst1
+syn match vimCount contained "\d\+"
syn match vimIsCommand "\<\%(\h\w*\|[23]mat\%[ch]\)\>" nextgroup=vimBang contains=vimCommand
syn match vimBang contained "!"
-syn match vimVar contained "\<\h[a-zA-Z0-9#_]*\>"
-syn match vimVar "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>"
-syn match vimVar "\s\zs&\%([lg]:\)\=\a\+\>"
-syn match vimVar "\s\zs&t_\S[a-zA-Z0-9]\>"
-syn match vimVar "\s\zs&t_k;"
-syn match vimFBVar contained "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>"
-syn keyword vimCommand contained in
-syn cluster vimExprList contains=vimEnvvar,vimFunc,vimNumber,vimOper,vimOperParen,vimLetRegister,vimString,vimVar,@vim9ExprList
-syn cluster vim9ExprList contains=vim9Boolean,vim9Null
+syn region vimSubscript contained matchgroup=vimSubscriptBracket start="\[" end="]" nextgroup=vimSubscript contains=@vimExprList
+
+syn match vimVar contained "\<\h[a-zA-Z0-9#_]*\>" nextgroup=vimSubscript contains=vim9Super,vim9This
+syn match vimVar "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>" nextgroup=vimSubscript
+syn match vimVar "\<a:\%(000\|\d\+\)\>" nextgroup=vimSubscript
+syn match vimFBVar contained "\<[bwglsta]:\h[a-zA-Z0-9#_]*\>" nextgroup=vimSubscript
+
+syn match vimVimVar "\<v:\h\w*\>" nextgroup=vimSubscript
+syn match vimOptionVar "&\%([lg]:\)\=\a\+\>" nextgroup=vimSubscript
+syn match vimOptionVar "&t_\S[a-zA-Z0-9]\>" nextgroup=vimSubscript
+syn match vimOptionVar "&t_k;" nextgroup=vimSubscript
+syn cluster vimSpecialVar contains=vimEnvvar,vimLetRegister,vimOptionVar,vimVimVar
+
+Vim9 syn match vim9LhsVariable "\s\=\h[a-zA-Z0-9#_]*\ze\s\+[-+/*%]\=="
+Vim9 syn match vim9LhsVariable "\s\=\h[a-zA-Z0-9#_]*\ze\s\+\.\.="
+Vim9 syn match vim9LhsVariable "\s\=\h[a-zA-Z0-9#_]*\ze\s\+=<<"
+Vim9 syn match vim9LhsVariable "\s\=\h[a-zA-Z0-9#_]*\ze\s*->" contains=vim9Super,vim9This
+Vim9 syn match vim9LhsVariable "\s\=\h[a-zA-Z0-9#_]*\ze\[" nextgroup=vimSubscript
+Vim9 syn match vim9LhsVariable "\s\=\h[a-zA-Z0-9#_]*\ze\." nextgroup=vimOper contains=vim9Super,vim9This
+
+Vim9 syn match vim9LhsVariableList "\[\_[^]]\+]\ze\s\+[-+/*%]\==" contains=vimVar,@vimSpecialVar
+Vim9 syn match vim9LhsVariableList "\[\_[^]]\+]\ze\s\+\.\.=" contains=vimVar,@vimSpecialVar
+
+Vim9 syn match vim9LhsRegister "@["0-9\-a-zA-Z#=*+_/]\ze\s\+\%(\.\.\)\=="
+
+syn cluster vimExprList contains=@vimSpecialVar,vimFunc,vimNumber,vimOper,vimOperParen,vimLambda,vimString,vimVar,@vim9ExprList
+syn cluster vim9ExprList contains=vim9Boolean,vim9LambdaParams,vim9Null
" Insertions And Appends: insert append {{{2
" (buftype != nofile test avoids having append, change, insert show up in the command window)
@@ -233,6 +253,11 @@ syn keyword vimBehaveModel contained mswin xterm
" ====
syn match vimCall "\<call\=\>" skipwhite nextgroup=vimFunc
+" Debuggreedy {{{2
+" ===========
+" TODO: special-cased until generalised range/count support is implemented
+syn match vimDebuggreedy "\<0\=debugg\%[reedy]\>" contains=vimCount
+
" Exception Handling {{{2
syn keyword vimThrow th[row] skipwhite nextgroup=@vimExprList
syn keyword vimCatch cat[ch] skipwhite nextgroup=vimCatchPattern
@@ -255,7 +280,7 @@ syn keyword vimFTOption contained detect indent off on plugin
" Augroup : vimAugroupError removed because long augroups caused sync'ing problems. {{{2
" ======= : Trade-off: Increasing synclines with slower editing vs augroup END error checking.
-syn cluster vimAugroupList contains=@vimCmdList,vimFilter,vimFunc,vimLineComment,vimSpecFile,vimOper,vimNumber,vimOperParen,@vimComment,vimString,vimSubst,vimRegister,vimCmplxRepeat,vimNotation,vimCtrlChar,vimFuncVar,vimContinue
+syn cluster vimAugroupList contains=@vimCmdList,vimFilter,vimFunc,vimLineComment,vimSpecFile,vimOper,vimNumber,vimOperParen,@vimComment,vimString,vimSubst,vimRegister,vimCmplxRepeat,vimNotation,vimCtrlChar,vimContinue
syn match vimAugroup "\<aug\%[roup]\>" contains=vimAugroupKey,vimAugroupBang skipwhite nextgroup=vimAugroupBang,vimAutoCmdGroup
if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'a'
syn region vimAugroup fold start="\<aug\%[roup]\>\ze\s\+\%([eE][nN][dD]\)\@!\S\+" matchgroup=vimAugroupKey end="\<aug\%[roup]\>\ze\s\+[eE][nN][dD]\>" contains=vimAutoCmd,@vimAugroupList,vimAugroupkey skipwhite nextgroup=vimAugroupEnd
@@ -273,31 +298,64 @@ syn keyword vimAugroupKey contained aug[roup] skipwhite nextgroup=vimAugroupBan
" Operators: {{{2
" =========
-syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,@vimContinue,vim9Comment,vimVar,vimBoolean,vimNull
-syn match vimOper "\a\@<!!" skipwhite nextgroup=vimString,vimSpecFile
-syn match vimOper "||\|&&\|[-+*/%.]" skipwhite nextgroup=vimString,vimSpecFile
-syn match vimOper "?" skipwhite nextgroup=@vimExprList
+syn cluster vimOperGroup contains=@vimContinue,@vimExprList,vim9Comment
+syn match vimOper "\a\@<!!" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList,vimSpecFile
+syn match vimOper "||\|&&\|[-+*/%.]" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList,vimSpecFile
+syn match vimOper "?" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList
" distinguish ternary : from ex-colon
-syn match vimOper "\s\@1<=:\ze\s\|\s\@1<=:$" skipwhite nextgroup=@vimExprList
-syn match vimOper "??" skipwhite nextgroup=@vimExprList
-syn match vimOper "=" skipwhite nextgroup=vimString,vimSpecFile
-syn match vimOper "\%#=1\%(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\)[?#]\=" skipwhite nextgroup=vimString,vimSpecFile
-syn match vimOper "\<is\%(not\)\=\>" skipwhite nextgroup=vimString,vimSpecFile
-syn match vimOper "\<is\%(not\)\=[?#]" skipwhite nextgroup=vimString,vimSpecFile
-syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=@vimOperGroup
-syn region vimOperParen matchgroup=vimSep start="#\={" end="}" contains=@vimOperGroup nextgroup=vimVar,vimFuncVar
+syn match vimOper "\s\@1<=:\ze\s\|\s\@1<=:$" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList
+syn match vimOper "??" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList
+syn match vimOper "=" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList,vimSpecFile
+syn match vimOper "\%#=1\%(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\)[?#]\=" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList,vimSpecFile
+syn match vimOper "\<is\%(not\)\=\>" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList,vimSpecFile
+syn match vimOper "\<is\%(not\)\=[?#]" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList,vimSpecFile
+syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=@vimOperGroup nextgroup=vimSubscript
+syn region vimOperParen matchgroup=vimSep start="#\={" end="}" contains=@vimOperGroup nextgroup=vimSubscript,vimVar
+syn region vimOperParen contained matchgroup=vimSep start="\[" end="]" contains=@vimOperGroup nextgroup=vimSubscript,vimVar
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noopererror")
syn match vimOperError ")"
endif
+syn match vimOperContinue contained "^\s*\zs\\" skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList
+syn match vimOperContinueComment contained '^\s*\zs["#]\\ .*' skipwhite skipnl nextgroup=@vimOperContinue,@vimExprList
+syn cluster vimOperContinue contains=vimOperContinue,vimOperContinueComment
+
+" Lambda Expressions: {{{2
+" ==================
+syn match vimLambdaOperator contained "->" skipwhite nextgroup=@vimExprList
+syn region vimLambda contained matchgroup=Delimiter start="{\ze[[:space:][:alnum:]_.,]*->" end="}" end="$" skip=+\s*\n\s*\\\|\s*\n\s*"\\ + contains=@vimContinue,@vimExprList,vimLambdaParams
+syn match vimLambdaParams contained "{\@1<=.\{-}\%(->\)\@=" nextgroup=vimLambdaOperator contains=vimFuncParam
+
+syn match vim9LambdaOperator contained "=>" skipwhite skipempty nextgroup=@vimExprList,vim9LambdaBlock,vim9LambdaOperatorComment
+syn match vim9LambdaParamsParen contained "[()]"
+syn region vim9LambdaParams contained
+ \ matchgroup=vim9LambdaParamsParen
+ \ start="(\ze\s*\(\.\.\.\)\=\h\w*[,:]\%(\s\|$\)"
+ \ start="(\ze\s*\n
+ "\ line continuations
+ \\%(\s*\%(#\\ .*\|\\\s*\)\n\)*\s*\\\s*
+ "\ parameter names
+ \\(\.\.\.\)\=\h\w*[,:]\%(\s\|$\)"
+ \ end=")\ze\%(:\s\|\s\+=>\)"
+ \ matchgroup=vimContinue
+ \ end="^\s*\\\ze\s\+=>"
+ \ skipwhite nextgroup=vim9LambdaReturnType,vim9LambdaOperator
+ \ contains=@vim9Continue,vimDefParam,vim9LambdaParamsParen
+syn match vim9LambdaParams contained "(\s*)\|(\s*\(\.\.\.\)\=\h\w*\s*)\ze\%(:\s\|\s\+=>\)" skipwhite nextgroup=vim9LambdaReturnType,vim9LambdaOperator contains=vimDefParam,vim9LambdaParamsParen
+
+syn region vim9LambdaReturnType contained start=":\s" end="$" end="\ze#" end="\ze=>" skipwhite skipempty nextgroup=vim9LambdaOperator,vim9LamdaOperatorComment contains=vimTypeSep transparent
+syn region vim9LambdaBlock contained matchgroup=vimSep start="{" end="^\s*\zs}" contains=@vimDefBodyList
+
+syn match vim9LambdaOperatorComment contained "#.*" skipwhite skipempty nextgroup=@vimExprList,vim9LambdaBlock,vim9LambdaOperatorComment
+
" Functions: Tag is provided for those who wish to highlight tagged functions {{{2
" =========
-syn cluster vimFuncList contains=vimFuncBang,vimFunctionError,vimFuncKey,vimFuncSID,Tag
-syn cluster vimDefList contains=vimFuncBang,vimFunctionError,vimDefKey,vimFuncSID,Tag
+syn cluster vimFuncList contains=vimFuncBang,vimFunctionError,vimFuncKey,vimFuncScope,vimFuncSID,Tag
+syn cluster vimDefList contains=vimFuncBang,vimFunctionError,vimDefKey,vimFuncScope,vimFuncSID,Tag
-syn cluster vimFuncBodyCommon contains=@vimCmdList,vimCmplxRepeat,vimContinue,vimCtrlChar,vimDef,vimEnvvar,vimFBVar,vimFunc,vimFunction,vimLetHereDoc,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegister,vimSpecFile,vimString,vimSubst,vimFuncFold,vimDefFold
-syn cluster vimFuncBodyList contains=@vimFuncBodyCommon,vimComment,vimLineComment,vimFuncVar,vimInsert,vimConst,vimLet,vimSearch
-syn cluster vimDefBodyList contains=@vimFuncBodyCommon,vim9Comment,vim9LineComment,vim9Const,vim9Final,vim9Var,vim9Null,vim9Boolean,vim9For,vim9Search
+syn cluster vimFuncBodyCommon contains=@vimCmdList,vimCmplxRepeat,vimContinue,vimCtrlChar,vimDef,vimFBVar,vimFunc,vimFunction,vimLetHereDoc,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegister,vimSpecFile,vimString,vimSubst,vimFuncFold,vimDefFold
+syn cluster vimFuncBodyList contains=@vimFuncBodyCommon,vimComment,vimLineComment,vimInsert,vimConst,vimLet,vimSearch
+syn cluster vimDefBodyList contains=@vimFuncBodyCommon,vim9Comment,vim9LineComment,vim9Block,vim9Const,vim9Final,vim9Var,vim9Null,vim9Boolean,vim9For,vim9LhsVariable,vim9LhsVariableList,vim9LhsRegister,vim9Search,@vimSpecialVar
syn region vimFuncPattern contained matchgroup=vimOper start="/" end="$" contains=@vimSubstList
syn match vimFunction "\<fu\%[nction]\>" skipwhite nextgroup=vimCmdSep,vimComment,vimFuncPattern contains=vimFuncKey
@@ -311,7 +369,7 @@ syn match vimDefComment contained "#.*" skipwhite skipempty nextgroup=vimDefBody
syn match vimFuncBang contained "!"
syn match vimFuncSID contained "\c<sid>"
-syn match vimFuncSID contained "\<[sg]:"
+syn match vimFuncScope contained "\<[sg]:"
syn keyword vimFuncKey contained fu[nction]
syn keyword vimDefKey contained def
@@ -334,7 +392,6 @@ if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'f'
syn region vimDefFold start="\<def\>!\=\s*\%(<[sS][iI][dD]>\|[sg]:\)\=\%(\i\|[#.]\)\+(" end="\<enddef\>" contains=vimDef fold keepend extend transparent
endif
-syn match vimFuncVar contained "a:\%(\K\k*\|\d\+\)\>"
syn match vimFuncBlank contained "\s\+"
" Types: {{{2
@@ -357,12 +414,24 @@ syn cluster vimType contains=vimType,vimCompoundType,vimUserType
if s:vim9script
" Methods {{{3
- syn match vim9MethodDef contained "\<def\>" skipwhite nextgroup=vim9MethodDefName
+ syn match vim9MethodDef contained "\<def\>" skipwhite nextgroup=vim9MethodDefName,vim9ConstructorDefName
syn match vim9MethodDefName contained "\<\h\w*\>" nextgroup=vim9MethodDefParams contains=@vim9MethodName
syn region vim9MethodDefParams contained
\ matchgroup=Delimiter start="(" end=")"
\ skipwhite skipnl nextgroup=vim9MethodDefBody,vimDefComment,vimEnddef,vim9MethodDefReturnType,vimCommentError
\ contains=vimDefParam,vim9Comment,vimFuncParamEquals
+
+ syn match vim9ConstructorDefName contained "\<new\w*\>"
+ \ nextgroup=vim9ConstructorDefParams
+ \ contains=@vim9MethodName
+ syn match vim9ConstructorDefParam contained "\<\%(this\.\)\=\h\w*\>"
+ \ skipwhite nextgroup=vimParamType,vimFuncParamEquals
+ \ contains=vim9This,vimOper
+ syn region vim9ConstructorDefParams contained
+ \ matchgroup=Delimiter start="(" end=")"
+ \ skipwhite skipnl nextgroup=vim9MethodDefBody,vimDefComment,vimEnddef,vimCommentError
+ \ contains=vim9ConstructorDefParam,vim9Comment,vimFuncParamEquals
+
syn region vim9MethodDefReturnType contained
\ start=":\s" end="$" matchgroup=vim9Comment end="\ze[#"]"
\ skipwhite skipnl nextgroup=vim9MethodDefBody,vimDefComment,vimCommentError
@@ -378,7 +447,7 @@ if s:vim9script
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimfunctionerror")
syn match vim9MethodNameError contained "\<[a-z0-9]\i\>"
endif
- syn match vim9MethodName contained "\<new\i*\>"
+ syn match vim9MethodName contained "\<new\w*\>"
syn keyword vim9MethodName contained empty len string
syn cluster vim9MethodName contains=vim9MethodName,vim9MethodNameError
@@ -403,8 +472,11 @@ if s:vim9script
syn keyword vim9Implements contained implements skipwhite skipnl nextgroup=vim9ImplementedInterface
syn keyword vim9Public contained public
syn keyword vim9Static contained static
- syn keyword vim9This contained this
- syn keyword vim9Super contained super
+ " FIXME: don't match as dictionary keys, remove when operators are not
+ " shared between Vim9 and legacy script
+ syn match vim9This contained "\.\@1<!\<this\>:\@!"
+ " super must be folowed by '.'
+ syn match vim9Super contained "\.\@1<!\<super\.\@="
VimFoldc syn region vim9ClassBody start="\<class\>" matchgroup=vimCommand end="\<endclass\>" contains=@vim9ClassBodyList transparent
@@ -437,15 +509,19 @@ if s:vim9script
VimFoldi syn region vim9InterfaceBody start="\<interface\>" matchgroup=vimCommand end="\<endinterface\>" contains=@vim9InterfaceBodyList transparent
- " type {{{3
+ " Type Aliases {{{3
syn match vim9Type "\<ty\%[pe]\>" skipwhite nextgroup=vim9TypeAlias,vim9TypeAliasError
syn match vim9TypeAlias contained "\<\u\w*\>" skipwhite nextgroup=vim9TypeEquals
syn match vim9TypeEquals contained "=" skipwhite nextgroup=@vimType
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_notypealiaserror")
- syn match vim9TypeAliasError contained "\<\U\w*"
+ syn match vim9TypeAliasError contained "\<\l\w*\>" skipwhite nextgroup=vim9TypeEquals
endif
endif
+" Blocks: {{{2
+" ======
+Vim9 syn region vim9Block matchgroup=vimSep start="{" end="^\s*\zs}" contains=@vimDefBodyList
+
" Keymaps: {{{2
" =======
@@ -512,7 +588,7 @@ syn keyword vimUserCmdAttrAddr contained arguments arg buffers buf lines line lo
syn match vimUserCmdAttrAddr contained "?"
syn case match
-syn region vimUserCmdBlock contained matchgroup=vimSep start="{" end="}" contains=@vimDefBodyList
+syn region vimUserCmdBlock contained matchgroup=vimSep start="{" end="^\s*\zs}" contains=@vimDefBodyList
syn match vimDelcommand "\<delc\%[ommand]\>" skipwhite nextgroup=vimDelcommandAttr
syn match vimDelcommandAttr contained "-buffer\>"
@@ -559,8 +635,8 @@ syn region vimPatSepZone oneline contained matchgroup=vimPatSepZ start="\\%\
syn region vimPatRegion contained transparent matchgroup=vimPatSepR start="\\[z%]\=(" end="\\)" contains=@vimSubstList oneline
syn match vimNotPatSep contained "\\\\"
syn cluster vimStringGroup contains=vimEscape,vimEscapeBrace,vimPatSep,vimNotPatSep,vimPatSepErr,vimPatSepZone,@Spell
-syn region vimString oneline keepend matchgroup=vimString start=+[^a-zA-Z>\\@]"+lc=1 skip=+\\\\\|\\"+ matchgroup=vimStringEnd end=+"+ contains=@vimStringGroup extend
-syn region vimString oneline matchgroup=vimString start=+[^a-zA-Z>\\@]'+lc=1 end=+'+ contains=vimQuoteEscape extend
+syn region vimString oneline keepend matchgroup=vimString start=+[^a-zA-Z>\\@]"+lc=1 skip=+\\\\\|\\"+ matchgroup=vimStringEnd end=+"+ nextgroup=vimSubscript contains=@vimStringGroup extend
+syn region vimString oneline matchgroup=vimString start=+[^a-zA-Z>\\@]'+lc=1 end=+'+ nextgroup=vimSubscript contains=vimQuoteEscape extend
"syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup " see tst45.vim
syn match vimString contained +"[^"]*\\$+ skipnl nextgroup=vimStringCont
syn match vimStringCont contained +\(\\\\\|.\)\{-}[^\\]"+
@@ -572,8 +648,8 @@ syn match vimEscape contained "\\<" contains=vimNotation
syn match vimEscape contained "\\<\*[^>]*>\=>"
syn match vimQuoteEscape contained "''"
-syn region vimString oneline matchgroup=vimString start=+$'+ skip=+''+ end=+'+ contains=vimQuoteEscape,@vimStringInterpolation extend
-syn region vimString oneline matchgroup=vimString start=+$"+ end=+"+ contains=@vimStringGroup,@vimStringInterpolation extend
+syn region vimString oneline matchgroup=vimString start=+$'+ skip=+''+ end=+'+ nextgroup=vimSubscript contains=vimQuoteEscape,@vimStringInterpolation extend
+syn region vimString oneline matchgroup=vimString start=+$"+ end=+"+ nextgroup=vimSubscript contains=@vimStringGroup,@vimStringInterpolation extend
syn region vimStringInterpolationExpr oneline contained matchgroup=vimSep start=+{+ end=+}+ contains=@vimExprList
syn match vimStringInterpolationBrace contained "{{"
syn match vimStringInterpolationBrace contained "}}"
@@ -622,7 +698,7 @@ syn match vimRegister '\<norm\s\+\zs"[a-zA-Z0-9]'
syn match vimRegister '\<normal\s\+\zs"[a-zA-Z0-9]'
syn match vimRegister '@"'
syn match vimPlainRegister contained '"[a-zA-Z0-9\-:.%#*+=]'
-syn match vimLetRegister contained '@["0-9\-a-zA-Z#=*+_/]'
+syn match vimLetRegister contained '@["0-9\-a-zA-Z:.%#=*+~_/]'
syn match vimAddress ",\zs[.$]" skipwhite nextgroup=vimSubst1
syn match vimAddress "%\ze\a" skipwhite nextgroup=vimString,vimSubst1
@@ -649,13 +725,18 @@ syn match vimSetMod contained "\a\@1<=\%(&vim\=\|[!&?<]\)"
" Variable Declarations: {{{2
" =====================
-VimL syn keyword vimLet let skipwhite nextgroup=vimVar,vimFuncVar,vimLetRegister,vimVarList
-VimL syn keyword vimConst cons[t] skipwhite nextgroup=vimVar,vimVarList
-syn region vimVarList contained start="\[" end="]" contains=vimVar,@vimContinue
-
-VimL syn keyword vimUnlet unl[et] skipwhite nextgroup=vimUnletBang,vimUnletVars
-syn match vimUnletBang contained "!" skipwhite nextgroup=vimUnletVars
-syn region vimUnletVars contained start="$\I\|\h" skip="\n\s*\\" end="$" end="|" contains=vimVar,vimEnvvar,vimContinue,vimString,vimNumber
+VimL syn keyword vimLet let skipwhite nextgroup=@vimSpecialVar,vimVar,vimVarList
+VimL syn keyword vimConst cons[t] skipwhite nextgroup=@vimSpecialVar,vimVar,vimVarList
+syn region vimVarList contained
+ \ start="\[" end="]"
+ \ contains=@vimContinue,@vimSpecialVar,vimVar
+
+VimL syn keyword vimUnlet unl[et] skipwhite nextgroup=vimUnletBang,vimUnletVars
+syn match vimUnletBang contained "\a\@1<=!" skipwhite nextgroup=vimUnletVars
+syn region vimUnletVars contained
+ \ start="$\I\|\h" skip=+\n\s*\\\|\n\s*"\\ \|^\s*"\\ + end="$" end="\ze[|"]"
+ \ nextgroup=vimCmdSep,vimComment
+ \ contains=@vimContinue,vimEnvvar,vimVar
VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='\%(^\z(\s*\)\S.*\)\@<==<<\s*trim\%(\s\+\)\@>\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\z1\=\z2$' extend
VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\%(\s*\)\@>\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\z1$' extend
@@ -667,15 +748,39 @@ Vim9 syn keyword vim9Final final skipwhite nextgroup=vim9Variable,vim9VariableLi
Vim9 syn keyword vim9Var var skipwhite nextgroup=vim9Variable,vim9VariableList
syn match vim9Variable contained "\<\h\w*\>" skipwhite nextgroup=vimTypeSep,vimLetHereDoc,vimOper
-syn region vim9VariableList contained start="\[" end="]" contains=vim9Variable,@vimContinue
+syn region vim9VariableList contained start="\[" end="]" contains=@vimContinue,@vimSpecialVar,vim9Variable
+
+" Lockvar and Unlockvar: {{{2
+" =====================
+syn keyword vimLockvar lockv[ar] skipwhite nextgroup=vimLockvarBang,vimLockvarDepth,vimLockvarVars
+syn keyword vimUnlockvar unlo[ckvar] skipwhite nextgroup=vimLockvarBang,vimLockvarDepth,vimLockvarVars
+syn match vimLockvarBang contained "\a\@1<=!" skipwhite nextgroup=vimLockvarVars
+syn match vimLockvarDepth contained "\<[0-3]\>" skipwhite nextgroup=vimLockvarVars
+syn region vimLockvarVars contained
+ \ start="\h" skip=+\n\s*\\\|\n\s*"\\ \|^\s*"\\ + end="$" end="\ze[|"]"
+ \ nextgroup=vimCmdSep,vimComment
+ \ contains=@vimContinue,vimVar
+
+hi def link vimLockvar vimCommand
+hi def link vimUnlockvar vimCommand
+hi def link vimLockvarBang vimBang
+hi def link vimLockvarDepth vimNumber
" For: {{{2
" ===
-if s:vim9script
- syn keyword vim9For for skipwhite nextgroup=vim9Variable,vim9VariableList
-else
- syn keyword vimFor for skipwhite nextgroup=vimVar,vimVarList
-endif
+" handles Vim9 and legacy for now
+syn region vimFor
+ \ matchgroup=vimCommand
+ \ start="\<for\>" end="\<in\>"
+ \ skipwhite skipnl nextgroup=@vimForInContinue,vim9ForInComment,@vimExprList
+ \ contains=@vimContinue,vimVar,vimVarList,vim9VariableList
+ \ transparent
+
+syn match vim9ForInComment contained "#.*" skipwhite skipempty nextgroup=vimForInComment,@vimExprList
+
+syn match vimForInContinue contained "^\s*\zs\\" skipwhite skipnl nextgroup=@vimForInContinue,@vimExprList
+syn match vimForInContinueComment contained '^\s*\zs["#]\\ .*' skipwhite skipnl nextgroup=@vimForInContinue,@vimExprList
+syn cluster vimForInContinue contains=vimForInContinue,vimForInContinueComment
" Abbreviations: {{{2
" =============
@@ -693,7 +798,7 @@ syn match vimAutoCmdSfxList contained "\S*" skipwhite nextgroup=vimAutoCmdMod,vi
syn keyword vimAutoCmd au[tocmd] skipwhite nextgroup=vimAutoCmdBang,vimAutoEventList
syn keyword vimAutoCmd do[autocmd] doautoa[ll] skipwhite nextgroup=vimAutoEventList
syn match vimAutoCmdMod "\(++\)\=\(once\|nested\)" skipwhite nextgroup=vimAutoCmdBlock
-syn region vimAutoCmdBlock contained matchgroup=vimSep start="{" end="}" contains=@vimDefBodyList
+syn region vimAutoCmdBlock contained matchgroup=vimSep start="{" end="^\s*\zs}" contains=@vimDefBodyList
" Echo And Execute: -- prefer strings! {{{2
" ================
@@ -794,8 +899,8 @@ syn case match
" User Function Highlighting: {{{2
" (following Gautam Iyer's suggestion)
" ==========================
-syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\ze\s*(" contains=vimFuncEcho,vimFuncName,vimUserFunc,vimExecute
-syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation,vim9MethodName
+syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\ze\s*(" skipwhite nextgroup=vimOperParen contains=vimFuncEcho,vimFuncName,vimUserFunc,vimExecute
+syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation,vim9MethodName,vim9Super,vim9This
syn keyword vimFuncEcho contained ec ech echo
syn match vimMap "\<map\%(\s\+(\)\@=" skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
@@ -1307,10 +1412,12 @@ if !exists("skip_vim_syntax_inits")
hi def link vimConst vimCommand
hi def link vimContinue Special
hi def link vimContinueComment vimComment
+ hi def link vimCount Number
hi def link vimCtrlChar SpecialChar
+ hi def link vimDebuggreedy vimCommand
hi def link vimDefComment vim9Comment
hi def link vimDefKey vimCommand
- hi def link vimDefParam vimVar
+ hi def link vimDefParam vimVar
hi def link vimDelcommand vimCommand
hi def link vimDelcommandAttr vimUserCmdAttr
hi def link vimEcho vimCommand
@@ -1326,6 +1433,8 @@ if !exists("skip_vim_syntax_inits")
hi def link vimFgBgAttrib vimHiAttrib
hi def link vimFuncEcho vimCommand
hi def link vimFor vimCommand
+ hi def link vimForInContinue vimContinue
+ hi def link vimForInContinueComment vimContinueComment
hi def link vimFTCmd vimCommand
hi def link vimFTOption vimSynType
hi def link vimFuncBang vimBang
@@ -1335,8 +1444,8 @@ if !exists("skip_vim_syntax_inits")
hi def link vimFuncMod Special
hi def link vimFuncParam vimVar
hi def link vimFuncParamEquals vimOper
- hi def link vimFuncSID Special
- hi def link vimFuncVar Identifier
+ hi def link vimFuncScope vimVar
+ hi def link vimFuncSID vimNotation
hi def link vimGroupAdd vimSynOption
hi def link vimGroupName vimGroup
hi def link vimGroupRem vimSynOption
@@ -1366,6 +1475,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vim9KeymapLineComment vimKeymapLineComment
hi def link vimKeymapLineComment vimComment
hi def link vimKeymapTailComment vimComment
+ hi def link vimLambdaOperator vimOper
hi def link vimLet vimCommand
hi def link vimLetHereDoc vimString
hi def link vimLetHereDocStart Special
@@ -1399,7 +1509,11 @@ if !exists("skip_vim_syntax_inits")
hi def link vimNumber Number
hi def link vimOperError Error
hi def link vimOper Operator
+ hi def link vimOperContinue vimContinue
+ hi def link vimOperContinueComment vimContinueComment
hi def link vimOption PreProc
+ hi def link vimOptionVar Identifier
+ hi def link vimVimVar Identifier
hi def link vimParenSep Delimiter
hi def link vimPatSepErr vimError
hi def link vimPatSepR vimPatSep
@@ -1482,7 +1596,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vimUserCmdError Error
hi def link vimUserCmdKey vimCommand
hi def link vimUserFunc Normal
- hi def link vimVar Identifier
+ hi def link vimVar Normal
hi def link vimWarn WarningMsg
hi def link vim9Abstract vimCommand
@@ -1491,6 +1605,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vim9Comment Comment
hi def link vim9CommentError vimError
hi def link vim9CommentTitle PreProc
+ hi def link vim9ConstructorDefParam vimVar
hi def link vim9Const vimCommand
hi def link vim9ContinueComment vimContinueComment
hi def link vim9Enum vimCommand
@@ -1498,9 +1613,15 @@ if !exists("skip_vim_syntax_inits")
hi def link vim9Extends Keyword
hi def link vim9Final vimCommand
hi def link vim9For vimCommand
+ hi def link vim9ForInComment vim9Comment
hi def link vim9Implements Keyword
hi def link vim9AbstractDef vimCommand
hi def link vim9Interface vimCommand
+ hi def link vim9LambdaOperator vimOper
+ hi def link vim9LambdaOperatorComment vim9Comment
+ hi def link vim9LambdaParamsParen vimParenSep
+ hi def link vim9LhsRegister vimLetRegister
+ hi def link vim9LhsVariable vimVar
hi def link vim9LineComment vimComment
hi def link vim9MethodDef vimCommand
hi def link vim9MethodNameError vimFunctionError
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index fb7fdfb8b2..047bbbfdaa 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1875,6 +1875,11 @@ static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change)
static int recursive = 0;
static char questions[4];
+ if (buf->b_ml.ml_mfp == NULL) { // there are no lines
+ buf->b_ml.ml_line_len = 1;
+ return "";
+ }
+
if (lnum > buf->b_ml.ml_line_count) { // invalid line number
if (recursive == 0) {
// Avoid giving this message for a recursive call, may happen when
@@ -1892,11 +1897,6 @@ errorret:
}
lnum = MAX(lnum, 1); // pretend line 0 is line 1
- if (buf->b_ml.ml_mfp == NULL) { // there are no lines
- buf->b_ml.ml_line_len = 1;
- return "";
- }
-
// See if it is the same line as requested last time.
// Otherwise may need to flush last used line.
// Don't use the last used line when 'swapfile' is reset, need to load all
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index 7d034222c8..b9c1e9f897 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -305,6 +305,24 @@ describe('lua buffer event callbacks: on_lines', function()
n.assert_alive()
end)
+ it('no invalid lnum error for closed memline in on_detach #31251', function()
+ eq(vim.NIL, exec_lua('return _G.did_detach'))
+ exec_lua([[
+ vim.api.nvim_buf_set_lines(0, 0, -1, false, { '' })
+ local bufname = 'buf2'
+ local buf = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_name(buf, bufname)
+ vim.bo[buf].bufhidden = 'wipe'
+ vim.cmd('vertical diffsplit '..bufname)
+ vim.api.nvim_buf_attach(0, false, { on_detach = function()
+ vim.cmd("redraw")
+ _G.did_detach = true
+ end})
+ vim.cmd.bdelete()
+ ]])
+ eq(true, exec_lua('return _G.did_detach'))
+ end)
+
it('#12718 lnume', function()
api.nvim_buf_set_lines(0, 0, -1, true, { '1', '2', '3' })
exec_lua(function()
diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua
index 4e90c2fd1b..33c025daba 100644
--- a/test/functional/plugin/lsp/completion_spec.lua
+++ b/test/functional/plugin/lsp/completion_spec.lua
@@ -770,13 +770,14 @@ end)
--- @param name string
--- @param completion_result lsp.CompletionList
+--- @param trigger_chars? string[]
--- @return integer
-local function create_server(name, completion_result)
+local function create_server(name, completion_result, trigger_chars)
return exec_lua(function()
local server = _G._create_server({
capabilities = {
completionProvider = {
- triggerCharacters = { '.' },
+ triggerCharacters = trigger_chars or { '.' },
},
},
handlers = {
@@ -793,6 +794,7 @@ local function create_server(name, completion_result)
cmd = server.cmd,
on_attach = function(client, bufnr0)
vim.lsp.completion.enable(true, client.id, bufnr0, {
+ autotrigger = trigger_chars ~= nil,
convert = function(item)
return { abbr = item.label:gsub('%b()', '') }
end,
@@ -957,6 +959,39 @@ describe('vim.lsp.completion: protocol', function()
end)
end)
+ it('insert char triggers clients matching trigger characters', function()
+ local results1 = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hello',
+ },
+ },
+ }
+ create_server('dummy1', results1, { 'e' })
+ local results2 = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'hallo',
+ },
+ },
+ }
+ create_server('dummy2', results2, { 'h' })
+
+ feed('h')
+ exec_lua(function()
+ vim.v.char = 'h'
+ vim.cmd.startinsert()
+ vim.api.nvim_exec_autocmds('InsertCharPre', {})
+ end)
+
+ assert_matches(function(matches)
+ eq(1, #matches)
+ eq('hallo', matches[1].word)
+ end)
+ end)
+
it('executes commands', function()
local completion_list = {
isIncomplete = false,
@@ -1078,4 +1113,42 @@ describe('vim.lsp.completion: integration', function()
end)
)
end)
+
+ it('#clear multiple-lines word', function()
+ local completion_list = {
+ isIncomplete = false,
+ items = {
+ {
+ label = 'then...end',
+ sortText = '0001',
+ insertText = 'then\n\t$0\nend',
+ kind = 15,
+ insertTextFormat = 2,
+ },
+ },
+ }
+ exec_lua(function()
+ vim.o.completeopt = 'menuone,noselect'
+ end)
+ create_server('dummy', completion_list)
+ feed('Sif true <C-X><C-O>')
+ retry(nil, nil, function()
+ eq(
+ 1,
+ exec_lua(function()
+ return vim.fn.pumvisible()
+ end)
+ )
+ end)
+ feed('<C-n><C-y>')
+ eq(
+ { true, { 'if true then', '\t', 'end' } },
+ exec_lua(function()
+ return {
+ vim.snippet.active({ direction = 1 }),
+ vim.api.nvim_buf_get_lines(0, 0, -1, true),
+ }
+ end)
+ )
+ end)
end)