9de8543385
A literal `<span style="color:…">` in prose (the sample wiki's own colorize instructions used one, with a `…` ellipsis as the colour) was matched by the scanner and fed to `highlight guifg=…`, which raised E254 on the un-silenced guifg line. That aborted the whole nuwiki#colors#refresh(), so on the Vim clients NO spans got concealed (start-vim) and follow-link crashed mid FileType autocmd (start-vim-coc). Neovim happened to dodge it depending on which buffer was scanned. s:define() now: - validates the colour (only #hex or an alphabetic name) and skips anything else — rgb()/hsl() functions and prose examples no longer create bogus conceal regions or errors; - runs both `highlight` calls under `silent!`, so a valid-format but unknown name can't abort the refresh either (tags still conceal, text just isn't recoloured). Also reworded the sample wiki's colorize note so it no longer embeds a literal span tag. Test: colorize.skips_unallocatable_colour (vim) — an rgb() span before a real one: refresh doesn't error, the rgb span isn't concealed, the real span still is. nvim 269, vim 260+18, all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
70 lines
2.9 KiB
VimL
70 lines
2.9 KiB
VimL
" autoload/nuwiki/colors.vim — conceal colour spans down to their text.
|
|
"
|
|
" `:VimwikiColorize NAME` wraps text in `<span style="color:NAME">TEXT</span>`.
|
|
" This hides the two tags (conceal) and paints TEXT in NAME, so the buffer
|
|
" shows just the coloured word — matching how the HTML export renders it.
|
|
"
|
|
" Pure syntax + `:highlight`, no LSP needed, so it works the same in Vim,
|
|
" coc.nvim, and Neovim. New colours appear as the user runs :VimwikiColorize,
|
|
" so the ftplugin re-runs refresh() on text changes; we track which colours
|
|
" already have a syntax group in b:nuwiki_color_seen to stay idempotent.
|
|
|
|
" Scan the buffer for `<span style="color:…">` and define a concealing,
|
|
" colouring syntax region for each colour not yet seen.
|
|
function! nuwiki#colors#refresh() abort
|
|
if !exists('b:nuwiki_color_seen')
|
|
let b:nuwiki_color_seen = {}
|
|
endif
|
|
let l:n = line('$')
|
|
let l:lnum = 1
|
|
while l:lnum <= l:n
|
|
let l:line = getline(l:lnum)
|
|
if stridx(l:line, '<span style="color:') >= 0
|
|
let l:pos = 0
|
|
while 1
|
|
let l:mp = matchstrpos(l:line, '<span style="color:[^"]\{-}">', l:pos)
|
|
if l:mp[1] < 0
|
|
break
|
|
endif
|
|
let l:pos = l:mp[2]
|
|
call s:define(matchstr(l:mp[0], 'color:\zs[^"]\{-}\ze">'))
|
|
endwhile
|
|
endif
|
|
let l:lnum += 1
|
|
endwhile
|
|
endfunction
|
|
|
|
" Define (once per colour) a region that conceals `<span …>` / `</span>` and
|
|
" paints the wrapped text in that colour.
|
|
function! s:define(color) abort
|
|
if a:color ==# '' || has_key(b:nuwiki_color_seen, a:color)
|
|
return
|
|
endif
|
|
let b:nuwiki_color_seen[a:color] = 1
|
|
" Only handle colours Vim can actually allocate: a #hex value or an
|
|
" alphabetic name. Anything else — rgb()/hsl() functions, or a literal
|
|
" `<span style="color:…">` that turns up in prose/examples — is skipped, so
|
|
" a stray match can't create a bogus conceal region or abort the refresh.
|
|
if a:color !~# '^#\x\{3,8}$' && a:color !~# '^[A-Za-z][A-Za-z0-9]*$'
|
|
return
|
|
endif
|
|
let l:grp = 'nuwikiColorSpan_' . substitute(a:color, '[^A-Za-z0-9]', '_', 'g')
|
|
let l:esc = escape(a:color, '/\.*$^~[]')
|
|
" Clear first so re-runs / load-order never stack duplicate regions.
|
|
silent! execute 'syntax clear ' . l:grp
|
|
" `concealends` hides the start/end matches (the tags); the region body
|
|
" (the text) keeps the l:grp highlight. `oneline` since spans don't wrap.
|
|
execute 'syntax region ' . l:grp
|
|
\ . ' matchgroup=Conceal'
|
|
\ . ' start=/<span style="color:' . l:esc . '">/'
|
|
\ . ' end=#</span>#'
|
|
\ . ' oneline keepend concealends'
|
|
" guifg works for names and #hex under 'termguicolors'; ctermfg only for
|
|
" named colours. Both are best-effort — `silent!` swallows E254 for a name
|
|
" Vim doesn't know (the tags still conceal, the text just isn't recoloured).
|
|
silent! execute 'highlight default ' . l:grp . ' guifg=' . a:color
|
|
if a:color !~# '^#'
|
|
silent! execute 'highlight ' . l:grp . ' ctermfg=' . a:color
|
|
endif
|
|
endfunction
|