fix(client): colour-span conceal must skip unallocatable colours
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>
This commit is contained in:
@@ -41,6 +41,13 @@ function! s:define(color) abort
|
|||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
let b:nuwiki_color_seen[a:color] = 1
|
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:grp = 'nuwikiColorSpan_' . substitute(a:color, '[^A-Za-z0-9]', '_', 'g')
|
||||||
let l:esc = escape(a:color, '/\.*$^~[]')
|
let l:esc = escape(a:color, '/\.*$^~[]')
|
||||||
" Clear first so re-runs / load-order never stack duplicate regions.
|
" Clear first so re-runs / load-order never stack duplicate regions.
|
||||||
@@ -52,9 +59,10 @@ function! s:define(color) abort
|
|||||||
\ . ' start=/<span style="color:' . l:esc . '">/'
|
\ . ' start=/<span style="color:' . l:esc . '">/'
|
||||||
\ . ' end=#</span>#'
|
\ . ' end=#</span>#'
|
||||||
\ . ' oneline keepend concealends'
|
\ . ' oneline keepend concealends'
|
||||||
" guifg works for names and #hex under 'termguicolors'. ctermfg only accepts
|
" guifg works for names and #hex under 'termguicolors'; ctermfg only for
|
||||||
" named colours, so try it for non-hex and swallow E254 for unknown names.
|
" named colours. Both are best-effort — `silent!` swallows E254 for a name
|
||||||
execute 'highlight default ' . l:grp . ' guifg=' . a:color
|
" 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 !~# '^#'
|
if a:color !~# '^#'
|
||||||
silent! execute 'highlight ' . l:grp . ' ctermfg=' . a:color
|
silent! execute 'highlight ' . l:grp . ' ctermfg=' . a:color
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -97,9 +97,9 @@ super^script^ and sub,,script,,, and inline math $e^{i\pi} + 1 = 0$.
|
|||||||
|
|
||||||
Put the cursor on a word and run `:VimwikiColorize red` (or press
|
Put the cursor on a word and run `:VimwikiColorize red` (or press
|
||||||
`<Leader>wc` and type a colour); or visually select a phrase and press
|
`<Leader>wc` and type a colour); or visually select a phrase and press
|
||||||
`<Leader>wc`. Each wraps the target in `<span style="color:…">…</span>` —
|
`<Leader>wc`. Each wraps the target in an inline colour-span tag whose
|
||||||
the tags are concealed, so you see just the word painted in that colour
|
markup is concealed, so you see just the word painted in that colour (move
|
||||||
(move the cursor onto it to reveal the raw markup).
|
the cursor onto it to reveal the raw markup).
|
||||||
|
|
||||||
- colorize this important word
|
- colorize this important word
|
||||||
- now select and colour this whole phrase
|
- now select and colour this whole phrase
|
||||||
|
|||||||
@@ -545,6 +545,24 @@ call s:record(
|
|||||||
\ 'concealed=' . synconcealed(1, 1)[0]
|
\ 'concealed=' . synconcealed(1, 1)[0]
|
||||||
\ . ' grp=' . synIDattr(synID(1, stridx(s:cz_l2, 'target') + 1, 1), 'name'))
|
\ . ' grp=' . synIDattr(synID(1, stridx(s:cz_l2, 'target') + 1, 1), 'name'))
|
||||||
|
|
||||||
|
" A span whose colour Vim can't allocate (rgb()/prose) must be skipped — not
|
||||||
|
" abort refresh, not conceal — while a real span afterwards still conceals.
|
||||||
|
call s:set_buf(['plain', 'x <span style="color:rgb(1,2,3)">y</span> z', '<span style="color:red">word</span> z'])
|
||||||
|
call cursor(1, 1)
|
||||||
|
let s:cz_e = ''
|
||||||
|
try
|
||||||
|
call nuwiki#colors#refresh()
|
||||||
|
catch
|
||||||
|
let s:cz_e = v:exception
|
||||||
|
endtry
|
||||||
|
call s:record(
|
||||||
|
\ s:cz_e ==# ''
|
||||||
|
\ && synconcealed(3, 1)[0] == 1
|
||||||
|
\ && synconcealed(2, stridx(getline(2), '<span') + 1)[0] == 0 ? 1 : 0,
|
||||||
|
\ 'colorize.skips_unallocatable_colour',
|
||||||
|
\ 'err=' . s:cz_e . ' real=' . synconcealed(3, 1)[0]
|
||||||
|
\ . ' rgb=' . synconcealed(2, stridx(getline(2), '<span') + 1)[0])
|
||||||
|
|
||||||
" ===== Follow-link resolves + opens in the current window (regression) =====
|
" ===== Follow-link resolves + opens in the current window (regression) =====
|
||||||
" follow_link_or_create() must resolve the definition itself and `:edit` the
|
" follow_link_or_create() must resolve the definition itself and `:edit` the
|
||||||
" target in the CURRENT window — including a page that does not exist yet
|
" target in the CURRENT window — including a page that does not exist yet
|
||||||
|
|||||||
Reference in New Issue
Block a user