@@ -278,6 +278,38 @@ get_sign_display_info(
278278#endif
279279
280280#if defined(FEAT_PROP_POPUP ) || defined(PROTO )
281+ /*
282+ * Return the cell size of virtual text after truncation.
283+ */
284+ static int
285+ textprop_size_after_trunc (
286+ win_T * wp ,
287+ int flags , // TP_FLAG_ALIGN_*
288+ int added ,
289+ char_u * text ,
290+ int * n_used_ptr )
291+ {
292+ int space = (flags & (TP_FLAG_ALIGN_BELOW | TP_FLAG_ALIGN_ABOVE ))
293+ ? wp -> w_width : added ;
294+ int len = (int )STRLEN (text );
295+ int strsize = 0 ;
296+ int n_used ;
297+
298+ // if the remaining size is to small wrap anyway and use the next line
299+ if (space < PROP_TEXT_MIN_CELLS )
300+ space += wp -> w_width ;
301+ for (n_used = 0 ; n_used < len ; n_used += (* mb_ptr2len )(text + n_used ))
302+ {
303+ int clen = ptr2cells (text + n_used );
304+
305+ if (strsize + clen > space )
306+ break ;
307+ strsize += clen ;
308+ }
309+ * n_used_ptr = n_used ;
310+ return strsize ;
311+ }
312+
281313/*
282314 * Take care of padding, right-align and truncation of virtual text after a
283315 * line.
@@ -297,43 +329,53 @@ text_prop_position(
297329 int * n_attr_skip ) // cells to skip attr, NULL if not used
298330{
299331 int right = (tp -> tp_flags & TP_FLAG_ALIGN_RIGHT );
332+ int above = (tp -> tp_flags & TP_FLAG_ALIGN_ABOVE );
300333 int below = (tp -> tp_flags & TP_FLAG_ALIGN_BELOW );
301334 int wrap = (tp -> tp_flags & TP_FLAG_WRAP );
302335 int padding = tp -> tp_col == MAXCOL && tp -> tp_len > 1
303336 ? tp -> tp_len - 1 : 0 ;
304337 int col_with_padding = vcol + (below ? 0 : padding );
305338 int col_off = 0 ;
306339 int room = wp -> w_width - col_with_padding ;
307- int added = room ;
340+ int before = room ; // spaces before the text
341+ int after = 0 ; // spaces after the text
308342 int n_used = * n_extra ;
309343 char_u * l = NULL ;
310344 int strsize = vim_strsize (* p_extra );
311- int cells = wrap ? strsize
312- : textprop_size_after_trunc ( wp , below , added , * p_extra , & n_used );
345+ int cells = wrap ? strsize : textprop_size_after_trunc ( wp ,
346+ tp -> tp_flags , before , * p_extra , & n_used );
313347
314- if (wrap || right || below || padding > 0 || n_used < * n_extra )
348+ if (wrap || right || above || below || padding > 0 || n_used < * n_extra )
315349 {
316- // Right-align: fill with spaces
317- if (right )
318- added -= cells ;
319- if (added < 0
320- || !(right || below )
321- || (below
322- ? (col_with_padding == 0 || !wp -> w_p_wrap )
323- : (n_used < * n_extra )))
350+ if (above )
324351 {
325- if (right && (wrap || room < PROP_TEXT_MIN_CELLS ))
326- {
327- // right-align on next line instead of wrapping if possible
328- col_off = win_col_off (wp ) + win_col_off2 (wp );
329- added = wp -> w_width - col_off - strsize + room ;
330- if (added < 0 )
331- added = 0 ;
352+ before = 0 ;
353+ after = wp -> w_width - cells ;
354+ }
355+ else
356+ {
357+ // Right-align: fill with before
358+ if (right )
359+ before -= cells ;
360+ if (before < 0
361+ || !(right || below )
362+ || (below
363+ ? (col_with_padding == 0 || !wp -> w_p_wrap )
364+ : (n_used < * n_extra )))
365+ {
366+ if (right && (wrap || room < PROP_TEXT_MIN_CELLS ))
367+ {
368+ // right-align on next line instead of wrapping if possible
369+ col_off = win_col_off (wp ) + win_col_off2 (wp );
370+ before = wp -> w_width - col_off - strsize + room ;
371+ if (before < 0 )
372+ before = 0 ;
373+ else
374+ n_used = * n_extra ;
375+ }
332376 else
333- n_used = * n_extra ;
377+ before = 0 ;
334378 }
335- else
336- added = 0 ;
337379 }
338380
339381 // With 'nowrap' add one to show the "extends" character if needed (it
@@ -346,15 +388,15 @@ text_prop_position(
346388
347389 // add 1 for NUL, 2 for when '…' is used
348390 if (n_attr != NULL )
349- l = alloc (n_used + added + padding + 3 );
391+ l = alloc (n_used + before + after + padding + 3 );
350392 if (n_attr == NULL || l != NULL )
351393 {
352394 int off = 0 ;
353395
354396 if (n_attr != NULL )
355397 {
356- vim_memset (l , ' ' , added );
357- off += added ;
398+ vim_memset (l , ' ' , before );
399+ off += before ;
358400 if (padding > 0 )
359401 {
360402 vim_memset (l + off , ' ' , padding );
@@ -365,8 +407,8 @@ text_prop_position(
365407 }
366408 else
367409 {
368- off = added + padding + n_used ;
369- cells += added + padding ;
410+ off = before + after + padding + n_used ;
411+ cells += before + after + padding ;
370412 }
371413 if (n_attr != NULL )
372414 {
@@ -385,10 +427,16 @@ text_prop_position(
385427 // change last character to '>'
386428 * lp = '>' ;
387429 }
430+ else if (after > 0 )
431+ {
432+ vim_memset (l + off , ' ' , after );
433+ l [off + after ] = NUL ;
434+ }
435+
388436 * p_extra = l ;
389- * n_extra = n_used + added + padding ;
437+ * n_extra = n_used + before + after + padding ;
390438 * n_attr = mb_charlen (* p_extra );
391- * n_attr_skip = added + padding + col_off ;
439+ * n_attr_skip = before + padding + col_off ;
392440 }
393441 }
394442 }
@@ -1694,11 +1742,14 @@ win_line(
16941742 // text prop can show.
16951743 while (text_prop_next < text_prop_count
16961744 && (text_props [text_prop_next ].tp_col == MAXCOL
1697- ? (* ptr == NUL
1745+ ? (( * ptr == NUL
16981746 && (wp -> w_p_wrap
16991747 || wlv .row == startrow
17001748 || (text_props [text_prop_next ].tp_flags
17011749 & TP_FLAG_ALIGN_BELOW )))
1750+ || (bcol == 0 &&
1751+ (text_props [text_prop_next ].tp_flags
1752+ & TP_FLAG_ALIGN_ABOVE )))
17021753 : bcol >= text_props [text_prop_next ].tp_col - 1 ))
17031754 {
17041755 if (text_props [text_prop_next ].tp_col == MAXCOL
@@ -1773,6 +1824,8 @@ win_line(
17731824 {
17741825 int right = (tp -> tp_flags
17751826 & TP_FLAG_ALIGN_RIGHT );
1827+ int above = (tp -> tp_flags
1828+ & TP_FLAG_ALIGN_ABOVE );
17761829 int below = (tp -> tp_flags
17771830 & TP_FLAG_ALIGN_BELOW );
17781831 int wrap = (tp -> tp_flags & TP_FLAG_WRAP );
@@ -1797,18 +1850,15 @@ win_line(
17971850 // don't combine char attr after EOL
17981851 text_prop_flags &= ~PT_FLAG_COMBINE ;
17991852#ifdef FEAT_LINEBREAK
1800- if (below || right || !wrap )
1853+ if (above || below || right || !wrap )
18011854 {
18021855 // no 'showbreak' before "below" text property
1803- // or after "right" text property
1856+ // or after "above" or " right" text property
18041857 need_showbreak = FALSE;
18051858 dont_use_showbreak = TRUE;
18061859 }
18071860#endif
1808- // Keep in sync with where
1809- // textprop_size_after_trunc() is called in
1810- // win_lbr_chartabsize().
1811- if ((right || below || !wrap || padding > 0 )
1861+ if ((right || above || below || !wrap || padding > 0 )
18121862 && wp -> w_width > 2 )
18131863 {
18141864 char_u * prev_p_extra = wlv .p_extra ;
0 commit comments