diff options
Diffstat (limited to 'src/nvim/decoration.c')
-rw-r--r-- | src/nvim/decoration.c | 418 |
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); } |