runtime(vim): include Vim Syntax generator

Commit: 
https://github.com/vim/vim/commit/9b53c052d58f73f2078c61a74622687306e51c17
Author: h-east <h.east....@gmail.com>
Date:   Tue Feb 13 21:09:22 2024 +0100

    runtime(vim): include Vim Syntax generator
    
    fixes: https://github.com/vim/vim/issues/13939
    closes: https://github.com/vim/vim/issues/14021
    related: vim-jp/syntax-vim-ex#28
    
    Signed-off-by: h-east <h.east....@gmail.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/.gitignore b/.gitignore
index 3a55d25b1..52444475e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,6 +97,11 @@ src/kword_test
 # Generated by "make install"
 runtime/doc/doctags
 
+# Temporarily generated by "runtime/syntax/generator/make"
+runtime/syntax/generator/generator.err
+runtime/syntax/generator/sanity_check.err
+runtime/syntax/generator/vim.vim.rc
+
 # Generated by "make shadow".  The directory names could be anything but we
 # restrict them to shadow (the default) or shadow-*
 src/shadow
diff --git a/Filelist b/Filelist
index 237923e87..acc931822 100644
--- a/Filelist
+++ b/Filelist
@@ -827,6 +827,11 @@ RT_SCRIPTS =       \
                runtime/syntax/testdir/runtest.vim \
                runtime/syntax/testdir/input/*.* \
                runtime/syntax/testdir/dumps/*.dump \
+               runtime/syntax/generator/Makefile \
+               runtime/syntax/generator/README.md \
+               runtime/syntax/generator/gen_syntax_vim.vim \
+               runtime/syntax/generator/update_date.vim \
+               runtime/syntax/generator/vim.vim.base \
 
 # Unix runtime
 RT_UNIX =      \
diff --git a/nsis/gvim.nsi b/nsis/gvim.nsi
index 72252527c..cb0aef9c3 100644
--- a/nsis/gvim.nsi
+++ b/nsis/gvim.nsi
@@ -419,7 +419,7 @@ Section "$(str_section_exe)" id_section_exe
        File ${VIMSRC} im.ico
 
        SetOutPath $0\syntax
-       File /r /x testdir ${VIMRT}\syntax\*.*
+       File /r /x testdir /x generator ${VIMRT}\syntax\*.*
 
        SetOutPath $0\spell
        File ${VIMRT}\spell\*.txt
diff --git a/runtime/syntax/generator/Makefile 
b/runtime/syntax/generator/Makefile
new file mode 100644
index 000000000..33dcfbc2b
--- /dev/null
+++ b/runtime/syntax/generator/Makefile
@@ -0,0 +1,44 @@
+VIM_SRCDIR = ../../../src
+RUN_VIM = $(VIM_SRCDIR)/vim -N -u NONE -i NONE -n
+REVISION ?= $(shell date +%Y-%m-%dT%H:%M:%S%:z)
+
+SRC =  $(VIM_SRCDIR)/eval.c $(VIM_SRCDIR)/ex_cmds.h $(VIM_SRCDIR)/ex_docmd.c \
+               $(VIM_SRCDIR)/fileio.c $(VIM_SRCDIR)/option.c 
$(VIM_SRCDIR)/syntax.c
+
+export VIM_SRCDIR
+
+.PHONY: generate clean
+all: generate
+
+generate: vim.vim
+
+vim.vim: vim.vim.rc update_date.vim
+       @echo "Generating vim.vim ..."
+       @cp -f vim.vim.rc ../vim.vim
+       @$(RUN_VIM) -S update_date.vim
+       @sed -i -e 's/__REVISION__/$(REVISION)/' ../vim.vim
+       @echo "done."
+
+vim.vim.rc: gen_syntax_vim.vim vim.vim.base $(SRC)
+       @echo "Generating vim.vim.rc ..."
+       @rm -f sanity_check.err generator.err
+       @$(RUN_VIM) -S gen_syntax_vim.vim
+       @if test -f sanity_check.err ; then \
+               echo ; \
+               echo "Sanity errors:" ; \
+               cat sanity_check.err ; \
+               exit 1 ; \
+       fi
+       @if test -f generator.err ; then \
+               echo ; \
+               echo "Generator errors:" ; \
+               cat generator.err ; \
+               echo ; \
+               exit 1 ; \
+       fi
+       @echo "done."
+
+clean:
+       rm -f vim.vim.rc
+       rm -f vim.vim
+       rm -f sanity_check.err generator.err
diff --git a/runtime/syntax/generator/README.md 
b/runtime/syntax/generator/README.md
new file mode 100644
index 000000000..83acedabe
--- /dev/null
+++ b/runtime/syntax/generator/README.md
@@ -0,0 +1,26 @@
+# Generator of Vim Script Syntax File
+
+This directory contains a Vim Script generator, that will parse the Vim source 
file and
+generate a vim.vim syntax file.
+
+Files in this directory where copied from 
https://github.com/vim-jp/syntax-vim-ex/
+and included here on Feb, 13th, 2024 for the Vim Project.
+
+- Maintainer: Hirohito Higashi
+- License: Vim License
+
+## How to generate
+
+    $ make
+
+This will generate `../vim.vim`
+
+## Files
+
+Name                 |Description
+---------------------|------------------------------------------------------
+`Makefile`           |Makefile to generate ../vim.vim
+`README.md`          |This file
+`gen_syntax_vim.vim` |Script to generate vim.vim
+`update_date.vim`    |Script to update "Last Change:"
+`vim.vim.base`       |Template for vim.vim
diff --git a/runtime/syntax/generator/gen_syntax_vim.vim 
b/runtime/syntax/generator/gen_syntax_vim.vim
new file mode 100644
index 000000000..85f094552
--- /dev/null
+++ b/runtime/syntax/generator/gen_syntax_vim.vim
@@ -0,0 +1,694 @@
+" Vim syntax file generator
+" Language: Vim script
+" Maintainer: Hirohito Higashi (h_east)
+" URL: https://github.com/vim-jp/syntax-vim-ex
+" Last Change: Feb 11, 2024
+" Version: 2.0.0
+
+let s:keepcpo= &cpo
+set cpo&vim
+
+language C
+
+function! s:parse_vim_option(opt, missing_opt, term_out_code)
+       try
+               let file_name = $VIM_SRCDIR . '/optiondefs.h'
+               let item = {}
+
+               new
+               exec 'read ' . file_name
+               norm! gg
+               exec 
'/^.*\s*options\[\]\s*=\s*$/+1;/^\s*#\s*define\s*p_term(/-1yank a'
+               exec '/^#define\s\+p_term(/+1;/^};$/-1yank b'
+               %delete _
+
+               put a
+               " workaround for 'shortname'
+               g/^#\s*ifdef\s*SHORT_FNAME\>/j
+               g/^#/d
+               g/^\s*{\s*"\w\+"\%(\s*,\s*[^,]*\)\{2}[^,]$/j
+               g/^\s*{\s*"\w\+"\s*,.*$/j
+               g!/^\s*{\s*"\w\+"\s*,.*$/d
+
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, 
'^\s*{\s*"\(\w\+\)"\s*,\s*\%("\(\w\+\)"\|NULL\)\s*,\s*\%([^,]*\(P_BOOL\)[^,]*\|[^,]*\)\s*,\s*\([^,]*NULL\)\?.*')
+                       let item.name = list[1]
+                       let item.short_name = list[2]
+                       let item.is_bool = empty(list[3]) ? 0 : 1
+                       if empty(list[4])
+                               call add(a:opt, copy(item))
+                       else
+                               call add(a:missing_opt, copy(item))
+                       endif
+               endfor
+               if empty(a:opt)
+                       throw 'opt is empty'
+               endif
+               if empty(a:missing_opt)
+                       throw 'missing_opt is empty'
+               endif
+
+               %delete _
+               put b
+               g!/^\s*p_term(\s*"\w\+"\s*,.*$/d
+
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, 
'^\s*p_term(\s*"\(\w\+\)"\s*,')
+                       let item.name = list[1]
+                       call add(a:term_out_code, copy(item))
+               endfor
+               quit!
+               if empty(a:term_out_code)
+                       throw 'term_out_code is empty'
+               endif
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+function! s:append_syn_vimopt(lnum, str_info, opt_list, prefix, bool_only)
+       let ret_lnum = a:lnum
+       let str = a:str_info.start
+
+       for o in a:opt_list
+               if !a:bool_only || o.is_bool
+                       if !empty(o.short_name)
+                               let str .= ' ' . a:prefix . o.short_name
+                       endif
+                       let str .= ' ' . a:prefix . o.name
+                       if len(str) > s:line_break_len
+                               if !empty(a:str_info.end)
+                                       let str .= ' ' . a:str_info.end
+                               endif
+                               call append(ret_lnum, str)
+                               let str = a:str_info.start
+                               let ret_lnum += 1
+                       endif
+               endif
+       endfor
+       if str !=# a:str_info.start
+               if !empty(a:str_info.end)
+                       let str .= ' ' . a:str_info.end
+               endif
+               call append(ret_lnum, str)
+               let ret_lnum += 1
+       endif
+       return ret_lnum
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:parse_vim_command(cmd)
+       try
+               let file_name = $VIM_SRCDIR . '/ex_cmds.h'
+               let item = {}
+
+               new
+               exec 'read ' . file_name
+               norm! gg
+               exec '/^}\?\s*cmdnames\[\]\s*=\s*$/+1;/^};/-1yank'
+               %delete _
+               put
+               g!/^EXCMD(/d
+
+               let lcmd = {}
+               for key in range(char2nr('a'), char2nr('z'))
+                       let lcmd[nr2char(key)] = []
+               endfor
+               let lcmd['~'] = []
+
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, '^EXCMD(\w\+\s*,\s*"\( 
\w*\)"\s*,')
+                       if !empty(list)
+                               " Small ascii character or other.
+                               let key = (list[1][:0] =~# '\l') ? list[1][:0] 
: '~'
+                               call add(lcmd[key], list[1])
+                       endif
+               endfor
+               quit!
+
+               for key in sort(keys(lcmd))
+                       for my in range(len(lcmd[key]))
+                               let omit_idx = 0
+                               if my > 0
+                                       let omit_idx = (key =~# '\l') ? 1 : 0
+                                       for idx in range(1, 
strlen(lcmd[key][my]))
+            let spec=0
+            if lcmd[key][my] ==# 'ex'
+              let spec=1
+              echo "cmd name:" lcmd[key][my]
+            endif
+                                               let matched = 0
+                                               for pre in range(my - 1, 0, -1)
+              if spec
+                echo "pre:" pre ", my:" my
+              endif
+                                                       if pre == my
+                if spec
+                  echo "continue"
+                endif
+                                                               continue
+                                                       endif
+                                                       " for weird 
abbreviations for delete. (See :help :d)
+                                                       " And k{char} is used 
as mark. (See :help :k)
+                                                       if lcmd[key][my][:idx] 
==# lcmd[key][pre][:idx] ||
+                                                       \       (key ==# 'd' &&
+                                                       \               
lcmd[key][my][:idx] =~# '^d\%[elete][lp]$')
+                                                       \       || (key ==# 'k' 
&&
+                                                       \               
lcmd[key][my][:idx] =~# '^k[a-zA-Z]$')
+                                                               let matched = 1
+                                                               let omit_idx = 
idx + 1
+                if spec
+                  echo "match. break. omit_idx:" omit_idx
+                endif
+                                                               break
+                                                       endif
+                                               endfor
+                                               if !matched
+              if spec
+                echo "not match. break"
+              endif
+                                                       break
+                                               endif
+                                       endfor
+                               endif
+
+                               let item.name = lcmd[key][my]
+                               let item.type = 
s:get_vim_command_type(item.name)
+                               if omit_idx + 1 < strlen(item.name)
+                                       let item.omit_idx = omit_idx
+                                       let item.syn_str = item.name[:omit_idx] 
. '[' . 
+                                       \               item.name[omit_idx+1:] 
. ']'
+                               else
+                                       let item.omit_idx = -1
+                                       let item.syn_str = item.name
+                               endif
+                               call add(a:cmd, copy(item))
+                       endfor
+               endfor
+
+               " Check exists in the help. (Usually it does not check...)
+               let doc_dir = './vim/runtime/doc'
+               if 0
+                       for vimcmd in a:cmd
+                               let find_ptn = '^|:' . vimcmd.name . '|\s\+'
+                               exec "silent! vimgrep /" . find_ptn . "/gj " . 
doc_dir . "/index.txt"
+                               let li = getqflist()
+                               if empty(li)
+                                       call s:err_sanity(printf('Ex-cmd `:%s` 
is not found in doc/index.txt.', vimcmd.name))
+                               elseif len(li) > 1
+                                       call s:err_sanity(printf('Ex-cmd `:%s` 
is duplicated in doc/index.txt.', vimcmd.name))
+                               else
+                                       let doc_syn_str = 
substitute(li[0].text, find_ptn . '\(\S\+\)\s\+.*', ' ', '')
+                                       if doc_syn_str ==# vimcmd.syn_str
+                                               call 
s:err_sanity(printf('Ex-cmd `%s` short name differ in doc/index.txt. code: 
`%s`, document: `%s`', vimcmd.name, vimcmd.syn_str, doc_syn_str))
+                                       endif
+                               endif
+
+                               if 1
+                               for i in range(2)
+                                       if i || vimcmd.omit_idx >= 0
+                                               if !i
+                                                       let base_ptn = 
vimcmd.name[:vimcmd.omit_idx]
+                                               else
+                                                       let base_ptn = 
vimcmd.name
+                                               endif
+                                               let find_ptn = '\*:' . base_ptn 
. '\*'
+                                               exec "silent! vimgrep /" . 
find_ptn . "/gj " . doc_dir . "/*.txt"
+                                               let li = getqflist()
+                                               if empty(li)
+                                                       call 
s:err_sanity(printf('Ex-cmd `:%s`%s is not found in the help tag.', base_ptn, 
!i ? ' (short name of `:' . vimcmd.name . '`)' : ''))
+                                               elseif len(li) > 1
+                                                       call 
s:err_sanity(printf('Ex-cmd `:%s`%s is duplicated in the help tag.', base_ptn, 
!i ? ' (short name of `:' . vimcmd.name . '`)' : ''))
+                                               endif
+                                       endif
+                               endfor
+                       endif
+                       endfor
+               endif
+
+               " Add weird abbreviations for delete. (See :help :d)
+               for i in ['l', 'p']
+                       let str = 'delete'
+                       let item.name = str . i
+                       let item.type = s:get_vim_command_type(item.name)
+                       let item.omit_idx = -1
+                       for x in range(strlen(str))
+                               let item.syn_str = str[:x] . i
+                               if item.syn_str !=# "del"
+                                       call add(a:cmd, copy(item))
+                               endif
+                       endfor
+               endfor
+
+               " Required for original behavior
+               let item.name = 'a'             " append
+               let item.type = 0
+               let item.omit_idx = -1
+               let item.syn_str = item.name
+               call add(a:cmd, copy(item))
+               let item.name = 'i'             " insert
+               call add(a:cmd, copy(item))
+
+               if empty(a:cmd)
+                       throw 'cmd is empty'
+               endif
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+function! s:get_vim_command_type(cmd_name)
+       " Return value:
+       "   0: normal
+       "   1: (Reserved)
+       "   2: abbrev (without un)
+       "   3: menu
+       "   4: map
+       "   5: mapclear
+       "   6: unmap
+       "   99: (Exclude registration of "syn keyword")
+       let menu_prefix = '^\%([acinosvx]\?\|tl\)'
+       let map_prefix  = '^[acilnostvx]\?'
+       let exclude_list = [
+       \       'map',
+       \       'substitute', 'smagic', 'snomagic',
+       \       'setlocal', 'setglobal', 'set', 'var',
+       \       'autocmd', 'doautocmd', 'doautoall',
+       \       'echo', 'echohl', 'execute',
+       \       'behave', 'augroup', 'normal', 'syntax',
+       \       'append', 'insert',
+       \       'Next', 'Print', 'X',
+       \ ]
+       " Required for original behavior
+       " \     'global', 'vglobal'
+
+       if index(exclude_list, a:cmd_name) != -1
+               let ret = 99
+       elseif a:cmd_name =~# 
'^\%(abbreviate\|noreabbrev\|\l\%(nore\)\?abbrev\)$'
+               let ret = 2
+       elseif a:cmd_name =~# menu_prefix . '\%(nore\|un\)\?menu$'
+               let ret = 3
+       elseif a:cmd_name =~# map_prefix . '\%(nore\)\?map$'
+               let ret = 4
+       elseif a:cmd_name =~# map_prefix . 'mapclear$'
+               let ret = 5
+       elseif a:cmd_name =~# map_prefix . 'unmap$'
+               let ret = 6
+       else
+               let ret = 0
+       endif
+       return ret
+endfunc
+
+function! s:append_syn_vimcmd(lnum, str_info, cmd_list, type)
+       let ret_lnum = a:lnum
+       let str = a:str_info.start
+
+       for o in a:cmd_list
+               if o.type == a:type
+                       let str .= ' ' . o.syn_str
+                       if len(str) > s:line_break_len
+                               if !empty(a:str_info.end)
+                                       let str .= ' ' . a:str_info.end
+                               endif
+                               call append(ret_lnum, str)
+                               let str = a:str_info.start
+                               let ret_lnum += 1
+                       endif
+               endif
+       endfor
+       if str !=# a:str_info.start
+               if !empty(a:str_info.end)
+                       let str .= ' ' . a:str_info.end
+               endif
+               call append(ret_lnum, str)
+               let ret_lnum += 1
+       endif
+       return ret_lnum
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:parse_vim_event(li)
+       try
+               let file_name = $VIM_SRCDIR . '/autocmd.c'
+               let item = {}
+
+               new
+               exec 'read ' . file_name
+               norm! gg
+               exec '/^}\s*event_names\[\]\s*=\s*$/+1;/^};/-1yank'
+               %delete _
+
+               put
+               g!/^\s*{\s*"\w\+"\s*,.*$/d
+
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, '^\s*{\s*"\(\w\+\)"\s*,')
+                       let item.name = list[1]
+                       call add(a:li, copy(item))
+               endfor
+
+               quit!
+
+               if empty(a:li)
+                       throw 'event is empty'
+               endif
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:parse_vim_function(li)
+       try
+               let file_name = $VIM_SRCDIR . '/evalfunc.c'
+               let item = {}
+
+               new
+               exec 'read ' . file_name
+               norm! gg
+               exec 
'/^static\s\+funcentry_T\s\+global_functions\[\]\s*=\s*$/+1;/^};/-1yank'
+               %delete _
+
+               put
+               g!/^\s*{\s*"\w\+"\s*,.*$/d
+               g/^\s*{\s*"test"\s*,.*$/d
+               g@//\s*obsolete@d
+               g@/\*\s*obsolete\s*\*/@d
+
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, '^\s*{\s*"\(\w\+\)"\s*,')
+                       let item.name = list[1]
+                       call add(a:li, copy(item))
+               endfor
+
+               quit!
+
+               if empty(a:li)
+                       throw 'function is empty'
+               endif
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:parse_vim_hlgroup(li)
+       try
+               let file_name = $VIM_SRCDIR . '/highlight.c'
+               let item = {}
+
+               new
+               exec 'read ' . file_name
+               call cursor(1, 1)
+               exec 
'/^static\s\+char\s\+\*(highlight_init_both\[\])\s*=\%(\s*{\)\?$/+1;/^\s*};/-1yank
 a'
+               exec 
'/^static\s\+char\s\+\*(highlight_init_light\[\])\s*=\%(\s*{\)\?$/+1;/^\s*};/-1yank
 b'
+               exec '/^set_normal_colors(\%(void\)\?)$/+1;/^}$/-1yank d'
+               %delete _
+               put a
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, 
'^\s*\%(CENT(\)\?"\%(default\s\+link\s\+\)\?\( \+\).*",.*')
+                       if !empty(list)
+                               let item.name = list[1]
+                               let item.type = 'both'
+                               call add(a:li, copy(item))
+                       endif
+               endfor
+
+               %delete _
+               put b
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, 
'^\s*\%(CENT(\)\?"\%(default\s\+link\s\+\)\?\( \+\).*",.*')
+                       if !empty(list)
+                               let item.name = list[1]
+                               let item.type = 'light'
+                               call add(a:li, copy(item))
+                       endif
+               endfor
+
+               %delete _
+               put d
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, 
'^\s*if\s*(set_group_colors(.*"\( \+\)",')
+                       if !empty(list) && list[1] !=# 'Normal'
+                               let item.name = list[1]
+                               let item.type = 'gui'
+                               call add(a:li, copy(item))
+                       endif
+               endfor
+
+               let item.name = 'CursorIM'
+               let item.type = 'gui'
+               call add(a:li, copy(item))
+
+               quit!
+
+               if empty(a:li)
+                       throw 'hlgroup is empty'
+               endif
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:parse_vim_complete_name(li)
+       try
+               let file_name = $VIM_SRCDIR . '/usercmd.c'
+               let item = {}
+
+               new
+               exec 'read ' . file_name
+               norm! gg
+               exec '/^}\s*command_complete\[\]\s*=\s*$/+1;/^};/-1yank'
+               %delete _
+
+               put
+               g!/^\s*{.*"\w\+"\s*}\s*,.*$/d
+               g/"custom\(list\)\?"/d
+
+               for line in getline(1, line('$'))
+                       let list = matchlist(line, '^\s*{.*"\(\w\+\)"\s*}\s*,')
+                       let item.name = list[1]
+                       call add(a:li, copy(item))
+               endfor
+
+               quit!
+
+               if empty(a:li)
+                       throw 'complete_name is empty'
+               endif
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:append_syn_any(lnum, str_info, li)
+       let ret_lnum = a:lnum
+       let str = a:str_info.start
+
+       for o in a:li
+               let str .= ' ' . o.name
+               if len(str) > s:line_break_len
+                       if !empty(a:str_info.end)
+                               let str .= ' ' . a:str_info.end
+                       endif
+                       call append(ret_lnum, str)
+                       let str = a:str_info.start
+                       let ret_lnum += 1
+               endif
+       endfor
+       if str !=# a:str_info.start
+               if !empty(a:str_info.end)
+                       let str .= ' ' . a:str_info.end
+               endif
+               call append(ret_lnum, str)
+               let ret_lnum += 1
+       endif
+       return ret_lnum
+endfunc
+
+function! s:update_syntax_vim_file(vim_info)
+       try
+               function! s:search_and_check(kword, base_fname, str_info)
+                       let a:str_info.start = ''
+                       let a:str_info.end = ''
+
+                       let pattern = '^" GEN_SYN_VIM: ' . a:kword . '\s*,'
+                       let lnum = search(pattern)
+                       if lnum == 0
+                               throw 'Search pattern ''' . pattern . ''' not 
found in ' .
+                               \               a:base_fname
+                       endif
+                       let li = matchlist(getline(lnum), pattern . 
'\s*START_STR\s*=\s*''\(.\{-}\)''\s*,\s*END_STR\s*=\s*''\(.\{-}\)''')
+                       if empty(li)
+                               throw 'Bad str_info line:' . getline(lnum)
+                       endif
+                       let a:str_info.start = li[1]
+                       let a:str_info.end = li[2]
+                       return lnum
+               endfunc
+
+               let target_fname = 'vim.vim.rc'
+               let base_fname = 'vim.vim.base'
+               let str_info = {}
+               let str_info.start = ''
+               let str_info.end = ''
+
+               new
+               exec 'edit ' . target_fname
+               %d _
+               exec 'read ' . base_fname
+               1delete _
+               call cursor(1, 1)
+
+               " vimCommand
+               let li = a:vim_info.cmd
+               " vimCommand - normal
+               let lnum = s:search_and_check('vimCommand normal', base_fname, 
str_info)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 0)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 3)           
" menu
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 4)           
" map
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 5)           
" mapclear
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 6)           
" unmap
+
+               " vimOption
+               let kword = 'vimOption'
+               let li = a:vim_info.opt
+               " vimOption - normal
+               let lnum = s:search_and_check(kword . ' normal', base_fname, 
str_info)
+               let lnum = s:append_syn_vimopt(lnum, str_info, li, '', 0)
+               " vimOption - turn-off
+               let lnum = s:search_and_check(kword . ' turn-off', base_fname, 
str_info)
+               let lnum = s:append_syn_vimopt(lnum, str_info, li, 'no', 1)
+               " vimOption - invertible
+               let lnum = s:search_and_check(kword . ' invertible', 
base_fname, str_info)
+               let lnum = s:append_syn_vimopt(lnum, str_info, li, 'inv', 1)
+               " vimOption - term output code
+               let li = a:vim_info.term_out_code
+               let lnum = s:search_and_check(kword . ' term output code', 
base_fname, str_info)
+               let lnum = s:append_syn_any(lnum, str_info, li)
+
+               " Missing vimOption
+               let li = a:vim_info.missing_opt
+               let lnum = s:search_and_check('Missing vimOption', base_fname, 
str_info)
+               let lnum = s:append_syn_vimopt(lnum, str_info, li, '', 0)
+               let lnum = s:append_syn_vimopt(lnum, str_info, li, 'no', 1)
+               let lnum = s:append_syn_vimopt(lnum, str_info, li, 'inv', 1)
+
+               " vimAutoEvent
+               let li = a:vim_info.event
+               let lnum = s:search_and_check('vimAutoEvent', base_fname, 
str_info)
+               let lnum = s:append_syn_any(lnum, str_info, li)
+
+               " vimHLGroup
+               let li = a:vim_info.hlgroup
+               let lnum = s:search_and_check('vimHLGroup', base_fname, 
str_info)
+               let lnum = s:append_syn_any(lnum, str_info, li)
+
+               " vimFuncName
+               let li = a:vim_info.func
+               let lnum = s:search_and_check('vimFuncName', base_fname, 
str_info)
+               let lnum = s:append_syn_any(lnum, str_info, li)
+
+               " vimUserAttrbCmplt
+               let li = a:vim_info.compl_name
+               let lnum = s:search_and_check('vimUserAttrbCmplt', base_fname, 
str_info)
+               let lnum = s:append_syn_any(lnum, str_info, li)
+
+               " vimCommand - abbrev
+               let kword = 'vimCommand'
+               let li = a:vim_info.cmd
+               let lnum = s:search_and_check(kword . ' abbrev', base_fname, 
str_info)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 2)
+               " vimCommand - map
+               let lnum = s:search_and_check(kword . ' map', base_fname, 
str_info)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 4)
+               let lnum = s:search_and_check(kword . ' mapclear', base_fname, 
str_info)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 5)
+               let lnum = s:search_and_check(kword . ' unmap', base_fname, 
str_info)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 6)
+               " vimCommand - menu
+               let lnum = s:search_and_check(kword . ' menu', base_fname, 
str_info)
+               let lnum = s:append_syn_vimcmd(lnum, str_info, li, 3)
+
+               update
+               quit!
+
+       catch /.*/
+               call s:err_gen('')
+               throw 'exit'
+       endtry
+endfunc
+
+" 
------------------------------------------------------------------------------
+function! s:err_gen(arg)
+       call s:write_error(a:arg, 'generator.err')
+endfunc
+
+function! s:err_sanity(arg)
+       call s:write_error(a:arg, 'sanity_check.err')
+endfunc
+
+function! s:write_error(arg, fname)
+       let li = []
+       if !empty(v:throwpoint)
+               call add(li, v:throwpoint)
+       endif
+       if !empty(v:exception)
+               call add(li, v:exception)
+       endif
+       if type(a:arg) == type([])
+               call extend(li, a:arg)
+       elseif type(a:arg) == type("")
+               if !empty(a:arg)
+                       call add(li, a:arg)
+               endif
+       endif
+       if !empty(li)
+               call writefile(li, a:fname, 'a')
+       else
+               call writefile(['UNKNOWN'], a:fname, 'a')
+       endif
+endfunc
+
+" 
------------------------------------------------------------------------------
+try
+       let s:line_break_len = 768
+       let s:vim_info = {}
+       let s:vim_info.opt = []
+       let s:vim_info.missing_opt = []
+       let s:vim_info.term_out_code = []
+       let s:vim_info.cmd = []
+       let s:vim_info.event = []
+       let s:vim_info.func = []
+       let s:vim_info.hlgroup = []
+       let s:vim_info.compl_name = []
+
+       set lazyredraw
+       silent call s:parse_vim_option(s:vim_info.opt, s:vim_info.missing_opt,
+       \                                               
s:vim_info.term_out_code)
+       silent call s:parse_vim_command(s:vim_info.cmd)
+       silent call s:parse_vim_event(s:vim_info.event)
+       silent call s:parse_vim_function(s:vim_info.func)
+       silent call s:parse_vim_hlgroup(s:vim_info.hlgroup)
+       silent call s:parse_vim_complete_name(s:vim_info.compl_name)
+
+       call s:update_syntax_vim_file(s:vim_info)
+       set nolazyredraw
+
+finally
+       quitall!
+endtry
+
+" ---------------------------------------------------------------------
+let &cpo = s:keepcpo
+unlet s:keepcpo
+" vim:ts=2 sw=2
diff --git a/runtime/syntax/generator/update_date.vim 
b/runtime/syntax/generator/update_date.vim
new file mode 100644
index 000000000..662e5054b
--- /dev/null
+++ b/runtime/syntax/generator/update_date.vim
@@ -0,0 +1,14 @@
+" Update the date of following line in vim.vim.rc.
+"     '" Last Change:  '
+"
+language C
+silent new vim.vim
+normal gg
+let pat = '^"\s*Last\s*Change:\s\+'
+let lnum = search(pat, 'We', 10)
+if lnum > 0
+   exec 'norm! lD"=strftime("%b %d, %Y")' . "
p"
+   silent update
+endif
+quitall!
+" vim:ts=4 sw=4 et
diff --git a/runtime/syntax/generator/vim.vim.base 
b/runtime/syntax/generator/vim.vim.base
new file mode 100644
index 000000000..7c8373727
--- /dev/null
+++ b/runtime/syntax/generator/vim.vim.base
@@ -0,0 +1,1110 @@
+" Vim syntax file
+" Language:    Vim script
+" Maintainer:  Hirohito Higashi <h.east.727 ATMARK gmail.com>
+" URL: https://github.com/vim-jp/syntax-vim-ex
+" Former Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
+" Base File URL:     http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM
+" Base File Version: 9.0-25
+" Base File Date:    May 09, 2023
+
+" DO NOT CHANGE DIRECTLY.
+" THIS FILE PARTLY GENERATED BY gen_syntax_vim.vim.
+" (Search string "GEN_SYN_VIM:" in this file)
+
+" Automatically generated keyword lists: {{{1
+
+" Quit when a syntax file was already loaded {{{2
+if exists("b:current_syntax")
+  finish
+endif
+let b:loaded_syntax_vim_ex="__REVISION__"
+let s:keepcpo= &cpo
+set cpo&vim
+
+" vimTodo: contains common special-notices for comments {{{2
+" Use the vimCommentGroup cluster to add your own.
+syn keyword vimTodo contained  COMBAK  FIXME   TODO    XXX
+syn cluster vimCommentGroup    contains=vimTodo,@Spell
+
+" regular vim commands {{{2
+" GEN_SYN_VIM: vimCommand normal, START_STR='syn keyword vimCommand 
contained', END_STR=''
+
+syn keyword vimCommand contained       2mat[ch] 3mat[ch]
+
+syn match   vimCommand contained       "\<z[-+^.=]\=\>"
+syn keyword vimStdPlugin contained     Arguments Asm Break Cfilter Clear 
Continue DiffOrig Evaluate Finish Gdb Lfilter Man Over Program Run S Source 
Step Stop Termdebug TermdebugCommand TOhtml Until Winbar XMLent XMLns
+
+" vimOptions are caught only when contained in a vimSet {{{2
+" GEN_SYN_VIM: vimOption normal, START_STR='syn keyword vimOption contained', 
END_STR=''
+
+" vimOptions: These are the turn-off setting variants {{{2
+" GEN_SYN_VIM: vimOption turn-off, START_STR='syn keyword vimOption 
contained', END_STR=''
+
+" vimOptions: These are the invertible variants {{{2
+" GEN_SYN_VIM: vimOption invertible, START_STR='syn keyword vimOption 
contained', END_STR=''
+
+" termcap codes (which can also be set) {{{2
+" GEN_SYN_VIM: vimOption term output code, START_STR='syn keyword vimOption 
contained', END_STR=''
+" term key codes
+syn keyword vimOption contained        t_F1 t_F2 t_F3 t_F4 t_F5 t_F6 t_F7 t_F8 
t_F9 t_k1 t_K1 t_k2 t_k3 t_K3 t_k4 t_K4 t_k5 t_K5 t_k6 t_K6 t_k7 t_K7 t_k8 t_K8 
t_k9 t_K9 t_KA t_kb t_kB t_KB t_KC t_kd t_kD t_KD t_KE t_KF t_KG t_kh t_KH t_kI 
t_KI t_KJ t_KK t_kl t_KL t_kN t_kP t_kr t_ku
+syn match   vimOption contained        "t_%1"
+syn match   vimOption contained        "t_#2"
+syn match   vimOption contained        "t_#4"
+syn match   vimOption contained        "t_@7"
+syn match   vimOption contained        "t_*7"
+syn match   vimOption contained        "t_&8"
+syn match   vimOption contained        "t_%i"
+syn match   vimOption contained        "t_k;"
+
+" unsupported settings: some were supported by vi but don't do anything in vim 
{{{2
+" GEN_SYN_VIM: Missing vimOption, START_STR='syn keyword vimErrSetting 
contained', END_STR=''
+
+" AutoCmd Events {{{2
+syn case ignore
+" GEN_SYN_VIM: vimAutoEvent, START_STR='syn keyword vimAutoEvent contained', 
END_STR=''
+
+" Highlight commonly used Groupnames {{{2
+syn keyword vimGroup contained Comment Constant String Character Number 
Boolean Float Identifier Function Statement Conditional Repeat Label Operator 
Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass 
Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug 
Underlined Ignore Error Todo
+
+" Default highlighting groups {{{2
+" GEN_SYN_VIM: vimHLGroup, START_STR='syn keyword vimHLGroup contained', 
END_STR=''
+syn case match
+
+" Function Names {{{2
+" GEN_SYN_VIM: vimFuncName, START_STR='syn keyword vimFuncName contained', 
END_STR=''
+
+"--- syntax here and above generated by mkvimvim ---
+" Special Vim Highlighting (not automatic) {{{1
+
+" Set up folding commands for this syntax highlighting file {{{2
+if exists("g:vimsyn_folding") && g:vimsyn_folding =~# '[afhlmpPrt]'
+ if g:vimsyn_folding =~# 'a'
+  com! -nargs=* VimFolda <args> fold
+ else
+  com! -nargs=* VimFolda <args>
+ endif
+ if g:vimsyn_folding =~# 'f'
+  com! -nargs=* VimFoldf <args> fold
+ else
+  com! -nargs=* VimFoldf <args>
+ endif
+ if g:vimsyn_folding =~# 'h'
+  com! -nargs=* VimFoldh <args> fold
+ else
+  com! -nargs=* VimFoldh <args>
+ endif
+ if g:vimsyn_folding =~# 'l'
+  com! -nargs=* VimFoldl <args> fold
+ else
+  com! -nargs=* VimFoldl <args>
+ endif
+ if g:vimsyn_folding =~# 'm'
+  com! -nargs=* VimFoldm <args> fold
+ else
+  com! -nargs=* VimFoldm <args>
+ endif
+ if g:vimsyn_folding =~# 'p'
+  com! -nargs=* VimFoldp <args> fold
+ else
+  com! -nargs=* VimFoldp <args>
+ endif
+ if g:vimsyn_folding =~# 'P'
+  com! -nargs=* VimFoldP <args> fold
+ else
+  com! -nargs=* VimFoldP <args>
+ endif
+ if g:vimsyn_folding =~# 'r'
+  com! -nargs=* VimFoldr <args> fold
+ else
+  com! -nargs=* VimFoldr <args>
+ endif
+ if g:vimsyn_folding =~# 't'
+  com! -nargs=* VimFoldt <args> fold
+ else
+  com! -nargs=* VimFoldt <args>
+ endif
+else
+ com! -nargs=* VimFolda        <args>
+ com! -nargs=* VimFoldf        <args>
+ com! -nargs=* VimFoldh        <args>
+ com! -nargs=* VimFoldl        <args>
+ com! -nargs=* VimFoldm        <args>
+ com! -nargs=* VimFoldp        <args>
+ com! -nargs=* VimFoldP        <args>
+ com! -nargs=* VimFoldr        <args>
+ com! -nargs=* VimFoldt        <args>
+endif
+
+" Deprecated variable options {{{2
+if exists("g:vim_minlines")
+ let g:vimsyn_minlines= g:vim_minlines
+endif
+if exists("g:vim_maxlines")
+ let g:vimsyn_maxlines= g:vim_maxlines
+endif
+if exists("g:vimsyntax_noerror")
+ let g:vimsyn_noerror= g:vimsyntax_noerror
+endif
+
+" Variable options {{{2
+if exists("g:vim_maxlines")
+ let s:vimsyn_maxlines= g:vim_maxlines
+else
+ let s:vimsyn_maxlines= 60
+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
+
+" 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 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#_]*\>"
+syn match vimVar               "\s\zs&\%([lg]:\)\= \+\>"
+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
+
+" Insertions And Appends: insert append {{{2
+"   (buftype != nofile test avoids having append, change, insert show up in 
the command window)
+" =======================
+if &buftype != 'nofile'
+ syn region vimInsert  matchgroup=vimCommand start="^[:        
]*\(\d\+\(,\d\+\)\=\)\=a\%[ppend]$"             matchgroup=vimCommand 
end="^\.$""
+ syn region vimInsert  matchgroup=vimCommand start="^[:        
]*\(\d\+\(,\d\+\)\=\)\=c\%[hange]$"             matchgroup=vimCommand 
end="^\.$""
+ syn region vimInsert  matchgroup=vimCommand start="^[:        
]*\(\d\+\(,\d\+\)\=\)\=i\%[nsert]$"             matchgroup=vimCommand 
end="^\.$""
+endif
+
+" Behave! {{{2
+" =======
+syn match   vimBehave  "\<be\%[have]\>" skipwhite 
nextgroup=vimBehaveModel,vimBehaveError
+syn keyword vimBehaveModel contained   mswin   xterm
+if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_nobehaveerror")
+ syn match   vimBehaveError contained  "[^ ]\+"
+endif
+
+" Filetypes {{{2
+" =========
+syn match   vimFiletype        "\<filet\%[ype]\(\s\+\I\i*\)*"  skipwhite 
contains=vimFTCmd,vimFTOption,vimFTError
+if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_vimFTError")
+ syn match   vimFTError  contained     "\I\i*"
+endif
+syn keyword vimFTCmd    contained      filet[ype]
+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=vimAugroup,vimIsCommand,vimUserCmd,vimExecute,vimNotFunc,vimFuncName,vimFunction,vimFunctionError,vimLineComment,vimNotFunc,vimMap,vimSpecFile,vimOper,vimNumber,vimOperParen,vimComment,vim9Comment,vimString,vimSubst,vimMark,vimRegister,vimAddress,vimFilter,vimCmplxRepeat,vimComment,vim9Comment,vimLet,vimSet,vimAutoCmd,vimRegion,vimSynLine,vimNotation,vimCtrlChar,vimFuncVar,vimContinue,vimOption
+if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'a'
+ syn region  vimAugroup        fold matchgroup=vimAugroupKey 
start="\<aug\%[roup]\>\ze\s\+\K\k*" end="\<aug\%[roup]\>\ze\s\+[eE][nN][dD]\>"  
  contains=vimAutoCmd,@vimAugroupList
+else
+ syn region  vimAugroup        matchgroup=vimAugroupKey 
start="\<aug\%[roup]\>\ze\s\+\K\k*" end="\<aug\%[roup]\>\ze\s\+[eE][nN][dD]\>"  
       contains=vimAutoCmd,@vimAugroupList
+endif
+syn match   vimAugroup "aug\%[roup]!"  contains=vimAugroupKey
+if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noaugrouperror")
+ syn match   vimAugroupError   "\<aug\%[roup]\>\s\+[eE][nN][dD]\>"
+endif
+syn keyword vimAugroupKey contained    aug[roup]
+
+" Operators: {{{2
+" =========
+syn cluster    vimOperGroup    
contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimType,vimRegister,@vimContinue,vim9Comment,vimVar
+syn match      vimOper "||\|&&\|[-+*/%.!]"                             
skipwhite nextgroup=vimString,vimSpecFile
+syn match      vimOper 
"\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\|!\~#\)[?#]\{0,2}"    skipwhite 
nextgroup=vimString,vimSpecFile
+syn match      vimOper "\(\<is\|\<isnot\)[?#]\{0,2}\>"                 
skipwhite nextgroup=vimString,vimSpecFile
+syn region     vimOperParen    matchgroup=vimParenSep  start="(" end=")" 
contains=vimoperStar,@vimOperGroup
+syn region     vimOperParen    matchgroup=vimSep               start="#\={" 
end="}" contains=@vimOperGroup nextgroup=vimVar,vimFuncVar
+if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noopererror")
+ syn match     vimOperError    ")"
+endif
+
+" Functions : Tag is provided for those who wish to highlight tagged functions 
{{{2
+" =========
+syn cluster    vimFuncList     
contains=vimCommand,vimFunctionError,vimFuncKey,Tag,vimFuncSID
+syn cluster    vimFuncBodyList 
contains=vimAbb,vimAddress,vimAugroupKey,vimAutoCmd,vimCmplxRepeat,vimComment,vim9Comment,vimContinue,vimCtrlChar,vimEcho,vimEchoHL,vimEnvvar,vimExecute,vimIsCommand,vimFBVar,vimFunc,vimFunction,vimFuncVar,vimGlobal,vimHighlight,vimIsCommand,vimLet,vimLetHereDoc,vimLineComment,vimMap,vimMark,vimNorm,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegion,vimRegister,vimSearch,vimSet,vimSpecFile,vimString,vimSubst,vimSynLine,vimUnmap,vimUserCommand
+syn match      vimFunction     
"\<\(fu\%[nction]\)!\=\s\+\%(<[sS][iI][dD]>\|[sSgGbBwWtTlL]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)*\ze\s*("
       contains=@vimFuncList nextgroup=vimFuncBody
+syn match      vimFunction     "\<def!\=\s\+\%(\i\|[#.]\|{.\{-1,}}\)*\ze\s*(" 
contains=@vimFuncList nextgroup=vimFuncBody
+"syn match     vimFunction     "\<def!\=\ze\s*(" contains=@vimFuncList 
nextgroup=vimFuncBody
+
+if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'f'
+ syn region    vimFuncBody  contained  fold start="\ze\s*("    
matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\|enddef\>\)"           
contains=@vimFuncBodyList
+else
+ syn region    vimFuncBody  contained  start="\ze\s*("         
matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\|enddef\>\)"           
contains=@vimFuncBodyList
+endif
+syn match      vimFuncVar   contained  "a:\(\K\k*\|\d\+\)"
+syn match      vimFuncSID   contained  "

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1rZzBH-00DAyE-5q%40256bit.org.

Raspunde prin e-mail lui