mirror of
https://github.com/neovim/neovim.git
synced 2024-12-29 14:41:06 -07:00
feat(decorations): support signs
Add the following options to extmarks: - sign_text - sign_hl_group - number_hl_group - line_hl_group - cursorline_hl_group Note: ranges are unsupported and decorations are only applied to start_row
This commit is contained in:
parent
83fc914337
commit
30e4cc3b3f
@ -445,6 +445,27 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
||||
/// - strict: boolean that indicates extmark should not be placed
|
||||
/// if the line or column value is past the end of the
|
||||
/// buffer or end of the line respectively. Defaults to true.
|
||||
/// - sign_text: string of length 1-2 used to display in the
|
||||
/// sign column.
|
||||
/// Note: ranges are unsupported and decorations are only
|
||||
/// applied to start_row
|
||||
/// - sign_hl_group: name of the highlight group used to
|
||||
/// highlight the sign column text.
|
||||
/// Note: ranges are unsupported and decorations are only
|
||||
/// applied to start_row
|
||||
/// - number_hl_group: name of the highlight group used to
|
||||
/// highlight the number column.
|
||||
/// Note: ranges are unsupported and decorations are only
|
||||
/// applied to start_row
|
||||
/// - line_hl_group: name of the highlight group used to
|
||||
/// highlight the whole line.
|
||||
/// Note: ranges are unsupported and decorations are only
|
||||
/// applied to start_row
|
||||
/// - cursorline_hl_group: name of the highlight group used to
|
||||
/// highlight the line when the cursor is on the same line
|
||||
/// as the mark and 'cursorline' is enabled.
|
||||
/// Note: ranges are unsupported and decorations are only
|
||||
/// applied to start_row
|
||||
///
|
||||
/// @param[out] err Error details, if any
|
||||
/// @return Id of the created/updated extmark
|
||||
@ -519,10 +540,25 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (HAS_KEY(opts->hl_group)) {
|
||||
decor.hl_id = object_to_hl_id(opts->hl_group, "hl_group", err);
|
||||
if (ERROR_SET(err)) {
|
||||
goto error;
|
||||
struct {
|
||||
const char *name;
|
||||
Object *opt;
|
||||
int *dest;
|
||||
} hls[] = {
|
||||
{ "hl_group" , &opts->hl_group , &decor.hl_id },
|
||||
{ "sign_hl_group" , &opts->sign_hl_group , &decor.sign_hl_id },
|
||||
{ "number_hl_group" , &opts->number_hl_group , &decor.number_hl_id },
|
||||
{ "line_hl_group" , &opts->line_hl_group , &decor.line_hl_id },
|
||||
{ "cursorline_hl_group", &opts->cursorline_hl_group, &decor.cursorline_hl_id },
|
||||
{ NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
for (int j = 0; hls[j].name && hls[j].dest; j++) {
|
||||
if (HAS_KEY(*hls[j].opt)) {
|
||||
*hls[j].dest = object_to_hl_id(*hls[j].opt, hls[j].name, err);
|
||||
if (ERROR_SET(err)) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,6 +658,17 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (opts->sign_text.type == kObjectTypeString) {
|
||||
if (!init_sign_text(&decor.sign_text,
|
||||
(char_u *)opts->sign_text.data.string.data)) {
|
||||
api_set_error(err, kErrorTypeValidation, "sign_text is not a valid value");
|
||||
goto error;
|
||||
}
|
||||
} else if (HAS_KEY(opts->sign_text)) {
|
||||
api_set_error(err, kErrorTypeValidation, "sign_text is not a String");
|
||||
goto error;
|
||||
}
|
||||
|
||||
bool right_gravity = true;
|
||||
OPTION_TO_BOOL(right_gravity, right_gravity, true);
|
||||
|
||||
@ -709,6 +756,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
|
||||
|
||||
error:
|
||||
clear_virttext(&decor.virt_text);
|
||||
xfree(decor.sign_text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,11 @@ return {
|
||||
"virt_lines_above";
|
||||
"virt_lines_leftcol";
|
||||
"strict";
|
||||
"sign_text";
|
||||
"sign_hl_group";
|
||||
"number_hl_group";
|
||||
"line_hl_group";
|
||||
"cursorline_hl_group";
|
||||
};
|
||||
keymap = {
|
||||
"noremap";
|
||||
|
@ -1643,3 +1643,39 @@ sctx_T api_set_sctx(uint64_t channel_id)
|
||||
}
|
||||
return old_current_sctx;
|
||||
}
|
||||
|
||||
// adapted from sign.c:sign_define_init_text.
|
||||
// TODO(lewis6991): Consider merging
|
||||
int init_sign_text(char_u **sign_text, char_u *text)
|
||||
{
|
||||
char_u *s;
|
||||
|
||||
char_u *endp = text + (int)STRLEN(text);
|
||||
|
||||
// Count cells and check for non-printable chars
|
||||
int cells = 0;
|
||||
for (s = text; s < endp; s += utfc_ptr2len(s)) {
|
||||
if (!vim_isprintc(utf_ptr2char(s))) {
|
||||
break;
|
||||
}
|
||||
cells += utf_ptr2cells(s);
|
||||
}
|
||||
// Currently must be empty, one or two display cells
|
||||
if (s != endp || cells > 2) {
|
||||
return FAIL;
|
||||
}
|
||||
if (cells < 1) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Allocate one byte more if we need to pad up
|
||||
// with a space.
|
||||
size_t len = (size_t)(endp - text + ((cells == 1) ? 1 : 0));
|
||||
*sign_text = vim_strnsave(text, len);
|
||||
|
||||
if (cells == 1) {
|
||||
STRCPY(*sign_text + len - 1, " ");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/diff.h"
|
||||
#include "nvim/digraph.h"
|
||||
#include "nvim/decoration.h"
|
||||
#include "nvim/eval.h"
|
||||
#include "nvim/ex_cmds.h"
|
||||
#include "nvim/ex_cmds2.h"
|
||||
@ -5469,6 +5470,11 @@ static int buf_signcols_inner(buf_T *buf, int maximum)
|
||||
|
||||
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
|
||||
if (sign->se_lnum > curline) {
|
||||
// Counted all signs, now add extmark signs
|
||||
if (curline > 0) {
|
||||
linesum += decor_signcols(buf, &decor_state, (int)curline-1, (int)curline-1,
|
||||
maximum-linesum);
|
||||
}
|
||||
if (linesum > signcols) {
|
||||
signcols = linesum;
|
||||
if (signcols >= maximum) {
|
||||
@ -5483,6 +5489,19 @@ static int buf_signcols_inner(buf_T *buf, int maximum)
|
||||
}
|
||||
}
|
||||
|
||||
if (curline > 0) {
|
||||
linesum += decor_signcols(buf, &decor_state, (int)curline-1, (int)curline-1, maximum-linesum);
|
||||
}
|
||||
if (linesum > signcols) {
|
||||
signcols = linesum;
|
||||
if (signcols >= maximum) {
|
||||
return maximum;
|
||||
}
|
||||
}
|
||||
|
||||
// Check extmarks between signs
|
||||
linesum = decor_signcols(buf, &decor_state, 0, (int)buf->b_ml.ml_line_count-1, maximum);
|
||||
|
||||
if (linesum > signcols) {
|
||||
signcols = linesum;
|
||||
if (signcols >= maximum) {
|
||||
|
@ -875,6 +875,7 @@ struct file_buffer {
|
||||
MarkTree b_marktree[1];
|
||||
Map(uint32_t, uint32_t) b_extmark_ns[1]; // extmark namespaces
|
||||
size_t b_virt_line_blocks; // number of virt_line blocks
|
||||
size_t b_signs; // number of sign extmarks
|
||||
|
||||
// array of channel_id:s which have asked to receive updates for this
|
||||
// buffer.
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "nvim/extmark.h"
|
||||
#include "nvim/highlight.h"
|
||||
#include "nvim/lua/executor.h"
|
||||
#include "nvim/move.h"
|
||||
#include "nvim/screen.h"
|
||||
#include "nvim/syntax.h"
|
||||
#include "nvim/vim.h"
|
||||
@ -65,8 +66,15 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
|
||||
|
||||
void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
||||
{
|
||||
if ((!decor || decor->hl_id) && row2 >= row1) {
|
||||
redraw_buf_range_later(buf, row1+1, row2+1);
|
||||
if (row2 >= row1) {
|
||||
if (decor && decor->sign_text) {
|
||||
buf->b_signcols_valid = false;
|
||||
changed_line_abv_curs();
|
||||
}
|
||||
|
||||
if (!decor || decor->hl_id || decor_has_sign(decor)) {
|
||||
redraw_buf_range_later(buf, row1+1, row2+1);
|
||||
}
|
||||
}
|
||||
|
||||
if (decor && kv_size(decor->virt_text)) {
|
||||
@ -82,9 +90,15 @@ void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
||||
void decor_remove(buf_T *buf, int row, int row2, Decoration *decor)
|
||||
{
|
||||
decor_redraw(buf, row, row2, decor);
|
||||
if (decor && kv_size(decor->virt_lines)) {
|
||||
assert(buf->b_virt_line_blocks > 0);
|
||||
buf->b_virt_line_blocks--;
|
||||
if (decor) {
|
||||
if (kv_size(decor->virt_lines)) {
|
||||
assert(buf->b_virt_line_blocks > 0);
|
||||
buf->b_virt_line_blocks--;
|
||||
}
|
||||
if (decor_has_sign(decor)) {
|
||||
assert(buf->b_signs > 0);
|
||||
buf->b_signs--;
|
||||
}
|
||||
}
|
||||
decor_free(decor);
|
||||
}
|
||||
@ -97,6 +111,7 @@ void decor_free(Decoration *decor)
|
||||
clear_virttext(&kv_A(decor->virt_lines, i).line);
|
||||
}
|
||||
kv_destroy(decor->virt_lines);
|
||||
xfree(decor->sign_text);
|
||||
xfree(decor);
|
||||
}
|
||||
}
|
||||
@ -136,6 +151,7 @@ bool decor_redraw_reset(buf_T *buf, DecorState *state)
|
||||
{
|
||||
state->row = -1;
|
||||
state->buf = buf;
|
||||
state->has_sign_decor = false;
|
||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||
DecorRange item = kv_A(state->active, i);
|
||||
if (item.virt_text_owned) {
|
||||
@ -180,9 +196,23 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
|
||||
|
||||
Decoration decor = get_decor(mark);
|
||||
|
||||
// Exclude non-paired marks unless they contain virt_text or a sign
|
||||
if (!mt_paired(mark)
|
||||
&& !kv_size(decor.virt_text)
|
||||
&& !decor_has_sign(&decor)) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
// Don't add signs for end marks as the start mark has already been added.
|
||||
if (mt_end(mark) && decor_has_sign(&decor)) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
mtpos_t altpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||
|
||||
if ((!mt_end(mark) && altpos.row < top_row
|
||||
// Exclude start marks if the end mark position is above the top row
|
||||
// Exclude end marks if we have already added the start mark
|
||||
if ((mt_start(mark) && altpos.row < top_row
|
||||
&& !kv_size(decor.virt_text))
|
||||
|| (mt_end(mark) && altpos.row >= top_row)) {
|
||||
goto next_mark;
|
||||
@ -241,6 +271,10 @@ static void decor_add(DecorState *state, int start_row, int start_col, int end_r
|
||||
kv_A(state->active, index) = kv_A(state->active, index-1);
|
||||
}
|
||||
kv_A(state->active, index) = range;
|
||||
|
||||
if (decor_has_sign(decor)) {
|
||||
state->has_sign_decor = true;
|
||||
}
|
||||
}
|
||||
|
||||
int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden, DecorState *state)
|
||||
@ -294,7 +328,8 @@ next_mark:
|
||||
bool active = false, keep = true;
|
||||
if (item.end_row < state->row
|
||||
|| (item.end_row == state->row && item.end_col <= col)) {
|
||||
if (!(item.start_row >= state->row && kv_size(item.decor.virt_text))) {
|
||||
if (!(item.start_row >= state->row && kv_size(item.decor.virt_text))
|
||||
&& !decor_has_sign(&item.decor)) {
|
||||
keep = false;
|
||||
}
|
||||
} else {
|
||||
@ -329,6 +364,131 @@ next_mark:
|
||||
return attr;
|
||||
}
|
||||
|
||||
void decor_redraw_signs(buf_T *buf, DecorState *state, int row,
|
||||
int *num_signs, sign_attrs_T sattrs[])
|
||||
{
|
||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||
DecorRange item = kv_A(state->active, i);
|
||||
Decoration *decor = &item.decor;
|
||||
|
||||
if (!decor_has_sign(decor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (state->row != item.start_row) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int j;
|
||||
for (j = (*num_signs); j > 0; j--) {
|
||||
if (sattrs[j].sat_prio <= decor->priority) {
|
||||
break;
|
||||
}
|
||||
sattrs[j] = sattrs[j-1];
|
||||
}
|
||||
if (j < SIGN_SHOW_MAX) {
|
||||
memset(&sattrs[j], 0, sizeof(sign_attrs_T));
|
||||
sattrs[j].sat_text = decor->sign_text;
|
||||
if (decor->sign_hl_id != 0) {
|
||||
sattrs[j].sat_texthl = syn_id2attr(decor->sign_hl_id);
|
||||
}
|
||||
if (decor->number_hl_id != 0) {
|
||||
sattrs[j].sat_numhl = syn_id2attr(decor->number_hl_id);
|
||||
}
|
||||
if (decor->line_hl_id != 0) {
|
||||
sattrs[j].sat_linehl = syn_id2attr(decor->line_hl_id);
|
||||
}
|
||||
if (decor->cursorline_hl_id != 0) {
|
||||
sattrs[j].sat_culhl = syn_id2attr(decor->cursorline_hl_id);
|
||||
}
|
||||
sattrs[j].sat_prio = decor->priority;
|
||||
(*num_signs)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the maximum required amount of sign columns needed between row and
|
||||
// end_row.
|
||||
int decor_signcols(buf_T *buf, DecorState *state, int row, int end_row, int max)
|
||||
{
|
||||
int count = 0; // count for the number of signs on a given row
|
||||
int count_remove = 0; // how much to decrement count by when iterating marks for a new row
|
||||
int signcols = 0; // highest value of count
|
||||
int currow = -1; // current row
|
||||
|
||||
if (max <= 1 && buf->b_signs >= (size_t)max) {
|
||||
return max;
|
||||
}
|
||||
|
||||
if (buf->b_signs == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, 0, -1, itr);
|
||||
while (true) {
|
||||
mtkey_t mark = marktree_itr_current(itr);
|
||||
if (mark.pos.row < 0 || mark.pos.row > end_row) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mark.pos.row < row && mt_end(mark))
|
||||
|| marktree_decor_level(mark) < kDecorLevelVisible
|
||||
|| !mark.decor_full) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
Decoration decor = get_decor(mark);
|
||||
|
||||
if (!decor.sign_text) {
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
if (mark.pos.row > currow) {
|
||||
count -= count_remove;
|
||||
count_remove = 0;
|
||||
currow = mark.pos.row;
|
||||
}
|
||||
|
||||
if (!mt_paired(mark)) {
|
||||
if (mark.pos.row >= row) {
|
||||
count++;
|
||||
if (count > signcols) {
|
||||
signcols = count;
|
||||
if (signcols >= max) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
count_remove++;
|
||||
}
|
||||
goto next_mark;
|
||||
}
|
||||
|
||||
mtpos_t altpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
|
||||
|
||||
if (mt_end(mark)) {
|
||||
if (mark.pos.row >= row && altpos.row <= end_row) {
|
||||
count_remove++;
|
||||
}
|
||||
} else {
|
||||
if (altpos.row >= row) {
|
||||
count++;
|
||||
if (count > signcols) {
|
||||
signcols = count;
|
||||
if (signcols >= max) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
next_mark:
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
|
||||
return signcols;
|
||||
}
|
||||
|
||||
void decor_redraw_end(DecorState *state)
|
||||
{
|
||||
state->buf = NULL;
|
||||
|
@ -47,13 +47,18 @@ struct Decoration {
|
||||
bool virt_text_hide;
|
||||
bool hl_eol;
|
||||
bool virt_lines_above;
|
||||
// TODO(bfredl): style, signs, etc
|
||||
// TODO(bfredl): style, etc
|
||||
DecorPriority priority;
|
||||
int col; // fixed col value, like win_col
|
||||
int virt_text_width; // width of virt_text
|
||||
char_u *sign_text;
|
||||
int sign_hl_id;
|
||||
int number_hl_id;
|
||||
int line_hl_id;
|
||||
int cursorline_hl_id;
|
||||
};
|
||||
#define DECORATION_INIT { KV_INITIAL_VALUE, KV_INITIAL_VALUE, 0, kVTEndOfLine, kHlModeUnknown, \
|
||||
false, false, false, DECOR_PRIORITY_BASE, 0, 0 }
|
||||
false, false, false, DECOR_PRIORITY_BASE, 0, 0, NULL, 0, 0, 0, 0 }
|
||||
|
||||
typedef struct {
|
||||
int start_row;
|
||||
@ -75,6 +80,7 @@ typedef struct {
|
||||
int col_until;
|
||||
int current;
|
||||
int eol_col;
|
||||
bool has_sign_decor;
|
||||
} DecorState;
|
||||
|
||||
typedef struct {
|
||||
@ -98,6 +104,15 @@ EXTERN bool provider_active INIT(= false);
|
||||
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
||||
LUA_NOREF, -1 }
|
||||
|
||||
static inline bool decor_has_sign(Decoration *decor)
|
||||
{
|
||||
return decor->sign_text
|
||||
|| decor->sign_hl_id
|
||||
|| decor->number_hl_id
|
||||
|| decor->line_hl_id
|
||||
|| decor->cursorline_hl_id;
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "decoration.h.generated.h"
|
||||
#endif
|
||||
|
@ -67,7 +67,9 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
|
||||
|
||||
uint8_t decor_level = kDecorLevelNone; // no decor
|
||||
if (decor) {
|
||||
if (kv_size(decor->virt_text) || kv_size(decor->virt_lines)) {
|
||||
if (kv_size(decor->virt_text)
|
||||
|| kv_size(decor->virt_lines)
|
||||
|| decor_has_sign(decor)) {
|
||||
decor_full = true;
|
||||
decor = xmemdup(decor, sizeof *decor);
|
||||
}
|
||||
@ -142,6 +144,9 @@ revised:
|
||||
if (kv_size(decor->virt_lines)) {
|
||||
buf->b_virt_line_blocks++;
|
||||
}
|
||||
if (decor_has_sign(decor)) {
|
||||
buf->b_signs++;
|
||||
}
|
||||
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,11 @@ static inline bool mt_end(mtkey_t key)
|
||||
return key.flags & MT_FLAG_END;
|
||||
}
|
||||
|
||||
static inline bool mt_start(mtkey_t key)
|
||||
{
|
||||
return mt_paired(key) && !mt_end(key);
|
||||
}
|
||||
|
||||
static inline bool mt_right(mtkey_t key)
|
||||
{
|
||||
return key.flags & MT_FLAG_RIGHT_GRAVITY;
|
||||
|
@ -2208,6 +2208,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
||||
buf_T *buf = wp->w_buffer;
|
||||
bool end_fill = (lnum == buf->b_ml.ml_line_count+1);
|
||||
|
||||
has_decor = decor_redraw_line(buf, lnum-1, &decor_state);
|
||||
|
||||
if (!number_only) {
|
||||
// To speed up the loop below, set extra_check when there is linebreak,
|
||||
// trailing white space and/or syntax processing to be done.
|
||||
@ -2229,9 +2231,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
||||
}
|
||||
}
|
||||
|
||||
has_decor = decor_redraw_line(wp->w_buffer, lnum-1,
|
||||
&decor_state);
|
||||
|
||||
for (size_t k = 0; k < kv_size(*providers); k++) {
|
||||
DecorProvider *p = kv_A(*providers, k);
|
||||
if (p && p->redraw_line != LUA_NOREF) {
|
||||
@ -2460,6 +2459,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
||||
|
||||
memset(sattrs, 0, sizeof(sattrs));
|
||||
num_signs = buf_get_signattrs(wp->w_buffer, lnum, sattrs);
|
||||
if (decor_state.has_sign_decor) {
|
||||
decor_redraw_signs(buf, &decor_state, lnum-1, &num_signs, sattrs);
|
||||
}
|
||||
|
||||
// If this line has a sign with line highlighting set line_attr.
|
||||
// TODO(bfredl, vigoux): this should not take priority over decoration!
|
||||
|
@ -506,6 +506,8 @@ int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
|
||||
if (sp->sn_num_hl != 0) {
|
||||
sattr.sat_numhl = syn_id2attr(sp->sn_num_hl);
|
||||
}
|
||||
// Store the priority so we can mesh in extmark signs later
|
||||
sattr.sat_prio = sign->se_priority;
|
||||
}
|
||||
|
||||
sattrs[nr_matches] = sattr;
|
||||
|
@ -40,6 +40,7 @@ typedef struct sign_attrs_S {
|
||||
int sat_linehl;
|
||||
int sat_culhl;
|
||||
int sat_numhl;
|
||||
int sat_prio; // Used for inserting extmark signs
|
||||
} sign_attrs_T;
|
||||
|
||||
#define SIGN_SHOW_MAX 9
|
||||
|
@ -1362,3 +1362,276 @@ if (h->n_buckets < new_n_buckets) { // expand
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
describe('decorations: signs', function()
|
||||
local screen, ns
|
||||
before_each(function()
|
||||
clear()
|
||||
screen = Screen.new(50, 10)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids {
|
||||
[1] = {foreground = Screen.colors.Blue4, background = Screen.colors.Grey};
|
||||
[2] = {foreground = Screen.colors.Blue1, bold = true};
|
||||
}
|
||||
|
||||
ns = meths.create_namespace 'test'
|
||||
meths.win_set_option(0, 'signcolumn', 'auto:9')
|
||||
end)
|
||||
|
||||
local example_text = [[
|
||||
l1
|
||||
l2
|
||||
l3
|
||||
l4
|
||||
l5
|
||||
]]
|
||||
|
||||
it('can add a single sign (no end row)', function()
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S'})
|
||||
|
||||
screen:expect{grid=[[
|
||||
{1: }^l1 |
|
||||
S l2 |
|
||||
{1: }l3 |
|
||||
{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add a single sign (with end row)', function()
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row=1})
|
||||
|
||||
screen:expect{grid=[[
|
||||
{1: }^l1 |
|
||||
S l2 |
|
||||
{1: }l3 |
|
||||
{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add multiple signs (single extmark)', function()
|
||||
pending('TODO(lewis6991): Support ranged signs')
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S', end_row = 2})
|
||||
|
||||
screen:expect{grid=[[
|
||||
{1: }^l1 |
|
||||
S l2 |
|
||||
S l3 |
|
||||
{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add multiple signs (multiple extmarks)', function()
|
||||
pending('TODO(lewis6991): Support ranged signs')
|
||||
insert(example_text)
|
||||
feed'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
|
||||
meths.buf_set_extmark(0, ns, 3, -1, {sign_text='S2', end_row = 4})
|
||||
|
||||
screen:expect{grid=[[
|
||||
{1: }^l1 |
|
||||
S1l2 |
|
||||
{1: }l3 |
|
||||
S2l4 |
|
||||
S2l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add multiple signs (multiple extmarks) 2', function()
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1'})
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
|
||||
|
||||
screen:expect{grid=[[
|
||||
{1: }^l1 |
|
||||
S2S1l2 |
|
||||
{1: }l3 |
|
||||
{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
-- TODO(lewis6991): Support ranged signs
|
||||
-- meths.buf_set_extmark(1, ns, 1, -1, {sign_text='S3', end_row = 2})
|
||||
|
||||
-- screen:expect{grid=[[
|
||||
-- {1: }^l1 |
|
||||
-- S3S2S1l2 |
|
||||
-- S3{1: }l3 |
|
||||
-- {1: }l4 |
|
||||
-- {1: }l5 |
|
||||
-- {1: } |
|
||||
-- {2:~ }|
|
||||
-- {2:~ }|
|
||||
-- {2:~ }|
|
||||
-- |
|
||||
-- ]]}
|
||||
|
||||
end)
|
||||
|
||||
it('can add multiple signs (multiple extmarks) 3', function()
|
||||
pending('TODO(lewis6991): Support ranged signs')
|
||||
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S1', end_row=2})
|
||||
meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S2', end_row=3})
|
||||
|
||||
screen:expect{grid=[[
|
||||
{1: }^l1 |
|
||||
S1{1: }l2 |
|
||||
S2S1l3 |
|
||||
S2{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('can add multiple signs (multiple extmarks) 4', function()
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1', end_row=0})
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2', end_row=1})
|
||||
|
||||
screen:expect{grid=[[
|
||||
S1^l1 |
|
||||
S2l2 |
|
||||
{1: }l3 |
|
||||
{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('works with old signs', function()
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
helpers.command('sign define Oldsign text=x')
|
||||
helpers.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
|
||||
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
|
||||
meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
|
||||
|
||||
screen:expect{grid=[[
|
||||
S4S1^l1 |
|
||||
S2x l2 |
|
||||
S5{1: }l3 |
|
||||
{1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('works with old signs (with range)', function()
|
||||
pending('TODO(lewis6991): Support ranged signs')
|
||||
insert(example_text)
|
||||
feed 'gg'
|
||||
|
||||
helpers.command('sign define Oldsign text=x')
|
||||
helpers.command([[exe 'sign place 42 line=2 name=Oldsign buffer=' . bufnr('')]])
|
||||
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S1'})
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='S2'})
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S3', end_row = 4})
|
||||
meths.buf_set_extmark(0, ns, 0, -1, {sign_text='S4'})
|
||||
meths.buf_set_extmark(0, ns, 2, -1, {sign_text='S5'})
|
||||
|
||||
screen:expect{grid=[[
|
||||
S3S4S1^l1 |
|
||||
S2S3x l2 |
|
||||
S5S3{1: }l3 |
|
||||
S3{1: }l4 |
|
||||
S3{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
end)
|
||||
|
||||
it('can add a ranged sign (with start out of view)', function()
|
||||
pending('TODO(lewis6991): Support ranged signs')
|
||||
|
||||
insert(example_text)
|
||||
command 'set signcolumn=yes:2'
|
||||
feed 'gg'
|
||||
feed '2<C-e>'
|
||||
|
||||
meths.buf_set_extmark(0, ns, 1, -1, {sign_text='X', end_row=3})
|
||||
|
||||
screen:expect{grid=[[
|
||||
X {1: }^l3 |
|
||||
X {1: }l4 |
|
||||
{1: }l5 |
|
||||
{1: } |
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
{2:~ }|
|
||||
|
|
||||
]]}
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
Loading…
Reference in New Issue
Block a user