@@ -1213,13 +1213,19 @@ win_line(
12131213 int save_did_emsg ;
12141214#endif
12151215#ifdef FEAT_PROP_POPUP
1216+ # define WIN_LINE_TEXT_PROP_STACK_LEN 32
12161217 int did_line = FALSE; // set to TRUE when line text done
12171218 int text_prop_count ;
12181219 int last_textprop_text_idx = -1 ;
12191220 int text_prop_next = 0 ; // next text property to use
1221+ textprop_T text_props_buf [WIN_LINE_TEXT_PROP_STACK_LEN ];
1222+ int text_prop_idxs_buf [WIN_LINE_TEXT_PROP_STACK_LEN ];
1223+ char_u text_prop_suffix_flags_buf [WIN_LINE_TEXT_PROP_STACK_LEN + 1 ];
12201224 textprop_T * text_props = NULL ;
12211225 int * text_prop_idxs = NULL ;
1226+ char_u * text_prop_suffix_flags = NULL ;
12221227 int text_props_active = 0 ;
1228+ int text_props_need_sort = FALSE;
12231229 proptype_T * text_prop_type = NULL ;
12241230 int text_prop_attr = 0 ;
12251231 int text_prop_attr_comb = 0 ; // text_prop_attr combined with
@@ -1694,15 +1700,40 @@ win_line(
16941700 {
16951701 // Make a copy of the properties, so that they are properly
16961702 // aligned.
1697- text_props = ALLOC_MULT (textprop_T , text_prop_count );
1703+ if (text_prop_count <= WIN_LINE_TEXT_PROP_STACK_LEN )
1704+ text_props = text_props_buf ;
1705+ else
1706+ text_props = ALLOC_MULT (textprop_T , text_prop_count );
16981707 if (text_props != NULL )
16991708 mch_memmove (text_props , prop_start ,
17001709 text_prop_count * sizeof (textprop_T ));
17011710
17021711 // Allocate an array for the indexes.
1703- text_prop_idxs = ALLOC_MULT (int , text_prop_count );
1712+ if (text_prop_count <= WIN_LINE_TEXT_PROP_STACK_LEN )
1713+ text_prop_idxs = text_prop_idxs_buf ;
1714+ else
1715+ text_prop_idxs = ALLOC_MULT (int , text_prop_count );
17041716 if (text_prop_idxs == NULL )
1705- VIM_CLEAR (text_props );
1717+ {
1718+ if (text_props != text_props_buf )
1719+ VIM_CLEAR (text_props );
1720+ else
1721+ text_props = NULL ;
1722+ }
1723+ if (text_prop_count <= WIN_LINE_TEXT_PROP_STACK_LEN )
1724+ text_prop_suffix_flags = text_prop_suffix_flags_buf ;
1725+ else
1726+ text_prop_suffix_flags = ALLOC_MULT (char_u , text_prop_count + 1 );
1727+ if (text_prop_suffix_flags == NULL )
1728+ {
1729+ if (text_prop_idxs != text_prop_idxs_buf )
1730+ vim_free (text_prop_idxs );
1731+ text_prop_idxs = NULL ;
1732+ if (text_props != text_props_buf )
1733+ VIM_CLEAR (text_props );
1734+ else
1735+ text_props = NULL ;
1736+ }
17061737
17071738 if (text_props != NULL )
17081739 {
@@ -1736,6 +1767,20 @@ win_line(
17361767 else
17371768 ++ wlv .text_prop_above_count ;
17381769 }
1770+
1771+ text_prop_suffix_flags [text_prop_count ] = 0 ;
1772+ for (int i = text_prop_count - 1 ; i >= 0 ; -- i )
1773+ {
1774+ int flags = text_prop_suffix_flags [i + 1 ];
1775+
1776+ if (text_props [i ].tp_col == MAXCOL )
1777+ {
1778+ flags |= 1 ;
1779+ if (text_props [i ].tp_flags & TP_FLAG_ALIGN_BELOW )
1780+ flags |= 2 ;
1781+ }
1782+ text_prop_suffix_flags [i ] = flags ;
1783+ }
17391784 }
17401785 }
17411786
@@ -1745,8 +1790,12 @@ win_line(
17451790 wlv .row += wlv .text_prop_above_count ;
17461791 if (wlv .row >= endrow )
17471792 {
1748- vim_free (text_props );
1749- vim_free (text_prop_idxs );
1793+ if (text_props != text_props_buf )
1794+ vim_free (text_props );
1795+ if (text_prop_idxs != text_prop_idxs_buf )
1796+ vim_free (text_prop_idxs );
1797+ if (text_prop_suffix_flags != text_prop_suffix_flags_buf )
1798+ vim_free (text_prop_suffix_flags );
17501799 return wlv .row ;
17511800 }
17521801 wlv .screen_row += wlv .text_prop_above_count ;
@@ -2122,6 +2171,7 @@ win_line(
21222171 sizeof (int )
21232172 * (text_props_active - (pi + 1 )));
21242173 -- text_props_active ;
2174+ text_props_need_sort = TRUE;
21252175 -- pi ;
21262176# ifdef FEAT_LINEBREAK
21272177 // not exactly right but should work in most cases
@@ -2164,7 +2214,10 @@ win_line(
21642214 }
21652215
21662216 if (active )
2217+ {
21672218 text_prop_idxs [text_props_active ++ ] = text_prop_next ;
2219+ text_props_need_sort = TRUE;
2220+ }
21682221 ++ text_prop_next ;
21692222 }
21702223
@@ -2190,10 +2243,14 @@ win_line(
21902243 text_prop_above = FALSE;
21912244 text_prop_follows = FALSE;
21922245
2193- // Sort the properties on priority and/or starting last.
2194- // Then combine the attributes, highest priority last.
2195- sort_text_props (wp -> w_buffer , text_props ,
2196- text_prop_idxs , text_props_active );
2246+ if (text_props_need_sort )
2247+ {
2248+ // The active set only changes when a property starts
2249+ // or ends, so avoid sorting again for every column.
2250+ sort_text_props (wp -> w_buffer , text_props ,
2251+ text_prop_idxs , text_props_active );
2252+ text_props_need_sort = FALSE;
2253+ }
21972254
21982255 for (pi = 0 ; pi < text_props_active ; ++ pi )
21992256 {
@@ -2402,19 +2459,10 @@ win_line(
24022459 // Or when not wrapping and at the rightmost column.
24032460
24042461 int only_below_follows = !wp -> w_p_wrap && wlv .col == wp -> w_width - 1 ;
2405- // TODO: Store "after"/"right"/"below" text properties in order
2406- // in the buffer so only `text_props[text_prop_count - 1]`
2407- // needs to be checked for following "below" virtual text
2408- for (int i = text_prop_next ; i < text_prop_count ; ++ i )
2409- {
2410- if (text_props [i ].tp_col == MAXCOL
2411- && (!only_below_follows
2412- || (text_props [i ].tp_flags & TP_FLAG_ALIGN_BELOW )))
2413- {
2414- text_prop_follows = TRUE;
2415- break ;
2416- }
2417- }
2462+ int suffix_flags = text_prop_suffix_flags [text_prop_next ];
2463+
2464+ text_prop_follows = (suffix_flags
2465+ & (only_below_follows ? 2 : 1 )) != 0 ;
24182466 }
24192467 }
24202468
@@ -4500,8 +4548,12 @@ win_line(
45004548
45014549 } // for every character in the line
45024550#ifdef FEAT_PROP_POPUP
4503- vim_free (text_props );
4504- vim_free (text_prop_idxs );
4551+ if (text_props != text_props_buf )
4552+ vim_free (text_props );
4553+ if (text_prop_idxs != text_prop_idxs_buf )
4554+ vim_free (text_prop_idxs );
4555+ if (text_prop_suffix_flags != text_prop_suffix_flags_buf )
4556+ vim_free (text_prop_suffix_flags );
45054557 vim_free (p_extra_free2 );
45064558#endif
45074559
0 commit comments