mirror of
https://github.com/neovim/neovim.git
synced 2025-09-13 23:08:16 +00:00

Problem: Buffer menu does not handle unicode names correctly
(after v9.1.1622)
Solution: Fix the BMHash() function (Yee Cheng Chin)
The Buffers menu uses a BMHash() function to generate a sortable number
to be used for the menu index. It used a naive (and incorrect) way of
encoding multiple ASCII values into a single integer, but assumes each
character to be only in the ASCII 32-96 range. This means if we use
non-ASCII file names (e.g. Unicode values like CJK or emojis) we get
integer underflow and overflow, causing the menu index to wrap around.
Vim's GUI implementations internally use a signed 32-bit integer for the
`gui_mch_add_menu_item()` function and so we need to make sure the menu
index is in the (0, 2^31-1) range.
To do this, if the file name starts with a non-ASCII value, we just use
the first character's value and set the high bit so it sorts after the
other ASCII ones. Otherwise, we just take the first 5 characters, and
use 5 bit for each character to encode a 30-bit number that can be
sorted.
This means Unicode file names won't be sorted beyond the first
character. This is likely going to be fine as there are lots of ways to
query buffers.
related: vim/vim#17403
closes: vim/vim#17928
8f9de4991e
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
81 lines
2.7 KiB
VimL
81 lines
2.7 KiB
VimL
|
|
func SetUp()
|
|
source $VIMRUNTIME/menu.vim
|
|
endfunc
|
|
|
|
func Test_colorscheme()
|
|
" call assert_equal('16777216', &t_Co)
|
|
|
|
let colorscheme_saved = exists('g:colors_name') ? g:colors_name : 'default'
|
|
let g:color_count = 0
|
|
augroup TestColors
|
|
au!
|
|
au ColorScheme * let g:color_count += 1
|
|
\ | let g:after_colors = g:color_count
|
|
\ | let g:color_after = expand('<amatch>')
|
|
au ColorSchemePre * let g:color_count += 1
|
|
\ | let g:before_colors = g:color_count
|
|
\ | let g:color_pre = expand('<amatch>')
|
|
augroup END
|
|
|
|
colorscheme torte
|
|
redraw!
|
|
call assert_equal('dark', &background)
|
|
call assert_equal(1, g:before_colors)
|
|
call assert_equal(2, g:after_colors)
|
|
call assert_equal('torte', g:color_pre)
|
|
call assert_equal('torte', g:color_after)
|
|
call assert_equal("\ntorte", execute('colorscheme'))
|
|
|
|
let a = substitute(execute('hi Search'), "\n\\s\\+", ' ', 'g')
|
|
" FIXME: temporarily check less while the colorscheme changes
|
|
" call assert_match("\nSearch xxx term=reverse cterm=reverse ctermfg=196 ctermbg=16 gui=reverse guifg=#ff0000 guibg=#000000", a)
|
|
" call assert_match("\nSearch xxx term=reverse ", a)
|
|
|
|
call assert_fails('colorscheme does_not_exist', 'E185:')
|
|
call assert_equal('does_not_exist', g:color_pre)
|
|
call assert_equal('torte', g:color_after)
|
|
|
|
exec 'colorscheme' colorscheme_saved
|
|
augroup TestColors
|
|
au!
|
|
augroup END
|
|
unlet g:color_count g:after_colors g:before_colors
|
|
redraw!
|
|
endfunc
|
|
|
|
" Test that Buffers menu generates the correct index for different buffer
|
|
" names for sorting.
|
|
func Test_Buffers_Menu()
|
|
doautocmd LoadBufferMenu VimEnter
|
|
|
|
" Non-ASCII characters only use the first character as idx
|
|
let idx_emoji = or(char2nr('😑'), 0x40000000)
|
|
|
|
" Only first five letters are used for alphanumeric:
|
|
" ('a'-32) << 24 + ('b'-32) << 18 + ('c'-32) << 12 + ('d'-32) << 6 + ('e'-32)
|
|
let idx_abcde = 0x218A3925
|
|
" ('a'-32) << 24 + ('b'-32) << 18 + ('c'-32) << 12 + ('d'-32) << 6 + ('f'-32)
|
|
let idx_abcdf = 0x218A3926
|
|
" ('a'-32) << 24 + 63 (clamped) << 18 + ('c'-32) << 12 + ('d'-32) << 6 + ('e'-32)
|
|
let idx_a_emoji_cde = 0x21FE3925
|
|
|
|
let names = ['😑', '😑1', '😑2', 'abcde', 'abcdefghi', 'abcdf', 'a😑cde']
|
|
let indices = [idx_emoji, idx_emoji, idx_emoji, idx_abcde, idx_abcde, idx_abcdf, idx_a_emoji_cde]
|
|
for i in range(len(names))
|
|
let name = names[i]
|
|
let idx = indices[i]
|
|
exe ':badd ' .. name
|
|
let nr = bufnr('$')
|
|
|
|
let cmd = printf(':amenu Buffers.%s\ (%d)', name, nr)
|
|
let menu = split(execute(cmd), '\n')[1]
|
|
call assert_inrange(0, 0x7FFFFFFF, idx)
|
|
call assert_match('^' .. idx .. ' '.. name, menu)
|
|
endfor
|
|
|
|
%bw!
|
|
endfunc
|
|
|
|
" vim: shiftwidth=2 sts=2 expandtab
|