aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/api.txt15
-rw-r--r--src/nvim/api/extmark.c2
-rw-r--r--src/nvim/api/vim.c8
-rw-r--r--src/nvim/api/window.c5
-rw-r--r--src/nvim/decoration.c22
-rw-r--r--src/nvim/decoration.h2
-rw-r--r--src/nvim/drawline.c8
-rw-r--r--src/nvim/drawscreen.c2
-rw-r--r--src/nvim/extmark.c20
-rw-r--r--src/nvim/marktree.c14
-rw-r--r--src/nvim/marktree.h17
-rw-r--r--src/nvim/spell.c6
12 files changed, 71 insertions, 50 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index d16b9274dc..b8590026c8 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1399,6 +1399,9 @@ nvim_set_hl({ns_id}, {name}, {*val}) *nvim_set_hl()*
Parameters: ~
• {ns_id} Namespace id for this highlight |nvim_create_namespace()|.
Use 0 to set a highlight group globally |:highlight|.
+ Highlights from non-global namespaces are not active by
+ default, use |nvim_set_hl_ns()| or |nvim_win_set_hl_ns()| to
+ activate them.
• {name} Highlight group name, e.g. "ErrorMsg"
• {val} Highlight definition map, accepts the following keys:
• fg (or foreground): color name or "#RRGGBB", see note.
@@ -1426,14 +1429,15 @@ nvim_set_hl({ns_id}, {name}, {*val}) *nvim_set_hl()*
map documented above.
nvim_set_hl_ns({ns_id}) *nvim_set_hl_ns()*
- Set active namespace for highlights. This can be set for a single window,
- see |nvim_win_set_hl_ns()|.
+ Set active namespace for highlights defined with |nvim_set_hl()|. This can
+ be set for a single window, see |nvim_win_set_hl_ns()|.
Parameters: ~
• {ns_id} the namespace to use
nvim_set_hl_ns_fast({ns_id}) *nvim_set_hl_ns_fast()*
- Set active namespace for highlights while redrawing.
+ Set active namespace for highlights defined with |nvim_set_hl()| while
+ redrawing.
This function meant to be called while redrawing, primarily from
|nvim_set_decoration_provider()| on_win and on_line callbacks, which are
@@ -2921,8 +2925,9 @@ nvim_win_set_height({window}, {height}) *nvim_win_set_height()*
• {height} Height as a count of rows
nvim_win_set_hl_ns({window}, {ns_id}) *nvim_win_set_hl_ns()*
- Set highlight namespace for a window. This will use highlights defined in
- this namespace, but fall back to global highlights (ns=0) when missing.
+ Set highlight namespace for a window. This will use highlights defined
+ with |nvim_set_hl()| for this namespace, but fall back to global
+ highlights (ns=0) when missing.
This takes precedence over the 'winhighlight' option.
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index 9e03cc8676..adc2925b7e 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -793,7 +793,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
}
// TODO(bfredl): synergize these two branches even more
- if (ephemeral && decor_state.buf == buf) {
+ if (ephemeral && decor_state.win && decor_state.win->w_buffer == buf) {
decor_add_ephemeral((int)line, (int)col, line2, col2, &decor, (uint64_t)ns_id, id);
} else {
if (ephemeral) {
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 315ccd13e6..a8cc7aa454 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -141,6 +141,8 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err)
///
/// @param ns_id Namespace id for this highlight |nvim_create_namespace()|.
/// Use 0 to set a highlight group globally |:highlight|.
+/// Highlights from non-global namespaces are not active by default, use
+/// |nvim_set_hl_ns()| or |nvim_win_set_hl_ns()| to activate them.
/// @param name Highlight group name, e.g. "ErrorMsg"
/// @param val Highlight definition map, accepts the following keys:
/// - fg (or foreground): color name or "#RRGGBB", see note.
@@ -183,8 +185,8 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err)
}
}
-/// Set active namespace for highlights. This can be set for a single window,
-/// see |nvim_win_set_hl_ns()|.
+/// Set active namespace for highlights defined with |nvim_set_hl()|. This can be set for
+/// a single window, see |nvim_win_set_hl_ns()|.
///
/// @param ns_id the namespace to use
/// @param[out] err Error details, if any
@@ -200,7 +202,7 @@ void nvim_set_hl_ns(Integer ns_id, Error *err)
redraw_all_later(UPD_NOT_VALID);
}
-/// Set active namespace for highlights while redrawing.
+/// Set active namespace for highlights defined with |nvim_set_hl()| while redrawing.
///
/// This function meant to be called while redrawing, primarily from
/// |nvim_set_decoration_provider()| on_win and on_line callbacks, which
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index e2c234ab29..abe11e6b72 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -445,8 +445,9 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err)
return res;
}
-/// Set highlight namespace for a window. This will use highlights defined in
-/// this namespace, but fall back to global highlights (ns=0) when missing.
+/// Set highlight namespace for a window. This will use highlights defined with
+/// |nvim_set_hl()| for this namespace, but fall back to global highlights (ns=0) when
+/// missing.
///
/// This takes precedence over the 'winhighlight' option.
///
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 7e47565247..217544175d 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -166,10 +166,10 @@ next_mark:
return NULL;
}
-bool decor_redraw_reset(buf_T *buf, DecorState *state)
+bool decor_redraw_reset(win_T *wp, DecorState *state)
{
state->row = -1;
- state->buf = buf;
+ state->win = wp;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange item = kv_A(state->active, i);
if (item.virt_text_owned) {
@@ -177,7 +177,7 @@ bool decor_redraw_reset(buf_T *buf, DecorState *state)
}
}
kv_size(state->active) = 0;
- return buf->b_marktree->n_keys;
+ return wp->w_buffer->b_marktree->n_keys;
}
Decoration get_decor(mtkey_t mark)
@@ -198,8 +198,9 @@ static bool decor_virt_pos(Decoration decor)
return kv_size(decor.virt_text) || decor.ui_watched;
}
-bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
+bool decor_redraw_start(win_T *wp, int top_row, DecorState *state)
{
+ buf_T *buf = wp->w_buffer;
state->top_row = top_row;
marktree_itr_get(buf->b_marktree, top_row, 0, state->itr);
if (!state->itr->node) {
@@ -250,10 +251,10 @@ next_mark:
return true; // TODO(bfredl): check if available in the region
}
-bool decor_redraw_line(buf_T *buf, int row, DecorState *state)
+bool decor_redraw_line(win_T *wp, int row, DecorState *state)
{
if (state->row == -1) {
- decor_redraw_start(buf, row, state);
+ decor_redraw_start(wp, row, state);
}
state->row = row;
state->col_until = -1;
@@ -282,8 +283,9 @@ static void decor_add(DecorState *state, int start_row, int start_col, int end_r
kv_A(state->active, index) = range;
}
-int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden, DecorState *state)
+int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *state)
{
+ buf_T *buf = wp->w_buffer;
if (col <= state->col_until) {
return state->current;
}
@@ -529,12 +531,12 @@ next_mark:
void decor_redraw_end(DecorState *state)
{
- state->buf = NULL;
+ state->win = NULL;
}
-bool decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr, int eol_col)
+bool decor_redraw_eol(win_T *wp, DecorState *state, int *eol_attr, int eol_col)
{
- decor_redraw_col(buf, MAXCOL, MAXCOL, false, state);
+ decor_redraw_col(wp, MAXCOL, MAXCOL, false, state);
state->eol_col = eol_col;
bool has_virttext = false;
for (size_t i = 0; i < kv_size(state->active); i++) {
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index c9ec8ede7f..f43002521c 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -88,7 +88,7 @@ typedef struct {
typedef struct {
MarkTreeIter itr[1];
kvec_t(DecorRange) active;
- buf_T *buf;
+ win_T *win;
int top_row;
int row;
int col_until;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index d9a8c6a6d9..6d8cf1c7e1 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -1096,7 +1096,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
}
}
- has_decor = decor_redraw_line(buf, lnum - 1, &decor_state);
+ has_decor = decor_redraw_line(wp, lnum - 1, &decor_state);
decor_providers_invoke_line(wp, providers, lnum - 1, &has_decor, provider_err);
@@ -1619,7 +1619,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
wlv.draw_state = WL_LINE;
if (has_decor && wlv.row == startrow + wlv.filler_lines) {
// hide virt_text on text hidden by 'nowrap'
- decor_redraw_col(wp->w_buffer, wlv.vcol, wlv.off, true, &decor_state);
+ decor_redraw_col(wp, wlv.vcol, wlv.off, true, &decor_state);
}
win_line_continue(&wlv); // use wlv.saved_ values
}
@@ -2011,7 +2011,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
if (has_decor && v > 0) {
bool selected = (area_active || (area_highlighting && noinvcur
&& wlv.vcol == wp->w_virtcol));
- int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, wlv.off,
+ int extmark_attr = decor_redraw_col(wp, (colnr_T)v - 1, wlv.off,
selected, &decor_state);
if (extmark_attr != 0) {
if (!attr_pri) {
@@ -2615,7 +2615,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
? 1 : 0);
if (has_decor) {
- has_virttext = decor_redraw_eol(wp->w_buffer, &decor_state, &wlv.line_attr,
+ has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr,
wlv.col + eol_skip);
}
diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c
index f456947f5a..499f4a39e3 100644
--- a/src/nvim/drawscreen.c
+++ b/src/nvim/drawscreen.c
@@ -1427,7 +1427,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
win_extmark_arr.size = 0;
- decor_redraw_reset(buf, &decor_state);
+ decor_redraw_reset(wp, &decor_state);
DecorProviders line_providers;
decor_providers_invoke_win(wp, providers, &line_providers, &provider_err);
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 1132a5e752..d385a2018f 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -92,7 +92,7 @@ void extmark_set(buf_T *buf, uint32_t ns_id, uint32_t *idp, int row, colnr_T col
extmark_del(buf, ns_id, id);
} else {
// TODO(bfredl): we need to do more if "revising" a decoration mark.
- assert(itr->node);
+ assert(marktree_itr_valid(itr));
if (old_mark.pos.row == row && old_mark.pos.col == col) {
if (marktree_decor_level(old_mark) > kDecorLevelNone) {
decor_remove(buf, row, row, old_mark.decor_full);
@@ -191,12 +191,12 @@ bool extmark_del(buf_T *buf, uint32_t ns_id, uint32_t id)
return false;
}
assert(key.pos.row >= 0);
- marktree_del_itr(buf->b_marktree, itr, false);
+ uint64_t other = marktree_del_itr(buf->b_marktree, itr, false);
mtkey_t key2 = key;
- if (mt_paired(key)) {
- key2 = marktree_lookup_ns(buf->b_marktree, ns_id, id, true, itr);
+ if (other) {
+ key2 = marktree_lookup(buf->b_marktree, other, itr);
assert(key2.pos.row >= 0);
marktree_del_itr(buf->b_marktree, itr, false);
}
@@ -258,8 +258,11 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
assert(mark.ns > 0 && mark.id > 0);
if (mark.ns == ns_id || all_ns) {
marks_cleared = true;
+ if (mark.decor_full && !mt_paired(mark)) { // if paired: deal with it later
+ decor_remove(buf, mark.pos.row, mark.pos.row, mark.decor_full);
+ }
+ uint64_t other = marktree_del_itr(buf->b_marktree, itr, false);
if (mt_paired(mark)) {
- uint64_t other = mt_lookup_id(mark.ns, mark.id, !mt_end(mark));
ssize_t decor_id = -1;
if (marktree_decor_level(mark) > kDecorLevelNone) {
// Save the decoration and the first pos. Clear the decoration
@@ -269,10 +272,7 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
((DecorItem) { .row1 = mark.pos.row }));
}
map_put(uint64_t, ssize_t)(&delete_set, other, decor_id);
- } else if (mark.decor_full) {
- decor_remove(buf, mark.pos.row, mark.pos.row, mark.decor_full);
}
- marktree_del_itr(buf->b_marktree, itr, false);
} else {
marktree_itr_next(buf->b_marktree, itr);
}
@@ -281,7 +281,7 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
ssize_t decor_id;
map_foreach(&delete_set, id, decor_id, {
mtkey_t mark = marktree_lookup(buf->b_marktree, id, itr);
- assert(itr->node);
+ assert(marktree_itr_valid(itr));
marktree_del_itr(buf->b_marktree, itr, false);
if (decor_id >= 0) {
DecorItem it = kv_A(decors, decor_id);
@@ -306,7 +306,7 @@ ExtmarkInfoArray extmark_get(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_co
ExtmarkInfoArray array = KV_INITIAL_VALUE;
MarkTreeIter itr[1];
// Find all the marks
- marktree_itr_get_ext(buf->b_marktree, (mtpos_t){ l_row, l_col },
+ marktree_itr_get_ext(buf->b_marktree, mtpos_t(l_row, l_col),
itr, reverse, false, NULL);
int order = reverse ? -1 : 1;
while ((int64_t)kv_size(array) < amount) {
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index cb981bb00c..7e900bafa2 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -279,13 +279,13 @@ void marktree_put_key(MarkTree *b, mtkey_t k)
/// 6. If 4 went all the way to the root node. The root node
/// might have ended up with size 0. Delete it then.
///
-/// NB: ideally keeps the iterator valid. Like point to the key after this
-/// if present.
+/// The iterator remains valid, and now points at the key _after_ the deleted
+/// one.
///
/// @param rev should be true if we plan to iterate _backwards_ and delete
/// stuff before this key. Most of the time this is false (the
/// recommended strategy is to always iterate forward)
-void marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
+uint64_t marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
{
int adjustment = 0;
@@ -294,6 +294,12 @@ void marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
uint64_t id = mt_lookup_key(cur->key[curi]);
// fprintf(stderr, "\nDELET %lu\n", id);
+ mtkey_t raw = rawkey(itr);
+ uint64_t other = 0;
+ if (mt_paired(raw)) {
+ other = mt_lookup_id(raw.ns, raw.id, !mt_end(raw));
+ }
+
if (itr->node->level) {
if (rev) {
abort();
@@ -442,6 +448,8 @@ void marktree_del_itr(MarkTree *b, MarkTreeIter *itr, bool rev)
marktree_itr_next(b, itr);
}
}
+
+ return other;
}
static mtnode_t *merge_node(MarkTree *b, mtnode_t *p, int i)
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index 5ce4b2cd24..046946bc95 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -22,21 +22,26 @@ typedef struct {
int32_t row;
int32_t col;
} mtpos_t;
+#define mtpos_t(r, c) ((mtpos_t){ .row = (r), .col = (c) })
typedef struct mtnode_s mtnode_t;
-typedef struct {
- int oldcol;
- int i;
-} iterstate_t;
typedef struct {
mtpos_t pos;
int lvl;
mtnode_t *node;
int i;
- iterstate_t s[MT_MAX_DEPTH];
+ struct {
+ int oldcol;
+ int i;
+ } s[MT_MAX_DEPTH];
+
+ size_t intersect_idx;
+ mtpos_t intersect_pos;
} MarkTreeIter;
+#define marktree_itr_valid(itr) ((itr)->node != NULL)
+
// Internal storage
//
// NB: actual marks have flags > 0, so we can use (row,col,0) pseudo-key for
@@ -123,8 +128,6 @@ struct mtnode_s {
mtnode_t *ptr[];
};
-// TODO(bfredl): the iterator is pretty much everpresent, make it part of the
-// tree struct itself?
typedef struct {
mtnode_t *root;
size_t n_keys, n_nodes;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index b514ed694d..c65f822080 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1203,7 +1203,7 @@ bool no_spell_checking(win_T *wp)
static void decor_spell_nav_start(win_T *wp)
{
decor_state = (DecorState){ 0 };
- decor_redraw_reset(wp->w_buffer, &decor_state);
+ decor_redraw_reset(wp, &decor_state);
}
static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum, int col,
@@ -1211,10 +1211,10 @@ static bool decor_spell_nav_col(win_T *wp, linenr_T lnum, linenr_T *decor_lnum,
{
if (*decor_lnum != lnum) {
decor_providers_invoke_spell(wp, lnum - 1, col, lnum - 1, -1, decor_error);
- decor_redraw_line(wp->w_buffer, lnum - 1, &decor_state);
+ decor_redraw_line(wp, lnum - 1, &decor_state);
*decor_lnum = lnum;
}
- decor_redraw_col(wp->w_buffer, col, col, false, &decor_state);
+ decor_redraw_col(wp, col, col, false, &decor_state);
return decor_state.spell == kTrue;
}