runtime(vim): Update syntax file, improve :substitute matching (#14093)

Commit: 
https://github.com/vim/vim/commit/2c51e15b66a4be9b5134c495ef546479aaa89ce9
Author: dkearns <[email protected]>
Date:   Tue Feb 27 07:10:18 2024 +1100

    runtime(vim): Update syntax file, improve :substitute matching 
(https://github.com/vim/vim/issues/14093)
    
    - Differentiate between :substitute and substitute(), fixes 
https://github.com/vim/vim/issues/13883.
    - Match all allowed :substitute delimiters.
    - Remove leading context from :substitute matches.
    
    Signed-off-by: Doug Kearns <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/syntax/generator/vim.vim.base 
b/runtime/syntax/generator/vim.vim.base
index 99a0488b3..6527fe178 100644
--- a/runtime/syntax/generator/vim.vim.base
+++ b/runtime/syntax/generator/vim.vim.base
@@ -157,16 +157,16 @@ endif
 
 " Numbers {{{2
 " =======
-syn match vimNumber    '\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=' skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '-\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\='  skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '\<0[xX]\x\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '\%(^\|\A\)\zs#\x\{6}'                         
skipwhite nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '\<0[zZ][a-zA-Z0-9.]\+'                    skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '0[0-7]\+'                     skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '0[bB][01]\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=' skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '-\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\='  skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\<0[xX]\x\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\%(^\|\A\)\zs#\x\{6}'                         
skipwhite nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\<0[zZ][a-zA-Z0-9.]\+'                    skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '0[0-7]\+'                     skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '0[bB][01]\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
 
 " All vimCommands are contained by vimIsCommand. {{{2
-syn match vimCmdSep    "[:|]\+"        skipwhite 
nextgroup=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimEcho,vimEchoHL,vimExecute,vimIsCommand,vimExtCmd,vimFilter,vimGlobal,vimHighlight,vimLet,vimMap,vimMark,vimNorm,vimSet,vimSyntax,vimUnlet,vimUnmap,vimUserCmd
+syn match vimCmdSep    "[:|]\+"        skipwhite 
nextgroup=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimEcho,vimEchoHL,vimExecute,vimIsCommand,vimExtCmd,vimFilter,vimGlobal,vimHighlight,vimLet,vimMap,vimMark,vimNorm,vimSet,vimSubst1,vimSyntax,vimUnlet,vimUnmap,vimUserCmd
 syn match vimIsCommand "\<\%(\h\w*\|[23]mat\%[ch]\)\>" contains=vimCommand
 syn match vimVar             contained "\<\h[a-zA-Z0-9#_]*\>"
 syn match vimVar               "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>"
@@ -194,7 +194,6 @@ syn match   vimBehave       "\<be\%[have]\>"        
nextgroup=vimBehaveBang,vimBehaveModel,vi
 syn match   vimBehaveBang      contained       " \@1<=!" 
nextgroup=vimBehaveModel skipwhite
 syn keyword vimBehaveModel     contained       mswin   xterm
 
-hi def link vimBehaveBang vimBang
 " Filetypes {{{2
 " =========
 syn match   vimFiletype        "\<filet\%[ype]\(\s\+\I\i*\)*"  skipwhite 
contains=vimFTCmd,vimFTOption,vimFTError
@@ -270,12 +269,12 @@ syn region vimKeymap matchgroup=vimCommand 
start="\<loadk\%[eymap]\>" end="\%$"
 
 " Special Filenames, Modifiers, Extension Removal: {{{2
 " ===============================================
-syn match      vimSpecFile     "<c\(word\|WORD\)>"     
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "<\([acs]file\|amatch\|abuf\)>" 
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "\s%[   :]"ms=s+1,me=e-1        
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "\s%$"ms=s+1    
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "\s%<"ms=s+1,me=e-1     
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "#\d\+\|[#%]<\>"        
nextgroup=vimSpecFileMod,vimSubst
+syn match      vimSpecFile     "<c\(word\|WORD\)>"     
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "<\([acs]file\|amatch\|abuf\)>" 
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "\s%[   :]"ms=s+1,me=e-1        
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "\s%$"ms=s+1            
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "\s%<"ms=s+1,me=e-1     
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "#\d\+\|[#%]<\>"                
nextgroup=vimSpecFileMod,vimSubst1
 syn match      vimSpecFileMod  "\(:[phtre]\)\+"        contained
 
 " User-Specified Commands: {{{2
@@ -356,33 +355,34 @@ syn match vimStringInterpolationBrace "}}"
 syn cluster    vimSubstList    
contains=vimPatSep,vimPatRegion,vimPatSepErr,vimSubstTwoBS,vimSubstRange,vimNotation
 syn cluster    vimSubstRepList 
contains=vimSubstSubstr,vimSubstTwoBS,vimNotation
 syn cluster    vimSubstList    add=vimCollection
-syn match      vimSubst        
"\(:\+\s*\|^\s*\||\s*\)\<\%(\<s\%[ubstitute]\>\|\<sm\%[agic]\>\|\<sno\%[magic]\>\)[:#[:alpha:]]\@!"
 nextgroup=vimSubstPat
-"syn match     vimSubst        
"\%(^\|[^\]\)\<s\%[ubstitute]\>[:#[:alpha:]]\@!"        nextgroup=vimSubstPat 
contained
-syn match      vimSubst        
"\%(^\|[^\\"']\)\<s\%[ubstitute]\>[:#[:alpha:]\"']\@!"  nextgroup=vimSubstPat 
contained
-syn match      vimSubst        "/\zs\<s\%[ubstitute]\>\ze/"            
nextgroup=vimSubstPat
-syn match      vimSubst        "\(:\+\s*\|^\s*\)s\ze#.\{-}#.\{-}#"             
nextgroup=vimSubstPat
-syn match      vimSubst1       contained       "\<s\%[ubstitute]\>"    
nextgroup=vimSubstPat
-syn match      vimSubst2       contained       "s\%[ubstitute]\>"      
nextgroup=vimSubstPat
-syn region     vimSubstPat     contained       matchgroup=vimSubstDelim 
start="\z([^a-zA-Z(    [\]&]\)"rs=s+1 skip="\\\|\\z1" end="\z1"re=e-1,me=e-1    
contains=@vimSubstList nextgroup=vimSubstRep4  oneline
-syn region     vimSubstRep4    contained       matchgroup=vimSubstDelim 
start="\z(.\)" skip="\\\|\\z1" end="\z1" matchgroup=vimNotation 
end="<[cC][rR]>" contains=@vimSubstRepList     nextgroup=vimSubstFlagErr       
oneline
-syn region     vimCollection   contained transparent   start="\\@<!\[" 
skip="\\[" end="\]"     contains=vimCollClass
-syn match      vimCollClassErr contained       "\[:.\{-\}:\]"
-syn match      vimCollClass    contained transparent   
"\%#=1\[:\(alnum\|alpha\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|xdigit\|retu\%[rn]\|tab\|escape\|backspace\):\]"
-syn match      vimSubstSubstr  contained       "\z\=\d"
-syn match      vimSubstTwoBS   contained       "\\"
-syn match      vimSubstFlagErr contained       "[^<    
|]\+" contains=vimSubstFlags
-syn match      vimSubstFlags   contained       "[&cegiIlnpr#]\+"
+syn match      vimSubst        
"^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)\>[\"#|]\@!"  
nextgroup=vimSubstPat
+syn match      vimSubst        
"^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)_\@=" nextgroup=vimSubstPat
+syn match      vimSubst        
"^\s*\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#"   
nextgroup=vimSubstPat
+syn match      vimSubst1       contained       
"\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\>[\"#|]\@!"            
nextgroup=vimSubstPat
+syn match      vimSubst1       contained       
"\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)_\@="                   
nextgroup=vimSubstPat
+syn match      vimSubst1       contained       
"\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#"               
nextgroup=vimSubstPat
+" TODO: Vim9 illegal separators for abbreviated :s form are [-.:], :su\%[...] 
required
+"     : # is allowed but "not recommended" (see :h pattern-delimiter)
+syn region     vimSubstPat     contained       matchgroup=vimSubstDelim 
start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)"rs=s+1 skip="\\\|\\z1" 
end="\z1"re=e-1,me=e-1     contains=@vimSubstList  nextgroup=vimSubstRep4  
oneline
+syn region     vimSubstRep4    contained       matchgroup=vimSubstDelim 
start="\z(.\)" skip="\\\|\\z1" end="\z1" matchgroup=vimNotation 
end="<[cC][rR]>"       contains=@vimSubstRepList       
nextgroup=vimSubstFlagErr       oneline
+syn region     vimCollection   contained       transparent     start="\\@<!\[" 
skip="\\[" end="\]"     contains=vimCollClass
+syn match      vimCollClassErr contained       "\[:.\{-\}:\]"
+syn match      vimCollClass    contained       transparent     
"\%#=1\[:\(alnum\|alpha\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|xdigit\|retu\%[rn]\|tab\|escape\|backspace\):\]"
+syn match      vimSubstSubstr  contained       "\z\=\d"
+syn match      vimSubstTwoBS   contained       "\\"
+syn match      vimSubstFlagErr contained       "[^<    
|]\+" contains=vimSubstFlags
+syn match      vimSubstFlags   contained       "[&cegiIlnpr#]\+"
 
 " 'String': {{{2
 syn match      vimString       "[^(,]'[^']\{-}\zs'"
 
 " Marks, Registers, Addresses, Filters: {{{2
-syn match      vimMark "'[a-zA-Z0-9]\ze[-+,!]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark "'[<>]\ze[-+,!]"                
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark ",\zs'[<>]\ze"          
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark "[!,:]\zs'[a-zA-Z0-9]"  
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMarkNumber   "[-+]\d\+"              contained 
contains=vimOper nextgroup=vimSubst2
+syn match      vimMark "'[a-zA-Z0-9]\ze[-+,!]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark "'[<>]\ze[-+,!]"                
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark ",\zs'[<>]\ze"          
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark "[!,:]\zs'[a-zA-Z0-9]"  
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMarkNumber   "[-+]\d\+"              contained 
contains=vimOper nextgroup=vimSubst1
 syn match      vimPlainMark contained  "'[a-zA-Z0-9]"
 syn match      vimRange        "[`'][a-zA-Z0-9],[`'][a-zA-Z0-9]"       
contains=vimMark        skipwhite nextgroup=vimFilter
 
@@ -713,8 +713,8 @@ syn match   vimCommentTitleLeader   '"\s\+'ms=s+1   
contained
 " ====================
 syn match      vimSearch       '^\s*[/?].*'            contains=vimSearchDelim
 syn match      vimSearchDelim  '^\s*\zs[/?]\|[/?]$'    contained
-syn region     vimGlobal       matchgroup=Statement start='\<g\%[lobal]!\=/'  
skip='\.' end='/'        skipwhite nextgroup=vimSubst
-syn region     vimGlobal       matchgroup=Statement start='\<v\%[global]!\=/' 
skip='\.' end='/'        skipwhite nextgroup=vimSubst
+syn region     vimGlobal       matchgroup=Statement start='\<g\%[lobal]!\=/'  
skip='\.' end='/'        skipwhite nextgroup=vimSubst1
+syn region     vimGlobal       matchgroup=Statement start='\<v\%[global]!\=/' 
skip='\.' end='/'        skipwhite nextgroup=vimSubst1
 
 " Embedded Scripts:  {{{2
 " ================
@@ -934,7 +934,7 @@ if !exists("skip_vim_syntax_inits")
  hi def link vimAutoCmdMod     Special
  hi def link vimAutoSet        vimCommand
  hi def link vimBang   vimOper
-  hi def link vimBehaveBang    vimBang
+ hi def link vimBehaveBang     vimBang
  hi def link vimBehaveModel    vimBehave
  hi def link vimBehave vimCommand
  hi def link vimBracket        Delimiter
diff --git a/runtime/syntax/testdir/dumps/vim_ex_commands_23.dump 
b/runtime/syntax/testdir/dumps/vim_ex_commands_23.dump
index d75c4b008..6baf838d1 100644
--- a/runtime/syntax/testdir/dumps/vim_ex_commands_23.dump
+++ b/runtime/syntax/testdir/dumps/vim_ex_commands_23.dump
@@ -15,6 +15,6 @@
 |:|r+0#af5f00255&|u|n|d|o| +0#0000000&@68
 |:|r+0#af5f00255&|u|n|t|i|m|e| +0#0000000&@66
 |:|r+0#af5f00255&|v|i|m|i|n|f|o| +0#0000000&@65
-|:+0#af5f00255&|s|u|b|s|t|i|t|u|t|e| +0#0000000&@63
+|:|s+0#af5f00255&|u|b|s|t|i|t|u|t|e| +0#0000000&@63
 |:|s+0#af5f00255&|N|e|x|t| +0#0000000&@68
 @57|4|1|5|,|1| @8|3|4|%| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_commands_25.dump 
b/runtime/syntax/testdir/dumps/vim_ex_commands_25.dump
index 746b0d80a..6b40f2cac 100644
--- a/runtime/syntax/testdir/dumps/vim_ex_commands_25.dump
+++ b/runtime/syntax/testdir/dumps/vim_ex_commands_25.dump
@@ -11,7 +11,7 @@
 |:|s+0#af5f00255&|l|e@1|p| +0#0000000&@68
 |:|s+0#af5f00255&|l|e@1|p|!| +0#0000000&@67
 |:|s+0#af5f00255&|l|a|s|t| +0#0000000&@68
-|:+0#af5f00255&|s|m|a|g|i|c| +0#0000000&@67
+|:|s+0#af5f00255&|m|a|g|i|c| +0#0000000&@67
 |:|s+0#af5f00255&|m|a|p| +0#0000000&@69
 |:|s+0#af5f00255&|m|a|p|c|l|e|a|r| +0#0000000&@64
 |:|s+0#af5f00255&|m|e|n|u| +0#0000000&@68
diff --git a/runtime/syntax/testdir/dumps/vim_ex_commands_26.dump 
b/runtime/syntax/testdir/dumps/vim_ex_commands_26.dump
index db27187c1..f388e4fe3 100644
--- a/runtime/syntax/testdir/dumps/vim_ex_commands_26.dump
+++ b/runtime/syntax/testdir/dumps/vim_ex_commands_26.dump
@@ -1,5 +1,5 @@
 |:+0&#ffffff0|s+0#af5f00255&|n|e|x|t| +0#0000000&@68
-|:+0#af5f00255&|s|n|o|m|a|g|i|c| +0#0000000&@65
+|:|s+0#af5f00255&|n|o|m|a|g|i|c| +0#0000000&@65
 |:|s+0#af5f00255&|n|o|r|e|m|a|p| +0#0000000&@65
 |:|s+0#af5f00255&|n|o|r|e|m|e|n|u| +0#0000000&@64
 |:|s+0#af5f00255&|o|r|t| +0#0000000&@69
diff --git a/runtime/syntax/testdir/dumps/vim_ex_commands_56.dump 
b/runtime/syntax/testdir/dumps/vim_ex_commands_56.dump
index 89b1df7a4..ba5754108 100644
--- a/runtime/syntax/testdir/dumps/vim_ex_commands_56.dump
+++ b/runtime/syntax/testdir/dumps/vim_ex_commands_56.dump
@@ -15,6 +15,6 @@
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|r+0#af5f00255&|u|n|d|o| +0#0000000&@56
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|r+0#af5f00255&|u|n|t|i|m|e| +0#0000000&@54
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|r+0#af5f00255&|v|i|m|i|n|f|o| +0#0000000&@53
-|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| 
+0#0000000&||+0#af5f00255&| |s|u|b|s|t|i|t|u|t|e| +0#0000000&@51
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|u|b|s|t|i|t|u|t|e| +0#0000000&@51
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|N|e|x|t| +0#0000000&@56
 @57|1|0@1|9|,|1| @7|8|5|%| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_commands_58.dump 
b/runtime/syntax/testdir/dumps/vim_ex_commands_58.dump
index 28f0d8918..1d24fd510 100644
--- a/runtime/syntax/testdir/dumps/vim_ex_commands_58.dump
+++ b/runtime/syntax/testdir/dumps/vim_ex_commands_58.dump
@@ -11,7 +11,7 @@
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|l|e@1|p| +0#0000000&@56
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|l|e@1|p|!| +0#0000000&@55
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|l|a|s|t| +0#0000000&@56
-|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| 
+0#0000000&||+0#af5f00255&| |s|m|a|g|i|c| +0#0000000&@55
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|m|a|g|i|c| +0#0000000&@55
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|m|a|p| +0#0000000&@57
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|m|a|p|c|l|e|a|r| +0#0000000&@52
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|m|e|n|u| +0#0000000&@56
diff --git a/runtime/syntax/testdir/dumps/vim_ex_commands_59.dump 
b/runtime/syntax/testdir/dumps/vim_ex_commands_59.dump
index d346f93a5..920861c52 100644
--- a/runtime/syntax/testdir/dumps/vim_ex_commands_59.dump
+++ b/runtime/syntax/testdir/dumps/vim_ex_commands_59.dump
@@ -1,5 +1,5 @@
 |c+0#af5f00255#ffffff0|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|n|e|x|t| +0#0000000&@56
-|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| 
+0#0000000&||+0#af5f00255&| |s|n|o|m|a|g|i|c| +0#0000000&@53
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|n|o|m|a|g|i|c| +0#0000000&@53
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|n|o|r|e|m|a|p| +0#0000000&@53
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|n|o|r|e|m|e|n|u| +0#0000000&@52
 |c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|o|r|t| +0#0000000&@57
diff --git a/runtime/syntax/testdir/dumps/vim_ex_substitute_00.dump 
b/runtime/syntax/testdir/dumps/vim_ex_substitute_00.dump
new file mode 100644
index 000000000..31094c952
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/vim_ex_substitute_00.dump
@@ -0,0 +1,20 @@
+>s+0#af5f00255#ffffff0|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@54
+|s+0#af5f00255&|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@45
+@75
+|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@56
+|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@47
+@75
+|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@58
+|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@49
+@75
+|:|s+0#af5f00255&|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@53
+|:|s+0#af5f00255&|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@44
+@75
+|:|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@55
+|:|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@46
+@75
+|:|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@57
+|:|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@48
+@75
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@41
+|"|i|n|p|u|t|/|v|i|m|_|e|x|_|s|u|b|s|t|i|t|u|t|e|.|v|i|m|"| |8|6|L|,| 
|1|5|1|0|B| @16|1|,|1| @10|T|o|p| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_substitute_01.dump 
b/runtime/syntax/testdir/dumps/vim_ex_substitute_01.dump
new file mode 100644
index 000000000..806101c29
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/vim_ex_substitute_01.dump
@@ -0,0 +1,20 @@
+|:+0&#ffffff0|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@46
+@75
+|:|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@57
+|:|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@48
+@75
+>c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@41
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@32
+@75
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@43
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|n|o|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@34
+@75
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|&|
 +0#0000000&@45
+|c+0#af5f00255&|a|l@1| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&||| 
|s+0#af5f00255&|m|a|g|i|c|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|c|e|g|i|I|n|p|#|l|r|
 +0#0000000&@36
+@75
+|l+0#af5f00255&|e|t| +0#0000000&|f+0#00e0e07&|o@1| +0#0000000&|=+0#af5f00255&| 
+0#0000000&|s|t|r|-+0#af5f00255&|>|s+0#00e0e07&|u|b|s|t|i|t|u|t|e|(+0#e000e06&|s+0#00e0e07&|t|r|,+0#0000000&|
 |p+0#00e0e07&|a|t|,+0#0000000&| |s+0#00e0e07&|u|b|,+0#0000000&| 
|f+0#00e0e07&|l|a|g|s|)+0#e000e06&| +0#0000000&@27
+@75
+|f+0#af5f00255&|u|n|c|t|i|o|n| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&@60
+| 
+0#af5f00255&@1|s|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|
 +0#0000000&@53
+@2|l+0#af5f00255&|e|t| +0#0000000&|b+0#00e0e07&|a|r| 
+0#0000000&|=+0#af5f00255&| 
+0#0000000&|s|t|r|-+0#af5f00255&|>|s+0#00e0e07&|u|b|s|t|i|t|u|t|e|(+0#e000e06&|s+0#00e0e07&|t|r|,+0#0000000&|
 |p+0#00e0e07&|a|t|,+0#0000000&| |s+0#00e0e07&|u|b|,+0#0000000&| 
|f+0#00e0e07&|l|a|g|s|)+0#e000e06&| +0#0000000&@25
+@57|1|9|,|1| @9|1|9|%| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_substitute_02.dump 
b/runtime/syntax/testdir/dumps/vim_ex_substitute_02.dump
new file mode 100644
index 000000000..b0e722d26
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/vim_ex_substitute_02.dump
@@ -0,0 +1,20 @@
+| +0&#ffffff0@1|l+0#af5f00255&|e|t| +0#0000000&|b+0#00e0e07&|a|r| 
+0#0000000&|=+0#af5f00255&| 
+0#0000000&|s|t|r|-+0#af5f00255&|>|s+0#00e0e07&|u|b|s|t|i|t|u|t|e|(+0#e000e06&|s+0#00e0e07&|t|r|,+0#0000000&|
 |p+0#00e0e07&|a|t|,+0#0000000&| |s+0#00e0e07&|u|b|,+0#0000000&| 
|f+0#00e0e07&|l|a|g|s|)+0#e000e06&| +0#0000000&@25
+|e+0#af5f00255&|n|d|f|u|n|c|t|i|o|n| +0#0000000&@63
+@75
+|d+0#af5f00255&|e|f| +0#0000000&|F|o@1|(+0#e000e06&|)| +0#0000000&@65
+| 
+0#af5f00255&@1|s|u|b|s|t|i|t|u|t|e|/+0#e000e06&|f+0#0000000&|o@1|/+0#e000e06&|b+0#0000000&|a|r|/+0#e000e06&|
 +0#0000000&@53
+@2>l+0#af5f00255&|e|t| +0#0000000&|b+0#00e0e07&|a|r| 
+0#0000000&|=+0#af5f00255&| 
+0#0000000&|s|t|r|-+0#af5f00255&|>|s+0#00e0e07&|u|b|s|t|i|t|u|t|e|(+0#e000e06&|s+0#00e0e07&|t|r|,+0#0000000&|
 |p+0#00e0e07&|a|t|,+0#0000000&| |s+0#00e0e07&|u|b|,+0#0000000&| 
|f+0#00e0e07&|l|a|g|s|)+0#e000e06&| +0#0000000&@25
+|e+0#af5f00255&|n|d@1|e|f| +0#0000000&@68
+@75
+|"+0#0000e05&| |v|a|r|i|o|u|s| |d|e|l|i|m|i|t|e|r|s| +0#0000000&@54
+@75
+|s+0#af5f00255&|!+0#e000e06&|/+0#0000000&|!+0#e000e06&|/+0#0000000&@1|!+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|"+0#0000e05&| |s|"|/|"|/@1|"| |"| |c|o|m@1|e|n|t| |(|w|o|r|k|s| |b|u|t| 
|d|i|s|a|l@1|o|w|e|d|)| +0#0000000&@32
+|s+0#af5f00255&|#+0#e000e06&|/+0#0000000&|#+0#e000e06&|/+0#0000000&@1|#+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|$+0#e000e06&|/+0#0000000&|$+0#e000e06&|/+0#0000000&@1|$+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|%+0#e000e06&|/+0#0000000&|%+0#e000e06&|/+0#0000000&@1|%+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|&+0#e000e06&|/+0#0000000&|&+0#e000e06&|/+0#0000000&@1|&+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|'+0#e000e06&|/+0#0000000&|'+0#e000e06&|/+0#0000000&@1|'+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|"+0#0000e05&| |F+0#0000001#ffff4012|I|X|M|E| +0#0000e05#ffffff0|-| 
|m|a|t|c|h|e|s| |v|i|m|U|s|e|r|F|u|n|c| +0#0000000&@45
+|"+0#0000e05&| |s|(|/|(|/@1|(| |"| |c|o|m@1|e|n|t| +0#0000000&@55
+@57|3|7|,|3| @9|4|6|%| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_substitute_03.dump 
b/runtime/syntax/testdir/dumps/vim_ex_substitute_03.dump
new file mode 100644
index 000000000..cb12bb38a
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/vim_ex_substitute_03.dump
@@ -0,0 +1,20 @@
+|"+0#0000e05#ffffff0| |s|(|/|(|/@1|(| |"| |c|o|m@1|e|n|t| +0#0000000&@55
+|s+0#af5f00255&|)+0#e000e06&|/+0#0000000&|)+0#e000e06&|/+0#0000000&@1|)+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|*+0#e000e06&|/+0#0000000&|*+0#e000e06&|/+0#0000000&@1|*+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|++0#e000e06&|/+0#0000000&|++0#e000e06&|/+0#0000000&@1|++0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|,+0#e000e06&|/+0#0000000&|,+0#e000e06&|/+0#0000000&@1|,+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+>s+0#af5f00255&|-+0#e000e06&|/+0#0000000&|-+0#e000e06&|/+0#0000000&@1|-+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|.+0#e000e06&|/+0#0000000&|.+0#e000e06&|/+0#0000000&@1|.+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|/+0#e000e06&|X+0#0000000&|/+0#e000e06&|X+0#0000000&@1|/+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|:+0#e000e06&|/+0#0000000&|:+0#e000e06&|/+0#0000000&@1|:+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|;+0#e000e06&|/+0#0000000&|;+0#e000e06&|/+0#0000000&@1|;+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|<+0#e000e06&|/+0#0000000&|<+0#e000e06&|/+0#0000000&@1|<+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|=+0#e000e06&|/+0#0000000&|=+0#e000e06&|/+0#0000000&@1|=+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|>+0#e000e06&|/+0#0000000&|>+0#e000e06&|/+0#0000000&@1|>+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|?+0#e000e06&|/+0#0000000&|?+0#e000e06&|/+0#0000000&@1|?+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|@+0#e000e06&|/+0#0000000&|@+0#e000e06&|/+0#0000000&@1|@+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|[+0#e000e06&|/+0#0000000&|[+0#e000e06&|/+0#0000000&@1|[+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|"+0#0000e05&| |s|\|/|\|/@1|\| |"| |c|o|m@1|e|n|t| |(|d|i|s|a|l@1|o|w|e|d|)| 
+0#0000000&@42
+|s+0#af5f00255&|]+0#e000e06&|/+0#0000000&|]+0#e000e06&|/+0#0000000&@1|]+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|^+0#e000e06&|/+0#0000000&|^+0#e000e06&|/+0#0000000&@1|^+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+@57|5@1|,|1| @9|7|3|%| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_substitute_04.dump 
b/runtime/syntax/testdir/dumps/vim_ex_substitute_04.dump
new file mode 100644
index 000000000..b37826020
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/vim_ex_substitute_04.dump
@@ -0,0 +1,20 @@
+|s+0#af5f00255#ffffff0|^+0#e000e06&|/+0#0000000&|^+0#e000e06&|/+0#0000000&@1|^+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|_+0#e000e06&|/+0#0000000&|_+0#e000e06&|/+0#0000000&@1|_+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|`+0#e000e06&|/+0#0000000&|`+0#e000e06&|/+0#0000000&@1|`+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|{+0#e000e06&|/+0#0000000&|{+0#e000e06&|/+0#0000000&@1|{+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|"+0#0000e05&| |s|||/|||/@1||| |"| |c|o|m@1|e|n|t| |(|d|i|s|a|l@1|o|w|e|d|)| 
+0#0000000&@42
+>s+0#af5f00255&|}+0#e000e06&|/+0#0000000&|}+0#e000e06&|/+0#0000000&@1|}+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|~+0#e000e06&|/+0#0000000&|~+0#e000e06&|/+0#0000000&@1|~+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+@75
+@75
+|"+0#0000e05&| |I|s@1|u|e| |#|1|3|8@1|3| +0#0000000&@60
+@75
+|s|t|r|[|s|]| @68
+|s|t|r|(+0#e000e06&|s+0#00e0e07&|)+0#e000e06&| +0#0000000&@68
+@75
+|d+0#af5f00255&|e|f| +0#0000000&|T|e|s|t|(+0#e000e06&|)| +0#0000000&@64
+@2|s|t|r|[|s|]| @66
+@2|s|t|r|(+0#e000e06&|s+0#00e0e07&|)+0#e000e06&| +0#0000000&@66
+|e+0#af5f00255&|n|d@1|e|f| +0#0000000&@68
+@75
+@57|7|3|,|1| @9|B|o|t| 
diff --git a/runtime/syntax/testdir/dumps/vim_ex_substitute_99.dump 
b/runtime/syntax/testdir/dumps/vim_ex_substitute_99.dump
new file mode 100644
index 000000000..88cb7dc21
--- /dev/null
+++ b/runtime/syntax/testdir/dumps/vim_ex_substitute_99.dump
@@ -0,0 +1,20 @@
+|s+0#af5f00255#ffffff0|^+0#e000e06&|/+0#0000000&|^+0#e000e06&|/+0#0000000&@1|^+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|_+0#e000e06&|/+0#0000000&|_+0#e000e06&|/+0#0000000&@1|_+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|`+0#e000e06&|/+0#0000000&|`+0#e000e06&|/+0#0000000&@1|`+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|{+0#e000e06&|/+0#0000000&|{+0#e000e06&|/+0#0000000&@1|{+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|"+0#0000e05&| |s|||/|||/@1||| |"| |c|o|m@1|e|n|t| |(|d|i|s|a|l@1|o|w|e|d|)| 
+0#0000000&@42
+|s+0#af5f00255&|}+0#e000e06&|/+0#0000000&|}+0#e000e06&|/+0#0000000&@1|}+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+|s+0#af5f00255&|~+0#e000e06&|/+0#0000000&|~+0#e000e06&|/+0#0000000&@1|~+0#e000e06&|
 +0#0000000&|"+0#0000e05&| |c|o|m@1|e|n|t| +0#0000000&@57
+@75
+@75
+|"+0#0000e05&| |I|s@1|u|e| |#|1|3|8@1|3| +0#0000000&@60
+@75
+|s|t|r|[|s|]| @68
+|s|t|r|(+0#e000e06&|s+0#00e0e07&|)+0#e000e06&| +0#0000000&@68
+@75
+|d+0#af5f00255&|e|f| +0#0000000&|T|e|s|t|(+0#e000e06&|)| +0#0000000&@64
+@2|s|t|r|[|s|]| @66
+@2|s|t|r|(+0#e000e06&|s+0#00e0e07&|)+0#e000e06&| +0#0000000&@66
+|e+0#af5f00255&|n|d@1|e|f| +0#0000000&@68
+> @74
+@57|8|6|,|0|-|1| @7|B|o|t| 
diff --git a/runtime/syntax/testdir/input/vim_ex_substitute.vim 
b/runtime/syntax/testdir/input/vim_ex_substitute.vim
new file mode 100644
index 000000000..340d573ac
--- /dev/null
+++ b/runtime/syntax/testdir/input/vim_ex_substitute.vim
@@ -0,0 +1,86 @@
+substitute/foo/bar/&
+substitute/foo/bar/cegiInp#lr
+
+snomagic/foo/bar/&
+snomagic/foo/bar/cegiInp#lr
+
+smagic/foo/bar/&
+smagic/foo/bar/cegiInp#lr
+
+:substitute/foo/bar/&
+:substitute/foo/bar/cegiInp#lr
+
+:snomagic/foo/bar/&
+:snomagic/foo/bar/cegiInp#lr
+
+:smagic/foo/bar/&
+:smagic/foo/bar/cegiInp#lr
+
+call Foo() | substitute/foo/bar/&
+call Foo() | substitute/foo/bar/cegiInp#lr
+
+call Foo() | snomagic/foo/bar/&
+call Foo() | snomagic/foo/bar/cegiInp#lr
+
+call Foo() | smagic/foo/bar/&
+call Foo() | smagic/foo/bar/cegiInp#lr
+
+let foo = str->substitute(str, pat, sub, flags)
+
+function Foo()
+  substitute/foo/bar/
+  let bar = str->substitute(str, pat, sub, flags)
+endfunction
+
+def Foo()
+  substitute/foo/bar/
+  let bar = str->substitute(str, pat, sub, flags)
+enddef
+
+" various delimiters
+
+s!/!//! " comment
+" s"/"//" " comment (works but disallowed)
+s#/#//# " comment
+s$/$//$ " comment
+s%/%//% " comment
+s&/&//& " comment
+s'/'//' " comment
+" FIXME - matches vimUserFunc
+" s(/(//( " comment
+s)/)//) " comment
+s*/*//* " comment
+s+/+//+ " comment
+s,/,//, " comment
+s-/-//- " comment
+s././/. " comment
+s/X/XX/ " comment
+s:/://: " comment
+s;/;//; " comment
+s</<//< " comment
+s=/=//= " comment
+s>/>//> " comment
+s?/?//? " comment
+s@/@//@ " comment
+s[/[//[ " comment
+" s\/\//\ " comment (disallowed)
+s]/]//] " comment
+s^/^//^ " comment
+s_/_//_ " comment
+s`/`//` " comment
+s{/{//{ " comment
+" s|/|//| " comment (disallowed)
+s}/}//} " comment
+s~/~//~ " comment
+
+
+" Issue #13883
+
+str[s]
+str(s)
+
+def Test()
+  str[s]
+  str(s)
+enddef
+
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 7dde1a340..c845651c9 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -3,7 +3,7 @@
 " Maintainer:  Hirohito Higashi <h.east.727 ATMARK gmail.com>
 "      Doug Kearns <[email protected]>
 " URL: https://github.com/vim-jp/syntax-vim-ex
-" Last Change: Feb 23, 2024
+" Last Change: Feb 27, 2024
 " Former Maintainer: Charles E. Campbell
 " Base File URL:     http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM
 " Base File Version: 9.0-25
@@ -199,16 +199,16 @@ endif
 
 " Numbers {{{2
 " =======
-syn match vimNumber    '\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=' skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '-\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\='  skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '\<0[xX]\x\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '\%(^\|\A\)\zs#\x\{6}'                         
skipwhite nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '\<0[zZ][a-zA-Z0-9.]\+'                    skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '0[0-7]\+'                     skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
-syn match vimNumber    '0[bB][01]\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\<\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=' skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '-\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\='  skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\<0[xX]\x\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\%(^\|\A\)\zs#\x\{6}'                         
skipwhite nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '\<0[zZ][a-zA-Z0-9.]\+'                    skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '0[0-7]\+'                     skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
+syn match vimNumber    '0[bB][01]\+'                  skipwhite 
nextgroup=vimGlobal,vimSubst1,vimCommand,vimComment,vim9Comment
 
 " All vimCommands are contained by vimIsCommand. {{{2
-syn match vimCmdSep    "[:|]\+"        skipwhite 
nextgroup=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimEcho,vimEchoHL,vimExecute,vimIsCommand,vimExtCmd,vimFilter,vimGlobal,vimHighlight,vimLet,vimMap,vimMark,vimNorm,vimSet,vimSyntax,vimUnlet,vimUnmap,vimUserCmd
+syn match vimCmdSep    "[:|]\+"        skipwhite 
nextgroup=vimAbb,vimAddress,vimAutoCmd,vimAugroup,vimBehave,vimEcho,vimEchoHL,vimExecute,vimIsCommand,vimExtCmd,vimFilter,vimGlobal,vimHighlight,vimLet,vimMap,vimMark,vimNorm,vimSet,vimSubst1,vimSyntax,vimUnlet,vimUnmap,vimUserCmd
 syn match vimIsCommand "\<\%(\h\w*\|[23]mat\%[ch]\)\>" contains=vimCommand
 syn match vimVar             contained "\<\h[a-zA-Z0-9#_]*\>"
 syn match vimVar               "\<[bwglstav]:\h[a-zA-Z0-9#_]*\>"
@@ -236,7 +236,6 @@ syn match   vimBehave       "\<be\%[have]\>"        
nextgroup=vimBehaveBang,vimBehaveModel,vi
 syn match   vimBehaveBang      contained       " \@1<=!" 
nextgroup=vimBehaveModel skipwhite
 syn keyword vimBehaveModel     contained       mswin   xterm
 
-hi def link vimBehaveBang vimBang
 " Filetypes {{{2
 " =========
 syn match   vimFiletype        "\<filet\%[ype]\(\s\+\I\i*\)*"  skipwhite 
contains=vimFTCmd,vimFTOption,vimFTError
@@ -312,12 +311,12 @@ syn region vimKeymap matchgroup=vimCommand 
start="\<loadk\%[eymap]\>" end="\%$"
 
 " Special Filenames, Modifiers, Extension Removal: {{{2
 " ===============================================
-syn match      vimSpecFile     "<c\(word\|WORD\)>"     
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "<\([acs]file\|amatch\|abuf\)>" 
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "\s%[   :]"ms=s+1,me=e-1        
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "\s%$"ms=s+1    
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "\s%<"ms=s+1,me=e-1     
nextgroup=vimSpecFileMod,vimSubst
-syn match      vimSpecFile     "#\d\+\|[#%]<\>"        
nextgroup=vimSpecFileMod,vimSubst
+syn match      vimSpecFile     "<c\(word\|WORD\)>"     
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "<\([acs]file\|amatch\|abuf\)>" 
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "\s%[   :]"ms=s+1,me=e-1        
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "\s%$"ms=s+1            
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "\s%<"ms=s+1,me=e-1     
nextgroup=vimSpecFileMod,vimSubst1
+syn match      vimSpecFile     "#\d\+\|[#%]<\>"                
nextgroup=vimSpecFileMod,vimSubst1
 syn match      vimSpecFileMod  "\(:[phtre]\)\+"        contained
 
 " User-Specified Commands: {{{2
@@ -399,33 +398,34 @@ syn match vimStringInterpolationBrace "}}"
 syn cluster    vimSubstList    
contains=vimPatSep,vimPatRegion,vimPatSepErr,vimSubstTwoBS,vimSubstRange,vimNotation
 syn cluster    vimSubstRepList 
contains=vimSubstSubstr,vimSubstTwoBS,vimNotation
 syn cluster    vimSubstList    add=vimCollection
-syn match      vimSubst        
"\(:\+\s*\|^\s*\||\s*\)\<\%(\<s\%[ubstitute]\>\|\<sm\%[agic]\>\|\<sno\%[magic]\>\)[:#[:alpha:]]\@!"
 nextgroup=vimSubstPat
-"syn match     vimSubst        
"\%(^\|[^\]\)\<s\%[ubstitute]\>[:#[:alpha:]]\@!"        nextgroup=vimSubstPat 
contained
-syn match      vimSubst        
"\%(^\|[^\\"']\)\<s\%[ubstitute]\>[:#[:alpha:]\"']\@!"  nextgroup=vimSubstPat 
contained
-syn match      vimSubst        "/\zs\<s\%[ubstitute]\>\ze/"            
nextgroup=vimSubstPat
-syn match      vimSubst        "\(:\+\s*\|^\s*\)s\ze#.\{-}#.\{-}#"             
nextgroup=vimSubstPat
-syn match      vimSubst1       contained       "\<s\%[ubstitute]\>"    
nextgroup=vimSubstPat
-syn match      vimSubst2       contained       "s\%[ubstitute]\>"      
nextgroup=vimSubstPat
-syn region     vimSubstPat     contained       matchgroup=vimSubstDelim 
start="\z([^a-zA-Z(    [\]&]\)"rs=s+1 skip="\\\|\\z1" end="\z1"re=e-1,me=e-1    
contains=@vimSubstList nextgroup=vimSubstRep4  oneline
-syn region     vimSubstRep4    contained       matchgroup=vimSubstDelim 
start="\z(.\)" skip="\\\|\\z1" end="\z1" matchgroup=vimNotation 
end="<[cC][rR]>" contains=@vimSubstRepList     nextgroup=vimSubstFlagErr       
oneline
-syn region     vimCollection   contained transparent   start="\\@<!\[" 
skip="\\[" end="\]"     contains=vimCollClass
-syn match      vimCollClassErr contained       "\[:.\{-\}:\]"
-syn match      vimCollClass    contained transparent   
"\%#=1\[:\(alnum\|alpha\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|xdigit\|retu\%[rn]\|tab\|escape\|backspace\):\]"
-syn match      vimSubstSubstr  contained       "\z\=\d"
-syn match      vimSubstTwoBS   contained       "\\"
-syn match      vimSubstFlagErr contained       "[^<    
|]\+" contains=vimSubstFlags
-syn match      vimSubstFlags   contained       "[&cegiIlnpr#]\+"
+syn match      vimSubst        
"^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)\>[\"#|]\@!"  
nextgroup=vimSubstPat
+syn match      vimSubst        
"^\s*\%(s\%[ubstitute]\|sm\%[agic]\|sno\%[magic]\)_\@=" nextgroup=vimSubstPat
+syn match      vimSubst        
"^\s*\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#"   
nextgroup=vimSubstPat
+syn match      vimSubst1       contained       
"\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\>[\"#|]\@!"            
nextgroup=vimSubstPat
+syn match      vimSubst1       contained       
"\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)_\@="                   
nextgroup=vimSubstPat
+syn match      vimSubst1       contained       
"\%(s\%[ubstitute]\|sm\%[agic]\>\|sno\%[magic]\)\ze#.\{-}#.\{-}#"               
nextgroup=vimSubstPat
+" TODO: Vim9 illegal separators for abbreviated :s form are [-.:], :su\%[...] 
required
+"     : # is allowed but "not recommended" (see :h pattern-delimiter)
+syn region     vimSubstPat     contained       matchgroup=vimSubstDelim 
start="\z([!#$%&'()*+,-./:;<=>?@[\]^_`{}~]\)"rs=s+1 skip="\\\|\\z1" 
end="\z1"re=e-1,me=e-1     contains=@vimSubstList  nextgroup=vimSubstRep4  
oneline
+syn region     vimSubstRep4    contained       matchgroup=vimSubstDelim 
start="\z(.\)" skip="\\\|\\z1" end="\z1" matchgroup=vimNotation 
end="<[cC][rR]>"       contains=@vimSubstRepList       
nextgroup=vimSubstFlagErr       oneline
+syn region     vimCollection   contained       transparent     start="\\@<!\[" 
skip="\\[" end="\]"     contains=vimCollClass
+syn match      vimCollClassErr contained       "\[:.\{-\}:\]"
+syn match      vimCollClass    contained       transparent     
"\%#=1\[:\(alnum\|alpha\|blank\|cntrl\|digit\|graph\|lower\|print\|punct\|space\|upper\|xdigit\|retu\%[rn]\|tab\|escape\|backspace\):\]"
+syn match      vimSubstSubstr  contained       "\z\=\d"
+syn match      vimSubstTwoBS   contained       "\\"
+syn match      vimSubstFlagErr contained       "[^<    
|]\+" contains=vimSubstFlags
+syn match      vimSubstFlags   contained       "[&cegiIlnpr#]\+"
 
 " 'String': {{{2
 syn match      vimString       "[^(,]'[^']\{-}\zs'"
 
 " Marks, Registers, Addresses, Filters: {{{2
-syn match      vimMark "'[a-zA-Z0-9]\ze[-+,!]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark "'[<>]\ze[-+,!]"                
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark ",\zs'[<>]\ze"          
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark "[!,:]\zs'[a-zA-Z0-9]"  
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst
-syn match      vimMarkNumber   "[-+]\d\+"              contained 
contains=vimOper nextgroup=vimSubst2
+syn match      vimMark "'[a-zA-Z0-9]\ze[-+,!]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark "'[<>]\ze[-+,!]"                
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark ",\zs'[<>]\ze"          
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark "[!,:]\zs'[a-zA-Z0-9]"  
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" 
nextgroup=vimFilter,vimMarkNumber,vimSubst1
+syn match      vimMarkNumber   "[-+]\d\+"              contained 
contains=vimOper nextgroup=vimSubst1
 syn match      vimPlainMark contained  "'[a-zA-Z0-9]"
 syn match      vimRange        "[`'][a-zA-Z0-9],[`'][a-zA-Z0-9]"       
contains=vimMark        skipwhite nextgroup=vimFilter
 
@@ -761,8 +761,8 @@ syn match   vimCommentTitleLeader   '"\s\+'ms=s+1   
contained
 " ====================
 syn match      vimSearch       '^\s*[/?].*'            contains=vimSearchDelim
 syn match      vimSearchDelim  '^\s*\zs[/?]\|[/?]$'    contained
-syn region     vimGlobal       matchgroup=Statement start='\<g\%[lobal]!\=/'  
skip='\.' end='/'        skipwhite nextgroup=vimSubst
-syn region     vimGlobal       matchgroup=Statement start='\<v\%[global]!\=/' 
skip='\.' end='/'        skipwhite nextgroup=vimSubst
+syn region     vimGlobal       matchgroup=Statement start='\<g\%[lobal]!\=/'  
skip='\.' end='/'        skipwhite nextgroup=vimSubst1
+syn region     vimGlobal       matchgroup=Statement start='\<v\%[global]!\=/' 
skip='\.' end='/'        skipwhite nextgroup=vimSubst1
 
 " Embedded Scripts:  {{{2
 " ================
@@ -982,7 +982,7 @@ if !exists("skip_vim_syntax_inits")
  hi def link vimAutoCmdMod     Special
  hi def link vimAutoSet        vimCommand
  hi def link vimBang   vimOper
-  hi def link vimBehaveBang    vimBang
+ hi def link vimBehaveBang     vimBang
  hi def link vimBehaveModel    vimBehave
  hi def link vimBehave vimCommand
  hi def link vimBracket        Delimiter

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rehNP-003DUl-4Z%40256bit.org.

Raspunde prin e-mail lui