1

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:

enter image description here

Some nice animation

enter image description here

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)?

1
  • It's starting to look like I'd be needing some kind of virtual function templating via exec(). – John Greene May 30 '20 at 20:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.