Skip to content

Conversation

@juanMarinero
Copy link
Contributor

#244

Test with next VIMRC settings:

let g:table_mode_color_cells = 1
function! g:TableModeColorCellsCustom()
  let g:TableModeSyntaxDict.contains .= ',highPriorityCell,completeCell,infoCell'
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained
  syntax match completeCell /|\@<= *X[^|]*/ contained
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction
autocmd VimEnter * call timer_start(10, {-> g:TableModeColorCellsCustom()})

Notes:

  • In plugin/ declared the dict to auto-run and so above autocmd VimEnter can run to
  • call timer_start(10 seems not best option. It should just run once the plugin is loaded (idk how)
  • g:TableModeSyntaxDict.containedin could be other than ALL? I just blinded copied it.
  • The README might need to explain how to expand the Highlight cells based on content, e.g. a link to this PR
  • As stayed in [Enhancement] Highlight cells based on content #244 the docs lack all info about Highlight cells based on content

Test with next VIMRC settings:
let g:table_mode_color_cells = 1
function! g:TableModeColorCellsCustom()
  let g:TableModeSyntaxDict.contains .= ',highPriorityCell,completeCell,infoCell'
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained
  syntax match completeCell /|\@<= *X[^|]*/ contained
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction
autocmd VimEnter * call timer_start(10, {-> g:TableModeColorCellsCustom()})
@juanMarinero
Copy link
Contributor Author

Amend.
The respective cell highlights are needed too in your VIMRC.

E.g.

hi highPriorityCell ctermfg=1 guifg=Red   cterm=bold gui=bold
hi completeCell     ctermfg=2 guifg=Green cterm=bold gui=bold
hi link infoCell    Comment " Or make it look like comments in your colorscheme

Test with next VIMRC settings:
let g:table_mode_color_cells = 1
function! g:TableModeColorCellsCustom()
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained
  syntax match completeCell /|\@<= *X[^|]*/ contained
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction
autocmd VimEnter * call timer_start(10, {-> g:TableModeColorCellsCustom()})
hi highPriorityCell ctermfg=1 guifg=Red   cterm=bold gui=bold
hi completeCell     ctermfg=2 guifg=Green cterm=bold gui=bold
hi link infoCell    Comment " Or make it look like comments in your colorscheme
@dhruvasagar dhruvasagar merged commit e156dbb into dhruvasagar:master Sep 1, 2025
2 checks passed
@juanMarinero
Copy link
Contributor Author

Code adapted to plugin syntax

We achieved that my dirty initial commit is adapted to syntax and other preferences of the plugin development.

Thanks for merging it!

Test

For everyone reading this issue.

Test the PR with next VIMRC settings:

let g:table_mode_always_active = 0 " default
let g:table_mode_color_cells = 1
function! g:TableModeColorCellsCustom()
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained
  syntax match completeCell /|\@<= *X[^|]*/ contained
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction
autocmd VimEnter * call timer_start(10, {-> g:TableModeColorCellsCustom()})

Open a TXT buffer. It must have a table with cells like in #244 initial message. E.g. starting with ! Essential, X done today or // An info cell.
Run :TableModeToggle to show the highlights.

ToDo-s

ToDo-s of my initial message in this PR. I copy-paste them but now numbered:

  1. In plugin/ declared the dict to auto-run and so above autocmd VimEnter can run to
  2. call timer_start(10 seems not best option. It should just run once the plugin is loaded (idk how)
  3. g:TableModeSyntaxDict.containedin could be other than ALL? I just blinded copied it.
  4. The README might need to explain how to expand the Highlight cells based on content, e.g. a link to this PR
  5. As stayed in [Enhancement] Highlight cells based on content #244 the docs lack all info about Highlight cells based on content

Which autocmd ?

Concerning the 1st and 2nd ToDo-s.

Option A. Via VimEnter if g:table_mode_always_active = 0 (default)

As stayed, we can enable our custom table syntax highlights with this approach. We need in our VIMRC:

autocmd VimEnter * call timer_start(10, {-> g:TableModeColorCellsCustom()})

The delay lets the plugin create [the default] g:table_mode_syntax_dict. So we can later expand [one of its keys] with let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'.

To use it, as I already explained [suppose you are in TXT file with a table with needed regexes], just run :TableModeEnable (or :TableModeToggle since g:table_mode_always_active = 0) to show the default and custom highlights.

Pros:

  • Works

Cons:

  • [None]

Option B. Via TableModeEnabled if g:table_mode_always_active = 0 (default)

autocmd User TableModeEnabled call g:TableModeColorCellsCustom()
autocmd User TableModeEnabled echo "DBG: Table Mode Enabled!"

Run :TableModeEnable (or :TableModeToggle since g:table_mode_always_active = 0) once.
The custom highlights will NOT work (for now) because next plugin chunk runs as soon as TableModeEnabled is fired.
See tablemode.vim#L72

function! s:ToggleSyntax() "{{{2
  if !g:table_mode_syntax | return | endif

  if tablemode#IsActive()
    let s:table_mode_syntax_dict = tablemode#utils#get_buffer_or_global_option('table_mode_syntax_dict')
    execute 'syntax match Table'
      \ '/' . tablemode#table#StartExpr() . '\zs|.\+|\ze' . tablemode#table#EndExpr() . '/'
      \ 'contains=' . s:table_mode_syntax_dict.contains
      \ 'containedin=' . s:table_mode_syntax_dict.containedin

While the user VIMRC autocmd User TableModeEnabled runs afterwards. So, the sequential is:

  1. The plugin chunk above runs. So g:table_mode_syntax_dict is created and also the Table syntax based on this global variable. We see only the default Table syntax highlights (table cells starting with yes in green, starting with no in red,...).
  2. The VIMRC autocmd updates g:table_mode_syntax_dict and run the new syntax match <whatever>Cell lines.
  3. Nothing more. The custom [Table cells] highlights are not colored as desired because the execute 'syntax match Table' lines have not run yet [i.e. that line has not run after [execute 'syntax match Table'](g:table_mode_syntax_dict) is updated].

Therefore, s:ToggleSyntax() must be called once more since the update of g:table_mode_syntax_dict was executed after the ToggleSyntax function run. We can achieve this via:

  • Run :TableModeToggle twice more.
  • Run :TableModeEnable [this will do nothing since this mode was already enabled]

TLDR:

  1. Open a TXT buffer
  2. Run :TableModeToggle three times

Pros:

  • Works. In a tedious way that requires to run the same command 3 times, but it works.

Cons:

  • The mentioned tedious steps

Workaround:

  • Create a function that runs :TableModeToggle three times, with some delays in between. Though this is a little hacky, ad-hoc, suboptimal... and it's not a plugin function.

Option C. Via VimEnter if g:table_mode_always_active = 1

Idk. I don't aim to auto-enable this plugin on startup.

Option D. Via TableModeEnabled if g:table_mode_always_active = 1

Idk. I don't aim to auto-enable this plugin on startup.

Customize the Table cell highlights live

What does live mean here?
In a big table or in a never read before we are not sure what we will see. As we read it we find newer cell regexes that we want to highlight (or disable older regexes highlights).

How to use it

The usage is explained with next example. For now I explain what the user must do, not what VIM does.

  1. VIMRC code in Option A. Except that initially our VIMRC holds no longer the g:TableModeColorCellsCustom() function declaration, instead those code lines reside in an isolated vimscript. And actually, for this example, it has just one custom cell highlight:
function! g:TableModeColorCellsCustom()
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell'

  syntax clear highPriorityCell " Never comment this line
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained " Comment if desired
endfunction

Just run :TableModeToggle to see the [default and] custom table-cell highlights. In this sceneario just highPriorityCell is custom.

  1. After some overview of the table content we think that we also need a syntax highlight for the "complete" cells. Thus, the isolated script becomes:
function! g:TableModeColorCellsCustom()
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell'

  syntax clear highPriorityCell " Never comment this line
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained " Comment if desired

  syntax clear completeCell " Never comment this line
  syntax match completeCell /|\@<= *X[^|]*/ contained
endfunction

Then, somehow we source this edited vim script. Note, later we see how calling :TableModeToggle twiceonce of next step will automatically source the vim script.

Run :TableModeToggle twice to see the completeCell highlights too.

  1. On the other hand, if we want to unset some highlights, then we must clear it. I.e. just comment the desired syntax match line. Now we both added a third custom regex and also disabled the first one:
function! g:TableModeColorCellsCustom()
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'

  syntax clear highPriorityCell " Never comment this line
  " syntax match highPriorityCell /|\@<= *\![^|]*/ contained " Comment if desired

  syntax clear completeCell " Never comment this line
  syntax match completeCell /|\@<= *X[^|]*/ contained

  syntax clear infoCell " Never comment this line
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction

Run :TableModeToggle twice to see the infoCell highlights too and no longer special highlights for highPriority-cells.

Note. We did not rewrite to (removing whats strikethrough-ed): let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'. An unset cell highlighted (syntax match line commented) can carry on be appended again in the g:table_mode_syntax_dict.contains list. This makes no error, and the rest of cell highlights will still work. More details about the list duplicated items in later section called "Avoid duplicates. A new ToDo".

How to enable this

In a script (e.g. <path>/vim-table-mode/TableModeColorCellsCustom.vim) declare next TableModeColorCellsCustom function. It must be in an isolated script to later be able to source it as we live edit it.

function! g:TableModeColorCellsCustom()
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'

  syntax clear highPriorityCell " Never comment this line
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained " Comment if desired

  syntax clear completeCell " Never comment this line
  syntax match completeCell /|\@<= *X[^|]*/ contained

  syntax clear infoCell " Never comment this line
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction

In a script auto-source by VIMRC (e.g. <path>/vim-table-mode/settings.vim) set alike in previous option A. Via VimEnter:

let g:table_mode_always_active = 0 " default
let g:table_mode_color_cells = 1

let s:CWD = fnamemodify(resolve(expand('<sfile>:p')), ':h')
execute 'source ' . s:CWD . '/TableModeColorCellsCustom.vim'

" On VimEnter use the initial table-cell highlighting of ./TableModeColorCellsCustom.vim
" If g:table_mode_always_active = 0 (default)
autocmd VimEnter * call timer_start(10, {-> g:TableModeColorCellsCustom()}) " Delay 10ms to let the plugin load
" Open the table script and run :TableModeToggle

So the [default and] custom cell highlights are enabled on VimEnter (if we run :TableModeToggle once).

And also add to this same script (e.g. <path>/vim-table-mode/settings.vim):

" Later, if we modify the table-cell highlighting, then we can use the following

" ❌ Opt. X: Via BufEnter. NOT working
if v:false
  autocmd BufEnter echo "DBG: BufEnter!"
  autocmd BufEnter execute 'source ' . s:CWD . '/TableModeColorCellsCustom.vim' " The function is re-defined (re-sourced)!
  autocmd BufEnter call timer_start(10, {-> g:TableModeColorCellsCustom()}) " 10ms delay is needed/recommended
  autocmd BufEnter call timer_start(10, {-> g:EchoFunctionLinesByName('g:TableModeColorCellsCustom')}) " DGB, test if fcn is re-defined
endif

" ✅ Opt. Y: Via TableModeDisabled
" Note this autocmd is not executed at VimEnter nor BufEnter, which is as we want
if v:true
  autocmd User TableModeDisabled echo "DBG: Table Mode Disbled!"
  autocmd User TableModeDisabled execute 'source ' . s:CWD . '/TableModeColorCellsCustom.vim  " Comment: The function is re-defined (re-sourced)!'
  autocmd User TableModeDisabled call timer_start(10, {-> g:TableModeColorCellsCustom()}) " 10ms delay is needed/recommended
  autocmd User TableModeDisabled call timer_start(10, {-> g:EchoFunctionLinesByName('g:TableModeColorCellsCustom')}) " DGB, test if fcn is re-defined
endif
EchoFunctionLinesByName declaration - Click to expand
function! EchoFunctionLinesByName(func_name)
  " Check if the function exists
  if !exists('*' . a:func_name)
    echohl ErrorMsg
    echo 'Function "' . a:func_name . '" not found'
    echohl None
    return
  endif
  " Save current more setting and disable it
  let l:more = &more
  set nomore
  " Display function definition directly
  execute 'function ' . a:func_name
  " Restore more setting
  let &more = l:more
endfunction
" Usage example (commented out to prevent automatic execution)
" call EchoFunctionLinesByName('g:TableModeColorCellsCustom')
Opt. X

I could not make the live edit work via option X (autocmd BufEnter).
I am not even sure if some BufEnter trigger also a VimEnter, and thus we would call g:TableModeColorCellsCustom() at VimEnter (which makes no error but is a duplicated action).

  • ?? Via :edit for example ??
  • ?? Or if multi-buffer session then :bd the table buffer script (e.g. a TXT) followed by :tabnew <dirname>/<basename>. Here autocmd BufEnter is triggered (I think) ??
  • ?? :qa ?? But then autocmd VimEnter is triggered for sure.

Opt. X might not be a good approach anyhow, I am not sure. I am not confident using the autocmd BufEnter.

Opt. Y

If you read previous Option B (via TableModeEnabled) then you can understand what Vim does (option Y):

  1. Edit properly <path>/vim-table-mode/TableModeColorCellsCustom.vim to not initial cell highlights requirements
  2. Run :TableModeToggle to let the autocmd User TableModeDisabled lines run.
  3. Run :TableModeToggle once more to see the new custom cell highlights too.

If desired, one can combine steps 2 and 3 in just a command via an almost exactly workaround as described before:

  • Create a function that runs :TableModeToggle threetwo times, with some delays in between. Though this is a little hacky, ad-hoc, suboptimal... and it's not a plugin function.

Questions

  • Is option Y a good approach? Can it be leveraged?
  • Is rather X a better way? How to make it work?
  • An alternative to call :TableModeToggle twice? Not to mention the previous hacky workaround.

Avoid duplicates. A new ToDo

Every time that TableModeEnabled is triggered then g:TableModeColorCellsCustom() runs, and therefore the 2nd and so on times that this runs then:

  • It runs again syntax match <whatever>Cell lines. Which is inefficient, if we already did set this. But its necessary because we run syntax clear (for commodity to later quick remove a highlight just commenting its syntax match line).
  • It runs again let g:table_mode_syntax_dict.contains .= appending more strings to an array that already had those strings. E.g. the 1st call echo g:table_mode_syntax_dict prints {'containedin': 'ALL', 'contains': 'TableBorder, TableSeparator, [...], darkCell,highPriorityCell,completeCell, infoCell'}, the 2nd time it echoes {'containedin': 'ALL', 'contains': 'TableBorder, TableSeparator, [...], darkCell,highPriorityCell, completeCell, infoCell, highPriorityCell, completeCell, infoCell'}, etc. In an alike Python set structure this would not happen, duplicate values are not allowed, but I don't know how to fix g:table_mode_syntax_dict.contains to be alike that set.

@juanMarinero
Copy link
Contributor Author

Amend. @dhruvasagar I forgot to tag you. My bad.

@juanMarinero
Copy link
Contributor Author

juanMarinero commented Sep 5, 2025

  • Avoid duplicates

From my last comment I must fix:

It runs again let g:table_mode_syntax_dict.contains .= appending more strings to an array that already had those strings.

It should be:
It runs again let g:table_mode_syntax_dict.contains .= appending more [sub-]strings to an array string that might already had those [sub-]strings.

Solution. Edit e.g. <path>/vim-table-mode/TableModeColorCellsCustom.vim

function! g:TableModeColorCellsCustom()
  if v:true " ‼️‼️
    " Expand string
    let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'
    " let g:table_mode_syntax_dict.contains .= ',highPriorityCell,xxxCell'
  else
    " Get default string just once
    if !exists('g:table_mode_syntax_contains_default')
      let g:table_mode_syntax_contains_default = g:table_mode_syntax_dict.contains
    endif
    " Alternative, edit the default string directly (hard-copy)
    if v:false
      let g:table_mode_syntax_contains_default = 'TableBorder,TableSeparator,TableColumnAlign'
      let g:table_mode_syntax_contains_default .= ',yesCell,noCell,maybeCell'
      let g:table_mode_syntax_contains_default .= ',redCell,greenCell,yellowCell,blueCell,whiteCell,darkCell'
    endif

    " Overwrite
    let g:table_mode_syntax_dict.contains = g:table_mode_syntax_contains_default

    " Expand
    let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'
    " let g:table_mode_syntax_dict.contains .= ',highPriorityCell,xxxCell'
  endif

  " Sort and apply unique ‼️‼️
  let g:table_mode_syntax_dict.contains = s:StringSortedUnique(g:table_mode_syntax_dict.contains)

  syntax clear highPriorityCell " Never comment this line
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained " Comment if desired

  syntax clear completeCell " Never comment this line
  syntax match completeCell /|\@<= *X[^|]*/ contained

  syntax clear infoCell " Never comment this line
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction

function! s:StringSortedUnique(input) abort
  " Split string into array
  let arr = split(a:input, ',')
  " Trim spaces
  let arr = map(arr, 'trim(v:val)')
  " Sort and apply unique
  let arr = uniq(sort(arr))
  " Rejoin to a string
  return join(arr, ',')
endfunction

Note. Ideally, StringSortedUnique function should be written in other vim-script. If so then source that script and change in its definition and calls the s: with g:.

Test:

  1. Open Vim in a TXT file
  2. :echo g:table_mode_syntax_dict.contains should output for example the string
    TableBorder,TableSeparator,TableColumnAlign,yesCell,noCell,maybeCell,redCell,greenCell,yellowCell,blueCell,whiteCell,darkCell,highPriorityCell,completeCell,infoCell
  3. Run :TableModeToggle once, or three times, or five times,... Each reset of syntax match Table's contains still prints same :echo g:table_mode_syntax_dict.contains.

A more real test:

  1. [same]
  2. [same]
  3. Run :TableModeToggle to check visually that the Table-cell highlights work
  4. Edit let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell' of function! g:TableModeColorCellsCustom() as needed. E.g. removing all customes but highPriorityCell and adding a xxxCell: let g:table_mode_syntax_dict.contains .= ',highPriorityCell,xxxCell'
  5. Run :TableModeToggle an odd even number of times (twice is enough)
  6. :echo g:table_mode_syntax_dict.contains should still have no duplicates of default Table-cell highlights substrings nor duplicate of highPriorityCell, while xxxCell should be [sorted] added.

Notice that the if v:true chunk just expanded the let g:table_mode_syntax_dict.contains string via .=. Thus in previous step 5 we would still see the completeCell and infoCell highlights (and in step 6 they are still substrings of the string). To no see their highlights I explained in my last comment that the lines syntax match completeCell and syntax match infoCell lines of the TableModeColorCellsCustom functions should be commented.

An alternative is the else (to the if v:true), which is triggered if edited to if v:false. Now the string is first re-set and afterwards expanded (previously was just expanded). In this scenario editing the line of custom Table-cell highlights (let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell') is enough, no need to comment any syntax match line.

This later approach even lets the user edit the default highlights!
Just:

  1. Set v:true the block preceded with comment " Alternative, edit the default string directly ([...])
  2. And remove the undesired default highlights.

I recommend this later approach whose <path>/vim-table-mode/TableModeColorCellsCustom.vim is simplified to:

function! g:TableModeColorCellsCustom()
  " Get default string just once
  if !exists('g:table_mode_syntax_contains_default')
    let g:table_mode_syntax_contains_default = g:table_mode_syntax_dict.contains
  endif
  " Alternative, edit the default string directly (hard-copied from plugin's scripts)
  if v:false
    let g:table_mode_syntax_contains_default = 'TableBorder,TableSeparator,TableColumnAlign'
    let g:table_mode_syntax_contains_default .= ',yesCell,noCell,maybeCell'
    let g:table_mode_syntax_contains_default .= ',redCell,greenCell,yellowCell,blueCell,whiteCell,darkCell'
  endif

  " Overwrite
  let g:table_mode_syntax_dict.contains = g:table_mode_syntax_contains_default

  " Expand
  let g:table_mode_syntax_dict.contains .= ',highPriorityCell,completeCell,infoCell'
  " let g:table_mode_syntax_dict.contains .= ',highPriorityCell,xxxCell'

  " Sort and apply unique
  let g:table_mode_syntax_dict.contains = s:StringSortedUnique(g:table_mode_syntax_dict.contains)

  syntax clear highPriorityCell " Never comment this line
  syntax match highPriorityCell /|\@<= *\![^|]*/ contained " Comment if desired

  syntax clear completeCell " Never comment this line
  syntax match completeCell /|\@<= *X[^|]*/ contained

  syntax clear infoCell " Never comment this line
  syntax match infoCell /|\@<= *\/\/[^|]*/ contained
endfunction

function! s:StringSortedUnique(input) abort
  " Split string into array
  let arr = split(a:input, ',')
  " Trim spaces
  let arr = map(arr, 'trim(v:val)')
  " Sort and apply unique
  let arr = uniq(sort(arr))
  " Rejoin to a string
  return join(arr, ',')
endfunction

@dhruvasagar please read this comment too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants