Merge pull request #19674 from zeertzjq/vim-8.2.1535

vim-patch:8.2.{1535,1537,3545}: setcellwidths()
This commit is contained in:
zeertzjq
2022-08-08 21:20:27 +08:00
committed by GitHub
14 changed files with 387 additions and 78 deletions

View File

@@ -396,6 +396,7 @@ setbufline({expr}, {lnum}, {text})
Number set line {lnum} to {text} in buffer
{expr}
setbufvar({buf}, {varname}, {val}) set {varname} in buffer {buf} to {val}
setcellwidths({list}) none set character cell width overrides
setcharpos({expr}, {list}) Number set the {expr} position to {list}
setcharsearch({dict}) Dict set character search from {dict}
setcmdpos({pos}) Number set cursor position in command-line
@@ -6817,6 +6818,32 @@ setbufvar({buf}, {varname}, {val}) *setbufvar()*
third argument: >
GetValue()->setbufvar(buf, varname)
setcellwidths({list}) *setcellwidths()*
Specify overrides for cell widths of character ranges. This
tells Vim how wide characters are, counted in screen cells.
This overrides 'ambiwidth'. Example: >
setcellwidths([[0xad, 0xad, 1],
\ [0x2194, 0x2199, 2]])
< *E1109* *E1110* *E1111* *E1112* *E1113*
The {list} argument is a list of lists with each three
numbers. These three numbers are [low, high, width]. "low"
and "high" can be the same, in which case this refers to one
character. Otherwise it is the range of characters from "low"
to "high" (inclusive). "width" is either 1 or 2, indicating
the character width in screen cells.
An error is given if the argument is invalid, also when a
range overlaps with another.
Only characters with value 0x100 and higher can be used.
If the new value causes 'fillchars' or 'listchars' to become
invalid it is rejected and an error is given.
To clear the overrides pass an empty list: >
setcellwidths([]);
setcharpos({expr}, {list}) *setcharpos()*
Same as |setpos()| but uses the specified column number as the
character index instead of the byte index in the line.

View File

@@ -591,7 +591,11 @@ A jump table for the options with a short description can be found at |Q_op|.
"double": Use twice the width of ASCII characters.
*E834* *E835*
The value "double" cannot be used if 'listchars' or 'fillchars'
contains a character that would be double width.
contains a character that would be double width. These errors may
also be given when calling setcellwidths().
The values are overruled for characters specified with
|setcellwidths()|.
There are a number of CJK fonts for which the width of glyphs for
those characters are solely based on how many octets they take in

View File

@@ -619,6 +619,7 @@ String manipulation: *string-functions*
strchars() length of a string in characters
strwidth() size of string when displayed
strdisplaywidth() size of string when displayed, deals with tabs
setcellwidths() set character cell width overrides
substitute() substitute a pattern match with a string
submatch() get a specific match in ":s" and substitute()
strpart() get part of a string using byte index

View File

@@ -327,6 +327,7 @@ return {
serverstop={args=1},
setbufline={args=3, base=3},
setbufvar={args=3, base=3},
setcellwidths={args=1, base=1},
setcharpos={args=2, base=2},
setcharsearch={args=1, base=1},
setcmdpos={args=1, base=1},

View File

@@ -13,7 +13,7 @@
#include "nvim/hashtab.h"
#include "nvim/lib/queue.h"
#include "nvim/macros.h"
#include "nvim/mbyte.h"
#include "nvim/mbyte_defs.h"
#include "nvim/message.h"
#include "nvim/pos.h" // for linenr_T
#include "nvim/profile.h" // for proftime_T

View File

@@ -12,8 +12,8 @@
-- 2 then interval applies only to first, third, fifth, … character in range.
-- Fourth value is number that should be added to the codepoint to yield
-- folded/lower/upper codepoint.
-- 4. emoji_width and emoji_all tables: sorted lists of non-overlapping closed
-- intervals of Emoji characters. emoji_width contains all the characters
-- 4. emoji_wide and emoji_all tables: sorted lists of non-overlapping closed
-- intervals of Emoji characters. emoji_wide contains all the characters
-- which don't have ambiguous or double width, and emoji_all has all Emojis.
if arg[1] == '--help' then
print('Usage:')
@@ -288,7 +288,7 @@ local build_emoji_table = function(ut_fp, emojiprops, doublewidth, ambiwidth)
end
ut_fp:write('};\n')
ut_fp:write('static const struct interval emoji_width[] = {\n')
ut_fp:write('static const struct interval emoji_wide[] = {\n')
for _, p in ipairs(emojiwidth) do
ut_fp:write(make_range(p[1], p[2]))
end

View File

@@ -1000,6 +1000,11 @@ EXTERN char e_fnametoolong[] INIT(= N_("E856: Filename too long"));
EXTERN char e_float_as_string[] INIT(= N_("E806: using Float as a String"));
EXTERN char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now"));
EXTERN char e_conflicts_with_value_of_listchars[]
INIT(= N_("E834: Conflicts with value of 'listchars'"));
EXTERN char e_conflicts_with_value_of_fillchars[]
INIT(= N_("E835: Conflicts with value of 'fillchars'"));
EXTERN char e_autocmd_err[] INIT(= N_("E5500: autocmd has thrown an exception: %s"));
EXTERN char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>"));
EXTERN char e_cmdmap_repeated[]

View File

@@ -6,6 +6,7 @@
#include "nvim/ascii.h"
#include "nvim/buffer_defs.h"
#include "nvim/grid_defs.h"
#include "nvim/mbyte.h"
/// By default, all windows are drawn on a single rectangular grid, represented by
/// this ScreenGrid instance. In multigrid mode each window will have its own

View File

@@ -74,6 +74,19 @@ struct interval {
# include "unicode_tables.generated.h"
#endif
static char e_list_item_nr_is_not_list[]
= N_("E1109: List item %d is not a List");
static char e_list_item_nr_does_not_contain_3_numbers[]
= N_("E1110: List item %d does not contain 3 numbers");
static char e_list_item_nr_range_invalid[]
= N_("E1111: List item %d range invalid");
static char e_list_item_nr_cell_width_invalid[]
= N_("E1112: List item %d cell width invalid");
static char e_overlapping_ranges_for_nr[]
= N_("E1113: Overlapping ranges for 0x%lx");
static char e_only_values_of_0x100_and_higher_supported[]
= N_("E1114: Only values of 0x100 and higher supported");
// To speed up BYTELEN(); keep a lookup table to quickly get the length in
// bytes of a UTF-8 character from the first byte of a UTF-8 string. Bytes
// which are illegal when used as the first byte have a 1. The NUL byte has
@@ -472,13 +485,18 @@ static bool intable(const struct interval *table, size_t n_items, int c)
int utf_char2cells(int c)
{
if (c >= 0x100) {
int n = cw_value(c);
if (n != 0) {
return n;
}
if (!utf_printable(c)) {
return 6; // unprintable, displays <xxxx>
}
if (intable(doublewidth, ARRAY_SIZE(doublewidth), c)) {
return 2;
}
if (p_emoji && intable(emoji_width, ARRAY_SIZE(emoji_width), c)) {
if (p_emoji && intable(emoji_wide, ARRAY_SIZE(emoji_wide), c)) {
return 2;
}
} else if (c >= 0x80 && !vim_isprintc(c)) {
@@ -2678,3 +2696,181 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp
return retval;
}
/// Table set by setcellwidths().
typedef struct {
long first;
long last;
char width;
} cw_interval_T;
static cw_interval_T *cw_table = NULL;
static size_t cw_table_size = 0;
/// Return the value of the cellwidth table for the character `c`.
///
/// @param c The source character.
/// @return 1 or 2 when `c` is in the cellwidth table, 0 if not.
static int cw_value(int c)
{
if (cw_table == NULL) {
return 0;
}
// first quick check for Latin1 etc. characters
if (c < cw_table[0].first) {
return 0;
}
// binary search in table
int bot = 0;
int top = (int)cw_table_size - 1;
while (top >= bot) {
int mid = (bot + top) / 2;
if (cw_table[mid].last < c) {
bot = mid + 1;
} else if (cw_table[mid].first > c) {
top = mid - 1;
} else {
return cw_table[mid].width;
}
}
return 0;
}
static int tv_nr_compare(const void *a1, const void *a2)
{
const listitem_T *const li1 = tv_list_first(*(const list_T **)a1);
const listitem_T *const li2 = tv_list_first(*(const list_T **)a2);
return (int)(TV_LIST_ITEM_TV(li1)->vval.v_number - TV_LIST_ITEM_TV(li2)->vval.v_number);
}
/// "setcellwidths()" function
void f_setcellwidths(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL) {
emsg(_(e_listreq));
return;
}
const list_T *const l = argvars[0].vval.v_list;
if (tv_list_len(l) == 0) {
// Clearing the table.
xfree(cw_table);
cw_table = NULL;
cw_table_size = 0;
return;
}
// Note: use list_T instead of listitem_T so that TV_LIST_ITEM_NEXT can be used properly below.
const list_T **ptrs = xmalloc(sizeof(const list_T *) * (size_t)tv_list_len(l));
// Check that all entries are a list with three numbers, the range is
// valid and the cell width is valid.
int item = 0;
TV_LIST_ITER_CONST(l, li, {
const typval_T *const li_tv = TV_LIST_ITEM_TV(li);
if (li_tv->v_type != VAR_LIST || li_tv->vval.v_list == NULL) {
semsg(_(e_list_item_nr_is_not_list), item);
xfree(ptrs);
return;
}
const list_T *const li_l = li_tv->vval.v_list;
ptrs[item] = li_l;
const listitem_T *lili = tv_list_first(li_l);
int i;
varnumber_T n1;
for (i = 0; lili != NULL; lili = TV_LIST_ITEM_NEXT(li_l, lili), i++) {
const typval_T *const lili_tv = TV_LIST_ITEM_TV(lili);
if (lili_tv->v_type != VAR_NUMBER) {
break;
}
if (i == 0) {
n1 = lili_tv->vval.v_number;
if (n1 < 0x100) {
emsg(_(e_only_values_of_0x100_and_higher_supported));
xfree(ptrs);
return;
}
} else if (i == 1 && lili_tv->vval.v_number < n1) {
semsg(_(e_list_item_nr_range_invalid), item);
xfree(ptrs);
return;
} else if (i == 2 && (lili_tv->vval.v_number < 1 || lili_tv->vval.v_number > 2)) {
semsg(_(e_list_item_nr_cell_width_invalid), item);
xfree(ptrs);
return;
}
}
if (i != 3) {
semsg(_(e_list_item_nr_does_not_contain_3_numbers), item);
xfree(ptrs);
return;
}
item++;
});
// Sort the list on the first number.
qsort((void *)ptrs, (size_t)tv_list_len(l), sizeof(const list_T *), tv_nr_compare);
cw_interval_T *table = xmalloc(sizeof(cw_interval_T) * (size_t)tv_list_len(l));
// Store the items in the new table.
for (item = 0; item < tv_list_len(l); item++) {
const list_T *const li_l = ptrs[item];
const listitem_T *lili = tv_list_first(li_l);
const varnumber_T n1 = TV_LIST_ITEM_TV(lili)->vval.v_number;
if (item > 0 && n1 <= table[item - 1].last) {
semsg(_(e_overlapping_ranges_for_nr), (long)n1);
xfree(ptrs);
xfree(table);
return;
}
table[item].first = n1;
lili = TV_LIST_ITEM_NEXT(li_l, lili);
table[item].last = TV_LIST_ITEM_TV(lili)->vval.v_number;
lili = TV_LIST_ITEM_NEXT(li_l, lili);
table[item].width = (char)TV_LIST_ITEM_TV(lili)->vval.v_number;
}
xfree(ptrs);
cw_interval_T *const cw_table_save = cw_table;
const size_t cw_table_size_save = cw_table_size;
cw_table = table;
cw_table_size = (size_t)tv_list_len(l);
// Check that the new value does not conflict with 'fillchars' or
// 'listchars'.
char *error = NULL;
if (set_chars_option(curwin, &p_fcs, false) != NULL) {
error = e_conflicts_with_value_of_fillchars;
} else if (set_chars_option(curwin, &p_lcs, false) != NULL) {
error = e_conflicts_with_value_of_listchars;
} else {
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
error = e_conflicts_with_value_of_listchars;
break;
}
if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
error = e_conflicts_with_value_of_fillchars;
break;
}
}
}
if (error != NULL) {
emsg(_(error));
cw_table = cw_table_save;
cw_table_size = cw_table_size_save;
xfree(table);
return;
}
xfree(cw_table_save);
redraw_all_later(NOT_VALID);
}

View File

@@ -5,8 +5,9 @@
#include <stdint.h>
#include <string.h>
#include "nvim/eval/typval.h"
#include "nvim/func_attr.h"
#include "nvim/iconv.h"
#include "nvim/mbyte_defs.h"
#include "nvim/os/os_defs.h" // For indirect
#include "nvim/types.h" // for char_u
@@ -19,52 +20,6 @@
#define MB_BYTE2LEN(b) utf8len_tab[b]
#define MB_BYTE2LEN_CHECK(b) (((b) < 0 || (b) > 255) ? 1 : utf8len_tab[b])
// max length of an unicode char
#define MB_MAXCHAR 6
// properties used in enc_canon_table[] (first three mutually exclusive)
#define ENC_8BIT 0x01
#define ENC_DBCS 0x02
#define ENC_UNICODE 0x04
#define ENC_ENDIAN_B 0x10 // Unicode: Big endian
#define ENC_ENDIAN_L 0x20 // Unicode: Little endian
#define ENC_2BYTE 0x40 // Unicode: UCS-2
#define ENC_4BYTE 0x80 // Unicode: UCS-4
#define ENC_2WORD 0x100 // Unicode: UTF-16
#define ENC_LATIN1 0x200 // Latin1
#define ENC_LATIN9 0x400 // Latin9
#define ENC_MACROMAN 0x800 // Mac Roman (not Macro Man! :-)
/// Flags for vimconv_T
typedef enum {
CONV_NONE = 0,
CONV_TO_UTF8 = 1,
CONV_9_TO_UTF8 = 2,
CONV_TO_LATIN1 = 3,
CONV_TO_LATIN9 = 4,
CONV_ICONV = 5,
} ConvFlags;
#define MBYTE_NONE_CONV { \
.vc_type = CONV_NONE, \
.vc_factor = 1, \
.vc_fail = false, \
}
/// Structure used for string conversions
typedef struct {
int vc_type; ///< Zero or more ConvFlags.
int vc_factor; ///< Maximal expansion factor.
#ifdef HAVE_ICONV
iconv_t vc_fd; ///< Value for CONV_ICONV.
#endif
bool vc_fail; ///< What to do with invalid characters: if true, fail,
///< otherwise use '?'.
} vimconv_T;
extern const uint8_t utf8len_tab_zero[256];
extern const uint8_t utf8len_tab[256];

56
src/nvim/mbyte_defs.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef NVIM_MBYTE_DEFS_H
#define NVIM_MBYTE_DEFS_H
#include <stdbool.h>
#include "nvim/iconv.h"
/// max length of an unicode char
enum { MB_MAXCHAR = 6, };
/// properties used in enc_canon_table[] (first three mutually exclusive)
enum {
ENC_8BIT = 0x01,
ENC_DBCS = 0x02,
ENC_UNICODE = 0x04,
ENC_ENDIAN_B = 0x10, ///< Unicode: Big endian
ENC_ENDIAN_L = 0x20, ///< Unicode: Little endian
ENC_2BYTE = 0x40, ///< Unicode: UCS-2
ENC_4BYTE = 0x80, ///< Unicode: UCS-4
ENC_2WORD = 0x100, ///< Unicode: UTF-16
ENC_LATIN1 = 0x200, ///< Latin1
ENC_LATIN9 = 0x400, ///< Latin9
ENC_MACROMAN = 0x800, ///< Mac Roman (not Macro Man! :-)
};
/// Flags for vimconv_T
typedef enum {
CONV_NONE = 0,
CONV_TO_UTF8 = 1,
CONV_9_TO_UTF8 = 2,
CONV_TO_LATIN1 = 3,
CONV_TO_LATIN9 = 4,
CONV_ICONV = 5,
} ConvFlags;
#define MBYTE_NONE_CONV { \
.vc_type = CONV_NONE, \
.vc_factor = 1, \
.vc_fail = false, \
}
/// Structure used for string conversions
typedef struct {
int vc_type; ///< Zero or more ConvFlags.
int vc_factor; ///< Maximal expansion factor.
#ifdef HAVE_ICONV
iconv_t vc_fd; ///< Value for CONV_ICONV.
#endif
bool vc_fail; ///< What to do with invalid characters: if true, fail,
///< otherwise use '?'.
} vimconv_T;
#endif // NVIM_MBYTE_DEFS_H

View File

@@ -2580,11 +2580,11 @@ static char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, c
} else {
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
errmsg = _("E834: Conflicts with value of 'listchars'");
errmsg = _(e_conflicts_with_value_of_listchars);
goto ambw_end;
}
if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
errmsg = _("E835: Conflicts with value of 'fillchars'");
errmsg = _(e_conflicts_with_value_of_fillchars);
goto ambw_end;
}
}
@@ -3605,7 +3605,7 @@ static int get_encoded_char_adv(char_u **p)
///
/// @param varp either &curwin->w_p_lcs or &curwin->w_p_fcs
/// @return error message, NULL if it's OK.
static char *set_chars_option(win_T *wp, char_u **varp, bool set)
char *set_chars_option(win_T *wp, char_u **varp, bool set)
{
int round, i, len, len2, entries;
char_u *p, *s;
@@ -3624,21 +3624,22 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
};
struct chars_tab *tab;
// XXX: Characters taking 2 columns is forbidden (TUI limitation?). Set old defaults in this case.
struct chars_tab fcs_tab[] = {
{ &wp->w_p_fcs_chars.stl, "stl", ' ' },
{ &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
{ &wp->w_p_fcs_chars.wbr, "wbr", ' ' },
{ &wp->w_p_fcs_chars.horiz, "horiz", 9472 }, // ─
{ &wp->w_p_fcs_chars.horizup, "horizup", 9524 }, // ┴
{ &wp->w_p_fcs_chars.horizdown, "horizdown", 9516 }, // ┬
{ &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │
{ &wp->w_p_fcs_chars.vertleft, "vertleft", 9508 }, // ┤
{ &wp->w_p_fcs_chars.vertright, "vertright", 9500 }, // ├
{ &wp->w_p_fcs_chars.verthoriz, "verthoriz", 9532 }, // ┼
{ &wp->w_p_fcs_chars.fold, "fold", 183 }, // ·
{ &wp->w_p_fcs_chars.horiz, "horiz", char2cells(0x2500) == 1 ? 0x2500 : '-' }, // ─
{ &wp->w_p_fcs_chars.horizup, "horizup", char2cells(0x2534) == 1 ? 0x2534 : '-' }, // ┴
{ &wp->w_p_fcs_chars.horizdown, "horizdown", char2cells(0x252c) == 1 ? 0x252c : '-' }, // ┬
{ &wp->w_p_fcs_chars.vert, "vert", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
{ &wp->w_p_fcs_chars.vertleft, "vertleft", char2cells(0x2524) == 1 ? 0x2524 : '|' }, // ┤
{ &wp->w_p_fcs_chars.vertright, "vertright", char2cells(0x251c) == 1 ? 0x251c : '|' }, // ├
{ &wp->w_p_fcs_chars.verthoriz, "verthoriz", char2cells(0x253c) == 1 ? 0x253c : '+' }, // ┼
{ &wp->w_p_fcs_chars.fold, "fold", char2cells(0x00b7) == 1 ? 0x00b7 : '-' }, // ·
{ &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
{ &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
{ &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │
{ &wp->w_p_fcs_chars.foldsep, "foldsep", char2cells(0x2502) == 1 ? 0x2502 : '|' }, // │
{ &wp->w_p_fcs_chars.diff, "diff", '-' },
{ &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
{ &wp->w_p_fcs_chars.eob, "eob", '~' },
@@ -3667,19 +3668,6 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
varp = &p_fcs;
}
if (*p_ambw == 'd') {
// XXX: If ambiwidth=double then some characters take 2 columns,
// which is forbidden (TUI limitation?). Set old defaults.
fcs_tab[3].def = '-';
fcs_tab[4].def = '-';
fcs_tab[5].def = '-';
fcs_tab[6].def = '|';
fcs_tab[7].def = '|';
fcs_tab[8].def = '|';
fcs_tab[9].def = '+';
fcs_tab[10].def = '-';
fcs_tab[13].def = '|';
}
}
// first round: check for valid value, second round: assign values

View File

@@ -140,6 +140,51 @@ func Test_list2str_str2list_latin1()
call assert_equal(s, sres)
endfunc
func Test_setcellwidths()
call setcellwidths([
\ [0x1330, 0x1330, 2],
\ [9999, 10000, 1],
\ [0x1337, 0x1339, 2],
\])
call assert_equal(2, strwidth("\u1330"))
call assert_equal(1, strwidth("\u1336"))
call assert_equal(2, strwidth("\u1337"))
call assert_equal(2, strwidth("\u1339"))
call assert_equal(1, strwidth("\u133a"))
call setcellwidths([])
call assert_fails('call setcellwidths(1)', 'E714:')
call assert_fails('call setcellwidths([1, 2, 0])', 'E1109:')
call assert_fails('call setcellwidths([[0x101]])', 'E1110:')
call assert_fails('call setcellwidths([[0x101, 0x102]])', 'E1110:')
call assert_fails('call setcellwidths([[0x101, 0x102, 1, 4]])', 'E1110:')
call assert_fails('call setcellwidths([["a"]])', 'E1110:')
call assert_fails('call setcellwidths([[0x102, 0x101, 1]])', 'E1111:')
call assert_fails('call setcellwidths([[0x101, 0x102, 0]])', 'E1112:')
call assert_fails('call setcellwidths([[0x101, 0x102, 3]])', 'E1112:')
call assert_fails('call setcellwidths([[0x111, 0x122, 1], [0x115, 0x116, 2]])', 'E1113:')
call assert_fails('call setcellwidths([[0x111, 0x122, 1], [0x122, 0x123, 2]])', 'E1113:')
call assert_fails('call setcellwidths([[0x33, 0x44, 2]])', 'E1114:')
set listchars=tab:--\\u2192
call assert_fails('call setcellwidths([[0x2192, 0x2192, 2]])', 'E834:')
set fillchars=stl:\\u2501
call assert_fails('call setcellwidths([[0x2501, 0x2501, 2]])', 'E835:')
set listchars&
set fillchars&
call setcellwidths([])
endfunc
func Test_print_overlong()
" Text with more composing characters than MB_MAXBYTES.
new

View File

@@ -161,6 +161,36 @@ describe('startup defaults', function()
~ |~ |
|
]])
-- change "vert" character to single-cell
funcs.setcellwidths({{0x2502, 0x2502, 1}})
screen:expect([[
1 │1 |
^+-- 2 lines: 2----------│+-- 2 lines: 2---------|
4 │4 |
~ │~ |
|
]])
-- change "vert" character to double-cell
funcs.setcellwidths({{0x2502, 0x2502, 2}})
screen:expect([[
1 |1 |
^+-- 2 lines: 2----------|+-- 2 lines: 2---------|
4 |4 |
~ |~ |
|
]])
-- "vert" character should still default to single-byte fillchars because of setcellwidths().
command('set ambiwidth=single')
screen:expect([[
1 |1 |
^+-- 2 lines: 2··········|+-- 2 lines: 2·········|
4 |4 |
~ |~ |
|
]])
end)
end)