diff options
author | Bram Moolenaar <Bram@vim.org> | 2022-08-23 18:39:37 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2022-08-23 18:39:37 +0100 |
commit | f396ce83eebf6c61596184231d39ce4d41eeac04 (patch) | |
tree | d3a624411eaea5463025bd186c39616688cc0876 /src/drawline.c | |
parent | adce965162dd89bf29ee0e5baf53652e7515762c (diff) |
patch 9.0.0247: cannot add padding to virtual text without highlightv9.0.0247
Problem: Cannot add padding to virtual text without highlight.
Solution: Add the "text_padding_left" argument. (issue #10906)
Diffstat (limited to 'src/drawline.c')
-rw-r--r-- | src/drawline.c | 278 |
1 files changed, 146 insertions, 132 deletions
diff --git a/src/drawline.c b/src/drawline.c index b29f5b19ae..039a8c94d7 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -277,74 +277,123 @@ get_sign_display_info( } #endif -#ifdef FEAT_PROP_POPUP -static textprop_T *current_text_props = NULL; -static buf_T *current_buf = NULL; - +#if defined(FEAT_PROP_POPUP) || defined(PROTO) /* - * Function passed to qsort() to sort text properties. - * Return 1 if "s1" has priority over "s2", -1 if the other way around, zero if - * both have the same priority. + * Take care of padding, right-align and truncation of virtual text after a + * line. + * if "n_attr" is not NULL then "n_extra" and "p_extra" are adjusted for any + * padding, right-align and truncation. Otherwise only the size is computed. + * When "n_attr" is NULL returns the number of screen cells used. + * Otherwise returns TRUE when drawing continues on the next line. */ - static int -text_prop_compare(const void *s1, const void *s2) + int +text_prop_position( + win_T *wp, + textprop_T *tp, + int vcol, // current screen column + int *n_extra, // nr of bytes for virtual text + char_u **p_extra, // virtual text + int *n_attr, // attribute cells, NULL if not used + int *n_attr_skip) // cells to skip attr, NULL if not used { - int idx1, idx2; - textprop_T *tp1, *tp2; - proptype_T *pt1, *pt2; - colnr_T col1, col2; - - idx1 = *(int *)s1; - idx2 = *(int *)s2; - tp1 = ¤t_text_props[idx1]; - tp2 = ¤t_text_props[idx2]; - col1 = tp1->tp_col; - col2 = tp2->tp_col; - if (col1 == MAXCOL && col2 == MAXCOL) + int right = (tp->tp_flags & TP_FLAG_ALIGN_RIGHT); + int below = (tp->tp_flags & TP_FLAG_ALIGN_BELOW); + int wrap = (tp->tp_flags & TP_FLAG_WRAP); + int padding = tp->tp_col == MAXCOL && tp->tp_len > 1 + ? tp->tp_len - 1 : 0; + int col_with_padding = vcol + (below ? 0 : padding); + int room = wp->w_width - col_with_padding; + int added = room; + int n_used = *n_extra; + char_u *l = NULL; + int strsize = vim_strsize(*p_extra); + int cells = wrap ? strsize + : textprop_size_after_trunc(wp, below, added, *p_extra, &n_used); + + if (wrap || right || below || padding > 0 || n_used < *n_extra) { - int flags1 = 0; - int flags2 = 0; - - // both props add text are after the line, order on 0: after (default), - // 1: right, 2: below (comes last) - if (tp1->tp_flags & TP_FLAG_ALIGN_RIGHT) - flags1 = 1; - if (tp1->tp_flags & TP_FLAG_ALIGN_BELOW) - flags1 = 2; - if (tp2->tp_flags & TP_FLAG_ALIGN_RIGHT) - flags2 = 1; - if (tp2->tp_flags & TP_FLAG_ALIGN_BELOW) - flags2 = 2; - if (flags1 != flags2) - return flags1 < flags2 ? 1 : -1; - } - - // property that inserts text has priority over one that doesn't - if ((tp1->tp_id < 0) != (tp2->tp_id < 0)) - return tp1->tp_id < 0 ? 1 : -1; + // Right-align: fill with spaces + if (right) + added -= cells; + if (added < 0 + || !(right || below) + || (below + ? (col_with_padding == 0 || !wp->w_p_wrap) + : (n_used < *n_extra))) + { + if (right && (wrap || room < PROP_TEXT_MIN_CELLS)) + { + // right-align on next line instead of wrapping if possible + added = wp->w_width - strsize + room; + if (added < 0) + added = 0; + else + n_used = *n_extra; + } + else + added = 0; + } - // check highest priority, defined by the type - pt1 = text_prop_type_by_id(current_buf, tp1->tp_type); - pt2 = text_prop_type_by_id(current_buf, tp2->tp_type); - if (pt1 != pt2) - { - if (pt1 == NULL) - return -1; - if (pt2 == NULL) - return 1; - if (pt1->pt_priority != pt2->pt_priority) - return pt1->pt_priority > pt2->pt_priority ? 1 : -1; - } + // With 'nowrap' add one to show the "extends" character if needed (it + // doesn't show if the text just fits). + if (!wp->w_p_wrap + && n_used < *n_extra + && wp->w_lcs_chars.ext != NUL + && wp->w_p_list) + ++n_used; + + // add 1 for NUL, 2 for when '…' is used + if (n_attr != NULL) + l = alloc(n_used + added + padding + 3); + if (n_attr == NULL || l != NULL) + { + int off = 0; - // same priority, one that starts first wins - if (col1 != col2) - return col1 < col2 ? 1 : -1; + if (n_attr != NULL) + { + vim_memset(l, ' ', added); + off += added; + if (padding > 0) + { + vim_memset(l + off, ' ', padding); + off += padding; + } + vim_strncpy(l + off, *p_extra, n_used); + off += n_used; + } + else + { + off = added + padding + n_used; + cells += added + padding; + } + if (n_attr != NULL) + { + if (n_used < *n_extra && wp->w_p_wrap) + { + char_u *lp = l + off - 1; - // for a property with text the id can be used as tie breaker - if (tp1->tp_id < 0) - return tp1->tp_id > tp2->tp_id ? 1 : -1; + if (has_mbyte) + { + // change last character to '…' + lp -= (*mb_head_off)(l, lp); + STRCPY(lp, "…"); + n_used = lp - l + 3 - padding; + } + else + // change last character to '>' + *lp = '>'; + } + *p_extra = l; + *n_extra = n_used + added + padding; + *n_attr = mb_charlen(*p_extra); + *n_attr_skip = added + padding; + } + } + } - return 0; + if (n_attr == NULL) + return cells; + return (below && col_with_padding > win_col_off(wp) && !wp->w_p_wrap); } #endif @@ -1219,6 +1268,9 @@ win_line( // Allocate an array for the indexes. text_prop_idxs = ALLOC_MULT(int, text_prop_count); + if (text_prop_idxs == NULL) + VIM_CLEAR(text_props); + area_highlighting = TRUE; extra_check = TRUE; } @@ -1609,8 +1661,9 @@ win_line( { int tpi = text_prop_idxs[pi]; - if (bcol >= text_props[tpi].tp_col - 1 - + text_props[tpi].tp_len) + if (text_props[tpi].tp_col != MAXCOL + && bcol >= text_props[tpi].tp_col - 1 + + text_props[tpi].tp_len) { if (pi + 1 < text_props_active) mch_memmove(text_prop_idxs + pi, @@ -1674,10 +1727,8 @@ win_line( // Sort the properties on priority and/or starting last. // Then combine the attributes, highest priority last. text_prop_follows = FALSE; - current_text_props = text_props; - current_buf = wp->w_buffer; - qsort((void *)text_prop_idxs, (size_t)text_props_active, - sizeof(int), text_prop_compare); + sort_text_props(wp->w_buffer, text_props, + text_prop_idxs, text_props_active); for (pi = 0; pi < text_props_active; ++pi) { @@ -1704,23 +1755,28 @@ win_line( && -text_prop_id <= wp->w_buffer->b_textprop_text.ga_len) { - char_u *p = ((char_u **)wp->w_buffer + textprop_T *tp = &text_props[used_tpi]; + char_u *p = ((char_u **)wp->w_buffer ->b_textprop_text.ga_data)[ -text_prop_id - 1]; // reset the ID in the copy to avoid it being used // again - text_props[used_tpi].tp_id = -MAXCOL; + tp->tp_id = -MAXCOL; if (p != NULL) { - int right = (text_props[used_tpi].tp_flags + int right = (tp->tp_flags & TP_FLAG_ALIGN_RIGHT); - int below = (text_props[used_tpi].tp_flags + int below = (tp->tp_flags & TP_FLAG_ALIGN_BELOW); - int wrap = (text_props[used_tpi].tp_flags - & TP_FLAG_WRAP); + int wrap = (tp->tp_flags & TP_FLAG_WRAP); + int padding = tp->tp_col == MAXCOL + && tp->tp_len > 1 + ? tp->tp_len - 1 : 0; + // Insert virtual text before the current + // character, or add after the end of the line. wlv.p_extra = p; wlv.c_extra = NUL; wlv.c_final = NUL; @@ -1746,72 +1802,30 @@ win_line( // Keep in sync with where // textprop_size_after_trunc() is called in // win_lbr_chartabsize(). - if ((right || below || !wrap) && wp->w_width > 2) + if ((right || below || !wrap || padding > 0) + && wp->w_width > 2) { - int added = wp->w_width - wlv.col; - int n_used = wlv.n_extra; - char_u *l; - int strsize = wrap - ? vim_strsize(wlv.p_extra) - : textprop_size_after_trunc(wp, - below, added, wlv.p_extra, &n_used); - - if (wrap || right || below - || n_used < wlv.n_extra) + char_u *prev_p_extra = wlv.p_extra; + int start_line; + + // Take care of padding, right-align and + // truncation. + // Shared with win_lbr_chartabsize(), must do + // exactly the same. + start_line = text_prop_position(wp, tp, + wlv.col, + &wlv.n_extra, &wlv.p_extra, + &n_attr, &n_attr_skip); + if (wlv.p_extra != prev_p_extra) { - // Right-align: fill with spaces - if (right) - added -= strsize; - if (added < 0 - || (below - ? wlv.col == 0 || !wp->w_p_wrap - : n_used < wlv.n_extra)) - added = 0; - - // With 'nowrap' add one to show the - // "extends" character if needed (it - // doesn't show it the text just fits). - if (!wp->w_p_wrap - && n_used < wlv.n_extra - && wp->w_lcs_chars.ext != NUL - && wp->w_p_list) - ++n_used; - - // add 1 for NUL, 2 for when '…' is used - l = alloc(n_used + added + 3); - if (l != NULL) - { - vim_memset(l, ' ', added); - vim_strncpy(l + added, wlv.p_extra, - n_used); - if (n_used < wlv.n_extra - && wp->w_p_wrap) - { - char_u *lp = l + added + n_used - 1; - - if (has_mbyte) - { - // change last character to '…' - lp -= (*mb_head_off)(l, lp); - STRCPY(lp, "…"); - n_used = lp - l + 3; - } - else - // change last character to '>' - *lp = '>'; - } - vim_free(p_extra_free2); - wlv.p_extra = p_extra_free2 = l; - wlv.n_extra = n_used + added; - n_attr_skip = added; - n_attr = mb_charlen(wlv.p_extra); - } + // wlv.p_extra was allocated + vim_free(p_extra_free2); + p_extra_free2 = wlv.p_extra; } // When 'wrap' is off then for "below" we need // to start a new line explictly. - if (below && wlv.col > win_col_off(wp) - && !wp->w_p_wrap) + if (start_line) { draw_screen_line(wp, &wlv); |