For Vim, are there any design guidelines for simultaneously doing autocompletion and syntax highlighting?
For the NFTABLES command line (and file) syntaxes, I see lots of recurring but partial syntax sub-branches with various terminating nextgroup=
.
So, I'm trying out the function
-based modular approach for a Linux NFTABLES simple list ruleset
and list table ...
syntaxes.
I did a quick review (but many) of the distro-based Vim syntax.vim files (for Debian 9+, typically in /usr/share/vim/vim81/syntax
directory). Of those that I've reviewed, I noticed that none use the modular approach yet I see potential saving for such modular approach.
Am I going overboard there? What are the reason for not doing the function
-based modular approach?
Take the simple example here:
list ruleset
list ruleset netdev
list ruleset oopsie; # invalid syntax
list table arp myArpTable
list table myIpTable
A working (but brute-force) approach of Vimscript syntax for nftables
has already been done in Github vim-nftables. But it is nearly 3,000 lines (and an estimated 9,000 more lines to go). The actual screenshot is:
Some nice animation
Now, I took a stab at modularization by delving into some rather advanced Vimscript programming.
Some example of the Vimscript code:
hi link nftables_base_cmd nftablesHL_Command
syn keyword nftables_base_cmd list skipwhite
\ nextgroup=
\ nftables_TABLE_table_spec_EOS,
\ nftables_list_RULESET_ruleset_spec_EOS,
call Nftables_TABLE_table_spec('', '', '', 1, 0)
call Nftables_RULESET_ruleset_spec('list', '', '', 1, 0)
function Nprefix(node)
if (a:node != '')
return 'nftables'.a:node
else
return 'nftables'
endif
endfunction
function Nparent(groupname)
return '_'.a:groupname
endfunction
function Nchild(child)
if (a:child != '')
return '_'.a:child
else
return ''
endif
endfunction
function Neos(flag)
if (a:flag != 0)
return '_EOS'
else
return ''
endif
endfunction
function Nhilite(hlname)
return Nprefix('HL_').a:hlname
endfunction
function Nftables_addEOS(flag)
if (a:flag != '')
return 'nftables_Semicolon,nftables_EOS'
else
return ''
endfunction
function Nftables_Hilite(thisnode, hlname)
let hilink = 'hi link '.a:thisnode.' '.Nhilite(a:hlname)
let cmdline = l:hilink
exec l:cmdline
endfunction
function Nftables_identifier(parent, child, nxt_group, hilite_type, eos, logme)
if (a:logme)
echom 'Nftables_identifier: started'
echom 'Nftables_identifier: parent: '.a:parent
echom 'Nftables_identifier: child: '.a:child
echom 'Nftables_identifier: nxt_group: '.a:nxt_group
echom 'Nftables_identifier: hilite: '.a:hilite_type
echom 'Nftables_identifier: eos: '.a:eos
endif
let new_parent = a:parent.'_identifier'
let new_groupname = Nprefix('').l:new_parent.Nchild(a:child).Neos(a:eos)
call Nftables_Hilite(l:new_groupname, a:hilite_type)
if (a:nxt_group != '')
let new_nextgroup = a:nxt_group.','.Nftables_addEOS(a:eos)
else
let new_nextgroup = Nftables_addEOS(a:eos)
endif
if (l:new_nextgroup != '')
let sm_add = 'nextgroup='.l:new_nextgroup
else
let sm_add = ''
endif
let cmd_sm = 'syn match '.l:new_groupname.' contained /[a-zA-Z\_]\{1,64}/ skip
white '.sm_add
echom 'cmd_sm:::: '.cmd_sm
exec l:cmd_sm
if (a:logme != 0)
exec 'syn list '.l:new_groupname
endif
if (a:logme)
echom 'Nftables_identifier: exited'
endif
return l:new_groupname
endfunction
" Should We keep child and EOS separate???
function Nftables_family_spec_explicit(parent, child, nxt_group, eos, logme)
let label = 'family_spec_explicit'
if (a:logme)
echom 'Nftables_family_spec_explicit: started'
echom 'Nftables_family_spec_exp: parent: '.a:parent
echom 'Nftables_family_spec_exp: child: '.a:child
echom 'Nftables_family_spec_exp: nxt_group: '.a:nxt_group
echom 'Nftables_family_spec_exp: eos: '.a:eos
endif
if (a:parent != '')
let new_parent = a:parent.l:label
else
let new_parent = l:label
endif
if (a:child != '')
let new_parent = l:new_parent.a:child
endif
let new_grpnam = Nprefix('').'_'.l:new_parent.Neos(a:eos)
echom ' XXX new_grpnam: '.l:new_grpnam
call Nftables_Hilite(l:new_grpnam, 'Underlined')
echom 'debug 1: '.l:new_grpnam
if (a:nxt_group != '')
let cmd_sk_add =' nextgroup='.a:nxt_group.','
else
let cmd_sk_add =''
endif
let cmd_sk = 'syntax keyword '.l:new_grpnam.' contained netdev bridge arp ip i
p6 inet skipwhite '.l:cmd_sk_add
exec cmd_sk
if (a:logme != 0)
exec 'syn list '.l:new_grpnam
endif
if (a:logme)
echom 'Nftables_family_spec_explicit: exited'
endif
return l:new_grpnam
endfunction
function Nftables_table_spec(parent, child, nxt_group, eos, logme)
echom 'Nftables_table_spec: started'
echom 'Nftables_table_spec: parent: '.a:parent
echom 'Nftables_table_spec: child: '.a:child
echom 'Nftables_table_spec: nxt_group: '.a:nxt_group
echom 'Nftables_table_spec: eos: '.a:eos
if (a:parent != '')
let l:new_parent = a:parent.'_table_spec'
else
let l:new_parent = 'table_spec'
endif
if (a:child != '')
let new_parent = l:new_parent.a:child
endif
let tblname = Nftables_identifier(l:new_parent, 'TableName', a:nxt_group, 'Tab
le', a:eos, a:logme)
let nxt_group = a:nxt_group
if (l:nxt_group != '')
let nxt_group = l:tblname.','.l:nxt_group
else
let nxt_group = l:tblname
endif
let famexp_gn = Nftables_family_spec_explicit(l:new_parent, '', l:nxt_group, 1
, a:logme)
let groupname = Nprefix('Cluster').l:new_parent.Neos(a:eos)
exec 'syntax cluster '.l:groupname.' contains='.l:famexp_gn.','.l:tblname
if (a:logme != 0)
exec 'syn list @'.l:groupname
endif
echom 'Nftables_table_spec: exited'
return l:groupname
endfunction
function Nftables_TABLE_table_spec(parent, child, nxt_group, eos, logme)
if (a:logme)
echom 'Nftables_TABLE_table_spec: called'
echom 'Nftables_TABLE_table_spec: parent: '.a:parent
echom 'Nftables_TABLE_table_spec: child: '.a:child
echom 'Nftables_TABLE_table_spec: nxt_group: '.a:nxt_group
echom 'Nftables_TABLE_table_spec: eos: '.a:eos
endif
let table_spec = Nftables_table_spec(a:parent.'_TABLE', a:child, a:nxt_group,
0, a:logme)
let groupname = Nprefix('').a:parent.'_TABLE_table_spec'.Neos(a:eos)
call Nftables_Hilite(l:groupname, 'Statement')
exec 'syntax keyword '.l:groupname.' contained table skipwhite nextgroup=@'.l:
table_spec.','.Nftables_addEOS(0)
if (a:logme != 0)
exec 'syn list '.l:groupname
endif
if (a:logme)
echom 'Nftables_TABLE_table_spec: exited'
endif
return l:groupname
endfunction
function Nftables_TABLE_table_spec_table_block(parent, child, nxt_group, eos, lo
gme)
if (a:logme)
echom 'Nftables_TABLE_table_spec_table_block: called'
echom 'Nftables_TABLE_table_spec_table_block: parent: '.a:parent
echom 'Nftables_TABLE_table_spec_table_block: child: '.a:child
echom 'Nftables_TABLE_table_spec_table_block: nxt_group: '.a:nxt_group
echom 'Nftables_TABLE_table_spec_table_block: eos: '.a:eos
endif
let table_spec = Nftables_table_spec(a:parent.'_TABLE', a:child, a:nxt_group,
0, a:logme)
let groupname = Nprefix('').a:parent.'_TABLE_table_spec_table_blck'.Neos(a:eos)
call Nftables_Hilite(l:groupname, 'Statement')
exec 'syntax keyword '.l:groupname.' contained table skipwhite nextgroup=@'.l:
table_spec.','.Nftables_addEOS(0)
if (a:logme != 0)
exec 'syn list '.l:groupname
endif
if (a:logme)
echom 'Nftables_TABLE_table_spec_table_block: exited'
endif
return l:groupname
endfunction
function Nftables_RULESET_ruleset_spec(parent, child, nxt_group, eos, logme)
echom 'Nftables_RULESET_ruleset_spec: started'
let label = 'RULESET_ruleset_spec'
if (a:parent != '')
let l:new_parent = a:parent.'_'.l:label
else
let l:new_parent = l:label
endif
if (a:child != '')
let new_parent = l:new_parent.'_'.a:child
endif
let groupname = Nprefix('').'_'.l:new_parent.Neos(1)
let nxt_group = a:nxt_group
if (l:nxt_group != '')
let nxt_group = l:nxt_group.','.Nftables_addEOS(1)
else
let nxt_group = Nftables_addEOS(1)
endif
echom 'nxt_group1: '.nxt_group
call Nftables_Hilite(l:groupname, 'Statement')
let fse = Nftables_family_spec_explicit(new_parent, '', l:nxt_group, 1, 1)
" exec 'syntax keyword '.l:groupname.' contained ruleset skipwhite nextgroup='
.l:fse.',@nftablesCluster_SEOS'
exec 'syntax keyword '.l:groupname.' contained ruleset skipwhite nextgroup='.l
:fse
if (a:logme != 0)
exec 'syn list '.l:groupname
endif
echom 'Nftables_RULESET_ruleset_spec: exited'
return l:groupname
endfunction
As you can see, it may not be worth the functional modular approach.
Hence this question is a call for some 'design guideline' for very large Vimscript programming, particularly if autocompletion and syntax highlighting can be done nearly at the same time.
Is there a working example of which I can reference that makes a good use of rapid definition using some form of a higher-abstraction of syntaxes (once defined)?
exec()
.