Skip to content

Commit 04e0ed1

Browse files
committed
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".
1 parent 55e9366 commit 04e0ed1

11 files changed

Lines changed: 200 additions & 105 deletions

File tree

runtime/doc/textprop.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ prop_add({lnum}, {col}, {props})
153153
the text wraps to the next screen
154154
line)
155155
below in the next screen line
156+
above just above the line
156157
When omitted "after" is used. Only one
157158
"right" property can fit in each line, if
158159
there are two ore more these will go in a

src/charset.c

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,40 +1069,6 @@ lbr_chartabsize_adv(chartabsize_T *cts)
10691069
return retval;
10701070
}
10711071

1072-
#if defined(FEAT_PROP_POPUP) || defined(PROTO)
1073-
/*
1074-
* Return the cell size of virtual text after truncation.
1075-
*/
1076-
int
1077-
textprop_size_after_trunc(
1078-
win_T *wp,
1079-
int below,
1080-
int added,
1081-
char_u *text,
1082-
int *n_used_ptr)
1083-
{
1084-
int space = below ? wp->w_width : added;
1085-
int len = (int)STRLEN(text);
1086-
int strsize = 0;
1087-
int n_used;
1088-
1089-
// if the remaining size is to small wrap
1090-
// anyway and use the next line
1091-
if (space < PROP_TEXT_MIN_CELLS)
1092-
space += wp->w_width;
1093-
for (n_used = 0; n_used < len; n_used += (*mb_ptr2len)(text + n_used))
1094-
{
1095-
int clen = ptr2cells(text + n_used);
1096-
1097-
if (strsize + clen > space)
1098-
break;
1099-
strsize += clen;
1100-
}
1101-
*n_used_ptr = n_used;
1102-
return strsize;
1103-
}
1104-
#endif
1105-
11061072
/*
11071073
* Return the screen size of the character indicated by "cts".
11081074
* "cts->cts_cur_text_width" is set to the extra size for a text property that
@@ -1142,6 +1108,7 @@ win_lbr_chartabsize(
11421108

11431109
#if defined(FEAT_PROP_POPUP)
11441110
cts->cts_cur_text_width = 0;
1111+
cts->cts_first_char = 0;
11451112
#endif
11461113

11471114
#if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP)
@@ -1194,9 +1161,12 @@ win_lbr_chartabsize(
11941161
if (tp->tp_id < 0
11951162
&& ((tp->tp_col - 1 >= col
11961163
&& tp->tp_col - 1 < col + charlen)
1197-
|| (tp->tp_col == MAXCOL && (s[0] == NUL || s[1] == NUL)
1198-
&& cts->cts_with_trailing))
1199-
&& -tp->tp_id - 1 < gap->ga_len)
1164+
|| (tp->tp_col == MAXCOL
1165+
&& ((tp->tp_flags & TP_FLAG_ALIGN_ABOVE)
1166+
? col == 0
1167+
: (s[0] == NUL || s[1] == NUL)
1168+
&& cts->cts_with_trailing)))
1169+
&& tp->tp_id - 1 < gap->ga_len)
12001170
{
12011171
char_u *p = ((char_u **)gap->ga_data)[-tp->tp_id - 1];
12021172

@@ -1218,6 +1188,8 @@ win_lbr_chartabsize(
12181188
else
12191189
cells = vim_strsize(p);
12201190
cts->cts_cur_text_width += cells;
1191+
if (tp->tp_flags & TP_FLAG_ALIGN_ABOVE)
1192+
cts->cts_first_char += cells;
12211193
cts->cts_start_incl = tp->tp_flags & TP_FLAG_START_INCL;
12221194
size += cells;
12231195
if (*s == TAB)
@@ -1564,6 +1536,11 @@ getvcol(
15641536
#endif
15651537
break;
15661538
}
1539+
#ifdef FEAT_PROP_POPUP
1540+
if (cursor == &wp->w_virtcol && cts.cts_ptr == cts.cts_line)
1541+
// do not count the virtual text above for w_curswant
1542+
wp->w_virtcol_first_char = cts.cts_first_char;
1543+
#endif
15671544

15681545
if (posptr != NULL && cts.cts_ptr >= posptr)
15691546
// character at pos->col

src/drawline.c

Lines changed: 86 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -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;

src/misc2.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ getviscol2(colnr_T col, colnr_T coladd UNUSED)
8585
}
8686

8787
/*
88-
* Try to advance the Cursor to the specified screen column.
88+
* Try to advance the Cursor to the specified screen column "wantcol".
8989
* If virtual editing: fine tune the cursor position.
9090
* Note that all virtual positions off the end of a line should share
9191
* a curwin->w_cursor.col value (n.b. this is equal to STRLEN(line)),
@@ -94,29 +94,30 @@ getviscol2(colnr_T col, colnr_T coladd UNUSED)
9494
* return OK if desired column is reached, FAIL if not
9595
*/
9696
int
97-
coladvance(colnr_T wcol)
97+
coladvance(colnr_T wantcol)
9898
{
99-
int rc = getvpos(&curwin->w_cursor, wcol);
99+
int rc = getvpos(&curwin->w_cursor, wantcol);
100100

101-
if (wcol == MAXCOL || rc == FAIL)
101+
if (wantcol == MAXCOL || rc == FAIL)
102102
curwin->w_valid &= ~VALID_VIRTCOL;
103103
else if (*ml_get_cursor() != TAB)
104104
{
105105
// Virtcol is valid when not on a TAB
106106
curwin->w_valid |= VALID_VIRTCOL;
107-
curwin->w_virtcol = wcol;
107+
curwin->w_virtcol = wantcol;
108108
}
109109
return rc;
110110
}
111111

112112
/*
113-
* Return in "pos" the position of the cursor advanced to screen column "wcol".
113+
* Return in "pos" the position of the cursor advanced to screen column
114+
* "wantcol".
114115
* return OK if desired column is reached, FAIL if not
115116
*/
116117
int
117-
getvpos(pos_T *pos, colnr_T wcol)
118+
getvpos(pos_T *pos, colnr_T wantcol)
118119
{
119-
return coladvance2(pos, FALSE, virtual_active(), wcol);
120+
return coladvance2(pos, FALSE, virtual_active(), wantcol);
120121
}
121122

122123
static int
@@ -156,8 +157,8 @@ coladvance2(
156157
}
157158
else
158159
{
159-
int width = curwin->w_width - win_col_off(curwin);
160-
chartabsize_T cts;
160+
int width = curwin->w_width - win_col_off(curwin);
161+
chartabsize_T cts;
161162

162163
if (finetune
163164
&& curwin->w_p_wrap
@@ -183,6 +184,9 @@ coladvance2(
183184
init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line);
184185
while (cts.cts_vcol <= wcol && *cts.cts_ptr != NUL)
185186
{
187+
#ifdef FEAT_PROP_POPUP
188+
int at_start = cts.cts_ptr == cts.cts_line;
189+
#endif
186190
// Count a tab for what it's worth (if list mode not on)
187191
#ifdef FEAT_LINEBREAK
188192
csize = win_lbr_chartabsize(&cts, &head);
@@ -191,6 +195,11 @@ coladvance2(
191195
csize = lbr_chartabsize_adv(&cts);
192196
#endif
193197
cts.cts_vcol += csize;
198+
#ifdef FEAT_PROP_POPUP
199+
if (at_start)
200+
// do not count the columns for virtual text above
201+
cts.cts_vcol -= cts.cts_first_char;
202+
#endif
194203
}
195204
col = cts.cts_vcol;
196205
idx = (int)(cts.cts_ptr - line);
@@ -2400,7 +2409,7 @@ update_mouseshape(int shape_idx)
24002409

24012410
/*
24022411
* Change directory to "new_dir". Search 'cdpath' for relative directory
2403-
* names, otherwise just mch_chdir().
2412+
* names.
24042413
*/
24052414
int
24062415
vim_chdir(char_u *new_dir)

0 commit comments

Comments
 (0)