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:
Lewis Russell
2022-01-03 12:22:13 +00:00
parent 83fc914337
commit 30e4cc3b3f
13 changed files with 589 additions and 17 deletions

View File

@@ -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;
}

View File

@@ -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";

View File

@@ -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;
}