aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuuk van Baal <luukvbaal@gmail.com>2024-01-11 14:30:12 +0100
committerLewis Russell <me@lewisr.dev>2024-01-15 09:37:53 +0000
commit967c7abde3c6fa3210a4920a5848a54dc913d851 (patch)
treea44518ccfcfab9a0011f05f62aa0be543fd8a3e2
parent4d91604c8868b7afaf429cc16b72192ce89ea698 (diff)
downloadrneovim-967c7abde3c6fa3210a4920a5848a54dc913d851.tar.gz
rneovim-967c7abde3c6fa3210a4920a5848a54dc913d851.tar.bz2
rneovim-967c7abde3c6fa3210a4920a5848a54dc913d851.zip
fix(column): keep track of number of lines with number of signs
Problem: Some edge cases to the old (pre-#26406) and current "b_signcols" structure result in an incorrectly sized "auto" 'signcolumn'. Solution: * Implement a simpler 'signcolumn' validation strategy by immediately counting the number of signs in a range upon sign insertion and deletion. Decrease in performance here but there is a clear path forward to decreasing this performance hit by moving signs to a dedicated marktree, or by adding meta-data to the existing marktree which may be queried more efficiently? * Also replace "max_count" and keep track of the number of lines with a certain number of signs. This makes it so that it is no longer necessary to scan the entire buffer when the maximum number of signs decreases. This likely makes the commit a net increase in performance. * To ensure correctness we also have re-initialize the count for an edited region that spans multiple lines. Such an edit may move the signs within it. Thus we count and decrement before splicing the marktree and count and increment after.
-rw-r--r--src/nvim/buffer.c4
-rw-r--r--src/nvim/buffer_defs.h10
-rw-r--r--src/nvim/decoration.c150
-rw-r--r--src/nvim/drawscreen.c35
-rw-r--r--src/nvim/extmark.c15
-rw-r--r--src/nvim/map.c3
-rw-r--r--src/nvim/map_defs.h3
-rw-r--r--src/nvim/types_defs.h7
-rw-r--r--src/nvim/undo.c33
-rw-r--r--test/functional/ui/decorations_spec.lua99
-rw-r--r--test/functional/ui/statuscolumn_spec.lua4
11 files changed, 215 insertions, 148 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index b29e87e91b..da1e27aebf 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -757,8 +757,6 @@ void buf_clear(void)
{
linenr_T line_count = curbuf->b_ml.ml_line_count;
extmark_free_all(curbuf); // delete any extmarks
- map_destroy(int, curbuf->b_signcols.invalid);
- *curbuf->b_signcols.invalid = (Map(int, SignRange)) MAP_INIT;
while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) {
ml_delete(1, false);
}
@@ -929,8 +927,6 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
}
uc_clear(&buf->b_ucmds); // clear local user commands
extmark_free_all(buf); // delete any extmarks
- map_destroy(int, buf->b_signcols.invalid);
- *buf->b_signcols.invalid = (Map(int, SignRange)) MAP_INIT;
map_clear_mode(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index f09aa70ef4..145a8435aa 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -685,10 +685,12 @@ struct file_buffer {
// may use a different synblock_T.
struct {
- int max; // maximum number of signs on a single line
- int max_count; // number of lines with max number of signs
- bool resized; // whether max changed at start of redraw
- Map(int, SignRange) invalid[1]; // map of invalid ranges to be checked
+ int max; // maximum number of signs on a single line
+ int count[SIGN_SHOW_MAX]; // number of lines with number of signs
+ bool resized; // whether max changed at start of redraw
+ bool autom; // whether 'signcolumn' is displayed in "auto:n>1"
+ // configured window. "b_signcols" calculation
+ // is skipped if false.
} b_signcols;
Terminal *terminal; // Terminal instance associated with the buffer
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index a3df5e704e..ddc4708740 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -207,7 +207,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
buf->b_signs++;
if (sh->text[0]) {
buf->b_signs_with_text++;
- buf_signcols_invalidate_range(buf, row1, row2, 1);
+ buf_signcols_count_range(buf, row1, row2, 1, kFalse);
}
}
}
@@ -254,8 +254,11 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh)
if (sh->text[0]) {
assert(buf->b_signs_with_text > 0);
buf->b_signs_with_text--;
- if (row2 >= row1) {
- buf_signcols_invalidate_range(buf, row1, row2, -1);
+ if (buf->b_signs_with_text) {
+ buf_signcols_count_range(buf, row1, row2, -1, kFalse);
+ } else {
+ buf->b_signcols.resized = true;
+ buf->b_signcols.max = buf->b_signcols.count[0] = 0;
}
}
}
@@ -785,42 +788,36 @@ DecorSignHighlight *decor_find_sign(DecorInline decor)
}
}
-static void buf_signcols_validate_row(buf_T *buf, int count, int add)
+/// Count the number of signs in a range after adding/removing a sign, or to
+/// (re-)initialize a range in "b_signcols.count".
+///
+/// @param add 1, -1 or 0 for an added, deleted or initialized range.
+/// @param clear kFalse, kTrue or kNone for an, added/deleted, cleared, or initialized range.
+void buf_signcols_count_range(buf_T *buf, int row1, int row2, int add, TriState clear)
{
- // If "count" is greater than current max, set it and reset "max_count".
- if (count > buf->b_signcols.max) {
- buf->b_signcols.max = count;
- buf->b_signcols.max_count = 0;
- buf->b_signcols.resized = true;
- }
- // If row has or had "max" signs, adjust "max_count" with sign of "add".
- if (count == buf->b_signcols.max - (add < 0 ? -add : 0)) {
- buf->b_signcols.max_count += (add > 0) - (add < 0);
+ if (!buf->b_signcols.autom || !buf->b_signs_with_text) {
+ return;
}
-}
-/// Validate a range by counting the number of overlapping signs and adjusting
-/// "b_signcols" accordingly.
-static void buf_signcols_validate_range(buf_T *buf, int row1, int row2, int add)
-{
- if (-add == buf->b_signcols.max) {
- buf->b_signcols.max_count -= (row2 + 1 - row1);
- return; // max signs were removed from the range, no need to count.
+ static int nested = 0;
+ // An undo/redo may trigger subsequent calls before its own kNone call.
+ if ((nested += clear) > (0 + (clear == kTrue))) {
+ return; // Avoid adding signs more than once.
}
- int currow = row1;
- MTPair pair = { 0 };
- MarkTreeIter itr[1];
-
- // Allocate an array of integers holding the overlapping signs in the range.
+ // Allocate an array of integers holding the number of signs in the range.
assert(row2 >= row1);
- int *overlap = xcalloc(sizeof(int), (size_t)(row2 + 1 - row1));
+ int *count = xcalloc(sizeof(int), (size_t)(row2 + 1 - row1));
+ MarkTreeIter itr[1];
+ MTPair pair = { 0 };
- // First find the number of overlapping signs at "row1".
- marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr);
+ // Increment count array for signs that start before "row1" but do overlap the range.
+ marktree_itr_get_overlap(buf->b_marktree, row1, 0, itr);
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
- if (!mt_invalid(pair.start) && pair.start.flags & MT_FLAG_DECOR_SIGNTEXT) {
- overlap[0]++;
+ if ((pair.start.flags & MT_FLAG_DECOR_SIGNTEXT) && !mt_invalid(pair.start)) {
+ for (int i = row1; i <= MIN(row2, pair.end_pos.row); i++) {
+ count[i - row1]++;
+ }
}
}
@@ -830,84 +827,37 @@ static void buf_signcols_validate_range(buf_T *buf, int row1, int row2, int add)
if (mark.pos.row > row2) {
break;
}
- // Finish the count at the previous row.
- if (mark.pos.row != currow) {
- buf_signcols_validate_row(buf, overlap[currow - row1], add);
- currow = mark.pos.row;
- }
- // Increment overlap array for the start and range of a paired sign mark.
- if (!mt_invalid(mark) && !mt_end(mark) && (mark.flags & MT_FLAG_DECOR_SIGNTEXT)) {
+ if ((mark.flags & MT_FLAG_DECOR_SIGNTEXT) && !mt_invalid(mark) && !mt_end(mark)) {
+ // Increment count array for the range of a paired sign mark.
MTPos end = marktree_get_altpos(buf->b_marktree, mark, NULL);
- for (int i = currow; i <= MIN(row2, end.row); i++) {
- overlap[i - row1]++;
+ for (int i = mark.pos.row; i <= MIN(row2, end.row); i++) {
+ count[i - row1]++;
}
}
marktree_itr_next(buf->b_marktree, itr);
}
- buf_signcols_validate_row(buf, overlap[currow - row1], add);
- xfree(overlap);
-}
-int buf_signcols_validate(win_T *wp, buf_T *buf, bool stc_check)
-{
- if (!map_size(buf->b_signcols.invalid)) {
- return buf->b_signcols.max;
- }
-
- int start;
- SignRange range;
- map_foreach(buf->b_signcols.invalid, start, range, {
- // Leave rest of the ranges invalid if max is already at configured
- // maximum or resize is detected for a 'statuscolumn' rebuild.
- if ((stc_check && buf->b_signcols.resized)
- || (!stc_check && range.add > 0 && buf->b_signcols.max >= wp->w_maxscwidth)) {
- return wp->w_maxscwidth;
- }
- buf_signcols_validate_range(buf, start, range.end, range.add);
- });
-
- // Check if we need to scan the entire buffer.
- if (buf->b_signcols.max_count == 0) {
- buf->b_signcols.max = 0;
- buf->b_signcols.resized = true;
- buf_signcols_validate_range(buf, 0, buf->b_ml.ml_line_count, 1);
- }
-
- map_clear(int, buf->b_signcols.invalid);
- return buf->b_signcols.max;
-}
-
-static void buf_signcols_invalidate_range(buf_T *buf, int row1, int row2, int add)
-{
- if (!buf->b_signs_with_text) {
- buf->b_signcols.max = buf->b_signcols.max_count = 0;
- buf->b_signcols.resized = true;
- map_clear(int, buf->b_signcols.invalid);
- return;
- }
-
- // Remove an invalid range if sum of added/removed signs is now 0.
- SignRange *srp = map_ref(int, SignRange)(buf->b_signcols.invalid, row1, NULL);
- if (srp && srp->end == row2 && srp->add + add == 0) {
- map_del(int, SignRange)(buf->b_signcols.invalid, row1, NULL);
- return;
- }
-
- // Merge with overlapping invalid range.
- int start;
- SignRange range;
- map_foreach(buf->b_signcols.invalid, start, range, {
- if (row1 <= range.end && start <= row2) {
- row1 = MIN(row1, start);
- row2 = MAX(row2, range.end);
- break;
+ // For each row increment "b_signcols.count" at the number of counted signs,
+ // and decrement at the previous number of signs. These two operations are
+ // split in separate calls if "clear" is not kNone (surrounding a marktree splice).
+ for (int i = 0; i < row2 + 1 - row1; i++) {
+ int width = MIN(SIGN_SHOW_MAX, count[i] - add);
+ if (clear != kNone && width > 0) {
+ buf->b_signcols.count[width - 1]--;
+ assert(buf->b_signcols.count[width - 1] >= 0);
+ }
+ width = MIN(SIGN_SHOW_MAX, count[i]);
+ if (clear != kTrue && width > 0) {
+ buf->b_signcols.count[width - 1]++;
+ if (width > buf->b_signcols.max) {
+ buf->b_signcols.resized = true;
+ buf->b_signcols.max = width;
+ }
}
- });
+ }
- srp = map_put_ref(int, SignRange)(buf->b_signcols.invalid, row1, NULL, NULL);
- srp->end = row2;
- srp->add += add;
+ xfree(count);
}
void decor_redraw_end(DecorState *state)
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index 7f794a58d2..b49de19349 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -1201,27 +1201,30 @@ void comp_col(void)
/// Redraw entire window "wp" if configured 'signcolumn' width changes.
static bool win_redraw_signcols(win_T *wp)
{
- int width;
- bool rebuild_stc = false;
buf_T *buf = wp->w_buffer;
- if (wp->w_minscwidth <= SCL_NO) {
- if (*wp->w_p_stc) {
- buf_signcols_validate(wp, buf, true);
- if (buf->b_signcols.resized) {
- rebuild_stc = true;
- wp->w_nrwidth_line_count = 0;
- }
- }
- width = 0;
- } else if (wp->w_maxscwidth <= 1 && buf->b_signs_with_text >= (size_t)wp->w_maxscwidth) {
- width = wp->w_maxscwidth;
- } else {
- width = MIN(wp->w_maxscwidth, buf_signcols_validate(wp, buf, false));
+ if (!buf->b_signcols.autom
+ && (*wp->w_p_stc != NUL || (wp->w_maxscwidth > 1 && wp->w_minscwidth != wp->w_maxscwidth))) {
+ buf->b_signcols.autom = true;
+ buf_signcols_count_range(buf, 0, buf->b_ml.ml_line_count, MAXLNUM, kNone);
+ }
+
+ while (buf->b_signcols.max > 0 && buf->b_signcols.count[buf->b_signcols.max - 1] == 0) {
+ buf->b_signcols.resized = true;
+ buf->b_signcols.max--;
+ }
+
+ int width = MIN(wp->w_maxscwidth, buf->b_signcols.max);
+ bool rebuild_stc = buf->b_signcols.resized && *wp->w_p_stc != NUL;
+
+ if (rebuild_stc) {
+ wp->w_nrwidth_line_count = 0;
+ } else if (wp->w_minscwidth == 0 && wp->w_maxscwidth == 1) {
+ width = buf->b_signs_with_text > 0;
}
int scwidth = wp->w_scwidth;
- wp->w_scwidth = MAX(wp->w_minscwidth, width);
+ wp->w_scwidth = MAX(MAX(0, wp->w_minscwidth), width);
return (wp->w_scwidth != scwidth || rebuild_stc);
}
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index a5f669acde..0321a11b0f 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -521,10 +521,19 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
extmark_splice_delete(buf, start_row, start_col, end_row, end_col, uvp, false, undo);
}
+ // Remove signs inside edited region from "b_signcols.count", add after splicing.
+ if (old_row > 0 || new_row > 0) {
+ buf_signcols_count_range(buf, start_row, start_row + old_row + 1, 0, kTrue);
+ }
+
marktree_splice(buf->b_marktree, (int32_t)start_row, start_col,
old_row, old_col,
new_row, new_col);
+ if (old_row > 0 || new_row > 0) {
+ buf_signcols_count_range(buf, start_row, start_row + new_row + 1, 0, kNone);
+ }
+
if (undo == kExtmarkUndo) {
u_header_T *uhp = u_force_get_undo_header(buf);
if (!uhp) {
@@ -603,10 +612,16 @@ void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, bcount_t
extent_row, extent_col, extent_byte,
0, 0, 0);
+ int row1 = MIN(start_row, new_row);
+ int row2 = MAX(start_row, new_row) + extent_row;
+ buf_signcols_count_range(buf, row1, row2, 0, kTrue);
+
marktree_move_region(buf->b_marktree, start_row, start_col,
extent_row, extent_col,
new_row, new_col);
+ buf_signcols_count_range(buf, row1, row2, 0, kNone);
+
buf_updates_send_splice(buf, new_row, new_col, new_byte,
0, 0, 0,
extent_row, extent_col, extent_byte);
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 0011c97f9b..be6bf58daa 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -111,9 +111,6 @@ void mh_clear(MapHash *h)
#define VAL_NAME(x) quasiquote(x, String)
#include "nvim/map_value_impl.c.h"
#undef VAL_NAME
-#define VAL_NAME(x) quasiquote(x, SignRange)
-#include "nvim/map_value_impl.c.h"
-#undef VAL_NAME
#undef KEY_NAME
#define KEY_NAME(x) x##ptr_t
diff --git a/src/nvim/map_defs.h b/src/nvim/map_defs.h
index b85ba5acaf..f3c4e4ea95 100644
--- a/src/nvim/map_defs.h
+++ b/src/nvim/map_defs.h
@@ -48,7 +48,6 @@ static const uint64_t value_init_uint64_t = 0;
static const int64_t value_init_int64_t = 0;
static const String value_init_String = STRING_INIT;
static const ColorItem value_init_ColorItem = COLOR_ITEM_INITIALIZER;
-static const SignRange value_init_SignRange = SIGNRANGE_INIT;
// layer 0: type non-specific code
@@ -151,7 +150,6 @@ KEY_DECLS(uint32_t)
KEY_DECLS(String)
KEY_DECLS(HlEntry)
KEY_DECLS(ColorKey)
-KEY_DECLS(SignRange)
MAP_DECLS(int, int)
MAP_DECLS(int, ptr_t)
@@ -168,7 +166,6 @@ MAP_DECLS(uint32_t, uint32_t)
MAP_DECLS(String, int)
MAP_DECLS(int, String)
MAP_DECLS(ColorKey, ColorItem)
-MAP_DECLS(int, SignRange)
#define set_has(T, set, key) set_has_##T(set, key)
#define set_put(T, set, key) set_put_##T(set, key, NULL)
diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h
index 99f448d8a1..934159b9d9 100644
--- a/src/nvim/types_defs.h
+++ b/src/nvim/types_defs.h
@@ -48,13 +48,6 @@ typedef enum {
typedef int64_t OptInt;
-// Range entry for the "b_signcols.invalid" map in which the keys are the range start.
-typedef struct {
- int end; // End of the invalid range.
- int add; // Number of signs added in the invalid range, negative for deleted signs.
-} SignRange;
-#define SIGNRANGE_INIT { 0, 0 }
-
enum { SIGN_WIDTH = 2, }; ///< Number of display cells for a sign in the signcolumn
typedef struct file_buffer buf_T;
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index b08ce96568..d343fb5fa0 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -89,6 +89,7 @@
#include "nvim/buffer_updates.h"
#include "nvim/change.h"
#include "nvim/cursor.h"
+#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
#include "nvim/edit.h"
#include "nvim/eval/funcs.h"
@@ -2423,17 +2424,38 @@ static void u_undoredo(bool undo, bool do_buf_event)
curbuf->b_op_end.lnum = curbuf->b_ml.ml_line_count;
}
+ int row1 = MAXLNUM;
+ int row2 = -1;
+ int row3 = -1;
+ // Tricky: ExtmarkSavePos may come after ExtmarkSplice which does call
+ // buf_signcols_count_range() but then misses the yet unrestored marks.
+ if (curbuf->b_signcols.autom && curbuf->b_signs_with_text) {
+ for (int i = 0; i < (int)kv_size(curhead->uh_extmark); i++) {
+ ExtmarkUndoObject undo_info = kv_A(curhead->uh_extmark, i);
+ if (undo_info.type == kExtmarkSplice) {
+ ExtmarkSplice s = undo_info.data.splice;
+ if (s.old_row > 0 || s.new_row > 0) {
+ row1 = MIN(row1, s.start_row);
+ row2 = MAX(row2, s.start_row + (undo ? s.new_row : s.old_row) + 1);
+ row3 = MAX(row3, s.start_row + (undo ? s.old_row : s.new_row) + 1);
+ }
+ }
+ }
+ if (row2 != -1) {
+ // Remove signs inside edited region from "b_signcols.count".
+ buf_signcols_count_range(curbuf, row1, row2, 0, kTrue);
+ }
+ }
// Adjust Extmarks
- ExtmarkUndoObject undo_info;
if (undo) {
for (int i = (int)kv_size(curhead->uh_extmark) - 1; i > -1; i--) {
- undo_info = kv_A(curhead->uh_extmark, i);
+ ExtmarkUndoObject undo_info = kv_A(curhead->uh_extmark, i);
extmark_apply_undo(undo_info, undo);
}
// redo
} else {
for (int i = 0; i < (int)kv_size(curhead->uh_extmark); i++) {
- undo_info = kv_A(curhead->uh_extmark, i);
+ ExtmarkUndoObject undo_info = kv_A(curhead->uh_extmark, i);
extmark_apply_undo(undo_info, undo);
}
}
@@ -2442,7 +2464,10 @@ static void u_undoredo(bool undo, bool do_buf_event)
// should have all info to send a buffer-reloaing on_lines/on_bytes event
buf_updates_unload(curbuf, true);
}
- // finish Adjusting extmarks
+ // Finish adjusting extmarks: add signs inside edited region to "b_signcols.count".
+ if (row2 != -1) {
+ buf_signcols_count_range(curbuf, row1, row3, 0, kNone);
+ }
curhead->uh_entry = newlist;
curhead->uh_flags = new_flags;
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 186bf19214..0844ddf249 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -4898,14 +4898,103 @@ l5
it('correct width with multiple overlapping signs', function()
screen:try_resize(20, 4)
insert(example_test3)
- api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=2})
- api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row=2})
+ api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
+ api.nvim_buf_set_extmark(0, ns, 0, -1, {sign_text='S2', end_row=2})
+ api.nvim_buf_set_extmark(0, ns, 1, -1, {sign_text='S3', end_row=2})
feed('gg')
+ local s1 = [[
+ S1S2^l1 |
+ S2S3l2 |
+ S2S3l3 |
+ |
+ ]]
+ screen:expect{grid=s1}
+ -- Correct width when :move'ing a line with signs
+ command('move2')
+ screen:expect{grid=[[
+ S3{1: }l2 |
+ S1S2S3^l1 |
+ {1: }l3 |
+ |
+ ]]}
+ command('silent undo')
+ screen:expect{grid=s1}
+ command('d')
+ screen:expect{grid=[[
+ S1S2S3^l2 |
+ S2S3{1: }l3 |
+ {1: }l4 |
+ |
+ ]]}
+ command('d')
+ screen:expect{grid=[[
+ S1S2S3^l3 |
+ {1: }l4 |
+ {1: }l5 |
+ |
+ ]]}
+ end)
+
+ it('correct width when adding and removing multiple signs', function()
+ screen:try_resize(20, 4)
+ insert(example_test3)
+ feed('gg')
+ command([[
+ let ns = nvim_create_namespace('')
+ call nvim_buf_set_extmark(0, ns, 0, 0, {'sign_text':'S1', 'end_row':3})
+ let s1 = nvim_buf_set_extmark(0, ns, 2, 0, {'sign_text':'S2', 'end_row':4})
+ let s2 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
+ let s3 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'})
+ let s4 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
+ let s5 = nvim_buf_set_extmark(0, ns, 6, 0, {'sign_text':'S3'})
+ redraw!
+ call nvim_buf_del_extmark(0, ns, s2)
+ call nvim_buf_del_extmark(0, ns, s3)
+ call nvim_buf_del_extmark(0, ns, s4)
+ call nvim_buf_del_extmark(0, ns, s5)
+ redraw!
+ call nvim_buf_del_extmark(0, ns, s1)
+ ]])
screen:expect{grid=[[
- S1{1: }^l1 |
- S1S2l2 |
- S1S2l3 |
+ S1^l1 |
+ S1l2 |
+ S1l3 |
+ |
+ ]]}
+ end)
+
+ it('correct width when deleting lines', function()
+ screen:try_resize(20, 4)
+ insert(example_test3)
+ feed('gg')
+ command([[
+ let ns = nvim_create_namespace('')
+ call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S1'})
+ call nvim_buf_set_extmark(0, ns, 4, 0, {'sign_text':'S2'})
+ let s3 = nvim_buf_set_extmark(0, ns, 5, 0, {'sign_text':'S3'})
+ call nvim_buf_del_extmark(0, ns, s3)
+ norm 4Gdd
+ ]])
+ screen:expect{grid=[[
+ {1: }l3 |
+ S1S2l5 |
+ {1: }^ |
+ |
+ ]]}
+ end)
+
+ it('correct width when splitting lines with signs on different columns', function()
+ screen:try_resize(20, 4)
+ insert(example_test3)
+ feed('gg')
+ api.nvim_buf_set_extmark(0, ns, 0, 0, {sign_text='S1'})
+ api.nvim_buf_set_extmark(0, ns, 0, 1, {sign_text='S2'})
+ feed('a<cr><esc>')
+ screen:expect{grid=[[
+ S1l |
+ S2^1 |
+ {1: }l2 |
|
]]}
end)
diff --git a/test/functional/ui/statuscolumn_spec.lua b/test/functional/ui/statuscolumn_spec.lua
index dec696d3c3..d5aeb2c51a 100644
--- a/test/functional/ui/statuscolumn_spec.lua
+++ b/test/functional/ui/statuscolumn_spec.lua
@@ -521,8 +521,8 @@ describe('statuscolumn', function()
command([[set stc=%6s\ %l]])
exec_lua('vim.api.nvim_buf_set_extmark(0, ns, 7, 0, {sign_text = "ð’€€"})')
screen:expect([[
- {0: ð’€€ 8}^aaaaa |
- {0: }{1: }{0: 9}aaaaa |
+ {0: ð’€€ 8 }^aaaaa |
+ {0: }{1: }{0: 9 }aaaaa |
|
]])
end)