[vim/vim] Wide unicode chars in -completelist kind make scrollbar broken (Issue #20124)

18 views
Skip to first unread message

Maxim Kim

unread,
May 2, 2026, 11:46:15 PM (9 days ago) May 2
to vim/vim, Subscribed
habamax created an issue (vim/vim#20124)

Steps to reproduce

image.png (view on web)
  1. vim -Nu NONE +"set wildoptions=pum"

  2. execute following:

vim9script

var subset = [
    {value: 0x324B, name: 'CIRCLED NUMBER FORTY ON BLACK SQUARE'},
    {value: 0x324C, name: 'CIRCLED NUMBER FIFTY ON BLACK SQUARE'},
    {value: 0x324D, name: 'CIRCLED NUMBER SIXTY ON BLACK SQUARE'},
    {value: 0x324E, name: 'CIRCLED NUMBER SEVENTY ON BLACK SQUARE'},
    {value: 0x324F, name: 'CIRCLED NUMBER EIGHTY ON BLACK SQUARE'},
    {value: 0x3250, name: 'PARTNERSHIP SIGN'},
    {value: 0x3251, name: 'CIRCLED NUMBER TWENTY ONE'},
    {value: 0x3252, name: 'CIRCLED NUMBER TWENTY TWO'},
    {value: 0x3253, name: 'CIRCLED NUMBER TWENTY THREE'},
    {value: 0x3254, name: 'CIRCLED NUMBER TWENTY FOUR'},
    {value: 0x3255, name: 'CIRCLED NUMBER TWENTY FIVE'},
    {value: 0x3256, name: 'CIRCLED NUMBER TWENTY SIX'},
    {value: 0x3257, name: 'CIRCLED NUMBER TWENTY SEVEN'},
    {value: 0x3258, name: 'CIRCLED NUMBER TWENTY EIGHT'},
    {value: 0x3259, name: 'CIRCLED NUMBER TWENTY NINE'},
    {value: 0x325A, name: 'CIRCLED NUMBER THIRTY'},
    {value: 0x325B, name: 'CIRCLED NUMBER THIRTY ONE'},
    {value: 0x325C, name: 'CIRCLED NUMBER THIRTY TWO'},
    {value: 0x325D, name: 'CIRCLED NUMBER THIRTY THREE'},
    {value: 0x325E, name: 'CIRCLED NUMBER THIRTY FOUR'},
    {value: 0x325F, name: 'CIRCLED NUMBER THIRTY FIVE'},
    {value: 0x32B1, name: 'CIRCLED NUMBER THIRTY SIX'},
    {value: 0x32B2, name: 'CIRCLED NUMBER THIRTY SEVEN'},
    {value: 0x32B3, name: 'CIRCLED NUMBER THIRTY EIGHT'},
    {value: 0x32B4, name: 'CIRCLED NUMBER THIRTY NINE'},
    {value: 0x32B5, name: 'CIRCLED NUMBER FORTY'},
    {value: 0x1D133, name: 'MUSICAL SYMBOL QUARTER TONE FLAT'},
    {value: 0x1D134, name: 'MUSICAL SYMBOL COMMON TIME'},
    {value: 0x1D135, name: 'MUSICAL SYMBOL CUT TIME'},
    {value: 0x1D136, name: 'MUSICAL SYMBOL OTTAVA ALTA'},
    {value: 0x1D137, name: 'MUSICAL SYMBOL OTTAVA BASSA'},
    {value: 0x1D138, name: 'MUSICAL SYMBOL QUINDICESIMA ALTA'},
    {value: 0x1D139, name: 'MUSICAL SYMBOL QUINDICESIMA BASSA'},
    {value: 0x1D13A, name: 'MUSICAL SYMBOL MULTI REST'},
    {value: 0x1D13B, name: 'MUSICAL SYMBOL WHOLE REST'},
    {value: 0x1D13C, name: 'MUSICAL SYMBOL HALF REST'},
    {value: 0x1D13D, name: 'MUSICAL SYMBOL QUARTER REST'},
    {value: 0x1D13E, name: 'MUSICAL SYMBOL EIGHTH REST'},
    {value: 0x1D13F, name: 'MUSICAL SYMBOL SIXTEENTH REST'},
    {value: 0x1D140, name: 'MUSICAL SYMBOL THIRTY-SECOND REST'},
    {value: 0x1D141, name: 'MUSICAL SYMBOL SIXTY-FOURTH REST'},
    {value: 0x1D142, name: 'MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST'},
    {value: 0x1D153, name: 'MUSICAL SYMBOL MOON NOTEHEAD BLACK'},
    {value: 0x1D154, name: 'MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE'},
    {value: 0x1D155, name: 'MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK'},
    {value: 0x1FBC7, name: 'STICK FIGURE LEANING LEFT'},
    {value: 0x1FBC8, name: 'STICK FIGURE LEANING RIGHT'},
    {value: 0x1FBC9, name: 'STICK FIGURE WITH DRESS'},
    {value: 0x1FBCA, name: 'WHITE UP-POINTING CHEVRON'},
    {value: 0x1FBF0, name: 'SEGMENTED DIGIT ZERO'},
    {value: 0x1FBF1, name: 'SEGMENTED DIGIT ONE'},
    {value: 0x1FBF2, name: 'SEGMENTED DIGIT TWO'},
    {value: 0x1FBF3, name: 'SEGMENTED DIGIT THREE'},
    {value: 0x1FBF4, name: 'SEGMENTED DIGIT FOUR'},
    {value: 0x1FBF5, name: 'SEGMENTED DIGIT FIVE'},
    {value: 0x1FBF6, name: 'SEGMENTED DIGIT SIX'},
    {value: 0x1FBF7, name: 'SEGMENTED DIGIT SEVEN'},
    {value: 0x1FBF8, name: 'SEGMENTED DIGIT EIGHT'},
    {value: 0x1FBF9, name: 'SEGMENTED DIGIT NINE'},
]


command! -nargs=1 -complete=customlist,TestComplete Test echo <q-args>
def TestComplete(arg: string, _, _): list<dict<any>>
    var ulist = subset->mapnew((_, v) => {
        return {
            word: printf("%04X", v.value),
            abbr: v.name,
            kind: printf("%6s", (nr2char(v.value, true) =~ '\p' ? nr2char(v.value, true) : " ")),
            menu: printf("%04X", v.value)}
    })
    if empty(arg)
        return ulist
    else
        return ulist->matchfuzzy(arg ?? '', {key: "abbr"})
    endif
enddef
  1. run :Test <tab>
image.png (view on web)

Expected behaviour

Scrollbar should not be broken

@mattn fyi

Version of Vim

9.2.433

Environment

debian 13,bash

Logs and stack traces


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124@github.com>

Maxim Kim

unread,
May 3, 2026, 12:06:22 AM (8 days ago) May 3
to vim/vim, Subscribed
habamax left a comment (vim/vim#20124)

It is not happening with gvim though, so I guess this is related to font&terminal and not to vim directly.

The original issue is in alacritty, simple terminal and xterm are better here, however still with issues.

image.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4365355269@github.com>

Mao-Yining

unread,
May 3, 2026, 8:37:58 AM (8 days ago) May 3
to vim/vim, Subscribed
mao-yining left a comment (vim/vim#20124)

I use FiraCode_Nerd_Font in Windows Terminal.

Magically, this also seems to be related to the characters in the background:

With characters:
default.png (view on web)

Without characters:
default.png (view on web)

@habamax On a side note, if you store the data as a tuple <number, string>, generating the completion string will be faster. This way, you won't need both the 'sub' and 'all' dictionaries.

Like: https://codeberg.org/mao-yining/dotfile_vim/src/branch/main/autoload/unicode.vim#L37807-L37808


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4366184650@github.com>

mattn

unread,
May 3, 2026, 12:22:05 PM (8 days ago) May 3
to vim/vim, Subscribed
mattn left a comment (vim/vim#20124)

Hi @habamax, before digging into Vim itself I'd like to rule out a width mismatch between Vim and your terminal/font. The kind column in your example mixes characters with different East Asian Width properties:

  • U+324B..U+324F (CIRCLED NUMBER FORTY..EIGHTY ON BLACK SQUARE) → EAW=A (Ambiguous). Vim treats these as 1 cell unless 'ambiwidth' is double, but many terminals/fonts render them as 2 cells.
  • U+3250..U+325F, U+32B1..U+32B5 → EAW=W (Wide). Vim agrees with terminals here.
  • U+1D133..U+1D155 (Musical Symbols), U+1FBC7..U+1FBCA, U+1FBF0..U+1FBF9 (Symbols for Legacy Computing) → EAW=N (Neutral). Vim treats them as 1 cell, but several Nerd Fonts (and some terminal fonts) render them as 2 cells.

If Vim's per-character width disagrees with what the terminal actually paints, the kind column overruns and the scrollbar column gets clobbered — which matches what you're seeing. The fact that it doesn't reproduce in gvim (where Vim measures glyphs itself) and that the result varies across terminals/fonts is also consistent with this.

Could you share the following so we can confirm?

:echo &ambiwidth &encoding &termencoding
:echo \$LANG \$LC_CTYPE

Plus the terminal name/version and the exact font you're using (the alacritty case and @mao-yining's Windows Terminal + FiraCode Nerd Font case may have different root causes).

As a quick test, could you try:

set ambiwidth=double
call setcellwidths([
      \ [0x1D133, 0x1D155, 2],
      \ [0x1FBC7, 0x1FBCA, 2],
      \ [0x1FBF0, 0x1FBF9, 2],
      \ ])

and see whether the scrollbar renders correctly. If it does, this is a font/terminal width mismatch rather than a Vim bug, and setcellwidths() is the intended escape hatch.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4366615927@github.com>

mattn

unread,
May 3, 2026, 12:30:35 PM (8 days ago) May 3
to vim/vim, Subscribed
mattn left a comment (vim/vim#20124)

By the way, if you'd like a fast way to figure out the right setcellwidths() table for your specific terminal+font combination, this script measures actual rendered widths via DSR cursor queries:

https://gist.github.com/mattn/9ba20cdde89198814dde40b0b6aca3fa

Run it in the terminal you're seeing the issue in:

python measure.py | tee ambiwidth.vim

Then :source ambiwidth.vim (or load it from your vimrc) — it emits the correct setcellwidths(...) calls based on what your terminal actually paints. That should make Vim's per-character width agree with your terminal and fix the scrollbar rendering.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4366633020@github.com>

Maxim Kim

unread,
May 3, 2026, 7:21:20 PM (8 days ago) May 3
to vim/vim, Subscribed
habamax left a comment (vim/vim#20124)

set ambiwidth=double


call setcellwidths([
\ [0x1D133, 0x1D155, 2],
\ [0x1FBC7, 0x1FBCA, 2],
\ [0x1FBF0, 0x1FBF9, 2],
\ ])

It doesn't help:

image.png (view on web)

:echo &ambiwidth &encoding &termencoding
:echo $LANG $LC_CTYPE

image.png (view on web)

ambiwidth is double here but this is due to previous check. Normally I have it default single.

Terminals: Windows Terminal, alacritty and xterm that are from debian 13 repositories (I don't have it at the moment so not sure what versions they are).


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4367428198@github.com>

zeertzjq

unread,
May 3, 2026, 7:23:21 PM (8 days ago) May 3
to vim/vim, Subscribed
zeertzjq left a comment (vim/vim#20124)

Does it work in kitty?


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4367431884@github.com>

Maxim Kim

unread,
May 3, 2026, 7:30:14 PM (8 days ago) May 3
to vim/vim, Subscribed
habamax left a comment (vim/vim#20124)

By the way, if you'd like a fast way to figure out the right setcellwidths() table for your specific terminal+font combination, this script measures actual rendered widths via DSR cursor queries:

https://gist.github.com/mattn/9ba20cdde89198814dde40b0b6aca3fa

Run it in the terminal you're seeing the issue in:

python measure.py | tee ambiwidth.vim

Then :source ambiwidth.vim (or load it from your vimrc) — it emits the correct setcellwidths(...) calls based on what your terminal actually paints. That should make Vim's per-character width agree with your terminal and fix the scrollbar rendering.

This didn't help with Windows terminal completely, some of the cases are still mangle with the scrollbar:

image.png (view on web)

But I believe this might be because of char coverage of the script.

I agree this probably has nothing to do with vim alone.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4367444219@github.com>

Maxim Kim

unread,
May 3, 2026, 10:25:02 PM (8 days ago) May 3
to vim/vim, Subscribed
habamax left a comment (vim/vim#20124)

I have removed following from customlist:

    # {value: 0x1F574, name: 'MAN IN BUSINESS SUIT LEVITATING'},
    # {value: 0x1F575, name: 'SLEUTH OR SPY'},
    # {value: 0x1D173, name: 'MUSICAL SYMBOL BEGIN BEAM'},
    # {value: 0x1D174, name: 'MUSICAL SYMBOL END BEAM'},
    # {value: 0x1D175, name: 'MUSICAL SYMBOL BEGIN TIE'},
    # {value: 0x1D176, name: 'MUSICAL SYMBOL END TIE'},
    # {value: 0x1D177, name: 'MUSICAL SYMBOL BEGIN SLUR'},
    # {value: 0x1D178, name: 'MUSICAL SYMBOL END SLUR'},
    # {value: 0x1D179, name: 'MUSICAL SYMBOL BEGIN PHRASE'},
    # {value: 0x1D17A, name: 'MUSICAL SYMBOL END PHRASE'},

and now no issues with the scrollbar.

With those chars:

image.png (view on web)
vim9script

var subset = [

    {value: 0x00BF, name: 'INVERTED QUESTION MARK'},
    {value: 0x00D7, name: 'MULTIPLICATION SIGN'},
    {value: 0x00F7, name: 'DIVISION SIGN'},
    {value: 0x2010, name: 'HYPHEN'},
    {value: 0x2011, name: 'NON-BREAKING HYPHEN'},
    {value: 0x2012, name: 'FIGURE DASH'},
    {value: 0x2013, name: 'EN DASH'},
    {value: 0x2014, name: 'EM DASH'},

    # these are the issues
    {value: 0x1F574, name: 'MAN IN BUSINESS SUIT LEVITATING'},
    {value: 0x1F575, name: 'SLEUTH OR SPY'},
    {value: 0x1D173, name: 'MUSICAL SYMBOL BEGIN BEAM'},
    {value: 0x1D174, name: 'MUSICAL SYMBOL END BEAM'},
    {value: 0x1D175, name: 'MUSICAL SYMBOL BEGIN TIE'},
    {value: 0x1D176, name: 'MUSICAL SYMBOL END TIE'},
    {value: 0x1D177, name: 'MUSICAL SYMBOL BEGIN SLUR'},
    {value: 0x1D178, name: 'MUSICAL SYMBOL END SLUR'},
    {value: 0x1D179, name: 'MUSICAL SYMBOL BEGIN PHRASE'},
    {value: 0x1D17A, name: 'MUSICAL SYMBOL END PHRASE'},
]


command! -nargs=1 -complete=customlist,TestComplete Test echo <q-args>
def TestComplete(arg: string, _, _): list<dict<any>>
    var ulist = subset->mapnew((_, v) => {
        return {
            word: printf("%04X", v.value),
            abbr: v.name,
            kind: printf("%6s", (nr2char(v.value, true) =~ '\p' ? nr2char(v.value, true) : " ")),
            menu: printf("%04X", v.value)}
    })
    if empty(arg)
        return ulist
    else
        return ulist->matchfuzzy(arg ?? '', {key: "abbr"})
    endif
enddef


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4367841836@github.com>

mattn

unread,
May 4, 2026, 7:45:17 AM (7 days ago) May 4
to vim/vim, Subscribed
mattn left a comment (vim/vim#20124)

Please try

printf("%6S", (nr2char(v.value, true) =~ '\p' ? nr2char(v.value, true) : " ")),


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4370744278@github.com>

Maxim Kim

unread,
May 4, 2026, 7:10:12 PM (7 days ago) May 4
to vim/vim, Subscribed
habamax left a comment (vim/vim#20124)

Please try

printf("%6S", (nr2char(v.value, true) =~ '\p' ? nr2char(v.value, true) : " ")),
image.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4375179923@github.com>

mattn

unread,
May 10, 2026, 7:53:43 AM (yesterday) May 10
to vim/vim, Subscribed
mattn left a comment (vim/vim#20124)

I think this issue mixes at least two separate width mismatches.

  • U+1D173..U+1D17A are width 1 in Vim, but in the screenshot they seem to be rendered via fallback glyphs, and those look wider than Vim expects.
  • U+1F574..U+1F575 are width 2 in Vim (emoji_wide), but in this environment they may render closer to width 1.

So this may not be a single scrollbar bug. It looks more like Vim's internal cell width and the terminal/font/fallback glyph width disagree in both directions, depending on the codepoint.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4415216307@github.com>

Maxim Kim

unread,
May 10, 2026, 7:58:23 PM (16 hours ago) May 10
to vim/vim, Subscribed

Closed #20124 as completed.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issue/20124/issue_event/25360855584@github.com>

Maxim Kim

unread,
May 10, 2026, 7:58:27 PM (16 hours ago) May 10
to vim/vim, Subscribed
habamax left a comment (vim/vim#20124)

Yes I agree.

Not sure if vim can do anything about it. Let's close for now.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/20124/4416677299@github.com>

Reply all
Reply to author
Forward
0 new messages