fix(edit): backspace adds extra spaces for inline virtual text (#28005)

Problem:  Backspace adds extra spaces for inline virtual text.
Solution: Ignore virtual text and wrapping when backspacing.
This commit is contained in:
vanaigr
2024-03-25 16:12:56 -05:00
committed by GitHub
parent a7bbda121d
commit 14839c5d18
3 changed files with 208 additions and 50 deletions

View File

@@ -3673,23 +3673,6 @@ static void ins_del(void)
AppendCharToRedobuff(K_DEL);
}
// Delete one character for ins_bs().
static void ins_bs_one(colnr_T *vcolp)
{
dec_cursor();
getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL);
if (State & REPLACE_FLAG) {
// Don't delete characters before the insert point when in
// Replace mode
if (curwin->w_cursor.lnum != Insstart.lnum
|| curwin->w_cursor.col >= Insstart.col) {
replace_do_bs(-1);
}
} else {
del_char(false);
}
}
/// Handle Backspace, delete-word and delete-line in Insert mode.
///
/// @param c character that was typed
@@ -3846,42 +3829,69 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
// Handle deleting one 'shiftwidth' or 'softtabstop'.
if (mode == BACKSPACE_CHAR
&& ((p_sta && in_indent)
|| ((get_sts_value() != 0
|| tabstop_count(curbuf->b_p_vsts_array))
|| ((get_sts_value() != 0 || tabstop_count(curbuf->b_p_vsts_array))
&& curwin->w_cursor.col > 0
&& (*(get_cursor_pos_ptr() - 1) == TAB
|| (*(get_cursor_pos_ptr() - 1) == ' '
&& (!*inserted_space_p || arrow_used)))))) {
colnr_T vcol;
colnr_T want_vcol;
*inserted_space_p = false;
// Compute the virtual column where we want to be. Since
// 'showbreak' may get in the way, need to get the last column of
// the previous character.
getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
colnr_T start_vcol = vcol;
dec_cursor();
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
inc_cursor();
if (p_sta && in_indent) {
int ts = get_sw_value(curbuf);
want_vcol = (want_vcol / ts) * ts;
bool const use_ts = !curwin->w_p_list || curwin->w_p_lcs_chars.tab1;
char *const line = ml_get_buf(curbuf, curwin->w_cursor.lnum);
char *const end_ptr = line + curwin->w_cursor.col;
colnr_T vcol = 0;
colnr_T space_vcol = 0;
StrCharInfo sci = utf_ptr2StrCharInfo(line);
StrCharInfo space_sci = sci;
bool prev_space = false;
while (sci.ptr < end_ptr) {
bool cur_space = ascii_iswhite(sci.chr.value);
if (!prev_space && cur_space) {
space_sci = sci;
space_vcol = vcol;
}
vcol += charsize_nowrap(curbuf, use_ts, vcol, sci.chr.value);
sci = utfc_next(sci);
prev_space = cur_space;
}
colnr_T want_vcol = vcol - 1;
if (want_vcol <= 0) {
want_vcol = 0;
} else if (p_sta && in_indent) {
want_vcol = want_vcol - want_vcol % get_sw_value(curbuf);
} else {
want_vcol = tabstop_start(want_vcol,
get_sts_value(),
curbuf->b_p_vsts_array);
want_vcol = tabstop_start(want_vcol, get_sts_value(), curbuf->b_p_vsts_array);
}
// delete characters until we are at or before want_vcol
while (vcol > want_vcol && curwin->w_cursor.col > 0
&& (cc = (uint8_t)(*(get_cursor_pos_ptr() - 1)), ascii_iswhite(cc))) {
ins_bs_one(&vcol);
while (true) {
int size = charsize_nowrap(curbuf, use_ts, space_vcol, space_sci.chr.value);
if (space_vcol + size > want_vcol) {
break;
}
space_vcol += size;
space_sci = utfc_next(space_sci);
}
colnr_T const want_col = (int)(space_sci.ptr - line);
// Delete characters until we are at or before want_col.
while (curwin->w_cursor.col > want_col) {
dec_cursor();
if (State & REPLACE_FLAG) {
// Don't delete characters before the insert point when in Replace mode.
if (curwin->w_cursor.lnum != Insstart.lnum
|| curwin->w_cursor.col >= Insstart.col) {
replace_do_bs(-1);
}
} else {
del_char(false);
}
}
// insert extra spaces until we are at want_vcol
while (vcol < want_vcol) {
// Remember the first char we inserted
// Insert extra spaces until we are at want_vcol.
for (; space_vcol < want_vcol; space_vcol++) {
// Remember the first char we inserted.
if (curwin->w_cursor.lnum == Insstart_orig.lnum
&& curwin->w_cursor.col < Insstart_orig.col) {
Insstart_orig.col = curwin->w_cursor.col;
@@ -3895,13 +3905,6 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
replace_push(NUL);
}
}
getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
}
// If we are now back where we started delete one character. Can
// happen when using 'sts' and 'linebreak'.
if (vcol >= start_vcol) {
ins_bs_one(&vcol);
}
} else {
// Delete up to starting point, start of line or previous word.

View File

@@ -375,6 +375,18 @@ CharSize charsize_fast(CharsizeArg *csarg, colnr_T const vcol, int32_t const cur
return charsize_fast_impl(csarg->win, csarg->use_tabstop, vcol, cur_char);
}
/// Get the number of cells taken up on the screen at given virtual column.
int charsize_nowrap(buf_T *buf, bool use_tabstop, colnr_T vcol, int32_t cur_char)
{
if (cur_char == TAB && use_tabstop) {
return tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array);
} else if (cur_char < 0) {
return kInvalidByteCells;
} else {
return char2cells(cur_char);
}
}
/// Check that virtual column "vcol" is in the rightmost column of window "wp".
///
/// @param wp window