patch 9.0.0438: cannot put virtual text above a line
Problem: Cannot put virtual text above a line.
Solution: Add the "above" value for "text_align".
diff --git a/src/drawline.c b/src/drawline.c
index 6c298b6..56d42e2 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -279,6 +279,38 @@
#if defined(FEAT_PROP_POPUP) || defined(PROTO)
/*
+ * Return the cell size of virtual text after truncation.
+ */
+ static int
+textprop_size_after_trunc(
+ win_T *wp,
+ int flags, // TP_FLAG_ALIGN_*
+ int added,
+ char_u *text,
+ int *n_used_ptr)
+{
+ int space = (flags & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_ABOVE))
+ ? wp->w_width : added;
+ int len = (int)STRLEN(text);
+ int strsize = 0;
+ int n_used;
+
+ // if the remaining size is to small wrap anyway and use the next line
+ if (space < PROP_TEXT_MIN_CELLS)
+ space += wp->w_width;
+ for (n_used = 0; n_used < len; n_used += (*mb_ptr2len)(text + n_used))
+ {
+ int clen = ptr2cells(text + n_used);
+
+ if (strsize + clen > space)
+ break;
+ strsize += clen;
+ }
+ *n_used_ptr = n_used;
+ return strsize;
+}
+
+/*
* 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
@@ -297,6 +329,7 @@
int *n_attr_skip) // cells to skip attr, NULL if not used
{
int right = (tp->tp_flags & TP_FLAG_ALIGN_RIGHT);
+ int above = (tp->tp_flags & TP_FLAG_ALIGN_ABOVE);
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
@@ -304,36 +337,45 @@
int col_with_padding = vcol + (below ? 0 : padding);
int col_off = 0;
int room = wp->w_width - col_with_padding;
- int added = room;
+ int before = room; // spaces before the text
+ int after = 0; // spaces after the text
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);
+ int cells = wrap ? strsize : textprop_size_after_trunc(wp,
+ tp->tp_flags, before, *p_extra, &n_used);
- if (wrap || right || below || padding > 0 || n_used < *n_extra)
+ if (wrap || right || above || below || padding > 0 || n_used < *n_extra)
{
- // 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 (above)
{
- if (right && (wrap || room < PROP_TEXT_MIN_CELLS))
+ before = 0;
+ after = wp->w_width - cells;
+ }
+ else
+ {
+ // Right-align: fill with before
+ if (right)
+ before -= cells;
+ if (before < 0
+ || !(right || below)
+ || (below
+ ? (col_with_padding == 0 || !wp->w_p_wrap)
+ : (n_used < *n_extra)))
{
- // right-align on next line instead of wrapping if possible
- col_off = win_col_off(wp) + win_col_off2(wp);
- added = wp->w_width - col_off - strsize + room;
- if (added < 0)
- added = 0;
+ if (right && (wrap || room < PROP_TEXT_MIN_CELLS))
+ {
+ // right-align on next line instead of wrapping if possible
+ col_off = win_col_off(wp) + win_col_off2(wp);
+ before = wp->w_width - col_off - strsize + room;
+ if (before < 0)
+ before = 0;
+ else
+ n_used = *n_extra;
+ }
else
- n_used = *n_extra;
+ before = 0;
}
- else
- added = 0;
}
// With 'nowrap' add one to show the "extends" character if needed (it
@@ -346,15 +388,15 @@
// add 1 for NUL, 2 for when '…' is used
if (n_attr != NULL)
- l = alloc(n_used + added + padding + 3);
+ l = alloc(n_used + before + after + padding + 3);
if (n_attr == NULL || l != NULL)
{
int off = 0;
if (n_attr != NULL)
{
- vim_memset(l, ' ', added);
- off += added;
+ vim_memset(l, ' ', before);
+ off += before;
if (padding > 0)
{
vim_memset(l + off, ' ', padding);
@@ -365,8 +407,8 @@
}
else
{
- off = added + padding + n_used;
- cells += added + padding;
+ off = before + after + padding + n_used;
+ cells += before + after + padding;
}
if (n_attr != NULL)
{
@@ -385,10 +427,16 @@
// change last character to '>'
*lp = '>';
}
+ else if (after > 0)
+ {
+ vim_memset(l + off, ' ', after);
+ l[off + after] = NUL;
+ }
+
*p_extra = l;
- *n_extra = n_used + added + padding;
+ *n_extra = n_used + before + after + padding;
*n_attr = mb_charlen(*p_extra);
- *n_attr_skip = added + padding + col_off;
+ *n_attr_skip = before + padding + col_off;
}
}
}
@@ -1694,11 +1742,14 @@
// text prop can show.
while (text_prop_next < text_prop_count
&& (text_props[text_prop_next].tp_col == MAXCOL
- ? (*ptr == NUL
+ ? ((*ptr == NUL
&& (wp->w_p_wrap
|| wlv.row == startrow
|| (text_props[text_prop_next].tp_flags
& TP_FLAG_ALIGN_BELOW)))
+ || (bcol == 0 &&
+ (text_props[text_prop_next].tp_flags
+ & TP_FLAG_ALIGN_ABOVE)))
: bcol >= text_props[text_prop_next].tp_col - 1))
{
if (text_props[text_prop_next].tp_col == MAXCOL
@@ -1773,6 +1824,8 @@
{
int right = (tp->tp_flags
& TP_FLAG_ALIGN_RIGHT);
+ int above = (tp->tp_flags
+ & TP_FLAG_ALIGN_ABOVE);
int below = (tp->tp_flags
& TP_FLAG_ALIGN_BELOW);
int wrap = (tp->tp_flags & TP_FLAG_WRAP);
@@ -1797,18 +1850,15 @@
// don't combine char attr after EOL
text_prop_flags &= ~PT_FLAG_COMBINE;
#ifdef FEAT_LINEBREAK
- if (below || right || !wrap)
+ if (above || below || right || !wrap)
{
// no 'showbreak' before "below" text property
- // or after "right" text property
+ // or after "above" or "right" text property
need_showbreak = FALSE;
dont_use_showbreak = TRUE;
}
#endif
- // Keep in sync with where
- // textprop_size_after_trunc() is called in
- // win_lbr_chartabsize().
- if ((right || below || !wrap || padding > 0)
+ if ((right || above || below || !wrap || padding > 0)
&& wp->w_width > 2)
{
char_u *prev_p_extra = wlv.p_extra;