Mercurial > vim
comparison src/drawline.c @ 29816:bbe62ea78aac v9.0.0247
patch 9.0.0247: cannot add padding to virtual text without highlight
Commit: https://github.com/vim/vim/commit/f396ce83eebf6c61596184231d39ce4d41eeac04
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Aug 23 18:39:37 2022 +0100
patch 9.0.0247: cannot add padding to virtual text without highlight
Problem: Cannot add padding to virtual text without highlight.
Solution: Add the "text_padding_left" argument. (issue https://github.com/vim/vim/issues/10906)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 23 Aug 2022 19:45:05 +0200 |
parents | 3035901eceb7 |
children | e6e0f1c39edb |
comparison
equal
deleted
inserted
replaced
29815:9941dc321348 | 29816:bbe62ea78aac |
---|---|
275 } | 275 } |
276 } | 276 } |
277 } | 277 } |
278 #endif | 278 #endif |
279 | 279 |
280 #ifdef FEAT_PROP_POPUP | 280 #if defined(FEAT_PROP_POPUP) || defined(PROTO) |
281 static textprop_T *current_text_props = NULL; | |
282 static buf_T *current_buf = NULL; | |
283 | |
284 /* | 281 /* |
285 * Function passed to qsort() to sort text properties. | 282 * Take care of padding, right-align and truncation of virtual text after a |
286 * Return 1 if "s1" has priority over "s2", -1 if the other way around, zero if | 283 * line. |
287 * both have the same priority. | 284 * if "n_attr" is not NULL then "n_extra" and "p_extra" are adjusted for any |
285 * padding, right-align and truncation. Otherwise only the size is computed. | |
286 * When "n_attr" is NULL returns the number of screen cells used. | |
287 * Otherwise returns TRUE when drawing continues on the next line. | |
288 */ | 288 */ |
289 static int | 289 int |
290 text_prop_compare(const void *s1, const void *s2) | 290 text_prop_position( |
291 win_T *wp, | |
292 textprop_T *tp, | |
293 int vcol, // current screen column | |
294 int *n_extra, // nr of bytes for virtual text | |
295 char_u **p_extra, // virtual text | |
296 int *n_attr, // attribute cells, NULL if not used | |
297 int *n_attr_skip) // cells to skip attr, NULL if not used | |
291 { | 298 { |
292 int idx1, idx2; | 299 int right = (tp->tp_flags & TP_FLAG_ALIGN_RIGHT); |
293 textprop_T *tp1, *tp2; | 300 int below = (tp->tp_flags & TP_FLAG_ALIGN_BELOW); |
294 proptype_T *pt1, *pt2; | 301 int wrap = (tp->tp_flags & TP_FLAG_WRAP); |
295 colnr_T col1, col2; | 302 int padding = tp->tp_col == MAXCOL && tp->tp_len > 1 |
296 | 303 ? tp->tp_len - 1 : 0; |
297 idx1 = *(int *)s1; | 304 int col_with_padding = vcol + (below ? 0 : padding); |
298 idx2 = *(int *)s2; | 305 int room = wp->w_width - col_with_padding; |
299 tp1 = ¤t_text_props[idx1]; | 306 int added = room; |
300 tp2 = ¤t_text_props[idx2]; | 307 int n_used = *n_extra; |
301 col1 = tp1->tp_col; | 308 char_u *l = NULL; |
302 col2 = tp2->tp_col; | 309 int strsize = vim_strsize(*p_extra); |
303 if (col1 == MAXCOL && col2 == MAXCOL) | 310 int cells = wrap ? strsize |
311 : textprop_size_after_trunc(wp, below, added, *p_extra, &n_used); | |
312 | |
313 if (wrap || right || below || padding > 0 || n_used < *n_extra) | |
304 { | 314 { |
305 int flags1 = 0; | 315 // Right-align: fill with spaces |
306 int flags2 = 0; | 316 if (right) |
307 | 317 added -= cells; |
308 // both props add text are after the line, order on 0: after (default), | 318 if (added < 0 |
309 // 1: right, 2: below (comes last) | 319 || !(right || below) |
310 if (tp1->tp_flags & TP_FLAG_ALIGN_RIGHT) | 320 || (below |
311 flags1 = 1; | 321 ? (col_with_padding == 0 || !wp->w_p_wrap) |
312 if (tp1->tp_flags & TP_FLAG_ALIGN_BELOW) | 322 : (n_used < *n_extra))) |
313 flags1 = 2; | 323 { |
314 if (tp2->tp_flags & TP_FLAG_ALIGN_RIGHT) | 324 if (right && (wrap || room < PROP_TEXT_MIN_CELLS)) |
315 flags2 = 1; | 325 { |
316 if (tp2->tp_flags & TP_FLAG_ALIGN_BELOW) | 326 // right-align on next line instead of wrapping if possible |
317 flags2 = 2; | 327 added = wp->w_width - strsize + room; |
318 if (flags1 != flags2) | 328 if (added < 0) |
319 return flags1 < flags2 ? 1 : -1; | 329 added = 0; |
330 else | |
331 n_used = *n_extra; | |
332 } | |
333 else | |
334 added = 0; | |
335 } | |
336 | |
337 // With 'nowrap' add one to show the "extends" character if needed (it | |
338 // doesn't show if the text just fits). | |
339 if (!wp->w_p_wrap | |
340 && n_used < *n_extra | |
341 && wp->w_lcs_chars.ext != NUL | |
342 && wp->w_p_list) | |
343 ++n_used; | |
344 | |
345 // add 1 for NUL, 2 for when '…' is used | |
346 if (n_attr != NULL) | |
347 l = alloc(n_used + added + padding + 3); | |
348 if (n_attr == NULL || l != NULL) | |
349 { | |
350 int off = 0; | |
351 | |
352 if (n_attr != NULL) | |
353 { | |
354 vim_memset(l, ' ', added); | |
355 off += added; | |
356 if (padding > 0) | |
357 { | |
358 vim_memset(l + off, ' ', padding); | |
359 off += padding; | |
360 } | |
361 vim_strncpy(l + off, *p_extra, n_used); | |
362 off += n_used; | |
363 } | |
364 else | |
365 { | |
366 off = added + padding + n_used; | |
367 cells += added + padding; | |
368 } | |
369 if (n_attr != NULL) | |
370 { | |
371 if (n_used < *n_extra && wp->w_p_wrap) | |
372 { | |
373 char_u *lp = l + off - 1; | |
374 | |
375 if (has_mbyte) | |
376 { | |
377 // change last character to '…' | |
378 lp -= (*mb_head_off)(l, lp); | |
379 STRCPY(lp, "…"); | |
380 n_used = lp - l + 3 - padding; | |
381 } | |
382 else | |
383 // change last character to '>' | |
384 *lp = '>'; | |
385 } | |
386 *p_extra = l; | |
387 *n_extra = n_used + added + padding; | |
388 *n_attr = mb_charlen(*p_extra); | |
389 *n_attr_skip = added + padding; | |
390 } | |
391 } | |
320 } | 392 } |
321 | 393 |
322 // property that inserts text has priority over one that doesn't | 394 if (n_attr == NULL) |
323 if ((tp1->tp_id < 0) != (tp2->tp_id < 0)) | 395 return cells; |
324 return tp1->tp_id < 0 ? 1 : -1; | 396 return (below && col_with_padding > win_col_off(wp) && !wp->w_p_wrap); |
325 | |
326 // check highest priority, defined by the type | |
327 pt1 = text_prop_type_by_id(current_buf, tp1->tp_type); | |
328 pt2 = text_prop_type_by_id(current_buf, tp2->tp_type); | |
329 if (pt1 != pt2) | |
330 { | |
331 if (pt1 == NULL) | |
332 return -1; | |
333 if (pt2 == NULL) | |
334 return 1; | |
335 if (pt1->pt_priority != pt2->pt_priority) | |
336 return pt1->pt_priority > pt2->pt_priority ? 1 : -1; | |
337 } | |
338 | |
339 // same priority, one that starts first wins | |
340 if (col1 != col2) | |
341 return col1 < col2 ? 1 : -1; | |
342 | |
343 // for a property with text the id can be used as tie breaker | |
344 if (tp1->tp_id < 0) | |
345 return tp1->tp_id > tp2->tp_id ? 1 : -1; | |
346 | |
347 return 0; | |
348 } | 397 } |
349 #endif | 398 #endif |
350 | 399 |
351 /* | 400 /* |
352 * Called when finished with the line: draw the screen line and handle any | 401 * Called when finished with the line: draw the screen line and handle any |
1217 mch_memmove(text_props, prop_start, | 1266 mch_memmove(text_props, prop_start, |
1218 text_prop_count * sizeof(textprop_T)); | 1267 text_prop_count * sizeof(textprop_T)); |
1219 | 1268 |
1220 // Allocate an array for the indexes. | 1269 // Allocate an array for the indexes. |
1221 text_prop_idxs = ALLOC_MULT(int, text_prop_count); | 1270 text_prop_idxs = ALLOC_MULT(int, text_prop_count); |
1271 if (text_prop_idxs == NULL) | |
1272 VIM_CLEAR(text_props); | |
1273 | |
1222 area_highlighting = TRUE; | 1274 area_highlighting = TRUE; |
1223 extra_check = TRUE; | 1275 extra_check = TRUE; |
1224 } | 1276 } |
1225 } | 1277 } |
1226 #endif | 1278 #endif |
1607 // Check if any active property ends. | 1659 // Check if any active property ends. |
1608 for (pi = 0; pi < text_props_active; ++pi) | 1660 for (pi = 0; pi < text_props_active; ++pi) |
1609 { | 1661 { |
1610 int tpi = text_prop_idxs[pi]; | 1662 int tpi = text_prop_idxs[pi]; |
1611 | 1663 |
1612 if (bcol >= text_props[tpi].tp_col - 1 | 1664 if (text_props[tpi].tp_col != MAXCOL |
1613 + text_props[tpi].tp_len) | 1665 && bcol >= text_props[tpi].tp_col - 1 |
1666 + text_props[tpi].tp_len) | |
1614 { | 1667 { |
1615 if (pi + 1 < text_props_active) | 1668 if (pi + 1 < text_props_active) |
1616 mch_memmove(text_prop_idxs + pi, | 1669 mch_memmove(text_prop_idxs + pi, |
1617 text_prop_idxs + pi + 1, | 1670 text_prop_idxs + pi + 1, |
1618 sizeof(int) | 1671 sizeof(int) |
1672 int other_tpi = -1; | 1725 int other_tpi = -1; |
1673 | 1726 |
1674 // Sort the properties on priority and/or starting last. | 1727 // Sort the properties on priority and/or starting last. |
1675 // Then combine the attributes, highest priority last. | 1728 // Then combine the attributes, highest priority last. |
1676 text_prop_follows = FALSE; | 1729 text_prop_follows = FALSE; |
1677 current_text_props = text_props; | 1730 sort_text_props(wp->w_buffer, text_props, |
1678 current_buf = wp->w_buffer; | 1731 text_prop_idxs, text_props_active); |
1679 qsort((void *)text_prop_idxs, (size_t)text_props_active, | |
1680 sizeof(int), text_prop_compare); | |
1681 | 1732 |
1682 for (pi = 0; pi < text_props_active; ++pi) | 1733 for (pi = 0; pi < text_props_active; ++pi) |
1683 { | 1734 { |
1684 int tpi = text_prop_idxs[pi]; | 1735 int tpi = text_prop_idxs[pi]; |
1685 proptype_T *pt = text_prop_type_by_id( | 1736 proptype_T *pt = text_prop_type_by_id( |
1702 } | 1753 } |
1703 if (text_prop_id < 0 && used_tpi >= 0 | 1754 if (text_prop_id < 0 && used_tpi >= 0 |
1704 && -text_prop_id | 1755 && -text_prop_id |
1705 <= wp->w_buffer->b_textprop_text.ga_len) | 1756 <= wp->w_buffer->b_textprop_text.ga_len) |
1706 { | 1757 { |
1707 char_u *p = ((char_u **)wp->w_buffer | 1758 textprop_T *tp = &text_props[used_tpi]; |
1759 char_u *p = ((char_u **)wp->w_buffer | |
1708 ->b_textprop_text.ga_data)[ | 1760 ->b_textprop_text.ga_data)[ |
1709 -text_prop_id - 1]; | 1761 -text_prop_id - 1]; |
1710 | 1762 |
1711 // reset the ID in the copy to avoid it being used | 1763 // reset the ID in the copy to avoid it being used |
1712 // again | 1764 // again |
1713 text_props[used_tpi].tp_id = -MAXCOL; | 1765 tp->tp_id = -MAXCOL; |
1714 | 1766 |
1715 if (p != NULL) | 1767 if (p != NULL) |
1716 { | 1768 { |
1717 int right = (text_props[used_tpi].tp_flags | 1769 int right = (tp->tp_flags |
1718 & TP_FLAG_ALIGN_RIGHT); | 1770 & TP_FLAG_ALIGN_RIGHT); |
1719 int below = (text_props[used_tpi].tp_flags | 1771 int below = (tp->tp_flags |
1720 & TP_FLAG_ALIGN_BELOW); | 1772 & TP_FLAG_ALIGN_BELOW); |
1721 int wrap = (text_props[used_tpi].tp_flags | 1773 int wrap = (tp->tp_flags & TP_FLAG_WRAP); |
1722 & TP_FLAG_WRAP); | 1774 int padding = tp->tp_col == MAXCOL |
1723 | 1775 && tp->tp_len > 1 |
1776 ? tp->tp_len - 1 : 0; | |
1777 | |
1778 // Insert virtual text before the current | |
1779 // character, or add after the end of the line. | |
1724 wlv.p_extra = p; | 1780 wlv.p_extra = p; |
1725 wlv.c_extra = NUL; | 1781 wlv.c_extra = NUL; |
1726 wlv.c_final = NUL; | 1782 wlv.c_final = NUL; |
1727 wlv.n_extra = (int)STRLEN(p); | 1783 wlv.n_extra = (int)STRLEN(p); |
1728 extra_for_textprop = TRUE; | 1784 extra_for_textprop = TRUE; |
1744 } | 1800 } |
1745 #endif | 1801 #endif |
1746 // Keep in sync with where | 1802 // Keep in sync with where |
1747 // textprop_size_after_trunc() is called in | 1803 // textprop_size_after_trunc() is called in |
1748 // win_lbr_chartabsize(). | 1804 // win_lbr_chartabsize(). |
1749 if ((right || below || !wrap) && wp->w_width > 2) | 1805 if ((right || below || !wrap || padding > 0) |
1806 && wp->w_width > 2) | |
1750 { | 1807 { |
1751 int added = wp->w_width - wlv.col; | 1808 char_u *prev_p_extra = wlv.p_extra; |
1752 int n_used = wlv.n_extra; | 1809 int start_line; |
1753 char_u *l; | 1810 |
1754 int strsize = wrap | 1811 // Take care of padding, right-align and |
1755 ? vim_strsize(wlv.p_extra) | 1812 // truncation. |
1756 : textprop_size_after_trunc(wp, | 1813 // Shared with win_lbr_chartabsize(), must do |
1757 below, added, wlv.p_extra, &n_used); | 1814 // exactly the same. |
1758 | 1815 start_line = text_prop_position(wp, tp, |
1759 if (wrap || right || below | 1816 wlv.col, |
1760 || n_used < wlv.n_extra) | 1817 &wlv.n_extra, &wlv.p_extra, |
1818 &n_attr, &n_attr_skip); | |
1819 if (wlv.p_extra != prev_p_extra) | |
1761 { | 1820 { |
1762 // Right-align: fill with spaces | 1821 // wlv.p_extra was allocated |
1763 if (right) | 1822 vim_free(p_extra_free2); |
1764 added -= strsize; | 1823 p_extra_free2 = wlv.p_extra; |
1765 if (added < 0 | |
1766 || (below | |
1767 ? wlv.col == 0 || !wp->w_p_wrap | |
1768 : n_used < wlv.n_extra)) | |
1769 added = 0; | |
1770 | |
1771 // With 'nowrap' add one to show the | |
1772 // "extends" character if needed (it | |
1773 // doesn't show it the text just fits). | |
1774 if (!wp->w_p_wrap | |
1775 && n_used < wlv.n_extra | |
1776 && wp->w_lcs_chars.ext != NUL | |
1777 && wp->w_p_list) | |
1778 ++n_used; | |
1779 | |
1780 // add 1 for NUL, 2 for when '…' is used | |
1781 l = alloc(n_used + added + 3); | |
1782 if (l != NULL) | |
1783 { | |
1784 vim_memset(l, ' ', added); | |
1785 vim_strncpy(l + added, wlv.p_extra, | |
1786 n_used); | |
1787 if (n_used < wlv.n_extra | |
1788 && wp->w_p_wrap) | |
1789 { | |
1790 char_u *lp = l + added + n_used - 1; | |
1791 | |
1792 if (has_mbyte) | |
1793 { | |
1794 // change last character to '…' | |
1795 lp -= (*mb_head_off)(l, lp); | |
1796 STRCPY(lp, "…"); | |
1797 n_used = lp - l + 3; | |
1798 } | |
1799 else | |
1800 // change last character to '>' | |
1801 *lp = '>'; | |
1802 } | |
1803 vim_free(p_extra_free2); | |
1804 wlv.p_extra = p_extra_free2 = l; | |
1805 wlv.n_extra = n_used + added; | |
1806 n_attr_skip = added; | |
1807 n_attr = mb_charlen(wlv.p_extra); | |
1808 } | |
1809 } | 1824 } |
1810 | 1825 |
1811 // When 'wrap' is off then for "below" we need | 1826 // When 'wrap' is off then for "below" we need |
1812 // to start a new line explictly. | 1827 // to start a new line explictly. |
1813 if (below && wlv.col > win_col_off(wp) | 1828 if (start_line) |
1814 && !wp->w_p_wrap) | |
1815 { | 1829 { |
1816 draw_screen_line(wp, &wlv); | 1830 draw_screen_line(wp, &wlv); |
1817 | 1831 |
1818 // When line got too long for screen break | 1832 // When line got too long for screen break |
1819 // here. | 1833 // here. |