summaryrefslogtreecommitdiffstats
path: root/src/drawline.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-08-23 18:39:37 +0100
committerBram Moolenaar <Bram@vim.org>2022-08-23 18:39:37 +0100
commitf396ce83eebf6c61596184231d39ce4d41eeac04 (patch)
treed3a624411eaea5463025bd186c39616688cc0876 /src/drawline.c
parentadce965162dd89bf29ee0e5baf53652e7515762c (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.c278
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 = &current_text_props[idx1];
- tp2 = &current_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);