Steps to reproduce
- Create a markdown file with a multibyte heading, e.g. a single line # 中文标题
- :set filetype=markdown
- :colorscheme default — the fuzzy-match highlight uses the IncSearch group; some colorschemes make it indistinguishable from the surrounding text, so a default colorscheme makes the effect visible
- :packadd helptoc | HelpToc
- Press / and type 标题
Actual behaviour
The highlight lands on the wrong column — it overlaps a neighboring character and splits a multibyte character (only the first byte of the 3-byte UTF-8 char is highlighted).
Expected behaviour
Each matched character 标 and 题 is highlighted (via the help-fuzzy-toc text property, IncSearch).
Cause
matchfuzzypos() returns match positions as character indices (:h matchfuzzypos(): "list of character positions ... You can use byteidx() to convert a character position to a byte position"). But text property col/length are in bytes (:h prop_add(), :h popup-props: "counted in bytes").
In runtime/pack/dist/opt/helptoc/autoload/helptoc.vim, FuzzySearch():
props: pos[i]->copy()->map((_, col: number) => ({
col: col + 1,
length: 1,
type: 'help-fuzzy-toc',
}))
col + 1 treats a character index as a byte column, and length: 1 is one byte instead of the byte length of the matched character. This is only correct for pure-ASCII text (where character index equals byte index), which is why it goes unnoticed in English help files.
Suggested fix
Convert character indices to byte offsets with byteidx() and use each matched character's byte length:
props: pos[i]->copy()->map((_, cp: number) => {
const col = byteidx(match.text, cp) + 1
const len = byteidx(match.text, cp + 1) - byteidx(match.text, cp)
return {col: col, length: len, type: 'help-fuzzy-toc'}
})
Version of Vim
9.2.0907
Environment
- Windows 10
- gvim 9.2.0907 (also present in 9.1)
Logs and stack traces
Steps to reproduce
Actual behaviour
The highlight lands on the wrong column — it overlaps a neighboring character and splits a multibyte character (only the first byte of the 3-byte UTF-8 char is highlighted).
Expected behaviour
Each matched character 标 and 题 is highlighted (via the help-fuzzy-toc text property, IncSearch).
Cause
matchfuzzypos() returns match positions as character indices (:h matchfuzzypos(): "list of character positions ... You can use byteidx() to convert a character position to a byte position"). But text property col/length are in bytes (:h prop_add(), :h popup-props: "counted in bytes").
In runtime/pack/dist/opt/helptoc/autoload/helptoc.vim, FuzzySearch():
col + 1 treats a character index as a byte column, and length: 1 is one byte instead of the byte length of the matched character. This is only correct for pure-ASCII text (where character index equals byte index), which is why it goes unnoticed in English help files.
Suggested fix
Convert character indices to byte offsets with byteidx() and use each matched character's byte length:
Version of Vim
9.2.0907
Environment
Logs and stack traces