mirror of
https://github.com/neovim/neovim
synced 2025-07-17 09:41:46 +00:00
feat(marks): virtual lines support horizontal scrolling (#32497)
Add a new field `virt_lines_overflow` that enables horizontal scrolling for virtual lines when set to "scroll".
This commit is contained in:
@ -2651,6 +2651,12 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
|
|||||||
• virt_lines_above: place virtual lines above instead.
|
• virt_lines_above: place virtual lines above instead.
|
||||||
• virt_lines_leftcol: Place virtual lines in the leftmost
|
• virt_lines_leftcol: Place virtual lines in the leftmost
|
||||||
column of the window, bypassing sign and number columns.
|
column of the window, bypassing sign and number columns.
|
||||||
|
• virt_lines_overflow: controls how to handle virtual lines
|
||||||
|
wider than the window. Currently takes the one of the
|
||||||
|
following values:
|
||||||
|
• "trunc": truncate virtual lines on the right (default).
|
||||||
|
• "scroll": virtual lines can scroll horizontally with
|
||||||
|
'nowrap', otherwise the same as "trunc".
|
||||||
• ephemeral : for use with |nvim_set_decoration_provider()|
|
• ephemeral : for use with |nvim_set_decoration_provider()|
|
||||||
callbacks. The mark will only be used for the current
|
callbacks. The mark will only be used for the current
|
||||||
redraw cycle, and not be permantently stored in the
|
redraw cycle, and not be permantently stored in the
|
||||||
|
@ -202,9 +202,12 @@ API
|
|||||||
• |nvim_echo()| `err` field to print error messages and `chunks` accepts
|
• |nvim_echo()| `err` field to print error messages and `chunks` accepts
|
||||||
highlight group IDs.
|
highlight group IDs.
|
||||||
• |nvim_open_win()| `relative` field can be set to "laststatus" and "tabline".
|
• |nvim_open_win()| `relative` field can be set to "laststatus" and "tabline".
|
||||||
• |nvim_buf_set_extmark()| `hl_group` field can be an array of layered groups
|
• |nvim_buf_set_extmark()| new field `virt_lines_overflow` accepts value `scroll` to
|
||||||
|
enable horizontal scrolling for virtual lines with 'nowrap'.
|
||||||
|
right aligned text that truncates before covering up buffer text.
|
||||||
|
• |nvim_buf_set_extmark()| `hl_group` field can be an array of layered groups.
|
||||||
• |vim.hl.range()| now has a optional `timeout` field which allows for a timed highlight
|
• |vim.hl.range()| now has a optional `timeout` field which allows for a timed highlight
|
||||||
• |nvim_buf_set_extmark()| virt_text_pos accepts `eol_right_align` to
|
• |nvim_buf_set_extmark()| `virt_text_pos` field accepts value `eol_right_align` to
|
||||||
allow for right aligned text that truncates before covering up buffer text.
|
allow for right aligned text that truncates before covering up buffer text.
|
||||||
|
|
||||||
DEFAULTS
|
DEFAULTS
|
||||||
|
6
runtime/lua/vim/_meta/api.lua
generated
6
runtime/lua/vim/_meta/api.lua
generated
@ -641,7 +641,11 @@ function vim.api.nvim_buf_line_count(buffer) end
|
|||||||
--- - virt_lines_leftcol: Place virtual lines in the leftmost
|
--- - virt_lines_leftcol: Place virtual lines in the leftmost
|
||||||
--- column of the window, bypassing
|
--- column of the window, bypassing
|
||||||
--- sign and number columns.
|
--- sign and number columns.
|
||||||
---
|
--- - virt_lines_overflow: controls how to handle virtual lines wider
|
||||||
|
--- than the window. Currently takes the one of the following values:
|
||||||
|
--- - "trunc": truncate virtual lines on the right (default).
|
||||||
|
--- - "scroll": virtual lines can scroll horizontally with 'nowrap',
|
||||||
|
--- otherwise the same as "trunc".
|
||||||
--- - ephemeral : for use with `nvim_set_decoration_provider()`
|
--- - ephemeral : for use with `nvim_set_decoration_provider()`
|
||||||
--- callbacks. The mark will only be used for the current
|
--- callbacks. The mark will only be used for the current
|
||||||
--- redraw cycle, and not be permantently stored in the
|
--- redraw cycle, and not be permantently stored in the
|
||||||
|
1
runtime/lua/vim/_meta/api_keysets.lua
generated
1
runtime/lua/vim/_meta/api_keysets.lua
generated
@ -258,6 +258,7 @@ error('Cannot require a meta file')
|
|||||||
--- @field virt_lines? any[]
|
--- @field virt_lines? any[]
|
||||||
--- @field virt_lines_above? boolean
|
--- @field virt_lines_above? boolean
|
||||||
--- @field virt_lines_leftcol? boolean
|
--- @field virt_lines_leftcol? boolean
|
||||||
|
--- @field virt_lines_overflow? string
|
||||||
--- @field strict? boolean
|
--- @field strict? boolean
|
||||||
--- @field sign_text? string
|
--- @field sign_text? string
|
||||||
--- @field sign_hl_group? integer|string
|
--- @field sign_hl_group? integer|string
|
||||||
|
@ -448,7 +448,11 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
|||||||
/// - virt_lines_leftcol: Place virtual lines in the leftmost
|
/// - virt_lines_leftcol: Place virtual lines in the leftmost
|
||||||
/// column of the window, bypassing
|
/// column of the window, bypassing
|
||||||
/// sign and number columns.
|
/// sign and number columns.
|
||||||
///
|
/// - virt_lines_overflow: controls how to handle virtual lines wider
|
||||||
|
/// than the window. Currently takes the one of the following values:
|
||||||
|
/// - "trunc": truncate virtual lines on the right (default).
|
||||||
|
/// - "scroll": virtual lines can scroll horizontally with 'nowrap',
|
||||||
|
/// otherwise the same as "trunc".
|
||||||
/// - ephemeral : for use with |nvim_set_decoration_provider()|
|
/// - ephemeral : for use with |nvim_set_decoration_provider()|
|
||||||
/// callbacks. The mark will only be used for the current
|
/// callbacks. The mark will only be used for the current
|
||||||
/// redraw cycle, and not be permantently stored in the
|
/// redraw cycle, and not be permantently stored in the
|
||||||
@ -669,7 +673,17 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool virt_lines_leftcol = opts->virt_lines_leftcol;
|
int virt_lines_flags = opts->virt_lines_leftcol ? kVLLeftcol : 0;
|
||||||
|
if (HAS_KEY(opts, set_extmark, virt_lines_overflow)) {
|
||||||
|
String str = opts->virt_lines_overflow;
|
||||||
|
if (strequal("scroll", str.data)) {
|
||||||
|
virt_lines_flags |= kVLScroll;
|
||||||
|
} else if (!strequal("trunc", str.data)) {
|
||||||
|
VALIDATE_S(false, "virt_lines_overflow", str.data, {
|
||||||
|
goto error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (HAS_KEY(opts, set_extmark, virt_lines)) {
|
if (HAS_KEY(opts, set_extmark, virt_lines)) {
|
||||||
Array a = opts->virt_lines;
|
Array a = opts->virt_lines;
|
||||||
@ -679,7 +693,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
|||||||
});
|
});
|
||||||
int dummig;
|
int dummig;
|
||||||
VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig);
|
VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig);
|
||||||
kv_push(virt_lines.data.virt_lines, ((struct virt_line){ jtem, virt_lines_leftcol }));
|
kv_push(virt_lines.data.virt_lines, ((struct virt_line){ jtem, virt_lines_flags }));
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ typedef struct {
|
|||||||
Array virt_lines;
|
Array virt_lines;
|
||||||
Boolean virt_lines_above;
|
Boolean virt_lines_above;
|
||||||
Boolean virt_lines_leftcol;
|
Boolean virt_lines_leftcol;
|
||||||
|
String virt_lines_overflow;
|
||||||
Boolean strict;
|
Boolean strict;
|
||||||
String sign_text;
|
String sign_text;
|
||||||
HLGroupID sign_hl_group;
|
HLGroupID sign_hl_group;
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
#define NIL ((Object)OBJECT_INIT)
|
#define NIL ((Object)OBJECT_INIT)
|
||||||
#define NULL_STRING ((String)STRING_INIT)
|
#define NULL_STRING ((String)STRING_INIT)
|
||||||
|
|
||||||
#define HAS_KEY(d, typ, key) (((d)->is_set__##typ##_ & (1 << KEYSET_OPTIDX_##typ##__##key)) != 0)
|
#define HAS_KEY(d, typ, key) (((d)->is_set__##typ##_ & (1ULL << KEYSET_OPTIDX_##typ##__##key)) != 0)
|
||||||
|
|
||||||
#define GET_BOOL_OR_TRUE(d, typ, key) (HAS_KEY(d, typ, key) ? (d)->key : true)
|
#define GET_BOOL_OR_TRUE(d, typ, key) (HAS_KEY(d, typ, key) ? (d)->key : true)
|
||||||
|
|
||||||
@ -75,7 +75,7 @@
|
|||||||
kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v }))
|
kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v }))
|
||||||
|
|
||||||
#define PUT_KEY(d, typ, key, v) \
|
#define PUT_KEY(d, typ, key, v) \
|
||||||
do { (d).is_set__##typ##_ |= (1 << KEYSET_OPTIDX_##typ##__##key); (d).key = v; } while (0)
|
do { (d).is_set__##typ##_ |= (1ULL << KEYSET_OPTIDX_##typ##__##key); (d).key = v; } while (0)
|
||||||
|
|
||||||
#define ADD(array, item) \
|
#define ADD(array, item) \
|
||||||
kv_push(array, item)
|
kv_push(array, item)
|
||||||
|
@ -1169,15 +1169,17 @@ void decor_to_dict_legacy(Dict *dict, DecorInline decor, bool hl_name, Arena *ar
|
|||||||
|
|
||||||
if (virt_lines) {
|
if (virt_lines) {
|
||||||
Array all_chunks = arena_array(arena, kv_size(virt_lines->data.virt_lines));
|
Array all_chunks = arena_array(arena, kv_size(virt_lines->data.virt_lines));
|
||||||
bool virt_lines_leftcol = false;
|
int virt_lines_flags = 0;
|
||||||
for (size_t i = 0; i < kv_size(virt_lines->data.virt_lines); i++) {
|
for (size_t i = 0; i < kv_size(virt_lines->data.virt_lines); i++) {
|
||||||
virt_lines_leftcol = kv_A(virt_lines->data.virt_lines, i).left_col;
|
virt_lines_flags = kv_A(virt_lines->data.virt_lines, i).flags;
|
||||||
Array chunks = virt_text_to_array(kv_A(virt_lines->data.virt_lines, i).line, hl_name, arena);
|
Array chunks = virt_text_to_array(kv_A(virt_lines->data.virt_lines, i).line, hl_name, arena);
|
||||||
ADD(all_chunks, ARRAY_OBJ(chunks));
|
ADD(all_chunks, ARRAY_OBJ(chunks));
|
||||||
}
|
}
|
||||||
PUT_C(*dict, "virt_lines", ARRAY_OBJ(all_chunks));
|
PUT_C(*dict, "virt_lines", ARRAY_OBJ(all_chunks));
|
||||||
PUT_C(*dict, "virt_lines_above", BOOLEAN_OBJ(virt_lines->flags & kVTLinesAbove));
|
PUT_C(*dict, "virt_lines_above", BOOLEAN_OBJ(virt_lines->flags & kVTLinesAbove));
|
||||||
PUT_C(*dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol));
|
PUT_C(*dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_flags & kVLLeftcol));
|
||||||
|
PUT_C(*dict, "virt_lines_overflow",
|
||||||
|
CSTR_AS_OBJ(virt_lines_flags & kVLScroll ? "scroll" : "trunc"));
|
||||||
priority = virt_lines->priority;
|
priority = virt_lines->priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,14 @@ typedef enum {
|
|||||||
kVPosWinCol,
|
kVPosWinCol,
|
||||||
} VirtTextPos;
|
} VirtTextPos;
|
||||||
|
|
||||||
typedef kvec_t(struct virt_line { VirtText line; bool left_col; }) VirtLines;
|
/// Flags for virtual lines
|
||||||
|
enum {
|
||||||
|
kVLLeftcol = 1, ///< Start at left window edge, ignoring number column, etc.
|
||||||
|
kVLScroll = 2, ///< Can scroll horizontally with 'nowrap'
|
||||||
|
// kVLWrap = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef kvec_t(struct virt_line { VirtText line; int flags; }) VirtLines;
|
||||||
|
|
||||||
typedef uint16_t DecorPriority;
|
typedef uint16_t DecorPriority;
|
||||||
#define DECOR_PRIORITY_BASE 0x1000
|
#define DECOR_PRIORITY_BASE 0x1000
|
||||||
|
@ -231,7 +231,8 @@ static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*p == TAB) {
|
if (*p == TAB) {
|
||||||
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
|
cells = tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array);
|
||||||
|
cells = MIN(cells, maxcells);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When overwriting the left half of a double-width char, clear the right half.
|
// When overwriting the left half of a double-width char, clear the right half.
|
||||||
@ -345,7 +346,7 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
|||||||
if (vt) {
|
if (vt) {
|
||||||
int vcol = item->draw_col - col_off;
|
int vcol = item->draw_col - col_off;
|
||||||
int col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text,
|
int col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text,
|
||||||
vt->hl_mode, max_col, vcol);
|
vt->hl_mode, max_col, vcol, 0);
|
||||||
if (do_eol && ((vt->pos == kVPosEndOfLine) || (vt->pos == kVPosEndOfLineRightAlign))) {
|
if (do_eol && ((vt->pos == kVPosEndOfLine) || (vt->pos == kVPosEndOfLineRightAlign))) {
|
||||||
state->eol_col = col + 1;
|
state->eol_col = col + 1;
|
||||||
}
|
}
|
||||||
@ -358,32 +359,45 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
|
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
|
||||||
int vcol)
|
int vcol, int skip_cells)
|
||||||
{
|
{
|
||||||
const char *p = "";
|
const char *virt_str = "";
|
||||||
int virt_attr = 0;
|
int virt_attr = 0;
|
||||||
size_t virt_pos = 0;
|
size_t virt_pos = 0;
|
||||||
|
|
||||||
while (col < max_col) {
|
while (col < max_col) {
|
||||||
if (!*p) {
|
if (skip_cells >= 0 && *virt_str == NUL) {
|
||||||
if (virt_pos >= kv_size(vt)) {
|
if (virt_pos >= kv_size(vt)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
virt_attr = 0;
|
virt_attr = 0;
|
||||||
p = next_virt_text_chunk(vt, &virt_pos, &virt_attr);
|
virt_str = next_virt_text_chunk(vt, &virt_pos, &virt_attr);
|
||||||
if (p == NULL) {
|
if (virt_str == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*p == NUL) {
|
// Skip cells in the text.
|
||||||
|
while (skip_cells > 0 && *virt_str != NUL) {
|
||||||
|
int c_len = utfc_ptr2len(virt_str);
|
||||||
|
int cells = *virt_str == TAB
|
||||||
|
? tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array)
|
||||||
|
: utf_ptr2cells(virt_str);
|
||||||
|
skip_cells -= cells;
|
||||||
|
vcol += cells;
|
||||||
|
virt_str += c_len;
|
||||||
|
}
|
||||||
|
// If a double-width char or TAB doesn't fit, pad with spaces.
|
||||||
|
const char *draw_str = skip_cells < 0 ? " " : virt_str;
|
||||||
|
if (*draw_str == NUL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
assert(skip_cells <= 0);
|
||||||
int attr;
|
int attr;
|
||||||
bool through = false;
|
bool through = false;
|
||||||
if (hl_mode == kHlModeCombine) {
|
if (hl_mode == kHlModeCombine) {
|
||||||
attr = hl_combine_attr(linebuf_attr[col], virt_attr);
|
attr = hl_combine_attr(linebuf_attr[col], virt_attr);
|
||||||
} else if (hl_mode == kHlModeBlend) {
|
} else if (hl_mode == kHlModeBlend) {
|
||||||
through = (*p == ' ');
|
through = (*draw_str == ' ');
|
||||||
attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
|
attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
|
||||||
} else {
|
} else {
|
||||||
attr = virt_attr;
|
attr = virt_attr;
|
||||||
@ -397,13 +411,18 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
|
|||||||
// Clear the right half as well for the assertion in line_putchar().
|
// Clear the right half as well for the assertion in line_putchar().
|
||||||
linebuf_char[col] = schar_from_ascii(' ');
|
linebuf_char[col] = schar_from_ascii(' ');
|
||||||
}
|
}
|
||||||
int cells = line_putchar(buf, &p, through ? dummy : &linebuf_char[col],
|
int cells = line_putchar(buf, &draw_str, through ? dummy : &linebuf_char[col],
|
||||||
maxcells, vcol);
|
maxcells, vcol);
|
||||||
for (int c = 0; c < cells; c++) {
|
for (int c = 0; c < cells; c++) {
|
||||||
linebuf_attr[col] = attr;
|
linebuf_attr[col] = attr;
|
||||||
col++;
|
col++;
|
||||||
}
|
}
|
||||||
vcol += cells;
|
if (skip_cells < 0) {
|
||||||
|
skip_cells++;
|
||||||
|
} else {
|
||||||
|
vcol += cells;
|
||||||
|
virt_str = draw_str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
@ -1587,8 +1606,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
|
|
||||||
const bool may_have_inline_virt
|
const bool may_have_inline_virt
|
||||||
= !has_foldtext && buf_meta_total(wp->w_buffer, kMTMetaInline) > 0;
|
= !has_foldtext && buf_meta_total(wp->w_buffer, kMTMetaInline) > 0;
|
||||||
int virt_line_index;
|
int virt_line_index = -1;
|
||||||
int virt_line_offset = -1;
|
int virt_line_flags = 0;
|
||||||
// Repeat for the whole displayed line.
|
// Repeat for the whole displayed line.
|
||||||
while (true) {
|
while (true) {
|
||||||
int has_match_conc = 0; ///< match wants to conceal
|
int has_match_conc = 0; ///< match wants to conceal
|
||||||
@ -1616,11 +1635,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
virt_line_index = (int)kv_size(virt_lines) - index;
|
virt_line_index = (int)kv_size(virt_lines) - index;
|
||||||
assert(virt_line_index >= 0);
|
assert(virt_line_index >= 0);
|
||||||
virt_line_offset = kv_A(virt_lines, virt_line_index).left_col ? 0 : win_col_off(wp);
|
virt_line_flags = kv_A(virt_lines, virt_line_index).flags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virt_line_offset == 0) {
|
if (virt_line_index >= 0 && (virt_line_flags & kVLLeftcol)) {
|
||||||
// skip columns
|
// skip columns
|
||||||
} else if (statuscol.draw) {
|
} else if (statuscol.draw) {
|
||||||
// Draw 'statuscolumn' if it is set.
|
// Draw 'statuscolumn' if it is set.
|
||||||
@ -2715,7 +2734,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (kv_size(fold_vt) > 0) {
|
if (kv_size(fold_vt) > 0) {
|
||||||
draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0);
|
draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0, 0);
|
||||||
}
|
}
|
||||||
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row);
|
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row);
|
||||||
// Set increasing virtual columns in grid->vcols[] to set correct curswant
|
// Set increasing virtual columns in grid->vcols[] to set correct curswant
|
||||||
@ -2923,7 +2942,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
|
|||||||
end_check:
|
end_check:
|
||||||
// At end of screen line and there is more to come: Display the line
|
// At end of screen line and there is more to come: Display the line
|
||||||
// so far. If there is no more to display it is caught above.
|
// so far. If there is no more to display it is caught above.
|
||||||
if (wlv.col >= grid->cols && (!has_foldtext || virt_line_offset >= 0)
|
if (wlv.col >= grid->cols && (!has_foldtext || virt_line_index >= 0)
|
||||||
&& (wlv.col <= leftcols_width
|
&& (wlv.col <= leftcols_width
|
||||||
|| *ptr != NUL
|
|| *ptr != NUL
|
||||||
|| wlv.filler_todo > 0
|
|| wlv.filler_todo > 0
|
||||||
@ -2956,9 +2975,14 @@ end_check:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virt_line_offset >= 0) {
|
if (virt_line_index >= 0) {
|
||||||
draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line,
|
draw_virt_text_item(buf,
|
||||||
kHlModeReplace, grid->cols, 0);
|
virt_line_flags & kVLLeftcol ? 0 : win_col_offset,
|
||||||
|
kv_A(virt_lines, virt_line_index).line,
|
||||||
|
kHlModeReplace,
|
||||||
|
grid->cols,
|
||||||
|
0,
|
||||||
|
virt_line_flags & kVLScroll ? wp->w_leftcol : 0);
|
||||||
} else if (wlv.filler_todo <= 0) {
|
} else if (wlv.filler_todo <= 0) {
|
||||||
draw_virt_text(wp, buf, win_col_offset, &draw_col, wlv.row);
|
draw_virt_text(wp, buf, win_col_offset, &draw_col, wlv.row);
|
||||||
}
|
}
|
||||||
@ -3008,7 +3032,8 @@ end_check:
|
|||||||
statuscol.draw = false; // don't draw status column if "n" is in 'cpo'
|
statuscol.draw = false; // don't draw status column if "n" is in 'cpo'
|
||||||
}
|
}
|
||||||
wlv.filler_todo--;
|
wlv.filler_todo--;
|
||||||
virt_line_offset = -1;
|
virt_line_index = -1;
|
||||||
|
virt_line_flags = 0;
|
||||||
// When the filler lines are actually below the last line of the
|
// When the filler lines are actually below the last line of the
|
||||||
// file, don't draw the line itself, break here.
|
// file, don't draw the line itself, break here.
|
||||||
if (wlv.filler_todo == 0 && (wp->w_botfill || end_fill)) {
|
if (wlv.filler_todo == 0 && (wp->w_botfill || end_fill)) {
|
||||||
|
@ -123,6 +123,10 @@ describe('API/extmarks', function()
|
|||||||
pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 0 })
|
pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 0 })
|
||||||
)
|
)
|
||||||
eq("Invalid 'hl_mode': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 'foo' }))
|
eq("Invalid 'hl_mode': 'foo'", pcall_err(set_extmark, ns, marks[2], 0, 0, { hl_mode = 'foo' }))
|
||||||
|
eq(
|
||||||
|
"Invalid 'virt_lines_overflow': 'foo'",
|
||||||
|
pcall_err(set_extmark, ns, marks[2], 0, 0, { virt_lines_overflow = 'foo' })
|
||||||
|
)
|
||||||
eq(
|
eq(
|
||||||
"Invalid 'id': expected Integer, got Array",
|
"Invalid 'id': expected Integer, got Array",
|
||||||
pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })
|
pcall_err(set_extmark, ns, {}, 0, 0, { end_col = 1, end_row = 1 })
|
||||||
@ -1576,11 +1580,6 @@ describe('API/extmarks', function()
|
|||||||
virt_text_hide = true,
|
virt_text_hide = true,
|
||||||
virt_text_pos = 'right_align',
|
virt_text_pos = 'right_align',
|
||||||
})
|
})
|
||||||
set_extmark(ns, marks[2], 0, 0, {
|
|
||||||
priority = 0,
|
|
||||||
virt_text = { { '', 'Macro' }, { '', { 'Type', 'Search' } }, { '' } },
|
|
||||||
virt_text_win_col = 1,
|
|
||||||
})
|
|
||||||
eq({
|
eq({
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -1607,12 +1606,20 @@ describe('API/extmarks', function()
|
|||||||
},
|
},
|
||||||
virt_lines_above = true,
|
virt_lines_above = true,
|
||||||
virt_lines_leftcol = true,
|
virt_lines_leftcol = true,
|
||||||
|
virt_lines_overflow = 'trunc',
|
||||||
virt_text = { { 'text', 'Macro' }, { '???' }, { 'stack', { 'Type', 'Search' } } },
|
virt_text = { { 'text', 'Macro' }, { '???' }, { 'stack', { 'Type', 'Search' } } },
|
||||||
virt_text_repeat_linebreak = false,
|
virt_text_repeat_linebreak = false,
|
||||||
virt_text_hide = true,
|
virt_text_hide = true,
|
||||||
virt_text_pos = 'right_align',
|
virt_text_pos = 'right_align',
|
||||||
},
|
},
|
||||||
}, get_extmark_by_id(ns, marks[1], { details = true }))
|
}, get_extmark_by_id(ns, marks[1], { details = true }))
|
||||||
|
|
||||||
|
set_extmark(ns, marks[2], 0, 0, {
|
||||||
|
priority = 0,
|
||||||
|
virt_text = { { '', 'Macro' }, { '', { 'Type', 'Search' } }, { '' } },
|
||||||
|
virt_text_repeat_linebreak = true,
|
||||||
|
virt_text_win_col = 1,
|
||||||
|
})
|
||||||
eq({
|
eq({
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -1621,13 +1628,35 @@ describe('API/extmarks', function()
|
|||||||
right_gravity = true,
|
right_gravity = true,
|
||||||
priority = 0,
|
priority = 0,
|
||||||
virt_text = { { '', 'Macro' }, { '', { 'Type', 'Search' } }, { '' } },
|
virt_text = { { '', 'Macro' }, { '', { 'Type', 'Search' } }, { '' } },
|
||||||
virt_text_repeat_linebreak = false,
|
virt_text_repeat_linebreak = true,
|
||||||
virt_text_hide = false,
|
virt_text_hide = false,
|
||||||
virt_text_pos = 'win_col',
|
virt_text_pos = 'win_col',
|
||||||
virt_text_win_col = 1,
|
virt_text_win_col = 1,
|
||||||
},
|
},
|
||||||
}, get_extmark_by_id(ns, marks[2], { details = true }))
|
}, get_extmark_by_id(ns, marks[2], { details = true }))
|
||||||
set_extmark(ns, marks[3], 0, 0, { cursorline_hl_group = 'Statement' })
|
|
||||||
|
set_extmark(ns, marks[3], 0, 0, {
|
||||||
|
priority = 0,
|
||||||
|
ui_watched = true,
|
||||||
|
virt_lines = { { { '', 'Macro' }, { '' }, { '', '' } } },
|
||||||
|
virt_lines_overflow = 'scroll',
|
||||||
|
})
|
||||||
|
eq({
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
ns_id = 1,
|
||||||
|
right_gravity = true,
|
||||||
|
ui_watched = true,
|
||||||
|
priority = 0,
|
||||||
|
virt_lines = { { { '', 'Macro' }, { '' }, { '', '' } } },
|
||||||
|
virt_lines_above = false,
|
||||||
|
virt_lines_leftcol = false,
|
||||||
|
virt_lines_overflow = 'scroll',
|
||||||
|
},
|
||||||
|
}, get_extmark_by_id(ns, marks[3], { details = true }))
|
||||||
|
|
||||||
|
set_extmark(ns, marks[4], 0, 0, { cursorline_hl_group = 'Statement' })
|
||||||
eq({
|
eq({
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -1637,8 +1666,9 @@ describe('API/extmarks', function()
|
|||||||
priority = 4096,
|
priority = 4096,
|
||||||
right_gravity = true,
|
right_gravity = true,
|
||||||
},
|
},
|
||||||
}, get_extmark_by_id(ns, marks[3], { details = true }))
|
}, get_extmark_by_id(ns, marks[4], { details = true }))
|
||||||
set_extmark(ns, marks[4], 0, 0, {
|
|
||||||
|
set_extmark(ns, marks[5], 0, 0, {
|
||||||
end_col = 1,
|
end_col = 1,
|
||||||
conceal = 'a',
|
conceal = 'a',
|
||||||
spell = true,
|
spell = true,
|
||||||
@ -1655,8 +1685,9 @@ describe('API/extmarks', function()
|
|||||||
right_gravity = true,
|
right_gravity = true,
|
||||||
spell = true,
|
spell = true,
|
||||||
},
|
},
|
||||||
}, get_extmark_by_id(ns, marks[4], { details = true }))
|
}, get_extmark_by_id(ns, marks[5], { details = true }))
|
||||||
set_extmark(ns, marks[5], 0, 0, {
|
|
||||||
|
set_extmark(ns, marks[6], 0, 0, {
|
||||||
end_col = 1,
|
end_col = 1,
|
||||||
spell = false,
|
spell = false,
|
||||||
})
|
})
|
||||||
@ -1671,7 +1702,8 @@ describe('API/extmarks', function()
|
|||||||
right_gravity = true,
|
right_gravity = true,
|
||||||
spell = false,
|
spell = false,
|
||||||
},
|
},
|
||||||
}, get_extmark_by_id(ns, marks[5], { details = true }))
|
}, get_extmark_by_id(ns, marks[6], { details = true }))
|
||||||
|
|
||||||
api.nvim_buf_clear_namespace(0, ns, 0, -1)
|
api.nvim_buf_clear_namespace(0, ns, 0, -1)
|
||||||
-- legacy sign mark includes sign name
|
-- legacy sign mark includes sign name
|
||||||
command('sign define sign1 text=s1 texthl=Title linehl=LineNR numhl=Normal culhl=CursorLine')
|
command('sign define sign1 text=s1 texthl=Title linehl=LineNR numhl=Normal culhl=CursorLine')
|
||||||
|
@ -4949,7 +4949,6 @@ 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'
|
||||||
@ -5020,6 +5019,140 @@ if (h->n_buckets < new_n_buckets) { // expand
|
|||||||
]]}
|
]]}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('scrolls horizontally with virt_lines_overflow = "scroll" #31000', function()
|
||||||
|
command('set nowrap signcolumn=yes')
|
||||||
|
insert('abcdefghijklmnopqrstuvwxyz')
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 0, {
|
||||||
|
virt_lines = {
|
||||||
|
{ { '12αβ̳γ̲口=', 'Special' }, { '❤️345678', 'Special' } },
|
||||||
|
{ { '123\t45\t678', 'NonText' } },
|
||||||
|
},
|
||||||
|
virt_lines_overflow = 'scroll',
|
||||||
|
})
|
||||||
|
screen:expect([[
|
||||||
|
{7: }abcdefghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:12αβ̳γ̲口=❤️345678} |
|
||||||
|
{7: }{1:123 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }bcdefghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:2αβ̳γ̲口=❤️345678} |
|
||||||
|
{7: }{1:23 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }cdefghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:αβ̳γ̲口=❤️345678} |
|
||||||
|
{7: }{1:3 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }defghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:β̳γ̲口=❤️345678} |
|
||||||
|
{7: }{1: 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }efghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:γ̲口=❤️345678} |
|
||||||
|
{7: }{1: 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }fghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:口=❤️345678} |
|
||||||
|
{7: }{1: 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }ghijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16: =❤️345678} |
|
||||||
|
{7: }{1: 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }hijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:=❤️345678} |
|
||||||
|
{7: }{1: 45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }ijklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:❤️345678} |
|
||||||
|
{7: }{1:45 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }jklmnopqrstuvwxy^z |
|
||||||
|
{7: }{16: 345678} |
|
||||||
|
{7: }{1:5 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }klmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:345678} |
|
||||||
|
{7: }{1: 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }lmnopqrstuvwxy^z |
|
||||||
|
{7: }{16:45678} |
|
||||||
|
{7: }{1: 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('zl')
|
||||||
|
screen:expect([[
|
||||||
|
{7: }mnopqrstuvwxy^z |
|
||||||
|
{7: }{16:5678} |
|
||||||
|
{7: }{1: 678} |
|
||||||
|
{1:~ }|*8
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 1, {
|
||||||
|
virt_lines = { { { '123\t45\t67', 'NonText' } } },
|
||||||
|
virt_lines_leftcol = true,
|
||||||
|
virt_lines_overflow = 'trunc',
|
||||||
|
})
|
||||||
|
api.nvim_buf_set_extmark(0, ns, 0, 2, {
|
||||||
|
virt_lines = { { { '123\t45\t6', 'NonText' } } },
|
||||||
|
virt_lines_leftcol = false,
|
||||||
|
virt_lines_overflow = 'trunc',
|
||||||
|
})
|
||||||
|
screen:expect([[
|
||||||
|
{7: }mnopqrstuvwxy^z |
|
||||||
|
{7: }{16:5678} |
|
||||||
|
{7: }{1: 678} |
|
||||||
|
{1:123 45 67} |
|
||||||
|
{7: }{1:123 45 6} |
|
||||||
|
{1:~ }|*6
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
it('does not show twice if end_row or end_col is specified #18622', function()
|
it('does not show twice if end_row or end_col is specified #18622', function()
|
||||||
screen:try_resize(50, 8)
|
screen:try_resize(50, 8)
|
||||||
insert([[
|
insert([[
|
||||||
|
Reference in New Issue
Block a user