mirror of
				https://github.com/vim/vim.git
				synced 2025-10-31 09:57:14 -04:00 
			
		
		
		
	This is a first-pass attempt to limit matching of Vim9 and legacy-script comments to the appropriate syntactic contexts. Vim9-script comments are highlighted at top level in a Vim9-script file, in all :def functions, and in all :autocmd and :commmand command blocks. Legacy-script comments are highlighted at top level in a legacy script file, in all :func functions and in the Vim9-script preamble before the :vim9script marker command. Fixes #13047, #11307 and #9587. Signed-off-by: Doug Kearns <dougkearns@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
		
			
				
	
	
		
			712 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			VimL
		
	
	
	
	
	
			
		
		
	
	
			712 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			VimL
		
	
	
	
	
	
| " Vim syntax file generator
 | |
| " Language: Vim script
 | |
| " Maintainer: Hirohito Higashi (h_east)
 | |
| " URL: https://github.com/vim-jp/syntax-vim-ex
 | |
| " Last Change: 2024 Apr 07
 | |
| " Version: 2.1.1
 | |
| 
 | |
| 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*"\(\a\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\+.*', '\1', '')
 | |
| 					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
 | |
| 		let item.syn_str = item.name
 | |
| 		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
 | |
| 	"   7: abclear
 | |
| 	"   99: (Exclude registration of "syn keyword")
 | |
| 	let ab_prefix   = '^[ci]\?'
 | |
| 	let menu_prefix = '^\%([acinostvx]\?\|tl\)'
 | |
| 	let map_prefix  = '^[acilnostvx]\?'
 | |
| 	let exclude_list = [
 | |
| 	\	'map', 'mapclear',
 | |
| 	\	'substitute', 'smagic', 'snomagic',
 | |
| 	\	'setlocal', 'setglobal', 'set', 'var',
 | |
| 	\	'autocmd', 'augroup', 'doautocmd', 'doautoall',
 | |
| 	\	'echo', 'echoconsole', 'echoerr', 'echohl', 'echomsg', 'echon', 'echowindow',
 | |
| 	\	'execute',
 | |
| 	\ 'function', 'endfunction', 'def', 'enddef',
 | |
| 	\	'behave', 'augroup', 'normal', 'syntax',
 | |
| 	\	'append', 'insert',
 | |
| 	\	'Next', 'Print', 'X',
 | |
| 	\	'new', 'popup',
 | |
| 	\	'vim9script',
 | |
| 	\ ]
 | |
| 	" Required for original behavior
 | |
| 	" \	'global', 'vglobal'
 | |
| 
 | |
| 	if index(exclude_list, a:cmd_name) != -1
 | |
| 		let ret = 99
 | |
| 	elseif a:cmd_name =~# '^\%(\%(un\)\?abbreviate\|noreabbrev\|\l\%(nore\|un\)\?abbrev\)$'
 | |
| 		let ret = 2
 | |
| 	elseif a:cmd_name =~# ab_prefix . 'abclear$'
 | |
| 		let ret = 7
 | |
| 	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 '/^static keyvalue_T event_tab\[] = {$/+1;/^};$/-1yank'
 | |
| 		%delete _
 | |
| 
 | |
| 		put
 | |
| 		g!/^\s*KEYVALUE_ENTRY(/d
 | |
| 
 | |
| 		for line in getline(1, line('$'))
 | |
| 			let list = matchlist(line, '^\s*KEYVALUE_ENTRY(EVENT_\w\+,\s*"\(\w\+\)"')
 | |
| 			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\+\)\?\(\a\+\).*",.*')
 | |
| 			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\+\)\?\(\a\+\).*",.*')
 | |
| 			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(.*"\(\a\+\)",')
 | |
| 			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))
 | |
| 
 | |
| 		" The following highlight groups cannot be extracted from highlight.c
 | |
| 		" (TODO: extract from HIGHLIGHT_INIT ?)
 | |
| 		let item.name = 'LineNrAbove'
 | |
| 		let item.type = 'both'
 | |
| 		call add(a:li, copy(item))
 | |
| 
 | |
| 		let item.name = 'LineNrBelow'
 | |
| 		let item.type = 'both'
 | |
| 		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)
 | |
| 
 | |
| 		" 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)
 | |
| 		let lnum = s:search_and_check(kword . ' abclear', base_fname, str_info)
 | |
| 		let lnum = s:append_syn_vimcmd(lnum, str_info, li, 7)
 | |
| 		" 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
 |