vim-patch:9.0.1783: Display issues with virt text smoothscroll and showbreak

Problem:  Wrong display with wrapping virtual text or unprintable chars,
          'showbreak' and 'smoothscroll'.
Solution: Don't skip cells taken by 'showbreak' in screen lines before
          "w_skipcol". Combined "n_skip" and "skip_cells".

closes: vim/vim#12597

b557f48982
This commit is contained in:
zeertzjq 2023-08-23 10:12:00 +08:00
parent 3e80b39a8e
commit a1d71ad55e
8 changed files with 557 additions and 88 deletions

View File

@ -991,6 +991,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en
chartabsize_T cts; chartabsize_T cts;
bool on_NUL = false; bool on_NUL = false;
init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line);
cts.cts_max_head_vcol = -1;
// This function is used very often, do some speed optimizations. // This function is used very often, do some speed optimizations.
// When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set // When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set

View File

@ -132,9 +132,12 @@ typedef struct {
bool reset_extra_attr; bool reset_extra_attr;
int skip_cells; // nr of cells to skip for virtual text int skip_cells; ///< nr of cells to skip for w_leftcol
int skipped_cells; // nr of skipped virtual text cells ///< or w_skipcol or concealing
bool more_virt_inline_chunks; // indicates if there is more inline virtual text after n_extra int skipped_cells; ///< nr of skipped cells for virtual text
///< to be added to wlv.vcol later
bool more_virt_inline_chunks; ///< indicates if there is more inline virtual text
///< after n_extra
} winlinevars_T; } winlinevars_T;
/// for line_putchar. Contains the state that needs to be remembered from /// for line_putchar. Contains the state that needs to be remembered from
@ -1090,9 +1093,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
int n_attr3 = 0; // chars with overruling special attr int n_attr3 = 0; // chars with overruling special attr
int saved_attr3 = 0; // char_attr saved for n_attr3 int saved_attr3 = 0; // char_attr saved for n_attr3
int n_skip = 0; // nr of chars to skip for 'nowrap' or
// concealing
int fromcol_prev = -2; // start of inverting after cursor int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor bool noinvcur = false; // don't invert the cursor
bool lnum_in_visual_area = false; bool lnum_in_visual_area = false;
@ -1500,10 +1500,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
char *prev_ptr = ptr; char *prev_ptr = ptr;
chartabsize_T cts; chartabsize_T cts;
int charsize = 0; int charsize = 0;
int head = 0;
init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr); init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr);
cts.cts_max_head_vcol = (int)v;
while (cts.cts_vcol < v && *cts.cts_ptr != NUL) { while (cts.cts_vcol < v && *cts.cts_ptr != NUL) {
charsize = win_lbr_chartabsize(&cts, NULL); head = 0;
charsize = win_lbr_chartabsize(&cts, &head);
cts.cts_vcol += charsize; cts.cts_vcol += charsize;
prev_ptr = cts.cts_ptr; prev_ptr = cts.cts_ptr;
MB_PTR_ADV(cts.cts_ptr); MB_PTR_ADV(cts.cts_ptr);
@ -1530,17 +1533,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (wlv.vcol > v) { if (wlv.vcol > v) {
wlv.vcol -= charsize; wlv.vcol -= charsize;
ptr = prev_ptr; ptr = prev_ptr;
// If the character fits on the screen, don't need to skip it.
// Except for a TAB.
if (utf_ptr2cells(ptr) >= charsize || *ptr == TAB) {
n_skip = (int)(v - wlv.vcol);
}
} }
// If there the text doesn't reach to the desired column, need to skip if (v > wlv.vcol) {
// "skip_cells" cells when virtual text follows. wlv.skip_cells = (int)v - wlv.vcol - head;
if ((!wp->w_p_wrap || (lnum == wp->w_topline && wp->w_skipcol > 0)) && v > wlv.vcol) {
wlv.skip_cells = (int)(v - wlv.vcol);
} }
// Adjust for when the inverted text is before the screen, // Adjust for when the inverted text is before the screen,
@ -1808,9 +1804,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
decor_attr = 0; decor_attr = 0;
search_attr_from_match = false; search_attr_from_match = false;
} }
if (wlv.n_extra > 0) {
n_skip = 0;
}
} }
} }
@ -2027,6 +2020,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Get a character from the line itself. // Get a character from the line itself.
c0 = c = (uint8_t)(*ptr); c0 = c = (uint8_t)(*ptr);
mb_c = c; mb_c = c;
if (c == NUL) {
// no more cells to skip
wlv.skip_cells = 0;
}
// If the UTF-8 character is more than one byte: Decode it // If the UTF-8 character is more than one byte: Decode it
// into "mb_c". // into "mb_c".
mb_l = utfc_ptr2len(ptr); mb_l = utfc_ptr2len(ptr);
@ -2118,7 +2117,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// If a double-width char doesn't fit at the left side display a '<' in // If a double-width char doesn't fit at the left side display a '<' in
// the first column. Don't do this for unprintable characters. // the first column. Don't do this for unprintable characters.
if (n_skip > 0 && mb_l > 1 && wlv.n_extra == 0) { if (wlv.skip_cells > 0 && mb_l > 1 && wlv.n_extra == 0) {
wlv.n_extra = 1; wlv.n_extra = 1;
wlv.c_extra = MB_FILLER_CHAR; wlv.c_extra = MB_FILLER_CHAR;
wlv.c_final = NUL; wlv.c_final = NUL;
@ -2619,9 +2618,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
} }
wlv.n_extra = 0; wlv.n_extra = 0;
wlv.n_attr = 0; wlv.n_attr = 0;
} else if (n_skip == 0) { } else if (wlv.skip_cells == 0) {
is_concealing = true; is_concealing = true;
n_skip = 1; wlv.skip_cells = 1;
} }
mb_c = c; mb_c = c;
mb_utf8 = check_mb_utf8(&c, u8cc); mb_utf8 = check_mb_utf8(&c, u8cc);
@ -2630,7 +2629,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
is_concealing = false; is_concealing = false;
} }
if (n_skip > 0 && did_decrement_ptr) { if (wlv.skip_cells > 0 && did_decrement_ptr) {
// not showing the '>', put pointer back to avoid getting stuck // not showing the '>', put pointer back to avoid getting stuck
ptr++; ptr++;
} }
@ -2641,7 +2640,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (!did_wcol && wlv.draw_state == WL_LINE if (!did_wcol && wlv.draw_state == WL_LINE
&& wp == curwin && lnum == wp->w_cursor.lnum && wp == curwin && lnum == wp->w_cursor.lnum
&& conceal_cursor_line(wp) && conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= wlv.vcol + n_skip) { && (int)wp->w_virtcol <= wlv.vcol + wlv.skip_cells) {
if (wp->w_p_rl) { if (wp->w_p_rl) {
wp->w_wcol = grid->cols - wlv.col + wlv.boguscols - 1; wp->w_wcol = grid->cols - wlv.col + wlv.boguscols - 1;
} else { } else {
@ -2946,7 +2945,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Store character to be displayed. // Store character to be displayed.
// Skip characters that are left of the screen for 'nowrap'. // Skip characters that are left of the screen for 'nowrap'.
if (wlv.draw_state < WL_LINE || n_skip <= 0) { if (wlv.draw_state < WL_LINE || wlv.skip_cells <= 0) {
// Store the character. // Store the character.
if (wp->w_p_rl && utf_char2cells(mb_c) > 1) { if (wp->w_p_rl && utf_char2cells(mb_c) > 1) {
// A double-wide character is: put first half in left cell. // A double-wide character is: put first half in left cell.
@ -2999,7 +2998,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.col++; wlv.col++;
} }
} else if (wp->w_p_cole > 0 && is_concealing) { } else if (wp->w_p_cole > 0 && is_concealing) {
n_skip--; wlv.skip_cells--;
wlv.vcol_off++; wlv.vcol_off++;
if (wlv.n_extra > 0) { if (wlv.n_extra > 0) {
wlv.vcol_off += wlv.n_extra; wlv.vcol_off += wlv.n_extra;
@ -3055,7 +3054,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
} }
} }
} else { } else {
n_skip--; wlv.skip_cells--;
} }
// The skipped cells need to be accounted for in vcol. // The skipped cells need to be accounted for in vcol.

View File

@ -232,7 +232,8 @@ static void insert_enter(InsertState *s)
may_trigger_modechanged(); may_trigger_modechanged();
stop_insert_mode = false; stop_insert_mode = false;
// need to position cursor again when on a TAB // need to position cursor again when on a TAB and
// when on a char with inline virtual text
if (gchar_cursor() == TAB || curbuf->b_virt_text_inline > 0) { if (gchar_cursor() == TAB || curbuf->b_virt_text_inline > 0) {
curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
} }
@ -3471,7 +3472,8 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
State = MODE_NORMAL; State = MODE_NORMAL;
may_trigger_modechanged(); may_trigger_modechanged();
// need to position cursor again when on a TAB // need to position cursor again when on a TAB and
// when on a char with inline virtual text
if (gchar_cursor() == TAB || curbuf->b_virt_text_inline > 0) { if (gchar_cursor() == TAB || curbuf->b_virt_text_inline > 0) {
curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL); curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
} }

View File

@ -369,16 +369,19 @@ int lbr_chartabsize_adv(chartabsize_T *cts)
return retval; return retval;
} }
/// Get the number of characters taken up on the screen indicated by "cts".
/// "cts->cts_cur_text_width_left" and "cts->cts_cur_text_width_right" are set
/// to the extra size for inline virtual text.
/// This function is used very often, keep it fast!!!! /// This function is used very often, keep it fast!!!!
/// ///
/// If "headp" not NULL, set *headp to the size of what we for 'showbreak' /// If "headp" not NULL, set "*headp" to the size of 'showbreak'/'breakindent'
/// string at start of line. Warning: *headp is only set if it's a non-zero /// included in the return value.
/// value, init to 0 before calling. /// When "cts->cts_max_head_vcol" is positive, only count in "*headp" the size
/// of 'showbreak'/'breakindent' before "cts->cts_max_head_vcol".
/// When "cts->cts_max_head_vcol" is negative, only count in "*headp" the size
/// of 'showbreak'/'breakindent' before where cursor should be placed.
/// ///
/// @param cts /// Warning: "*headp" may not be set if it's 0, init to 0 before calling.
/// @param headp
///
/// @return The number of characters taken up on the screen.
int win_lbr_chartabsize(chartabsize_T *cts, int *headp) int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
{ {
win_T *wp = cts->cts_win; win_T *wp = cts->cts_win;
@ -388,7 +391,6 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
colnr_T col_adj = 0; // vcol + screen size of tab colnr_T col_adj = 0; // vcol + screen size of tab
int mb_added = 0; int mb_added = 0;
int numberextra;
cts->cts_cur_text_width_left = 0; cts->cts_cur_text_width_left = 0;
cts->cts_cur_text_width_right = 0; cts->cts_cur_text_width_right = 0;
@ -449,7 +451,7 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
&& (wp->w_width_inner != 0)) { && (wp->w_width_inner != 0)) {
// Count all characters from first non-blank after a blank up to next // Count all characters from first non-blank after a blank up to next
// non-blank after a blank. // non-blank after a blank.
numberextra = win_col_off(wp); int numberextra = win_col_off(wp);
colnr_T col2 = vcol; colnr_T col2 = vcol;
colnr_T colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj); colnr_T colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj);
@ -490,72 +492,92 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// May have to add something for 'breakindent' and/or 'showbreak' // May have to add something for 'breakindent' and/or 'showbreak'
// string at start of line. // string at start of line.
// Set *headp to the size of what we add.
// Do not use 'showbreak' at the NUL after the text. // Do not use 'showbreak' at the NUL after the text.
int added = 0; int head = mb_added;
char *const sbr = c == NUL ? empty_option : get_showbreak_value(wp); char *const sbr = c == NUL ? empty_option : get_showbreak_value(wp);
if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) { if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap) {
colnr_T sbrlen = 0; int col_off_prev = win_col_off(wp);
int numberwidth = win_col_off(wp); int width2 = wp->w_width_inner - col_off_prev + win_col_off2(wp);
colnr_T wcol = vcol + col_off_prev;
numberextra = numberwidth; // cells taken by 'showbreak'/'breakindent' before current char
vcol += numberextra + mb_added; int head_prev = 0;
if (wcol >= wp->w_width_inner) {
if (vcol >= (colnr_T)wp->w_width_inner) { wcol -= wp->w_width_inner;
vcol -= wp->w_width_inner; col_off_prev = wp->w_width_inner - width2;
numberextra = wp->w_width_inner - (numberextra - win_col_off2(wp)); if (wcol >= width2 && width2 > 0) {
if (vcol >= numberextra && numberextra > 0) { wcol %= width2;
vcol %= numberextra;
} }
if (*sbr != NUL) { if (*sbr != NUL) {
sbrlen = (colnr_T)mb_charlen(sbr); head_prev += vim_strsize(sbr);
if (vcol >= sbrlen) {
vcol -= sbrlen;
}
} }
if (vcol >= numberextra && numberextra > 0) { if (wp->w_p_bri) {
vcol %= numberextra; head_prev += get_breakindent_win(wp, line);
} else if (vcol > 0 && numberextra > 0) {
vcol += numberwidth - win_col_off2(wp);
} }
if (wcol < head_prev) {
numberwidth -= win_col_off2(wp); wcol = head_prev;
}
wcol += col_off_prev;
} }
if (vcol == 0 || (vcol + size + sbrlen > (colnr_T)wp->w_width_inner)) { if ((vcol > 0 && wcol == col_off_prev + head_prev)
|| wcol + size > wp->w_width_inner) {
int added = 0;
colnr_T max_head_vcol = cts->cts_max_head_vcol;
if (vcol > 0 && wcol == col_off_prev + head_prev) {
added += head_prev;
if (max_head_vcol <= 0 || vcol < max_head_vcol) {
head += head_prev;
}
}
// cells taken by 'showbreak'/'breakindent' halfway current char
int head_mid = 0;
if (*sbr != NUL) { if (*sbr != NUL) {
if (size + sbrlen + numberwidth > (colnr_T)wp->w_width_inner) { head_mid += vim_strsize(sbr);
}
if (wp->w_p_bri) {
head_mid += get_breakindent_win(wp, line);
}
if (head_mid > 0) {
if (wcol + size > wp->w_width_inner) {
// Calculate effective window width. // Calculate effective window width.
int width = (colnr_T)wp->w_width_inner - sbrlen - numberwidth; int prev_rem = wp->w_width_inner - wcol;
int prev_width = vcol ? ((colnr_T)wp->w_width_inner - (sbrlen + vcol)) int width = width2 - head_mid;
: 0;
if (width <= 0) { if (width <= 0) {
width = 1; width = 1;
} }
added += ((size - prev_width) / width) * vim_strsize(sbr); // divide "size - prev_width" by "width", rounding up
if ((size - prev_width) % width) { int cnt = (size - prev_rem + width - 1) / width;
// Wrapped, add another length of 'sbr'. added += cnt * head_mid;
added += vim_strsize(sbr);
if (max_head_vcol == 0 || vcol + size + added < max_head_vcol) {
head += cnt * head_mid;
} else if (max_head_vcol > vcol + head_prev + prev_rem) {
head += (max_head_vcol - (vcol + head_prev + prev_rem)
+ width2 - 1) / width2 * head_mid;
} else if (max_head_vcol < 0) {
int off = 0;
if (c != NUL || !(State & MODE_NORMAL)) {
off += cts->cts_cur_text_width_left;
}
if (c != NUL && (State & MODE_NORMAL)) {
off += cts->cts_cur_text_width_right;
}
if (off >= prev_rem) {
head += (1 + (off - prev_rem) / width) * head_mid;
}
} }
} else {
added += vim_strsize(sbr);
} }
} }
if (wp->w_p_bri) {
added += get_breakindent_win(wp, line);
}
size += added; size += added;
if (vcol != 0) {
added = 0;
}
} }
} }
if (headp != NULL) { if (headp != NULL) {
*headp = added + mb_added; *headp = head;
} }
return size; return size;
} }

View File

@ -19,6 +19,7 @@ typedef struct {
MarkTreeIter cts_iter[1]; MarkTreeIter cts_iter[1];
int cts_vcol; ///< virtual column at current position int cts_vcol; ///< virtual column at current position
int cts_max_head_vcol; ///< see win_lbr_chartabsize()
} chartabsize_T; } chartabsize_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS

View File

@ -2021,7 +2021,7 @@ bbbbbbb]])
]]} ]]}
end) end)
it('cursor position is correct with virtual text attached to hard tabs', function() it('cursor position is correct with virtual text attached to hard TABs', function()
command('set noexpandtab') command('set noexpandtab')
feed('i') feed('i')
feed('<TAB>') feed('<TAB>')
@ -2692,7 +2692,7 @@ bbbbbbb]])
]]} ]]}
end) end)
it('correctly draws when overflowing virtual text is followed by tab with no wrap', function() it('correctly draws when overflowing virtual text is followed by TAB with no wrap', function()
command('set nowrap') command('set nowrap')
feed('i<TAB>test<ESC>') feed('i<TAB>test<ESC>')
meths.buf_set_extmark( meths.buf_set_extmark(
@ -2984,6 +2984,328 @@ bbbbbbb]])
{8:-- VISUAL BLOCK --} | {8:-- VISUAL BLOCK --} |
]]} ]]}
end) end)
local function test_virt_inline_showbreak_smoothscroll()
screen:try_resize(30, 6)
exec([[
highlight! link LineNr Normal
call setline(1, repeat('a', 28))
setlocal number showbreak=+ breakindent breakindentopt=shift:2
setlocal scrolloff=0 smoothscroll
normal! $
]])
meths.buf_set_extmark(0, ns, 0, 27, { virt_text = { { ('123'):rep(23) } }, virt_text_pos = 'inline' })
feed(':<CR>') -- Have a screen line that doesn't start with spaces
screen:expect{grid=[[
1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
{1:+}a1231231231231231231231|
{1:+}23123123123123123123123|
{1:+}12312312312312312312312|
{1:+}3^a |
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}a1231231231231231231231|
{1:+}23123123123123123123123|
{1:+}12312312312312312312312|
{1:+}3^a |
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}23123123123123123123123|
{1:+}12312312312312312312312|
{1:+}3^a |
{1:~ }|
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}12312312312312312312312|
{1:+}3^a |
{1:~ }|
{1:~ }|
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}3^a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
: |
]]}
feed('zbi')
screen:expect{grid=[[
1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
{1:+}a^1231231231231231231231|
{1:+}23123123123123123123123|
{1:+}12312312312312312312312|
{1:+}3a |
{8:-- INSERT --} |
]]}
feed('<BS>')
screen:expect{grid=[[
1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
{1:+}^12312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}a |
{8:-- INSERT --} |
]]}
feed('<Esc>l')
feed(':<CR>') -- Have a screen line that doesn't start with spaces
screen:expect{grid=[[
1 aaaaaaaaaaaaaaaaaaaaaaaaaa|
{1:+}12312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}^a |
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}12312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|
{1:~ }|
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}^a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
: |
]]}
feed('023x$')
screen:expect{grid=[[
1 aaa12312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}23123123123123123123123|
{1:+}^a |
{1:~ }|
{1:~ }|
{1:~ }|
: |
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}^a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
: |
]]}
feed('zbi')
screen:expect{grid=[[
1 aaa^12312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123123|
{1:+}a |
{1:~ }|
{8:-- INSERT --} |
]]}
feed('<C-U>')
screen:expect{grid=[[
1 ^12312312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123a |
{1:~ }|
{1:~ }|
{8:-- INSERT --} |
]]}
feed('<Esc>')
screen:expect{grid=[[
1 12312312312312312312312312|
{1:+}31231231231231231231231|
{1:+}23123123123123123123^a |
{1:~ }|
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}31231231231231231231231|
{1:+}23123123123123123123^a |
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:+}23123123123123123123^a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
end
describe('with showbreak, smoothscroll', function()
it('and cpoptions-=n', function()
test_virt_inline_showbreak_smoothscroll()
end)
it('and cpoptions+=n', function()
command('set cpoptions+=n')
-- because of 'breakindent' the screen states are the same
test_virt_inline_showbreak_smoothscroll()
end)
end)
it('before TABs with smoothscroll', function()
screen:try_resize(30, 6)
exec([[
call setline(1, repeat("\t", 4) .. 'a')
setlocal list listchars=tab:<-> scrolloff=0 smoothscroll
normal! $
]])
meths.buf_set_extmark(0, ns, 0, 3, { virt_text = { { ('12'):rep(32) } }, virt_text_pos = 'inline' })
screen:expect{grid=[[
{1:<------><------><------>}121212|
121212121212121212121212121212|
1212121212121212121212121212{1:<-}|
{1:----->}^a |
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:<<<}212121212121212121212121212|
1212121212121212121212121212{1:<-}|
{1:----->}^a |
{1:~ }|
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:<<<}2121212121212121212121212{1:<-}|
{1:----->}^a |
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:<<<-->}^a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
feed('zbh')
screen:expect{grid=[[
{1:<------><------><------>}121212|
121212121212121212121212121212|
1212121212121212121212121212{1:^<-}|
{1:----->}a |
{1:~ }|
|
]]}
feed('i')
screen:expect{grid=[[
{1:<------><------><------>}^121212|
121212121212121212121212121212|
1212121212121212121212121212{1:<-}|
{1:----->}a |
{1:~ }|
{8:-- INSERT --} |
]]}
feed('<C-O>:setlocal nolist<CR>')
screen:expect{grid=[[
^121212|
121212121212121212121212121212|
1212121212121212121212121212 |
a |
{1:~ }|
{8:-- INSERT --} |
]]}
feed('<Esc>l')
screen:expect{grid=[[
121212|
121212121212121212121212121212|
1212121212121212121212121212 |
^ a |
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:<<<}212121212121212121212121212|
1212121212121212121212121212 |
^ a |
{1:~ }|
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:<<<}2121212121212121212121212 |
^ a |
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
feed('<C-E>')
screen:expect{grid=[[
{1:<<<} ^ a |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]]}
end)
end) end)
describe('decorations: virtual lines', function() describe('decorations: virtual lines', function()
@ -3643,7 +3965,7 @@ if (h->n_buckets < new_n_buckets) { // expand
end) end)
it('works with hard tabs', function() it('works with hard TABs', function()
insert(example_text2) insert(example_text2)
feed 'gg' feed 'gg'
meths.buf_set_extmark(0, ns, 1, 0, { meths.buf_set_extmark(0, ns, 1, 0, {

View File

@ -14,7 +14,7 @@ function s:screen_lines(lnum, width) abort
endfunction endfunction
func s:compare_lines(expect, actual) func s:compare_lines(expect, actual)
call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) call assert_equal(a:expect, a:actual)
endfunc endfunc
function s:test_windows(...) function s:test_windows(...)
@ -330,4 +330,47 @@ func Test_list_with_tab_and_skipping_first_chars()
\ ] \ ]
call s:compare_lines(expect, lines) call s:compare_lines(expect, lines)
call s:close_windows() call s:close_windows()
endfu endfunc
func Test_ctrl_char_on_wrap_column()
call s:test_windows("setl nolbr wrap sbr=")
call setline(1, 'aaa' .. repeat("\<C-A>", 150) .. 'bbb')
call cursor(1,1)
norm! $
redraw!
let expect=[
\ '<<<^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^A^A^A^A^A^A^A^A^A^',
\ 'A^Abbb ']
let lines = s:screen_lines([1, 10], winwidth(0))
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
setl sbr=!!
redraw!
let expect=[
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^A^A^A^',
\ '!!A^A^A^A^A^A^Abbb ']
let lines = s:screen_lines([1, 10], winwidth(0))
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
call s:close_windows()
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -249,7 +249,6 @@ endfunc
func Test_chinese_char_on_wrap_column() func Test_chinese_char_on_wrap_column()
call s:test_windows("setl nolbr wrap sbr=") call s:test_windows("setl nolbr wrap sbr=")
syntax off
call setline(1, [ call setline(1, [
\ 'aaaaaaaaaaaaaaaaaaa中'. \ 'aaaaaaaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaaaaa中'. \ 'aaaaaaaaaaaaaaaaa中'.
@ -278,5 +277,85 @@ func Test_chinese_char_on_wrap_column()
\ '中hello '] \ '中hello ']
let lines = s:screen_lines([1, 10], winwidth(0)) let lines = s:screen_lines([1, 10], winwidth(0))
call s:compare_lines(expect, lines) call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
call s:close_windows() call s:close_windows()
endfu endfunc
func Test_chinese_char_on_wrap_column_sbr()
call s:test_windows("setl nolbr wrap sbr=!!!")
call setline(1, [
\ 'aaaaaaaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'aaaaaaaaaaaaaa中'.
\ 'hello'])
call cursor(1,1)
norm! $
redraw!
let expect=[
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中aaaaaaaaaaaaaa>',
\ '!!!中hello ']
let lines = s:screen_lines([1, 10], winwidth(0))
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
call s:close_windows()
endfunc
func Test_unprintable_char_on_wrap_column()
call s:test_windows("setl nolbr wrap sbr=")
call setline(1, 'aaa' .. repeat("\uFEFF", 50) .. 'bbb')
call cursor(1,1)
norm! $
redraw!
let expect=[
\ '<<<<feff><feff><feff',
\ '><feff><feff><feff><',
\ 'feff><feff><feff><fe',
\ 'ff><feff><feff><feff',
\ '><feff><feff><feff><',
\ 'feff><feff><feff><fe',
\ 'ff><feff><feff><feff',
\ '><feff><feff><feff><',
\ 'feff><feff><feff><fe',
\ 'ff>bbb ']
let lines = s:screen_lines([1, 10], winwidth(0))
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
setl sbr=!!
redraw!
let expect=[
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff><feff',
\ '!!><feff><feff>bbb ']
let lines = s:screen_lines([1, 10], winwidth(0))
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
call s:close_windows()
endfunc
" vim: shiftwidth=2 sts=2 expandtab