aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/decoration.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/decoration.c')
-rw-r--r--src/nvim/decoration.c418
1 files changed, 223 insertions, 195 deletions
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 11204a1b31..51d5d08f78 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -2,18 +2,24 @@
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
+#include <string.h>
#include "nvim/api/extmark.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/ascii_defs.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/change.h"
#include "nvim/decoration.h"
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
#include "nvim/fold.h"
#include "nvim/grid.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
+#include "nvim/marktree.h"
#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/option_vars.h"
@@ -82,26 +88,22 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
extmark_set(buf, (uint32_t)src_id, NULL,
(int)lnum - 1, hl_start, (int)lnum - 1 + end_off, hl_end,
- decor, MT_FLAG_DECOR_HL, true, false, true, false, NULL);
+ decor, MT_FLAG_DECOR_HL, true, false, true, false, false, NULL);
}
}
-void decor_redraw(buf_T *buf, int row1, int row2, DecorInline decor)
+void decor_redraw(buf_T *buf, int row1, int row2, int col1, DecorInline decor)
{
- if (row2 >= row1) {
- redraw_buf_range_later(buf, row1 + 1, row2 + 1);
- }
-
if (decor.ext) {
DecorVirtText *vt = decor.data.ext.vt;
while (vt) {
- if (vt->flags & kVTIsLines) {
- redraw_buf_line_later(buf, row1 + 1 + ((vt->flags & kVTLinesAbove) ? 0 : 1), true);
- changed_line_display_buf(buf);
- } else {
- if (vt->pos == kVPosInline) {
- changed_line_display_buf(buf);
- }
+ bool below = (vt->flags & kVTIsLines) && !(vt->flags & kVTLinesAbove);
+ linenr_T vt_lnum = row1 + 1 + below;
+ redraw_buf_line_later(buf, vt_lnum, true);
+ if (vt->flags & kVTIsLines || vt->pos == kVPosInline) {
+ // changed_lines_redraw_buf(buf, vt_lnum, vt_lnum + 1, 0);
+ colnr_T vt_col = vt->flags & kVTIsLines ? 0 : col1;
+ changed_lines_invalidate_buf(buf, vt_lnum, vt_col, vt_lnum + 1, 0);
}
vt = vt->next;
}
@@ -119,7 +121,8 @@ void decor_redraw(buf_T *buf, int row1, int row2, DecorInline decor)
void decor_redraw_sh(buf_T *buf, int row1, int row2, DecorSignHighlight sh)
{
- if (sh.hl_id || (sh.flags & (kSHIsSign|kSHSpellOn|kSHSpellOff))) {
+ if (sh.hl_id || (sh.url != NULL)
+ || (sh.flags & (kSHIsSign | kSHSpellOn | kSHSpellOff | kSHConceal))) {
if (row2 >= row1) {
redraw_buf_range_later(buf, row1 + 1, row2 + 1);
}
@@ -158,7 +161,7 @@ DecorSignHighlight decor_sh_from_inline(DecorHighlightInline item)
DecorSignHighlight conv = {
.flags = item.flags,
.priority = item.priority,
- .text.sc[0] = item.conceal_char,
+ .text[0] = item.conceal_char,
.hl_id = item.hl_id,
.number_hl_id = 0,
.line_hl_id = 0,
@@ -172,12 +175,6 @@ DecorSignHighlight decor_sh_from_inline(DecorHighlightInline item)
void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2)
{
if (decor.ext) {
- DecorVirtText *vt = decor.data.ext.vt;
- while (vt) {
- buf_put_decor_virt(buf, vt);
- vt = vt->next;
- }
-
uint32_t idx = decor.data.ext.sh_idx;
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
@@ -187,46 +184,25 @@ void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2)
}
}
-void buf_put_decor_virt(buf_T *buf, DecorVirtText *vt)
-{
- if (vt->flags &kVTIsLines) {
- buf->b_virt_line_blocks++;
- } else {
- if (vt->pos == kVPosInline) {
- buf->b_virt_text_inline++;
- }
- }
- if (vt->next) {
- buf_put_decor_virt(buf, vt->next);
- }
-}
-
static int sign_add_id = 0;
-void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row, int row2)
+void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2)
{
if (sh->flags & kSHIsSign) {
sh->sign_add_id = sign_add_id++;
- buf->b_signs++;
- if (sh->text.ptr) {
- buf->b_signs_with_text++;
- buf_signcols_add_check(buf, row + 1, row2 + 1);
+ if (sh->text[0]) {
+ buf_signcols_count_range(buf, row1, row2, 1, kFalse);
}
}
}
-void buf_decor_remove(buf_T *buf, int row, int row2, DecorInline decor, bool free)
+void buf_decor_remove(buf_T *buf, int row1, int row2, int col1, DecorInline decor, bool free)
{
- decor_redraw(buf, row, row2, decor);
+ decor_redraw(buf, row1, row2, col1, decor);
if (decor.ext) {
- DecorVirtText *vt = decor.data.ext.vt;
- while (vt) {
- buf_remove_decor_virt(buf, vt);
- vt = vt->next;
- }
uint32_t idx = decor.data.ext.sh_idx;
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
- buf_remove_decor_sh(buf, row, row2, sh);
+ buf_remove_decor_sh(buf, row1, row2, sh);
idx = sh->next;
}
if (free) {
@@ -235,29 +211,15 @@ void buf_decor_remove(buf_T *buf, int row, int row2, DecorInline decor, bool fre
}
}
-void buf_remove_decor_virt(buf_T *buf, DecorVirtText *vt)
-{
- if (vt->flags &kVTIsLines) {
- assert(buf->b_virt_line_blocks > 0);
- buf->b_virt_line_blocks--;
- } else {
- if (vt->pos == kVPosInline) {
- assert(buf->b_virt_text_inline > 0);
- buf->b_virt_text_inline--;
- }
- }
-}
-
-void buf_remove_decor_sh(buf_T *buf, int row, int row2, DecorSignHighlight *sh)
+void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh)
{
if (sh->flags & kSHIsSign) {
- assert(buf->b_signs > 0);
- buf->b_signs--;
- if (sh->text.ptr) {
- assert(buf->b_signs_with_text > 0);
- buf->b_signs_with_text--;
- if (row2 >= row) {
- buf_signcols_del_check(buf, row + 1, row2 + 1);
+ if (sh->text[0]) {
+ if (buf_meta_total(buf, kMTMetaSignText)) {
+ buf_signcols_count_range(buf, row1, row2, -1, kFalse);
+ } else {
+ buf->b_signcols.resized = true;
+ buf->b_signcols.max = buf->b_signcols.count[0] = 0;
}
}
}
@@ -295,7 +257,7 @@ void decor_free(DecorInline decor)
}
}
-void decor_free_inner(DecorVirtText *vt, uint32_t first_idx)
+static void decor_free_inner(DecorVirtText *vt, uint32_t first_idx)
{
while (vt) {
if (vt->flags & kVTIsLines) {
@@ -312,12 +274,12 @@ void decor_free_inner(DecorVirtText *vt, uint32_t first_idx)
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
if (sh->flags & kSHIsSign) {
- xfree(sh->text.ptr);
- }
- if (sh->flags & kSHIsSign) {
xfree(sh->sign_name);
}
sh->flags = 0;
+ if (sh->url != NULL) {
+ XFREE_CLEAR(sh->url);
+ }
if (sh->next == DECOR_ID_INVALID) {
sh->next = decor_freelist;
decor_freelist = first_idx;
@@ -362,8 +324,11 @@ void decor_check_invalid_glyphs(void)
{
for (size_t i = 0; i < kv_size(decor_items); i++) {
DecorSignHighlight *it = &kv_A(decor_items, i);
- if ((it->flags & kSHConceal) && schar_high(it->text.sc[0])) {
- it->text.sc[0] = schar_from_char(schar_get_first_codepoint(it->text.sc[0]));
+ int width = (it->flags & kSHIsSign) ? SIGN_WIDTH : ((it->flags & kSHConceal) ? 1 : 0);
+ for (int j = 0; j < width; j++) {
+ if (schar_high(it->text[j])) {
+ it->text[j] = schar_from_char(schar_get_first_codepoint(it->text[j]));
+ }
}
}
}
@@ -394,10 +359,10 @@ DecorVirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
MTKey mark = marktree_itr_current(itr);
if (mark.pos.row < 0 || mark.pos.row > row) {
break;
- } else if (mt_invalid(mark) || !(mark.flags & MT_FLAG_DECOR_EXT)) {
+ } else if (mt_invalid(mark)) {
goto next_mark;
}
- DecorVirtText *decor = mark.decor_data.ext.vt;
+ DecorVirtText *decor = mt_decor_virt(mark);
while (decor && (decor->flags & kVTIsLines)) {
decor = decor->next;
}
@@ -489,18 +454,21 @@ static void decor_range_add_from_inline(DecorState *state, int start_row, int st
if (decor.ext) {
DecorVirtText *vt = decor.data.ext.vt;
while (vt) {
- decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned);
+ decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned,
+ DECOR_PRIORITY_BASE);
vt = vt->next;
}
uint32_t idx = decor.data.ext.sh_idx;
while (idx != DECOR_ID_INVALID) {
DecorSignHighlight *sh = &kv_A(decor_items, idx);
- decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id);
+ decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id,
+ DECOR_PRIORITY_BASE);
idx = sh->next;
}
} else {
DecorSignHighlight sh = decor_sh_from_inline(decor.data.hl);
- decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id);
+ decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id,
+ DECOR_PRIORITY_BASE);
}
}
@@ -510,7 +478,8 @@ static void decor_range_insert(DecorState *state, DecorRange range)
size_t index;
for (index = kv_size(state->active) - 1; index > 0; index--) {
DecorRange item = kv_A(state->active, index - 1);
- if (item.priority <= range.priority) {
+ if ((item.priority < range.priority)
+ || ((item.priority == range.priority) && (item.subpriority <= range.subpriority))) {
break;
}
kv_A(state->active, index) = kv_A(state->active, index - 1);
@@ -519,7 +488,7 @@ static void decor_range_insert(DecorState *state, DecorRange range)
}
void decor_range_add_virt(DecorState *state, int start_row, int start_col, int end_row, int end_col,
- DecorVirtText *vt, bool owned)
+ DecorVirtText *vt, bool owned, DecorPriority subpriority)
{
bool is_lines = vt->flags & kVTIsLines;
DecorRange range = {
@@ -529,13 +498,15 @@ void decor_range_add_virt(DecorState *state, int start_row, int start_col, int e
.attr_id = 0,
.owned = owned,
.priority = vt->priority,
+ .subpriority = subpriority,
.draw_col = -10,
};
decor_range_insert(state, range);
}
void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end_row, int end_col,
- DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id)
+ DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id,
+ DecorPriority subpriority)
{
if (sh->flags & kSHIsSign) {
return;
@@ -548,10 +519,12 @@ void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end
.attr_id = 0,
.owned = owned,
.priority = sh->priority,
+ .subpriority = subpriority,
.draw_col = -10,
};
- if (sh->hl_id || (sh->flags & (kSHConceal | kSHSpellOn | kSHSpellOff))) {
+ if (sh->hl_id || (sh->url != NULL)
+ || (sh->flags & (kSHConceal | kSHSpellOn | kSHSpellOff))) {
if (sh->hl_id) {
range.attr_id = syn_id2attr(sh->hl_id);
}
@@ -568,7 +541,7 @@ void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end
}
/// Initialize the draw_col of a newly-added virtual text item.
-static void decor_init_draw_col(int win_col, bool hidden, DecorRange *item)
+void decor_init_draw_col(int win_col, bool hidden, DecorRange *item)
{
DecorVirtText *vt = item->kind == kDecorKindVirtText ? item->data.vt : NULL;
VirtTextPos pos = decor_virt_pos_kind(item);
@@ -609,15 +582,15 @@ int decor_redraw_col(win_T *wp, int col, int win_col, bool hidden, DecorState *s
break;
}
- if (mt_invalid(mark) || mt_end(mark) || !mt_decor_any(mark)) {
+ if (!mt_scoped_in_win(mark, wp)) {
goto next_mark;
}
- MTPos endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
- if (endpos.row == -1) {
- endpos = mark.pos;
+ if (mt_invalid(mark) || mt_end(mark) || !mt_decor_any(mark)) {
+ goto next_mark;
}
+ MTPos endpos = marktree_get_altpos(buf->b_marktree, mark, NULL);
decor_range_add_from_inline(state, mark.pos.row, mark.pos.col, endpos.row, endpos.col,
mt_decor(mark), false, mark.ns, mark.id);
@@ -661,7 +634,7 @@ next_mark:
if (item.start_row == state->row && item.start_col == col) {
DecorSignHighlight *sh = &item.data.sh;
conceal = 2;
- conceal_char = sh->text.sc[0];
+ conceal_char = sh->text[0];
state->col_until = MIN(state->col_until, item.start_col);
conceal_attr = item.attr_id;
}
@@ -672,6 +645,9 @@ next_mark:
} else if (item.data.sh.flags & kSHSpellOff) {
spell = kFalse;
}
+ if (item.data.sh.url != NULL) {
+ attr = hl_add_url(attr, item.data.sh.url);
+ }
}
if (item.start_row == state->row && item.start_col <= col
&& decor_virt_pos(&item) && item.draw_col == -10) {
@@ -679,9 +655,13 @@ next_mark:
}
if (keep) {
kv_A(state->active, j++) = item;
- } else if (item.owned && item.kind == kDecorKindVirtText) {
- clear_virttext(&item.data.vt->data.virt_text);
- xfree(item.data.vt);
+ } else if (item.owned) {
+ if (item.kind == kDecorKindVirtText) {
+ clear_virttext(&item.data.vt->data.virt_text);
+ xfree(item.data.vt);
+ } else if (item.kind == kDecorKindHighlight) {
+ xfree((void *)item.data.sh.url);
+ }
}
}
kv_size(state->active) = j;
@@ -693,21 +673,29 @@ next_mark:
return attr;
}
-typedef struct {
- DecorSignHighlight *sh;
- uint32_t id;
-} SignItem;
-
int sign_item_cmp(const void *p1, const void *p2)
{
const SignItem *s1 = (SignItem *)p1;
const SignItem *s2 = (SignItem *)p2;
- int n = s2->sh->priority - s1->sh->priority;
- return n ? n : (n = (int)(s2->id - s1->id))
- ? n : (s2->sh->sign_add_id - s1->sh->sign_add_id);
+ if (s1->sh->priority != s2->sh->priority) {
+ return s1->sh->priority < s2->sh->priority ? 1 : -1;
+ }
+
+ if (s1->id != s2->id) {
+ return s1->id < s2->id ? 1 : -1;
+ }
+
+ if (s1->sh->sign_add_id != s2->sh->sign_add_id) {
+ return s1->sh->sign_add_id < s2->sh->sign_add_id ? 1 : -1;
+ }
+
+ return 0;
}
+static const uint32_t sign_filter[4] = {[kMTMetaSignText] = kMTFilterSelect,
+ [kMTMetaSignHL] = kMTFilterSelect };
+
/// Return the sign attributes on the currently refreshed row.
///
/// @param[out] sattrs Output array for sign text and texthl id
@@ -717,35 +705,39 @@ int sign_item_cmp(const void *p1, const void *p2)
void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], int *line_id,
int *cul_id, int *num_id)
{
- MarkTreeIter itr[1];
- if (!buf->b_signs || !marktree_itr_get_overlap(buf->b_marktree, row, 0, itr)) {
+ if (!buf_has_signs(buf)) {
return;
}
MTPair pair;
int num_text = 0;
+ MarkTreeIter itr[1];
kvec_t(SignItem) signs = KV_INITIAL_VALUE;
// TODO(bfredl): integrate with main decor loop.
+ marktree_itr_get_overlap(buf->b_marktree, row, 0, itr);
while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
if (!mt_invalid(pair.start) && mt_decor_sign(pair.start)) {
DecorSignHighlight *sh = decor_find_sign(mt_decor(pair.start));
- num_text += (sh->text.ptr != NULL);
+ num_text += (sh->text[0] != NUL);
kv_push(signs, ((SignItem){ sh, pair.start.id }));
}
}
+ marktree_itr_step_out_filter(buf->b_marktree, itr, sign_filter);
+
while (itr->x) {
MTKey mark = marktree_itr_current(itr);
if (mark.pos.row != row) {
break;
}
- if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark)) {
+ if (!mt_end(mark) && !mt_invalid(mark) && mt_decor_sign(mark)
+ && mt_scoped_in_win(mark, wp)) {
DecorSignHighlight *sh = decor_find_sign(mt_decor(mark));
- num_text += (sh->text.ptr != NULL);
+ num_text += (sh->text[0] != NUL);
kv_push(signs, ((SignItem){ sh, mark.id }));
}
- marktree_itr_next(buf->b_marktree, itr);
+ marktree_itr_next_filter(buf->b_marktree, itr, row + 1, 0, sign_filter);
}
if (kv_size(signs)) {
@@ -755,8 +747,8 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[],
for (size_t i = 0; i < kv_size(signs); i++) {
DecorSignHighlight *sh = kv_A(signs, i).sh;
- if (idx >= 0 && sh->text.ptr) {
- sattrs[idx].text = sh->text.ptr;
+ if (idx >= 0 && sh->text[0]) {
+ memcpy(sattrs[idx].text, sh->text, SIGN_WIDTH * sizeof(sattr_T));
sattrs[idx--].hl_id = sh->hl_id;
}
if (*num_id == 0) {
@@ -791,50 +783,74 @@ DecorSignHighlight *decor_find_sign(DecorInline decor)
}
}
-// Increase the signcolumn size and update the sentinel line if necessary for
-// the invalidated range.
-void decor_validate_signcols(buf_T *buf, int max)
+static const uint32_t signtext_filter[4] = {[kMTMetaSignText] = kMTFilterSelect };
+
+/// Count the number of signs in a range after adding/removing a sign, or to
+/// (re-)initialize a range in "b_signcols.count".
+///
+/// @param add 1, -1 or 0 for an added, deleted or initialized range.
+/// @param clear kFalse, kTrue or kNone for an, added/deleted, cleared, or initialized range.
+void buf_signcols_count_range(buf_T *buf, int row1, int row2, int add, TriState clear)
{
- int signcols = 0; // highest value of count
- int currow = buf->b_signcols.invalid_top - 1;
- // TODO(bfredl): only need to use marktree_itr_get_overlap once.
- // then we can process both start and end events and update state for each row
- for (; currow < buf->b_signcols.invalid_bot; currow++) {
- MarkTreeIter itr[1];
- if (!marktree_itr_get_overlap(buf->b_marktree, currow, 0, itr)) {
- continue;
- }
+ if (!buf->b_signcols.autom || !buf_meta_total(buf, kMTMetaSignText)) {
+ return;
+ }
+
+ // Allocate an array of integers holding the number of signs in the range.
+ assert(row2 >= row1);
+ int *count = xcalloc(sizeof(int), (size_t)(row2 + 1 - row1));
+ MarkTreeIter itr[1];
+ MTPair pair = { 0 };
- int count = 0;
- MTPair pair;
- while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
- if (!mt_invalid(pair.start) && (pair.start.flags & MT_FLAG_DECOR_SIGNTEXT)) {
- count++;
+ // Increment count array for signs that start before "row1" but do overlap the range.
+ marktree_itr_get_overlap(buf->b_marktree, row1, 0, itr);
+ while (marktree_itr_step_overlap(buf->b_marktree, itr, &pair)) {
+ if ((pair.start.flags & MT_FLAG_DECOR_SIGNTEXT) && !mt_invalid(pair.start)) {
+ for (int i = row1; i <= MIN(row2, pair.end_pos.row); i++) {
+ count[i - row1]++;
}
}
+ }
- while (itr->x) {
- MTKey mark = marktree_itr_current(itr);
- if (mark.pos.row != currow) {
- break;
- }
- if (!mt_invalid(mark) && !mt_end(mark) && (mark.flags & MT_FLAG_DECOR_SIGNTEXT)) {
- count++;
+ marktree_itr_step_out_filter(buf->b_marktree, itr, signtext_filter);
+
+ // Continue traversing the marktree until beyond "row2".
+ while (itr->x) {
+ MTKey mark = marktree_itr_current(itr);
+ if (mark.pos.row > row2) {
+ break;
+ }
+ if ((mark.flags & MT_FLAG_DECOR_SIGNTEXT) && !mt_invalid(mark) && !mt_end(mark)) {
+ // Increment count array for the range of a paired sign mark.
+ MTPos end = marktree_get_altpos(buf->b_marktree, mark, NULL);
+ for (int i = mark.pos.row; i <= MIN(row2, end.row); i++) {
+ count[i - row1]++;
}
- marktree_itr_next(buf->b_marktree, itr);
}
- if (count > signcols) {
- if (count >= buf->b_signcols.size) {
- buf->b_signcols.size = count;
- buf->b_signcols.sentinel = currow + 1;
- }
- if (count >= max) {
- return;
+ marktree_itr_next_filter(buf->b_marktree, itr, row2 + 1, 0, signtext_filter);
+ }
+
+ // For each row increment "b_signcols.count" at the number of counted signs,
+ // and decrement at the previous number of signs. These two operations are
+ // split in separate calls if "clear" is not kFalse (surrounding a marktree splice).
+ for (int i = 0; i < row2 + 1 - row1; i++) {
+ int prevwidth = MIN(SIGN_SHOW_MAX, count[i] - add);
+ if (clear != kNone && prevwidth > 0) {
+ buf->b_signcols.count[prevwidth - 1]--;
+ assert(buf->b_signcols.count[prevwidth - 1] >= 0);
+ }
+ int width = MIN(SIGN_SHOW_MAX, count[i]);
+ if (clear != kTrue && width > 0) {
+ buf->b_signcols.count[width - 1]++;
+ if (width > buf->b_signcols.max) {
+ buf->b_signcols.resized = true;
+ buf->b_signcols.max = width;
}
- signcols = count;
}
}
+
+ xfree(count);
}
void decor_redraw_end(DecorState *state)
@@ -861,11 +877,13 @@ bool decor_redraw_eol(win_T *wp, DecorState *state, int *eol_attr, int eol_col)
return has_virt_pos;
}
+static const uint32_t lines_filter[4] = {[kMTMetaLines] = kMTFilterSelect };
+
/// @param has_fold whether line "lnum" has a fold, or kNone when not calculated yet
int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fold)
{
buf_T *buf = wp->w_buffer;
- if (!buf->b_virt_line_blocks) {
+ if (!buf_meta_total(buf, kMTMetaLines)) {
// Only pay for what you use: in case virt_lines feature is not active
// in a buffer, plines do not need to access the marktree at all
return 0;
@@ -884,39 +902,43 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo
return 0;
}
- int virt_lines = 0;
MarkTreeIter itr[1] = { 0 };
- marktree_itr_get(buf->b_marktree, start_row, 0, itr);
+ if (!marktree_itr_get_filter(buf->b_marktree, start_row, 0, end_row, 0, lines_filter, itr)) {
+ return 0;
+ }
+
+ int virt_lines = 0;
while (true) {
MTKey mark = marktree_itr_current(itr);
- if (mark.pos.row < 0 || mark.pos.row >= end_row) {
- break;
- } else if (mt_end(mark) || !(mark.flags & MT_FLAG_DECOR_VIRT_LINES)) {
- goto next_mark;
- }
- DecorVirtText *vt = mark.decor_data.ext.vt;
- while (vt) {
- if (vt->flags & kVTIsLines) {
- bool above = vt->flags & kVTLinesAbove;
- int draw_row = mark.pos.row + (above ? 0 : 1);
- if (draw_row == row) {
- virt_lines += (int)kv_size(vt->data.virt_lines);
- if (lines) {
- kv_splice(*lines, vt->data.virt_lines);
+ DecorVirtText *vt = mt_decor_virt(mark);
+ if (mt_scoped_in_win(mark, wp)) {
+ while (vt) {
+ if (vt->flags & kVTIsLines) {
+ bool above = vt->flags & kVTLinesAbove;
+ int draw_row = mark.pos.row + (above ? 0 : 1);
+ if (draw_row == row) {
+ virt_lines += (int)kv_size(vt->data.virt_lines);
+ if (lines) {
+ kv_splice(*lines, vt->data.virt_lines);
+ }
}
}
+ vt = vt->next;
}
- vt = vt->next;
}
-next_mark:
- marktree_itr_next(buf->b_marktree, itr);
+
+ if (!marktree_itr_next_filter(buf->b_marktree, itr, end_row, 0, lines_filter)) {
+ break;
+ }
}
return virt_lines;
}
/// This assumes maximum one entry of each kind, which will not always be the case.
-void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name)
+///
+/// NB: assumes caller has allocated enough space in dict for all fields!
+void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name, Arena *arena)
{
DecorSignHighlight sh_hl = DECOR_SIGN_HIGHLIGHT_INIT;
DecorSignHighlight sh_sign = DECOR_SIGN_HIGHLIGHT_INIT;
@@ -950,64 +972,70 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name)
}
if (sh_hl.hl_id) {
- PUT(*dict, "hl_group", hl_group_name(sh_hl.hl_id, hl_name));
- PUT(*dict, "hl_eol", BOOLEAN_OBJ(sh_hl.flags & kSHHlEol));
- if (sh_hl.flags & kSHConceal) {
- char buf[MAX_SCHAR_SIZE];
- schar_get(buf, sh_hl.text.sc[0]);
- PUT(*dict, "conceal", CSTR_TO_OBJ(buf));
- }
+ PUT_C(*dict, "hl_group", hl_group_name(sh_hl.hl_id, hl_name));
+ PUT_C(*dict, "hl_eol", BOOLEAN_OBJ(sh_hl.flags & kSHHlEol));
+ priority = sh_hl.priority;
+ }
- if (sh_hl.flags & kSHSpellOn) {
- PUT(*dict, "spell", BOOLEAN_OBJ(true));
- } else if (sh_hl.flags & kSHSpellOff) {
- PUT(*dict, "spell", BOOLEAN_OBJ(false));
- }
+ if (sh_hl.flags & kSHConceal) {
+ char buf[MAX_SCHAR_SIZE];
+ schar_get(buf, sh_hl.text[0]);
+ PUT_C(*dict, "conceal", CSTR_TO_ARENA_OBJ(arena, buf));
+ }
- priority = sh_hl.priority;
+ if (sh_hl.flags & kSHSpellOn) {
+ PUT_C(*dict, "spell", BOOLEAN_OBJ(true));
+ } else if (sh_hl.flags & kSHSpellOff) {
+ PUT_C(*dict, "spell", BOOLEAN_OBJ(false));
}
if (sh_hl.flags & kSHUIWatched) {
- PUT(*dict, "ui_watched", BOOLEAN_OBJ(true));
+ PUT_C(*dict, "ui_watched", BOOLEAN_OBJ(true));
+ }
+
+ if (sh_hl.url != NULL) {
+ PUT_C(*dict, "url", STRING_OBJ(cstr_as_string(sh_hl.url)));
}
if (virt_text) {
if (virt_text->hl_mode) {
- PUT(*dict, "hl_mode", CSTR_TO_OBJ(hl_mode_str[virt_text->hl_mode]));
+ PUT_C(*dict, "hl_mode", CSTR_AS_OBJ(hl_mode_str[virt_text->hl_mode]));
}
- Array chunks = virt_text_to_array(virt_text->data.virt_text, hl_name);
- PUT(*dict, "virt_text", ARRAY_OBJ(chunks));
- PUT(*dict, "virt_text_hide", BOOLEAN_OBJ(virt_text->flags & kVTHide));
+ Array chunks = virt_text_to_array(virt_text->data.virt_text, hl_name, arena);
+ PUT_C(*dict, "virt_text", ARRAY_OBJ(chunks));
+ PUT_C(*dict, "virt_text_hide", BOOLEAN_OBJ(virt_text->flags & kVTHide));
+ PUT_C(*dict, "virt_text_repeat_linebreak", BOOLEAN_OBJ(virt_text->flags & kVTRepeatLinebreak));
if (virt_text->pos == kVPosWinCol) {
- PUT(*dict, "virt_text_win_col", INTEGER_OBJ(virt_text->col));
+ PUT_C(*dict, "virt_text_win_col", INTEGER_OBJ(virt_text->col));
}
- PUT(*dict, "virt_text_pos",
- CSTR_TO_OBJ(virt_text_pos_str[virt_text->pos]));
+ PUT_C(*dict, "virt_text_pos", CSTR_AS_OBJ(virt_text_pos_str[virt_text->pos]));
priority = virt_text->priority;
}
if (virt_lines) {
- Array all_chunks = ARRAY_DICT_INIT;
+ Array all_chunks = arena_array(arena, kv_size(virt_lines->data.virt_lines));
bool virt_lines_leftcol = false;
for (size_t i = 0; i < kv_size(virt_lines->data.virt_lines); i++) {
virt_lines_leftcol = kv_A(virt_lines->data.virt_lines, i).left_col;
- Array chunks = virt_text_to_array(kv_A(virt_lines->data.virt_lines, i).line, hl_name);
+ Array chunks = virt_text_to_array(kv_A(virt_lines->data.virt_lines, i).line, hl_name, arena);
ADD(all_chunks, ARRAY_OBJ(chunks));
}
- PUT(*dict, "virt_lines", ARRAY_OBJ(all_chunks));
- PUT(*dict, "virt_lines_above", BOOLEAN_OBJ(virt_lines->flags & kVTLinesAbove));
- PUT(*dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol));
+ PUT_C(*dict, "virt_lines", ARRAY_OBJ(all_chunks));
+ PUT_C(*dict, "virt_lines_above", BOOLEAN_OBJ(virt_lines->flags & kVTLinesAbove));
+ PUT_C(*dict, "virt_lines_leftcol", BOOLEAN_OBJ(virt_lines_leftcol));
priority = virt_lines->priority;
}
if (sh_sign.flags & kSHIsSign) {
- if (sh_sign.text.ptr) {
- PUT(*dict, "sign_text", CSTR_TO_OBJ(sh_sign.text.ptr));
+ if (sh_sign.text[0]) {
+ char buf[SIGN_WIDTH * MAX_SCHAR_SIZE];
+ describe_sign_text(buf, sh_sign.text);
+ PUT_C(*dict, "sign_text", CSTR_TO_ARENA_OBJ(arena, buf));
}
if (sh_sign.sign_name) {
- PUT(*dict, "sign_name", CSTR_TO_OBJ(sh_sign.sign_name));
+ PUT_C(*dict, "sign_name", CSTR_AS_OBJ(sh_sign.sign_name));
}
// uncrustify:off
@@ -1024,14 +1052,14 @@ void decor_to_dict_legacy(Dictionary *dict, DecorInline decor, bool hl_name)
for (int j = 0; hls[j].name; j++) {
if (hls[j].val) {
- PUT(*dict, hls[j].name, hl_group_name(hls[j].val, hl_name));
+ PUT_C(*dict, hls[j].name, hl_group_name(hls[j].val, hl_name));
}
}
priority = sh_sign.priority;
}
if (priority != -1) {
- PUT(*dict, "priority", INTEGER_OBJ(priority));
+ PUT_C(*dict, "priority", INTEGER_OBJ(priority));
}
}
@@ -1059,7 +1087,7 @@ uint16_t decor_type_flags(DecorInline decor)
Object hl_group_name(int hl_id, bool hl_name)
{
if (hl_name) {
- return CSTR_TO_OBJ(syn_id2name(hl_id));
+ return CSTR_AS_OBJ(syn_id2name(hl_id));
} else {
return INTEGER_OBJ(hl_id);
}