mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #13241 from bfredl/decoration
decoration: split out "decoration" from "extmark" module
This commit is contained in:
commit
643f4a1787
@ -28,6 +28,7 @@
|
|||||||
#include "nvim/map.h"
|
#include "nvim/map.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/syntax.h"
|
#include "nvim/syntax.h"
|
||||||
@ -1470,14 +1471,14 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bfredl): synergize these two branches even more
|
// TODO(bfredl): synergize these two branches even more
|
||||||
if (ephemeral && redrawn_win && redrawn_win->w_buffer == buf) {
|
if (ephemeral && decor_state.buf == buf) {
|
||||||
int attr_id = hl_id > 0 ? syn_id2attr(hl_id) : 0;
|
int attr_id = hl_id > 0 ? syn_id2attr(hl_id) : 0;
|
||||||
VirtText *vt_allocated = NULL;
|
VirtText *vt_allocated = NULL;
|
||||||
if (kv_size(virt_text)) {
|
if (kv_size(virt_text)) {
|
||||||
vt_allocated = xmalloc(sizeof *vt_allocated);
|
vt_allocated = xmalloc(sizeof *vt_allocated);
|
||||||
*vt_allocated = virt_text;
|
*vt_allocated = virt_text;
|
||||||
}
|
}
|
||||||
decorations_add_ephemeral(attr_id, (int)line, (colnr_T)col,
|
decor_add_ephemeral(attr_id, (int)line, (colnr_T)col,
|
||||||
(int)line2, (colnr_T)col2, vt_allocated);
|
(int)line2, (colnr_T)col2, vt_allocated);
|
||||||
} else {
|
} else {
|
||||||
if (ephemeral) {
|
if (ephemeral) {
|
||||||
@ -1490,7 +1491,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
|
|||||||
decor->hl_id = hl_id;
|
decor->hl_id = hl_id;
|
||||||
decor->virt_text = virt_text;
|
decor->virt_text = virt_text;
|
||||||
} else if (hl_id) {
|
} else if (hl_id) {
|
||||||
decor = decoration_hl(hl_id);
|
decor = decor_hl(hl_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
|
id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
|
||||||
@ -1609,7 +1610,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
|
|||||||
extmark_set(buf, ns_id, 0,
|
extmark_set(buf, ns_id, 0,
|
||||||
(int)line, (colnr_T)col_start,
|
(int)line, (colnr_T)col_start,
|
||||||
end_line, (colnr_T)col_end,
|
end_line, (colnr_T)col_end,
|
||||||
decoration_hl(hl_id), kExtmarkNoUndo);
|
decor_hl(hl_id), kExtmarkNoUndo);
|
||||||
return src_id;
|
return src_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1728,7 +1729,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VirtText *existing = extmark_find_virttext(buf, (int)line, ns_id);
|
VirtText *existing = decor_find_virttext(buf, (int)line, ns_id);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
clear_virttext(existing);
|
clear_virttext(existing);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "nvim/map_defs.h"
|
#include "nvim/map_defs.h"
|
||||||
#include "nvim/map.h"
|
#include "nvim/map.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/option_defs.h"
|
#include "nvim/option_defs.h"
|
||||||
#include "nvim/version.h"
|
#include "nvim/version.h"
|
||||||
@ -1652,11 +1653,11 @@ const char *describe_ns(NS ns_id)
|
|||||||
return "(UNKNOWN PLUGIN)";
|
return "(UNKNOWN PLUGIN)";
|
||||||
}
|
}
|
||||||
|
|
||||||
DecorationProvider *get_provider(NS ns_id, bool force)
|
DecorProvider *get_provider(NS ns_id, bool force)
|
||||||
{
|
{
|
||||||
ssize_t i;
|
ssize_t i;
|
||||||
for (i = 0; i < (ssize_t)kv_size(decoration_providers); i++) {
|
for (i = 0; i < (ssize_t)kv_size(decor_providers); i++) {
|
||||||
DecorationProvider *item = &kv_A(decoration_providers, i);
|
DecorProvider *item = &kv_A(decor_providers, i);
|
||||||
if (item->ns_id == ns_id) {
|
if (item->ns_id == ns_id) {
|
||||||
return item;
|
return item;
|
||||||
} else if (item->ns_id > ns_id) {
|
} else if (item->ns_id > ns_id) {
|
||||||
@ -1668,12 +1669,12 @@ DecorationProvider *get_provider(NS ns_id, bool force)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ssize_t j = (ssize_t)kv_size(decoration_providers)-1; j >= i; j++) {
|
for (ssize_t j = (ssize_t)kv_size(decor_providers)-1; j >= i; j++) {
|
||||||
// allocates if needed:
|
// allocates if needed:
|
||||||
(void)kv_a(decoration_providers, (size_t)j+1);
|
(void)kv_a(decor_providers, (size_t)j+1);
|
||||||
kv_A(decoration_providers, (size_t)j+1) = kv_A(decoration_providers, j);
|
kv_A(decor_providers, (size_t)j+1) = kv_A(decor_providers, j);
|
||||||
}
|
}
|
||||||
DecorationProvider *item = &kv_a(decoration_providers, (size_t)i);
|
DecorProvider *item = &kv_a(decor_providers, (size_t)i);
|
||||||
*item = DECORATION_PROVIDER_INIT(ns_id);
|
*item = DECORATION_PROVIDER_INIT(ns_id);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
#include "nvim/getchar.h"
|
#include "nvim/getchar.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/ex_eval.h"
|
#include "nvim/ex_eval.h"
|
||||||
#include "nvim/lib/kvec.h"
|
#include "nvim/lib/kvec.h"
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
|
|||||||
/// Note that this method is not to be confused with |nvim_ui_pum_set_height()|,
|
/// Note that this method is not to be confused with |nvim_ui_pum_set_height()|,
|
||||||
/// which sets the number of visible items in the popup menu, while this
|
/// which sets the number of visible items in the popup menu, while this
|
||||||
/// function sets the bounding box of the popup menu, including visual
|
/// function sets the bounding box of the popup menu, including visual
|
||||||
/// decorations such as boarders and sliders. Floats need not use the same font
|
/// elements such as borders and sliders. Floats need not use the same font
|
||||||
/// size, nor be anchored to exact grid corners, so one can set floating-point
|
/// size, nor be anchored to exact grid corners, so one can set floating-point
|
||||||
/// numbers to the popup menu geometry.
|
/// numbers to the popup menu geometry.
|
||||||
///
|
///
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
#include "nvim/ops.h"
|
#include "nvim/ops.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/state.h"
|
#include "nvim/state.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/syntax.h"
|
#include "nvim/syntax.h"
|
||||||
#include "nvim/getchar.h"
|
#include "nvim/getchar.h"
|
||||||
#include "nvim/os/input.h"
|
#include "nvim/os/input.h"
|
||||||
@ -2685,7 +2685,7 @@ void nvim__screenshot(String path)
|
|||||||
ui_call_screenshot(path);
|
ui_call_screenshot(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_provider(DecorationProvider *p)
|
static void clear_provider(DecorProvider *p)
|
||||||
{
|
{
|
||||||
NLUA_CLEAR_REF(p->redraw_start);
|
NLUA_CLEAR_REF(p->redraw_start);
|
||||||
NLUA_CLEAR_REF(p->redraw_buf);
|
NLUA_CLEAR_REF(p->redraw_buf);
|
||||||
@ -2711,7 +2711,7 @@ static void clear_provider(DecorationProvider *p)
|
|||||||
/// callback can return `false` to disable the provider until the next redraw.
|
/// callback can return `false` to disable the provider until the next redraw.
|
||||||
/// Similarily, return `false` in `on_win` will skip the `on_lines` calls
|
/// Similarily, return `false` in `on_win` will skip the `on_lines` calls
|
||||||
/// for that window (but any extmarks set in `on_win` will still be used).
|
/// for that window (but any extmarks set in `on_win` will still be used).
|
||||||
/// A plugin managing multiple sources of decorations should ideally only set
|
/// A plugin managing multiple sources of decoration should ideally only set
|
||||||
/// one provider, and merge the sources internally. You can use multiple `ns_id`
|
/// one provider, and merge the sources internally. You can use multiple `ns_id`
|
||||||
/// for the extmarks set/modified inside the callback anyway.
|
/// for the extmarks set/modified inside the callback anyway.
|
||||||
///
|
///
|
||||||
@ -2739,7 +2739,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
|
|||||||
Error *err)
|
Error *err)
|
||||||
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
|
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
|
||||||
{
|
{
|
||||||
DecorationProvider *p = get_provider((NS)ns_id, true);
|
DecorProvider *p = get_provider((NS)ns_id, true);
|
||||||
clear_provider(p);
|
clear_provider(p);
|
||||||
|
|
||||||
// regardless of what happens, it seems good idea to redraw
|
// regardless of what happens, it seems good idea to redraw
|
||||||
|
@ -568,7 +568,7 @@ struct file_buffer {
|
|||||||
// negative when lines were deleted
|
// negative when lines were deleted
|
||||||
wininfo_T *b_wininfo; // list of last used info for each window
|
wininfo_T *b_wininfo; // list of last used info for each window
|
||||||
int b_mod_tick_syn; // last display tick syntax was updated
|
int b_mod_tick_syn; // last display tick syntax was updated
|
||||||
int b_mod_tick_deco; // last display tick decoration providers
|
int b_mod_tick_decor; // last display tick decoration providers
|
||||||
// where invoked
|
// where invoked
|
||||||
|
|
||||||
long b_mtime; // last change time of original file
|
long b_mtime; // last change time of original file
|
||||||
|
331
src/nvim/decoration.c
Normal file
331
src/nvim/decoration.c
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
||||||
|
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||||
|
//
|
||||||
|
//
|
||||||
|
#include "nvim/vim.h"
|
||||||
|
#include "nvim/extmark.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
|
#include "nvim/screen.h"
|
||||||
|
#include "nvim/syntax.h"
|
||||||
|
#include "nvim/highlight.h"
|
||||||
|
|
||||||
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
|
# include "decoration.c.generated.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static PMap(uint64_t) *hl_decors;
|
||||||
|
|
||||||
|
void decor_init(void)
|
||||||
|
{
|
||||||
|
hl_decors = pmap_new(uint64_t)();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add highlighting to a buffer, bounded by two cursor positions,
|
||||||
|
/// with an offset.
|
||||||
|
///
|
||||||
|
/// TODO(bfredl): make decoration powerful enough so that this
|
||||||
|
/// can be done with a single ephemeral decoration.
|
||||||
|
///
|
||||||
|
/// @param buf Buffer to add highlights to
|
||||||
|
/// @param src_id src_id to use or 0 to use a new src_id group,
|
||||||
|
/// or -1 for ungrouped highlight.
|
||||||
|
/// @param hl_id Highlight group id
|
||||||
|
/// @param pos_start Cursor position to start the hightlighting at
|
||||||
|
/// @param pos_end Cursor position to end the highlighting at
|
||||||
|
/// @param offset Move the whole highlighting this many columns to the right
|
||||||
|
void bufhl_add_hl_pos_offset(buf_T *buf,
|
||||||
|
int src_id,
|
||||||
|
int hl_id,
|
||||||
|
lpos_T pos_start,
|
||||||
|
lpos_T pos_end,
|
||||||
|
colnr_T offset)
|
||||||
|
{
|
||||||
|
colnr_T hl_start = 0;
|
||||||
|
colnr_T hl_end = 0;
|
||||||
|
Decoration *decor = decor_hl(hl_id);
|
||||||
|
|
||||||
|
// TODO(bfredl): if decoration had blocky mode, we could avoid this loop
|
||||||
|
for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
|
||||||
|
int end_off = 0;
|
||||||
|
if (pos_start.lnum < lnum && lnum < pos_end.lnum) {
|
||||||
|
// TODO(bfredl): This is quite ad-hoc, but the space between |num| and
|
||||||
|
// text being highlighted is the indication of \n being part of the
|
||||||
|
// substituted text. But it would be more consistent to highlight
|
||||||
|
// a space _after_ the previous line instead (like highlight EOL list
|
||||||
|
// char)
|
||||||
|
hl_start = MAX(offset-1, 0);
|
||||||
|
end_off = 1;
|
||||||
|
hl_end = 0;
|
||||||
|
} else if (lnum == pos_start.lnum && lnum < pos_end.lnum) {
|
||||||
|
hl_start = pos_start.col + offset;
|
||||||
|
end_off = 1;
|
||||||
|
hl_end = 0;
|
||||||
|
} else if (pos_start.lnum < lnum && lnum == pos_end.lnum) {
|
||||||
|
hl_start = MAX(offset-1, 0);
|
||||||
|
hl_end = pos_end.col + offset;
|
||||||
|
} else if (pos_start.lnum == lnum && pos_end.lnum == lnum) {
|
||||||
|
hl_start = pos_start.col + offset;
|
||||||
|
hl_end = pos_end.col + offset;
|
||||||
|
}
|
||||||
|
(void)extmark_set(buf, (uint64_t)src_id, 0,
|
||||||
|
(int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end,
|
||||||
|
decor, kExtmarkNoUndo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Decoration *decor_hl(int hl_id)
|
||||||
|
{
|
||||||
|
assert(hl_id > 0);
|
||||||
|
Decoration **dp = (Decoration **)pmap_ref(uint64_t)(hl_decors,
|
||||||
|
(uint64_t)hl_id, true);
|
||||||
|
if (*dp) {
|
||||||
|
return *dp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Decoration *decor = xcalloc(1, sizeof(*decor));
|
||||||
|
decor->hl_id = hl_id;
|
||||||
|
decor->shared = true;
|
||||||
|
*dp = decor;
|
||||||
|
return decor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decor_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
||||||
|
{
|
||||||
|
if (decor->hl_id && row2 >= row1) {
|
||||||
|
redraw_buf_range_later(buf, row1+1, row2+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kv_size(decor->virt_text)) {
|
||||||
|
redraw_buf_line_later(buf, row1+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void decor_free(Decoration *decor)
|
||||||
|
{
|
||||||
|
if (decor && !decor->shared) {
|
||||||
|
clear_virttext(&decor->virt_text);
|
||||||
|
xfree(decor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_virttext(VirtText *text)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < kv_size(*text); i++) {
|
||||||
|
xfree(kv_A(*text, i).text);
|
||||||
|
}
|
||||||
|
kv_destroy(*text);
|
||||||
|
*text = (VirtText)KV_INITIAL_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
|
||||||
|
{
|
||||||
|
MarkTreeIter itr[1] = { 0 };
|
||||||
|
marktree_itr_get(buf->b_marktree, row, 0, itr);
|
||||||
|
while (true) {
|
||||||
|
mtmark_t mark = marktree_itr_current(itr);
|
||||||
|
if (mark.row < 0 || mark.row > row) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||||
|
mark.id, false);
|
||||||
|
if (item && (ns_id == 0 || ns_id == item->ns_id)
|
||||||
|
&& item->decor && kv_size(item->decor->virt_text)) {
|
||||||
|
return &item->decor->virt_text;
|
||||||
|
}
|
||||||
|
marktree_itr_next(buf->b_marktree, itr);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decor_redraw_reset(buf_T *buf, DecorState *state)
|
||||||
|
{
|
||||||
|
state->row = -1;
|
||||||
|
state->buf = buf;
|
||||||
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
|
HlRange item = kv_A(state->active, i);
|
||||||
|
if (item.virt_text_owned) {
|
||||||
|
clear_virttext(item.virt_text);
|
||||||
|
xfree(item.virt_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kv_size(state->active) = 0;
|
||||||
|
return buf->b_extmark_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
|
||||||
|
{
|
||||||
|
state->top_row = top_row;
|
||||||
|
marktree_itr_get(buf->b_marktree, top_row, 0, state->itr);
|
||||||
|
if (!state->itr->node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
marktree_itr_rewind(buf->b_marktree, state->itr);
|
||||||
|
while (true) {
|
||||||
|
mtmark_t mark = marktree_itr_current(state->itr);
|
||||||
|
if (mark.row < 0) { // || mark.row > end_row
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((mark.row < top_row && mark.id&MARKTREE_END_FLAG)) {
|
||||||
|
goto next_mark;
|
||||||
|
}
|
||||||
|
mtpos_t altpos = marktree_lookup(buf->b_marktree,
|
||||||
|
mark.id^MARKTREE_END_FLAG, NULL);
|
||||||
|
|
||||||
|
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
|
||||||
|
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||||
|
start_id, false);
|
||||||
|
if (!item || !item->decor) {
|
||||||
|
// TODO(bfredl): dedicated flag for being a decoration?
|
||||||
|
goto next_mark;
|
||||||
|
}
|
||||||
|
Decoration *decor = item->decor;
|
||||||
|
|
||||||
|
if ((!(mark.id&MARKTREE_END_FLAG) && altpos.row < top_row
|
||||||
|
&& item && !kv_size(decor->virt_text))
|
||||||
|
|| ((mark.id&MARKTREE_END_FLAG) && altpos.row >= top_row)) {
|
||||||
|
goto next_mark;
|
||||||
|
}
|
||||||
|
|
||||||
|
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
|
||||||
|
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
|
||||||
|
HlRange range;
|
||||||
|
if (mark.id&MARKTREE_END_FLAG) {
|
||||||
|
range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
|
||||||
|
attr_id, vt, false };
|
||||||
|
} else {
|
||||||
|
range = (HlRange){ mark.row, mark.col, altpos.row,
|
||||||
|
altpos.col, attr_id, vt, false };
|
||||||
|
}
|
||||||
|
kv_push(state->active, range);
|
||||||
|
|
||||||
|
next_mark:
|
||||||
|
if (marktree_itr_node_done(state->itr)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
marktree_itr_next(buf->b_marktree, state->itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // TODO(bfredl): check if available in the region
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decor_redraw_line(buf_T *buf, int row, DecorState *state)
|
||||||
|
{
|
||||||
|
if (state->row == -1) {
|
||||||
|
decor_redraw_start(buf, row, state);
|
||||||
|
}
|
||||||
|
state->row = row;
|
||||||
|
state->col_until = -1;
|
||||||
|
return true; // TODO(bfredl): be more precise
|
||||||
|
}
|
||||||
|
|
||||||
|
int decor_redraw_col(buf_T *buf, int col, DecorState *state)
|
||||||
|
{
|
||||||
|
if (col <= state->col_until) {
|
||||||
|
return state->current;
|
||||||
|
}
|
||||||
|
state->col_until = MAXCOL;
|
||||||
|
while (true) {
|
||||||
|
mtmark_t mark = marktree_itr_current(state->itr);
|
||||||
|
if (mark.row < 0 || mark.row > state->row) {
|
||||||
|
break;
|
||||||
|
} else if (mark.row == state->row && mark.col > col) {
|
||||||
|
state->col_until = mark.col-1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mark.id&MARKTREE_END_FLAG)) {
|
||||||
|
// TODO(bfredl): check decoration flag
|
||||||
|
goto next_mark;
|
||||||
|
}
|
||||||
|
mtpos_t endpos = marktree_lookup(buf->b_marktree,
|
||||||
|
mark.id|MARKTREE_END_FLAG, NULL);
|
||||||
|
|
||||||
|
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||||
|
mark.id, false);
|
||||||
|
if (!item || !item->decor) {
|
||||||
|
// TODO(bfredl): dedicated flag for being a decoration?
|
||||||
|
goto next_mark;
|
||||||
|
}
|
||||||
|
Decoration *decor = item->decor;
|
||||||
|
|
||||||
|
if (endpos.row < mark.row
|
||||||
|
|| (endpos.row == mark.row && endpos.col <= mark.col)) {
|
||||||
|
if (item && !kv_size(decor->virt_text)) {
|
||||||
|
goto next_mark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
|
||||||
|
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
|
||||||
|
kv_push(state->active, ((HlRange){ mark.row, mark.col,
|
||||||
|
endpos.row, endpos.col,
|
||||||
|
attr_id, vt, false }));
|
||||||
|
|
||||||
|
next_mark:
|
||||||
|
marktree_itr_next(buf->b_marktree, state->itr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int attr = 0;
|
||||||
|
size_t j = 0;
|
||||||
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
|
HlRange item = kv_A(state->active, i);
|
||||||
|
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 && item.virt_text)) {
|
||||||
|
keep = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.start_row < state->row
|
||||||
|
|| (item.start_row == state->row && item.start_col <= col)) {
|
||||||
|
active = true;
|
||||||
|
if (item.end_row == state->row) {
|
||||||
|
state->col_until = MIN(state->col_until, item.end_col-1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.start_row == state->row) {
|
||||||
|
state->col_until = MIN(state->col_until, item.start_col-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (active && item.attr_id > 0) {
|
||||||
|
attr = hl_combine_attr(attr, item.attr_id);
|
||||||
|
}
|
||||||
|
if (keep) {
|
||||||
|
kv_A(state->active, j++) = kv_A(state->active, i);
|
||||||
|
} else if (item.virt_text_owned) {
|
||||||
|
clear_virttext(item.virt_text);
|
||||||
|
xfree(item.virt_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kv_size(state->active) = j;
|
||||||
|
state->current = attr;
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decor_redraw_end(DecorState *state)
|
||||||
|
{
|
||||||
|
state->buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtText *decor_redraw_virt_text(buf_T *buf, DecorState *state)
|
||||||
|
{
|
||||||
|
decor_redraw_col(buf, MAXCOL, state);
|
||||||
|
for (size_t i = 0; i < kv_size(state->active); i++) {
|
||||||
|
HlRange item = kv_A(state->active, i);
|
||||||
|
if (item.start_row == state->row && item.virt_text) {
|
||||||
|
return item.virt_text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decor_add_ephemeral(int attr_id, int start_row, int start_col,
|
||||||
|
int end_row, int end_col, VirtText *virt_text)
|
||||||
|
{
|
||||||
|
kv_push(decor_state.active,
|
||||||
|
((HlRange){ start_row, start_col,
|
||||||
|
end_row, end_col,
|
||||||
|
attr_id, virt_text, virt_text != NULL }));
|
||||||
|
}
|
71
src/nvim/decoration.h
Normal file
71
src/nvim/decoration.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef NVIM_DECORATION_H
|
||||||
|
#define NVIM_DECORATION_H
|
||||||
|
|
||||||
|
#include "nvim/pos.h"
|
||||||
|
#include "nvim/buffer_defs.h"
|
||||||
|
#include "nvim/extmark_defs.h"
|
||||||
|
|
||||||
|
// actual Decoration data is in extmark_defs.h
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *text;
|
||||||
|
int hl_id;
|
||||||
|
} VirtTextChunk;
|
||||||
|
|
||||||
|
typedef kvec_t(VirtTextChunk) VirtText;
|
||||||
|
#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
|
||||||
|
|
||||||
|
struct Decoration
|
||||||
|
{
|
||||||
|
int hl_id; // highlight group
|
||||||
|
VirtText virt_text;
|
||||||
|
// TODO(bfredl): style, signs, etc
|
||||||
|
bool shared; // shared decoration, don't free
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int start_row;
|
||||||
|
int start_col;
|
||||||
|
int end_row;
|
||||||
|
int end_col;
|
||||||
|
int attr_id;
|
||||||
|
VirtText *virt_text;
|
||||||
|
bool virt_text_owned;
|
||||||
|
} HlRange;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MarkTreeIter itr[1];
|
||||||
|
kvec_t(HlRange) active;
|
||||||
|
buf_T *buf;
|
||||||
|
int top_row;
|
||||||
|
int row;
|
||||||
|
int col_until;
|
||||||
|
int current;
|
||||||
|
VirtText *virt_text;
|
||||||
|
} DecorState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NS ns_id;
|
||||||
|
bool active;
|
||||||
|
LuaRef redraw_start;
|
||||||
|
LuaRef redraw_buf;
|
||||||
|
LuaRef redraw_win;
|
||||||
|
LuaRef redraw_line;
|
||||||
|
LuaRef redraw_end;
|
||||||
|
LuaRef hl_def;
|
||||||
|
int hl_valid;
|
||||||
|
} DecorProvider;
|
||||||
|
|
||||||
|
EXTERN kvec_t(DecorProvider) decor_providers INIT(= KV_INITIAL_VALUE);
|
||||||
|
EXTERN DecorState decor_state INIT(= { 0 });
|
||||||
|
|
||||||
|
#define DECORATION_PROVIDER_INIT(ns_id) (DecorProvider) \
|
||||||
|
{ ns_id, false, LUA_NOREF, LUA_NOREF, \
|
||||||
|
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
||||||
|
LUA_NOREF, -1 }
|
||||||
|
|
||||||
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
|
# include "decoration.h.generated.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NVIM_DECORATION_H
|
@ -41,6 +41,7 @@
|
|||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
|
@ -22,12 +22,18 @@
|
|||||||
// Deleting marks only happens when explicitly calling extmark_del, deleteing
|
// Deleting marks only happens when explicitly calling extmark_del, deleteing
|
||||||
// over a range of marks will only move the marks. Deleting on a mark will
|
// over a range of marks will only move the marks. Deleting on a mark will
|
||||||
// leave it in same position unless it is on the EOL of a line.
|
// leave it in same position unless it is on the EOL of a line.
|
||||||
|
//
|
||||||
|
// Extmarks are used to implement buffer decoration. Decoration is mostly
|
||||||
|
// regarded as an application of extmarks, however for practical reasons code
|
||||||
|
// that deletes an extmark with decoration will call back into the decoration
|
||||||
|
// code for redrawing the line with the deleted decoration.
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "nvim/api/vim.h"
|
#include "nvim/api/vim.h"
|
||||||
#include "nvim/vim.h"
|
#include "nvim/vim.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/buffer_updates.h"
|
#include "nvim/buffer_updates.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/pos.h"
|
#include "nvim/pos.h"
|
||||||
@ -36,20 +42,11 @@
|
|||||||
#include "nvim/lib/kbtree.h"
|
#include "nvim/lib/kbtree.h"
|
||||||
#include "nvim/undo.h"
|
#include "nvim/undo.h"
|
||||||
#include "nvim/buffer.h"
|
#include "nvim/buffer.h"
|
||||||
#include "nvim/syntax.h"
|
|
||||||
#include "nvim/highlight.h"
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "extmark.c.generated.h"
|
# include "extmark.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static PMap(uint64_t) *hl_decors;
|
|
||||||
|
|
||||||
void extmark_init(void)
|
|
||||||
{
|
|
||||||
hl_decors = pmap_new(uint64_t)();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
|
static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
|
||||||
if (!buf->b_extmark_ns) {
|
if (!buf->b_extmark_ns) {
|
||||||
if (!put) {
|
if (!put) {
|
||||||
@ -96,8 +93,8 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
|
|||||||
ExtmarkItem it = map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
ExtmarkItem it = map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
||||||
old_mark);
|
old_mark);
|
||||||
if (it.decor) {
|
if (it.decor) {
|
||||||
decoration_redraw(buf, row, row, it.decor);
|
decor_redraw(buf, row, row, it.decor);
|
||||||
free_decoration(it.decor);
|
decor_free(it.decor);
|
||||||
}
|
}
|
||||||
mark = marktree_revise(buf->b_marktree, itr);
|
mark = marktree_revise(buf->b_marktree, itr);
|
||||||
goto revised;
|
goto revised;
|
||||||
@ -130,7 +127,7 @@ revised:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (decor) {
|
if (decor) {
|
||||||
decoration_redraw(buf, row, end_row > -1 ? end_row : row, decor);
|
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -179,8 +176,8 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item.decor) {
|
if (item.decor) {
|
||||||
decoration_redraw(buf, pos.row, pos2.row, item.decor);
|
decor_redraw(buf, pos.row, pos2.row, item.decor);
|
||||||
free_decoration(item.decor);
|
decor_free(item.decor);
|
||||||
}
|
}
|
||||||
|
|
||||||
map_del(uint64_t, uint64_t)(ns->map, id);
|
map_del(uint64_t, uint64_t)(ns->map, id);
|
||||||
@ -238,8 +235,8 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
|
|||||||
marktree_del_itr(buf->b_marktree, itr, false);
|
marktree_del_itr(buf->b_marktree, itr, false);
|
||||||
if (*del_status >= 0) { // we had a decor_id
|
if (*del_status >= 0) { // we had a decor_id
|
||||||
DecorItem it = kv_A(decors, *del_status);
|
DecorItem it = kv_A(decors, *del_status);
|
||||||
decoration_redraw(buf, it.row1, mark.row, it.decor);
|
decor_redraw(buf, it.row1, mark.row, it.decor);
|
||||||
free_decoration(it.decor);
|
decor_free(it.decor);
|
||||||
}
|
}
|
||||||
map_del(uint64_t, ssize_t)(delete_set, mark.id);
|
map_del(uint64_t, ssize_t)(delete_set, mark.id);
|
||||||
continue;
|
continue;
|
||||||
@ -264,8 +261,8 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
|
|||||||
}
|
}
|
||||||
map_put(uint64_t, ssize_t)(delete_set, other, decor_id);
|
map_put(uint64_t, ssize_t)(delete_set, other, decor_id);
|
||||||
} else if (item.decor) {
|
} else if (item.decor) {
|
||||||
decoration_redraw(buf, mark.row, mark.row, item.decor);
|
decor_redraw(buf, mark.row, mark.row, item.decor);
|
||||||
free_decoration(item.decor);
|
decor_free(item.decor);
|
||||||
}
|
}
|
||||||
ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns;
|
ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns;
|
||||||
map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id);
|
map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id);
|
||||||
@ -283,8 +280,8 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
|
|||||||
marktree_del_itr(buf->b_marktree, itr, false);
|
marktree_del_itr(buf->b_marktree, itr, false);
|
||||||
if (decor_id >= 0) {
|
if (decor_id >= 0) {
|
||||||
DecorItem it = kv_A(decors, decor_id);
|
DecorItem it = kv_A(decors, decor_id);
|
||||||
decoration_redraw(buf, it.row1, pos.row, it.decor);
|
decor_redraw(buf, it.row1, pos.row, it.decor);
|
||||||
free_decoration(it.decor);
|
decor_free(it.decor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
map_clear(uint64_t, ssize_t)(delete_set);
|
map_clear(uint64_t, ssize_t)(delete_set);
|
||||||
@ -403,7 +400,7 @@ void extmark_free_all(buf_T *buf)
|
|||||||
|
|
||||||
map_foreach(buf->b_extmark_index, id, item, {
|
map_foreach(buf->b_extmark_index, id, item, {
|
||||||
(void)id;
|
(void)id;
|
||||||
free_decoration(item.decor);
|
decor_free(item.decor);
|
||||||
});
|
});
|
||||||
map_free(uint64_t, ExtmarkItem)(buf->b_extmark_index);
|
map_free(uint64_t, ExtmarkItem)(buf->b_extmark_index);
|
||||||
buf->b_extmark_index = NULL;
|
buf->b_extmark_index = NULL;
|
||||||
@ -737,295 +734,3 @@ uint64_t src2ns(Integer *src_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add highlighting to a buffer, bounded by two cursor positions,
|
|
||||||
/// with an offset.
|
|
||||||
///
|
|
||||||
/// @param buf Buffer to add highlights to
|
|
||||||
/// @param src_id src_id to use or 0 to use a new src_id group,
|
|
||||||
/// or -1 for ungrouped highlight.
|
|
||||||
/// @param hl_id Highlight group id
|
|
||||||
/// @param pos_start Cursor position to start the hightlighting at
|
|
||||||
/// @param pos_end Cursor position to end the highlighting at
|
|
||||||
/// @param offset Move the whole highlighting this many columns to the right
|
|
||||||
void bufhl_add_hl_pos_offset(buf_T *buf,
|
|
||||||
int src_id,
|
|
||||||
int hl_id,
|
|
||||||
lpos_T pos_start,
|
|
||||||
lpos_T pos_end,
|
|
||||||
colnr_T offset)
|
|
||||||
{
|
|
||||||
colnr_T hl_start = 0;
|
|
||||||
colnr_T hl_end = 0;
|
|
||||||
Decoration *decor = decoration_hl(hl_id);
|
|
||||||
|
|
||||||
// TODO(bfredl): if decoration had blocky mode, we could avoid this loop
|
|
||||||
for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
|
|
||||||
int end_off = 0;
|
|
||||||
if (pos_start.lnum < lnum && lnum < pos_end.lnum) {
|
|
||||||
// TODO(bfredl): This is quite ad-hoc, but the space between |num| and
|
|
||||||
// text being highlighted is the indication of \n being part of the
|
|
||||||
// substituted text. But it would be more consistent to highlight
|
|
||||||
// a space _after_ the previous line instead (like highlight EOL list
|
|
||||||
// char)
|
|
||||||
hl_start = MAX(offset-1, 0);
|
|
||||||
end_off = 1;
|
|
||||||
hl_end = 0;
|
|
||||||
} else if (lnum == pos_start.lnum && lnum < pos_end.lnum) {
|
|
||||||
hl_start = pos_start.col + offset;
|
|
||||||
end_off = 1;
|
|
||||||
hl_end = 0;
|
|
||||||
} else if (pos_start.lnum < lnum && lnum == pos_end.lnum) {
|
|
||||||
hl_start = MAX(offset-1, 0);
|
|
||||||
hl_end = pos_end.col + offset;
|
|
||||||
} else if (pos_start.lnum == lnum && pos_end.lnum == lnum) {
|
|
||||||
hl_start = pos_start.col + offset;
|
|
||||||
hl_end = pos_end.col + offset;
|
|
||||||
}
|
|
||||||
(void)extmark_set(buf, (uint64_t)src_id, 0,
|
|
||||||
(int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end,
|
|
||||||
decor, kExtmarkNoUndo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Decoration *decoration_hl(int hl_id)
|
|
||||||
{
|
|
||||||
assert(hl_id > 0);
|
|
||||||
Decoration **dp = (Decoration **)pmap_ref(uint64_t)(hl_decors,
|
|
||||||
(uint64_t)hl_id, true);
|
|
||||||
if (*dp) {
|
|
||||||
return *dp;
|
|
||||||
}
|
|
||||||
|
|
||||||
Decoration *decor = xcalloc(1, sizeof(*decor));
|
|
||||||
decor->hl_id = hl_id;
|
|
||||||
decor->shared = true;
|
|
||||||
*dp = decor;
|
|
||||||
return decor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void decoration_redraw(buf_T *buf, int row1, int row2, Decoration *decor)
|
|
||||||
{
|
|
||||||
if (decor->hl_id && row2 >= row1) {
|
|
||||||
redraw_buf_range_later(buf, row1+1, row2+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kv_size(decor->virt_text)) {
|
|
||||||
redraw_buf_line_later(buf, row1+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_decoration(Decoration *decor)
|
|
||||||
{
|
|
||||||
if (decor && !decor->shared) {
|
|
||||||
clear_virttext(&decor->virt_text);
|
|
||||||
xfree(decor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_virttext(VirtText *text)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < kv_size(*text); i++) {
|
|
||||||
xfree(kv_A(*text, i).text);
|
|
||||||
}
|
|
||||||
kv_destroy(*text);
|
|
||||||
*text = (VirtText)KV_INITIAL_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtText *extmark_find_virttext(buf_T *buf, int row, uint64_t ns_id)
|
|
||||||
{
|
|
||||||
MarkTreeIter itr[1] = { 0 };
|
|
||||||
marktree_itr_get(buf->b_marktree, row, 0, itr);
|
|
||||||
while (true) {
|
|
||||||
mtmark_t mark = marktree_itr_current(itr);
|
|
||||||
if (mark.row < 0 || mark.row > row) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
|
||||||
mark.id, false);
|
|
||||||
if (item && (ns_id == 0 || ns_id == item->ns_id)
|
|
||||||
&& item->decor && kv_size(item->decor->virt_text)) {
|
|
||||||
return &item->decor->virt_text;
|
|
||||||
}
|
|
||||||
marktree_itr_next(buf->b_marktree, itr);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool decorations_redraw_reset(buf_T *buf, DecorationRedrawState *state)
|
|
||||||
{
|
|
||||||
state->row = -1;
|
|
||||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
|
||||||
HlRange item = kv_A(state->active, i);
|
|
||||||
if (item.virt_text_owned) {
|
|
||||||
clear_virttext(item.virt_text);
|
|
||||||
xfree(item.virt_text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kv_size(state->active) = 0;
|
|
||||||
return buf->b_extmark_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool decorations_redraw_start(buf_T *buf, int top_row,
|
|
||||||
DecorationRedrawState *state)
|
|
||||||
{
|
|
||||||
state->top_row = top_row;
|
|
||||||
marktree_itr_get(buf->b_marktree, top_row, 0, state->itr);
|
|
||||||
if (!state->itr->node) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
marktree_itr_rewind(buf->b_marktree, state->itr);
|
|
||||||
while (true) {
|
|
||||||
mtmark_t mark = marktree_itr_current(state->itr);
|
|
||||||
if (mark.row < 0) { // || mark.row > end_row
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((mark.row < top_row && mark.id&MARKTREE_END_FLAG)) {
|
|
||||||
goto next_mark;
|
|
||||||
}
|
|
||||||
mtpos_t altpos = marktree_lookup(buf->b_marktree,
|
|
||||||
mark.id^MARKTREE_END_FLAG, NULL);
|
|
||||||
|
|
||||||
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
|
|
||||||
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
|
||||||
start_id, false);
|
|
||||||
if (!item || !item->decor) {
|
|
||||||
// TODO(bfredl): dedicated flag for being a decoration?
|
|
||||||
goto next_mark;
|
|
||||||
}
|
|
||||||
Decoration *decor = item->decor;
|
|
||||||
|
|
||||||
if ((!(mark.id&MARKTREE_END_FLAG) && altpos.row < top_row
|
|
||||||
&& item && !kv_size(decor->virt_text))
|
|
||||||
|| ((mark.id&MARKTREE_END_FLAG) && altpos.row >= top_row)) {
|
|
||||||
goto next_mark;
|
|
||||||
}
|
|
||||||
|
|
||||||
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
|
|
||||||
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
|
|
||||||
HlRange range;
|
|
||||||
if (mark.id&MARKTREE_END_FLAG) {
|
|
||||||
range = (HlRange){ altpos.row, altpos.col, mark.row, mark.col,
|
|
||||||
attr_id, vt, false };
|
|
||||||
} else {
|
|
||||||
range = (HlRange){ mark.row, mark.col, altpos.row,
|
|
||||||
altpos.col, attr_id, vt, false };
|
|
||||||
}
|
|
||||||
kv_push(state->active, range);
|
|
||||||
|
|
||||||
next_mark:
|
|
||||||
if (marktree_itr_node_done(state->itr)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
marktree_itr_next(buf->b_marktree, state->itr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // TODO(bfredl): check if available in the region
|
|
||||||
}
|
|
||||||
|
|
||||||
bool decorations_redraw_line(buf_T *buf, int row, DecorationRedrawState *state)
|
|
||||||
{
|
|
||||||
if (state->row == -1) {
|
|
||||||
decorations_redraw_start(buf, row, state);
|
|
||||||
}
|
|
||||||
state->row = row;
|
|
||||||
state->col_until = -1;
|
|
||||||
return true; // TODO(bfredl): be more precise
|
|
||||||
}
|
|
||||||
|
|
||||||
int decorations_redraw_col(buf_T *buf, int col, DecorationRedrawState *state)
|
|
||||||
{
|
|
||||||
if (col <= state->col_until) {
|
|
||||||
return state->current;
|
|
||||||
}
|
|
||||||
state->col_until = MAXCOL;
|
|
||||||
while (true) {
|
|
||||||
mtmark_t mark = marktree_itr_current(state->itr);
|
|
||||||
if (mark.row < 0 || mark.row > state->row) {
|
|
||||||
break;
|
|
||||||
} else if (mark.row == state->row && mark.col > col) {
|
|
||||||
state->col_until = mark.col-1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((mark.id&MARKTREE_END_FLAG)) {
|
|
||||||
// TODO(bfredl): check decorations flag
|
|
||||||
goto next_mark;
|
|
||||||
}
|
|
||||||
mtpos_t endpos = marktree_lookup(buf->b_marktree,
|
|
||||||
mark.id|MARKTREE_END_FLAG, NULL);
|
|
||||||
|
|
||||||
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
|
|
||||||
mark.id, false);
|
|
||||||
if (!item || !item->decor) {
|
|
||||||
// TODO(bfredl): dedicated flag for being a decoration?
|
|
||||||
goto next_mark;
|
|
||||||
}
|
|
||||||
Decoration *decor = item->decor;
|
|
||||||
|
|
||||||
if (endpos.row < mark.row
|
|
||||||
|| (endpos.row == mark.row && endpos.col <= mark.col)) {
|
|
||||||
if (item && !kv_size(decor->virt_text)) {
|
|
||||||
goto next_mark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
|
|
||||||
VirtText *vt = kv_size(decor->virt_text) ? &decor->virt_text : NULL;
|
|
||||||
kv_push(state->active, ((HlRange){ mark.row, mark.col,
|
|
||||||
endpos.row, endpos.col,
|
|
||||||
attr_id, vt, false }));
|
|
||||||
|
|
||||||
next_mark:
|
|
||||||
marktree_itr_next(buf->b_marktree, state->itr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int attr = 0;
|
|
||||||
size_t j = 0;
|
|
||||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
|
||||||
HlRange item = kv_A(state->active, i);
|
|
||||||
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 && item.virt_text)) {
|
|
||||||
keep = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (item.start_row < state->row
|
|
||||||
|| (item.start_row == state->row && item.start_col <= col)) {
|
|
||||||
active = true;
|
|
||||||
if (item.end_row == state->row) {
|
|
||||||
state->col_until = MIN(state->col_until, item.end_col-1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (item.start_row == state->row) {
|
|
||||||
state->col_until = MIN(state->col_until, item.start_col-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (active && item.attr_id > 0) {
|
|
||||||
attr = hl_combine_attr(attr, item.attr_id);
|
|
||||||
}
|
|
||||||
if (keep) {
|
|
||||||
kv_A(state->active, j++) = kv_A(state->active, i);
|
|
||||||
} else if (item.virt_text_owned) {
|
|
||||||
clear_virttext(item.virt_text);
|
|
||||||
xfree(item.virt_text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kv_size(state->active) = j;
|
|
||||||
state->current = attr;
|
|
||||||
return attr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtText *decorations_redraw_virt_text(buf_T *buf, DecorationRedrawState *state)
|
|
||||||
{
|
|
||||||
decorations_redraw_col(buf, MAXCOL, state);
|
|
||||||
for (size_t i = 0; i < kv_size(state->active); i++) {
|
|
||||||
HlRange item = kv_A(state->active, i);
|
|
||||||
if (item.start_row == state->row && item.virt_text) {
|
|
||||||
return item.virt_text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
@ -79,29 +79,6 @@ struct undo_object {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int start_row;
|
|
||||||
int start_col;
|
|
||||||
int end_row;
|
|
||||||
int end_col;
|
|
||||||
int attr_id;
|
|
||||||
VirtText *virt_text;
|
|
||||||
bool virt_text_owned;
|
|
||||||
} HlRange;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
MarkTreeIter itr[1];
|
|
||||||
kvec_t(HlRange) active;
|
|
||||||
int top_row;
|
|
||||||
int row;
|
|
||||||
int col_until;
|
|
||||||
int current;
|
|
||||||
VirtText *virt_text;
|
|
||||||
} DecorationRedrawState;
|
|
||||||
|
|
||||||
EXTERN kvec_t(DecorationProvider) decoration_providers INIT(= KV_INITIAL_VALUE);
|
|
||||||
EXTERN win_T *redrawn_win INIT(= NULL); // used for ephemeral extmarks
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "extmark.h.generated.h"
|
# include "extmark.h.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,21 +4,7 @@
|
|||||||
#include "nvim/types.h"
|
#include "nvim/types.h"
|
||||||
#include "nvim/lib/kvec.h"
|
#include "nvim/lib/kvec.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Decoration Decoration;
|
||||||
char *text;
|
|
||||||
int hl_id;
|
|
||||||
} VirtTextChunk;
|
|
||||||
|
|
||||||
typedef kvec_t(VirtTextChunk) VirtText;
|
|
||||||
#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int hl_id; // highlight group
|
|
||||||
VirtText virt_text;
|
|
||||||
// TODO(bfredl): style, signs, etc
|
|
||||||
bool shared; // shared decoration, don't free
|
|
||||||
} Decoration;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -42,21 +28,4 @@ typedef enum {
|
|||||||
kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable
|
kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable
|
||||||
} ExtmarkOp;
|
} ExtmarkOp;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
NS ns_id;
|
|
||||||
bool active;
|
|
||||||
LuaRef redraw_start;
|
|
||||||
LuaRef redraw_buf;
|
|
||||||
LuaRef redraw_win;
|
|
||||||
LuaRef redraw_line;
|
|
||||||
LuaRef redraw_end;
|
|
||||||
LuaRef hl_def;
|
|
||||||
int hl_valid;
|
|
||||||
} DecorationProvider;
|
|
||||||
|
|
||||||
#define DECORATION_PROVIDER_INIT(ns_id) (DecorationProvider) \
|
|
||||||
{ ns_id, false, LUA_NOREF, LUA_NOREF, \
|
|
||||||
LUA_NOREF, LUA_NOREF, LUA_NOREF, \
|
|
||||||
LUA_NOREF, -1 }
|
|
||||||
|
|
||||||
#endif // NVIM_EXTMARK_DEFS_H
|
#endif // NVIM_EXTMARK_DEFS_H
|
||||||
|
@ -156,7 +156,7 @@ static ColorKey colored_key(NS ns_id, int syn_id)
|
|||||||
|
|
||||||
void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
|
void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
|
||||||
{
|
{
|
||||||
DecorationProvider *p = get_provider(ns_id, true);
|
DecorProvider *p = get_provider(ns_id, true);
|
||||||
int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs);
|
int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs);
|
||||||
ColorItem it = { .attr_id = attr_id,
|
ColorItem it = { .attr_id = attr_id,
|
||||||
.link_id = link_id,
|
.link_id = link_id,
|
||||||
@ -175,7 +175,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link)
|
|||||||
ns_id = ns_hl_active;
|
ns_id = ns_hl_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecorationProvider *p = get_provider(ns_id, true);
|
DecorProvider *p = get_provider(ns_id, true);
|
||||||
ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id));
|
ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, colored_key(ns_id, hl_id));
|
||||||
// TODO(bfredl): map_ref true even this?
|
// TODO(bfredl): map_ref true even this?
|
||||||
bool valid_cache = it.version >= p->hl_valid;
|
bool valid_cache = it.version >= p->hl_valid;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "nvim/ex_cmds.h"
|
#include "nvim/ex_cmds.h"
|
||||||
#include "nvim/ex_cmds2.h"
|
#include "nvim/ex_cmds2.h"
|
||||||
#include "nvim/ex_docmd.h"
|
#include "nvim/ex_docmd.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/fileio.h"
|
#include "nvim/fileio.h"
|
||||||
#include "nvim/fold.h"
|
#include "nvim/fold.h"
|
||||||
#include "nvim/getchar.h"
|
#include "nvim/getchar.h"
|
||||||
@ -163,7 +163,7 @@ void early_init(mparm_T *paramp)
|
|||||||
env_init();
|
env_init();
|
||||||
fs_init();
|
fs_init();
|
||||||
handle_init();
|
handle_init();
|
||||||
extmark_init();
|
decor_init();
|
||||||
eval_init(); // init global variables
|
eval_init(); // init global variables
|
||||||
init_path(argv0 ? argv0 : "nvim");
|
init_path(argv0 ? argv0 : "nvim");
|
||||||
init_normal_cmds(); // Init the table of Normal mode commands.
|
init_normal_cmds(); // Init the table of Normal mode commands.
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
#include "nvim/main.h"
|
#include "nvim/main.h"
|
||||||
#include "nvim/mark.h"
|
#include "nvim/mark.h"
|
||||||
#include "nvim/extmark.h"
|
#include "nvim/extmark.h"
|
||||||
|
#include "nvim/decoration.h"
|
||||||
#include "nvim/mbyte.h"
|
#include "nvim/mbyte.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
@ -124,7 +125,7 @@
|
|||||||
#define MB_FILLER_CHAR '<' /* character used when a double-width character
|
#define MB_FILLER_CHAR '<' /* character used when a double-width character
|
||||||
* doesn't fit. */
|
* doesn't fit. */
|
||||||
|
|
||||||
typedef kvec_withinit_t(DecorationProvider *, 4) Providers;
|
typedef kvec_withinit_t(DecorProvider *, 4) Providers;
|
||||||
|
|
||||||
// temporary buffer for rendering a single screenline, so it can be
|
// temporary buffer for rendering a single screenline, so it can be
|
||||||
// compared with previous contents to calculate smallest delta.
|
// compared with previous contents to calculate smallest delta.
|
||||||
@ -473,8 +474,8 @@ int update_screen(int type)
|
|||||||
|
|
||||||
Providers providers;
|
Providers providers;
|
||||||
kvi_init(providers);
|
kvi_init(providers);
|
||||||
for (size_t i = 0; i < kv_size(decoration_providers); i++) {
|
for (size_t i = 0; i < kv_size(decor_providers); i++) {
|
||||||
DecorationProvider *p = &kv_A(decoration_providers, i);
|
DecorProvider *p = &kv_A(decor_providers, i);
|
||||||
if (!p->active) {
|
if (!p->active) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -556,16 +557,16 @@ int update_screen(int type)
|
|||||||
buf->b_mod_tick_syn = display_tick;
|
buf->b_mod_tick_syn = display_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf->b_mod_tick_deco < display_tick) {
|
if (buf->b_mod_tick_decor < display_tick) {
|
||||||
for (size_t i = 0; i < kv_size(providers); i++) {
|
for (size_t i = 0; i < kv_size(providers); i++) {
|
||||||
DecorationProvider *p = kv_A(providers, i);
|
DecorProvider *p = kv_A(providers, i);
|
||||||
if (p && p->redraw_buf != LUA_NOREF) {
|
if (p && p->redraw_buf != LUA_NOREF) {
|
||||||
FIXED_TEMP_ARRAY(args, 1);
|
FIXED_TEMP_ARRAY(args, 1);
|
||||||
args.items[0] = BUFFER_OBJ(buf->handle);
|
args.items[0] = BUFFER_OBJ(buf->handle);
|
||||||
provider_invoke(p->ns_id, "buf", p->redraw_buf, args, true);
|
provider_invoke(p->ns_id, "buf", p->redraw_buf, args, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf->b_mod_tick_deco = display_tick;
|
buf->b_mod_tick_decor = display_tick;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -579,8 +580,6 @@ int update_screen(int type)
|
|||||||
|
|
||||||
|
|
||||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||||
redrawn_win = wp;
|
|
||||||
|
|
||||||
if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid.chars) {
|
if (wp->w_redr_type == CLEAR && wp->w_floating && wp->w_grid.chars) {
|
||||||
grid_invalidate(&wp->w_grid);
|
grid_invalidate(&wp->w_grid);
|
||||||
wp->w_redr_type = NOT_VALID;
|
wp->w_redr_type = NOT_VALID;
|
||||||
@ -598,8 +597,6 @@ int update_screen(int type)
|
|||||||
if (wp->w_redr_status) {
|
if (wp->w_redr_status) {
|
||||||
win_redr_status(wp);
|
win_redr_status(wp);
|
||||||
}
|
}
|
||||||
|
|
||||||
redrawn_win = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
end_search_hl();
|
end_search_hl();
|
||||||
@ -631,7 +628,7 @@ int update_screen(int type)
|
|||||||
did_intro = TRUE;
|
did_intro = TRUE;
|
||||||
|
|
||||||
for (size_t i = 0; i < kv_size(providers); i++) {
|
for (size_t i = 0; i < kv_size(providers); i++) {
|
||||||
DecorationProvider *p = kv_A(providers, i);
|
DecorProvider *p = kv_A(providers, i);
|
||||||
if (!p->active) {
|
if (!p->active) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -701,18 +698,6 @@ bool win_cursorline_standout(const win_T *wp)
|
|||||||
|| (wp->w_p_cole > 0 && (VIsual_active || !conceal_cursor_line(wp)));
|
|| (wp->w_p_cole > 0 && (VIsual_active || !conceal_cursor_line(wp)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static DecorationRedrawState decorations;
|
|
||||||
|
|
||||||
void decorations_add_ephemeral(int attr_id,
|
|
||||||
int start_row, int start_col,
|
|
||||||
int end_row, int end_col, VirtText *virt_text)
|
|
||||||
{
|
|
||||||
kv_push(decorations.active,
|
|
||||||
((HlRange){ start_row, start_col,
|
|
||||||
end_row, end_col,
|
|
||||||
attr_id, virt_text, virt_text != NULL }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update a single window.
|
* Update a single window.
|
||||||
*
|
*
|
||||||
@ -1306,7 +1291,7 @@ static void win_update(win_T *wp, Providers *providers)
|
|||||||
srow = 0;
|
srow = 0;
|
||||||
lnum = wp->w_topline; // first line shown in window
|
lnum = wp->w_topline; // first line shown in window
|
||||||
|
|
||||||
decorations_redraw_reset(buf, &decorations);
|
decor_redraw_reset(buf, &decor_state);
|
||||||
|
|
||||||
Providers line_providers;
|
Providers line_providers;
|
||||||
kvi_init(line_providers);
|
kvi_init(line_providers);
|
||||||
@ -1316,7 +1301,7 @@ static void win_update(win_T *wp, Providers *providers)
|
|||||||
: (wp->w_topline + wp->w_height_inner));
|
: (wp->w_topline + wp->w_height_inner));
|
||||||
|
|
||||||
for (size_t k = 0; k < kv_size(*providers); k++) {
|
for (size_t k = 0; k < kv_size(*providers); k++) {
|
||||||
DecorationProvider *p = kv_A(*providers, k);
|
DecorProvider *p = kv_A(*providers, k);
|
||||||
if (p && p->redraw_win != LUA_NOREF) {
|
if (p && p->redraw_win != LUA_NOREF) {
|
||||||
FIXED_TEMP_ARRAY(args, 4);
|
FIXED_TEMP_ARRAY(args, 4);
|
||||||
args.items[0] = WINDOW_OBJ(wp->handle);
|
args.items[0] = WINDOW_OBJ(wp->handle);
|
||||||
@ -1755,6 +1740,7 @@ static void win_update(win_T *wp, Providers *providers)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* restore got_int, unless CTRL-C was hit while redrawing */
|
/* restore got_int, unless CTRL-C was hit while redrawing */
|
||||||
if (!got_int)
|
if (!got_int)
|
||||||
got_int = save_got_int;
|
got_int = save_got_int;
|
||||||
@ -2102,7 +2088,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|
|||||||
int prev_c1 = 0; // first composing char for prev_c
|
int prev_c1 = 0; // first composing char for prev_c
|
||||||
|
|
||||||
bool search_attr_from_match = false; // if search_attr is from :match
|
bool search_attr_from_match = false; // if search_attr is from :match
|
||||||
bool has_decorations = false; // this buffer has decorations
|
bool has_decor = false; // this buffer has decoration
|
||||||
bool do_virttext = false; // draw virtual text for this line
|
bool do_virttext = false; // draw virtual text for this line
|
||||||
|
|
||||||
char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
|
char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
|
||||||
@ -2170,18 +2156,18 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
has_decorations = decorations_redraw_line(wp->w_buffer, lnum-1,
|
has_decor = decor_redraw_line(wp->w_buffer, lnum-1,
|
||||||
&decorations);
|
&decor_state);
|
||||||
|
|
||||||
for (size_t k = 0; k < kv_size(*providers); k++) {
|
for (size_t k = 0; k < kv_size(*providers); k++) {
|
||||||
DecorationProvider *p = kv_A(*providers, k);
|
DecorProvider *p = kv_A(*providers, k);
|
||||||
if (p && p->redraw_line != LUA_NOREF) {
|
if (p && p->redraw_line != LUA_NOREF) {
|
||||||
FIXED_TEMP_ARRAY(args, 3);
|
FIXED_TEMP_ARRAY(args, 3);
|
||||||
args.items[0] = WINDOW_OBJ(wp->handle);
|
args.items[0] = WINDOW_OBJ(wp->handle);
|
||||||
args.items[1] = BUFFER_OBJ(buf->handle);
|
args.items[1] = BUFFER_OBJ(buf->handle);
|
||||||
args.items[2] = INTEGER_OBJ(lnum-1);
|
args.items[2] = INTEGER_OBJ(lnum-1);
|
||||||
if (provider_invoke(p->ns_id, "line", p->redraw_line, args, true)) {
|
if (provider_invoke(p->ns_id, "line", p->redraw_line, args, true)) {
|
||||||
has_decorations = true;
|
has_decor = true;
|
||||||
} else {
|
} else {
|
||||||
// return 'false' or error: skip rest of this window
|
// return 'false' or error: skip rest of this window
|
||||||
kv_A(*providers, k) = NULL;
|
kv_A(*providers, k) = NULL;
|
||||||
@ -2191,7 +2177,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_decorations) {
|
if (has_decor) {
|
||||||
extra_check = true;
|
extra_check = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2377,7 +2363,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If this line has a sign with line highlighting set line_attr.
|
// If this line has a sign with line highlighting set line_attr.
|
||||||
// TODO(bfredl, vigoux): this should not take priority over decorations!
|
// TODO(bfredl, vigoux): this should not take priority over decoration!
|
||||||
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL, 0, 1);
|
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL, 0, 1);
|
||||||
if (v != 0) {
|
if (v != 0) {
|
||||||
line_attr = sign_get_attr((int)v, SIGN_LINEHL);
|
line_attr = sign_get_attr((int)v, SIGN_LINEHL);
|
||||||
@ -3402,9 +3388,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|
|||||||
char_attr = hl_combine_attr(spell_attr, char_attr);
|
char_attr = hl_combine_attr(spell_attr, char_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_decorations && v > 0) {
|
if (has_decor && v > 0) {
|
||||||
int extmark_attr = decorations_redraw_col(wp->w_buffer, (colnr_T)v-1,
|
int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v-1,
|
||||||
&decorations);
|
&decor_state);
|
||||||
if (extmark_attr != 0) {
|
if (extmark_attr != 0) {
|
||||||
if (!attr_pri) {
|
if (!attr_pri) {
|
||||||
char_attr = hl_combine_attr(char_attr, extmark_attr);
|
char_attr = hl_combine_attr(char_attr, extmark_attr);
|
||||||
@ -3906,8 +3892,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|
|||||||
kv_push(virt_text, ((VirtTextChunk){ .text = err_text,
|
kv_push(virt_text, ((VirtTextChunk){ .text = err_text,
|
||||||
.hl_id = hl_err }));
|
.hl_id = hl_err }));
|
||||||
do_virttext = true;
|
do_virttext = true;
|
||||||
} else if (has_decorations) {
|
} else if (has_decor) {
|
||||||
VirtText *vp = decorations_redraw_virt_text(wp->w_buffer, &decorations);
|
VirtText *vp = decor_redraw_virt_text(wp->w_buffer, &decor_state);
|
||||||
if (vp) {
|
if (vp) {
|
||||||
virt_text = *vp;
|
virt_text = *vp;
|
||||||
do_virttext = true;
|
do_virttext = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user