aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/extmark.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/extmark.c')
-rw-r--r--src/nvim/extmark.c331
1 files changed, 18 insertions, 313 deletions
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 0de396fd1f..413ea4116a 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -22,12 +22,18 @@
// 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
// 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 "nvim/api/vim.h"
#include "nvim/vim.h"
#include "nvim/charset.h"
#include "nvim/extmark.h"
+#include "nvim/decoration.h"
#include "nvim/buffer_updates.h"
#include "nvim/memline.h"
#include "nvim/pos.h"
@@ -36,20 +42,11 @@
#include "nvim/lib/kbtree.h"
#include "nvim/undo.h"
#include "nvim/buffer.h"
-#include "nvim/syntax.h"
-#include "nvim/highlight.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "extmark.c.generated.h"
#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) {
if (!buf->b_extmark_ns) {
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,
old_mark);
if (it.decor) {
- decoration_redraw(buf, row, row, it.decor);
- free_decoration(it.decor);
+ decor_redraw(buf, row, row, it.decor);
+ decor_free(it.decor);
}
mark = marktree_revise(buf->b_marktree, itr);
goto revised;
@@ -130,7 +127,7 @@ revised:
}
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;
}
@@ -179,8 +176,8 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
}
if (item.decor) {
- decoration_redraw(buf, pos.row, pos2.row, item.decor);
- free_decoration(item.decor);
+ decor_redraw(buf, pos.row, pos2.row, item.decor);
+ decor_free(item.decor);
}
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);
if (*del_status >= 0) { // we had a decor_id
DecorItem it = kv_A(decors, *del_status);
- decoration_redraw(buf, it.row1, mark.row, it.decor);
- free_decoration(it.decor);
+ decor_redraw(buf, it.row1, mark.row, it.decor);
+ decor_free(it.decor);
}
map_del(uint64_t, ssize_t)(delete_set, mark.id);
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);
} else if (item.decor) {
- decoration_redraw(buf, mark.row, mark.row, item.decor);
- free_decoration(item.decor);
+ decor_redraw(buf, mark.row, mark.row, item.decor);
+ decor_free(item.decor);
}
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);
@@ -283,8 +280,8 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
marktree_del_itr(buf->b_marktree, itr, false);
if (decor_id >= 0) {
DecorItem it = kv_A(decors, decor_id);
- decoration_redraw(buf, it.row1, pos.row, it.decor);
- free_decoration(it.decor);
+ decor_redraw(buf, it.row1, pos.row, it.decor);
+ decor_free(it.decor);
}
});
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, {
(void)id;
- free_decoration(item.decor);
+ decor_free(item.decor);
});
map_free(uint64_t, ExtmarkItem)(buf->b_extmark_index);
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;
-}