@@ -132,6 +132,7 @@ static int dbcs_char2cells(int c);
132132static int dbcs_ptr2cells_len (char_u * p , int size );
133133static int dbcs_ptr2char (char_u * p );
134134static int dbcs_head_off (char_u * base , char_u * p );
135+ static int cw_value (int c );
135136
136137/*
137138 * Lookup table to quickly get the length in bytes of a UTF-8 character from
@@ -1487,7 +1488,7 @@ utf_char2cells(int c)
14871488 // Sorted list of non-overlapping intervals of Emoji characters that don't
14881489 // have ambiguous or double width,
14891490 // based on http://unicode.org/emoji/charts/emoji-list.html
1490- static struct interval emoji_width [] =
1491+ static struct interval emoji_wide [] =
14911492 {
14921493 {0x1f1e6 , 0x1f1ff },
14931494 {0x1f321 , 0x1f321 },
@@ -1532,12 +1533,18 @@ utf_char2cells(int c)
15321533
15331534 if (c >= 0x100 )
15341535 {
1536+ int n ;
1537+
1538+ n = cw_value (c );
1539+ if (n != 0 )
1540+ return n ;
1541+
15351542#ifdef USE_WCHAR_FUNCTIONS
15361543 /*
15371544 * Assume the library function wcwidth() works better than our own
15381545 * stuff. It should return 1 for ambiguous width chars!
15391546 */
1540- int n = wcwidth (c );
1547+ n = wcwidth (c );
15411548
15421549 if (n < 0 )
15431550 return 6 ; // unprintable, displays <xxxx>
@@ -1549,7 +1556,7 @@ utf_char2cells(int c)
15491556 if (intable (doublewidth , sizeof (doublewidth ), c ))
15501557 return 2 ;
15511558#endif
1552- if (p_emoji && intable (emoji_width , sizeof (emoji_width ), c ))
1559+ if (p_emoji && intable (emoji_wide , sizeof (emoji_wide ), c ))
15531560 return 2 ;
15541561 }
15551562
@@ -2570,6 +2577,8 @@ utf_printable(int c)
25702577
25712578// Sorted list of non-overlapping intervals of all Emoji characters,
25722579// based on http://unicode.org/emoji/charts/emoji-list.html
2580+ // Generated by ../runtime/tools/unicode.vim.
2581+ // Excludes 0x00a9 and 0x00ae because they are considered latin1.
25732582static struct interval emoji_all [] =
25742583{
25752584 {0x203c , 0x203c },
@@ -5342,3 +5351,177 @@ string_convert_ext(
53425351
53435352 return retval ;
53445353}
5354+
5355+ /*
5356+ * Table set by setcellwidths().
5357+ */
5358+ typedef struct
5359+ {
5360+ long first ;
5361+ long last ;
5362+ char width ;
5363+ } cw_interval_T ;
5364+
5365+ static cw_interval_T * cw_table = NULL ;
5366+ static size_t cw_table_size = 0 ;
5367+
5368+ /*
5369+ * Return 1 or 2 when "c" is in the cellwidth table.
5370+ * Return 0 if not.
5371+ */
5372+ static int
5373+ cw_value (int c )
5374+ {
5375+ int mid , bot , top ;
5376+
5377+ if (cw_table == NULL )
5378+ return 0 ;
5379+
5380+ // first quick check for Latin1 etc. characters
5381+ if (c < cw_table [0 ].first )
5382+ return 0 ;
5383+
5384+ // binary search in table
5385+ bot = 0 ;
5386+ top = (int )cw_table_size - 1 ;
5387+ while (top >= bot )
5388+ {
5389+ mid = (bot + top ) / 2 ;
5390+ if (cw_table [mid ].last < c )
5391+ bot = mid + 1 ;
5392+ else if (cw_table [mid ].first > c )
5393+ top = mid - 1 ;
5394+ else
5395+ return cw_table [mid ].width ;
5396+ }
5397+ return 0 ;
5398+ }
5399+
5400+ static int
5401+ tv_nr_compare (const void * a1 , const void * a2 )
5402+ {
5403+ listitem_T * li1 = (listitem_T * )a1 ;
5404+ listitem_T * li2 = (listitem_T * )a2 ;
5405+
5406+ return li1 -> li_tv .vval .v_number - li2 -> li_tv .vval .v_number ;
5407+ }
5408+
5409+ void
5410+ f_setcellwidths (typval_T * argvars , typval_T * rettv UNUSED )
5411+ {
5412+ list_T * l ;
5413+ listitem_T * li ;
5414+ int item ;
5415+ int i ;
5416+ listitem_T * * ptrs ;
5417+ cw_interval_T * table ;
5418+
5419+ if (argvars [0 ].v_type != VAR_LIST || argvars [0 ].vval .v_list == NULL )
5420+ {
5421+ emsg (_ (e_listreq ));
5422+ return ;
5423+ }
5424+ l = argvars [0 ].vval .v_list ;
5425+ if (l -> lv_len == 0 )
5426+ {
5427+ // Clearing the table.
5428+ vim_free (cw_table );
5429+ cw_table = NULL ;
5430+ cw_table_size = 0 ;
5431+ return ;
5432+ }
5433+
5434+ ptrs = ALLOC_MULT (listitem_T * , l -> lv_len );
5435+ if (ptrs == NULL )
5436+ return ;
5437+
5438+ // Check that all entries are a list with three numbers, the range is
5439+ // valid and the cell width is valid.
5440+ item = 0 ;
5441+ for (li = l -> lv_first ; li != NULL ; li = li -> li_next )
5442+ {
5443+ listitem_T * lili ;
5444+ varnumber_T n1 ;
5445+
5446+ if (li -> li_tv .v_type != VAR_LIST || li -> li_tv .vval .v_list == NULL )
5447+ {
5448+ semsg (_ (e_list_item_nr_is_not_list ), item );
5449+ vim_free (ptrs );
5450+ return ;
5451+ }
5452+ for (lili = li -> li_tv .vval .v_list -> lv_first , i = 0 ; lili != NULL ;
5453+ lili = lili -> li_next , ++ i )
5454+ {
5455+ if (lili -> li_tv .v_type != VAR_NUMBER )
5456+ break ;
5457+ if (i == 0 )
5458+ {
5459+ n1 = lili -> li_tv .vval .v_number ;
5460+ if (n1 < 0x100 )
5461+ {
5462+ emsg (_ (e_only_values_of_0x100_and_higher_supported ));
5463+ vim_free (ptrs );
5464+ return ;
5465+ }
5466+ }
5467+ else if (i == 1 && lili -> li_tv .vval .v_number < n1 )
5468+ {
5469+ semsg (_ (e_list_item_nr_range_invalid ), item );
5470+ vim_free (ptrs );
5471+ return ;
5472+ }
5473+ else if (i == 2 && (lili -> li_tv .vval .v_number < 1
5474+ || lili -> li_tv .vval .v_number > 2 ))
5475+ {
5476+ semsg (_ (e_list_item_nr_cell_width_invalid ), item );
5477+ vim_free (ptrs );
5478+ return ;
5479+ }
5480+ }
5481+ if (i != 3 )
5482+ {
5483+ semsg (_ (e_list_item_nr_does_not_contain_3_numbers ), item );
5484+ vim_free (ptrs );
5485+ return ;
5486+ }
5487+ ptrs [item ++ ] = lili ;
5488+ }
5489+
5490+ // Sort the list on the first number.
5491+ qsort ((void * )ptrs , (size_t )l -> lv_len , sizeof (listitem_T * ), tv_nr_compare );
5492+
5493+ table = ALLOC_MULT (cw_interval_T , l -> lv_len );
5494+ if (table == NULL )
5495+ {
5496+ vim_free (ptrs );
5497+ return ;
5498+ }
5499+
5500+ // Store the items in the new table.
5501+ item = 0 ;
5502+ for (li = l -> lv_first ; li != NULL ; li = li -> li_next )
5503+ {
5504+ listitem_T * lili = li -> li_tv .vval .v_list -> lv_first ;
5505+ varnumber_T n1 ;
5506+
5507+ n1 = lili -> li_tv .vval .v_number ;
5508+ if (item > 0 && n1 <= table [item - 1 ].last )
5509+ {
5510+ semsg (_ (e_overlapping_ranges_for_nr ), (long )n1 );
5511+ vim_free (ptrs );
5512+ vim_free (table );
5513+ return ;
5514+ }
5515+ table [item ].first = n1 ;
5516+ lili = lili -> li_next ;
5517+ table [item ].last = lili -> li_tv .vval .v_number ;
5518+ lili = lili -> li_next ;
5519+ table [item ].width = lili -> li_tv .vval .v_number ;
5520+ ++ item ;
5521+ }
5522+
5523+ vim_free (ptrs );
5524+ vim_free (cw_table );
5525+ cw_table = table ;
5526+ cw_table_size = l -> lv_len ;
5527+ }
0 commit comments