comparison src/drawline.c @ 29560:14b139cbec49 v9.0.0121

patch 9.0.0121: cannot put virtual text after or below a line Commit: https://github.com/vim/vim/commit/b7963df98f9dbbb824713acad2f47c9989fcf8f3 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Jul 31 17:12:43 2022 +0100 patch 9.0.0121: cannot put virtual text after or below a line Problem: Cannot put virtual text after or below a line. Solution: Add "text_align" and "text_wrap" arguments.
author Bram Moolenaar <Bram@vim.org>
date Sun, 31 Jul 2022 18:15:03 +0200
parents ec5f48ab361b
children f7a64755dbe9
comparison
equal deleted inserted replaced
29559:69ceb540c619 29560:14b139cbec49
206 206
207 static int 207 static int
208 text_prop_compare(const void *s1, const void *s2) 208 text_prop_compare(const void *s1, const void *s2)
209 { 209 {
210 int idx1, idx2; 210 int idx1, idx2;
211 textprop_T *tp1, *tp2;
211 proptype_T *pt1, *pt2; 212 proptype_T *pt1, *pt2;
212 colnr_T col1, col2; 213 colnr_T col1, col2;
213 214
214 idx1 = *(int *)s1; 215 idx1 = *(int *)s1;
215 idx2 = *(int *)s2; 216 idx2 = *(int *)s2;
216 pt1 = text_prop_type_by_id(current_buf, current_text_props[idx1].tp_type); 217 tp1 = &current_text_props[idx1];
217 pt2 = text_prop_type_by_id(current_buf, current_text_props[idx2].tp_type); 218 tp2 = &current_text_props[idx2];
219 pt1 = text_prop_type_by_id(current_buf, tp1->tp_type);
220 pt2 = text_prop_type_by_id(current_buf, tp2->tp_type);
218 if (pt1 == pt2) 221 if (pt1 == pt2)
219 return 0; 222 return 0;
220 if (pt1 == NULL) 223 if (pt1 == NULL)
221 return -1; 224 return -1;
222 if (pt2 == NULL) 225 if (pt2 == NULL)
223 return 1; 226 return 1;
224 if (pt1->pt_priority != pt2->pt_priority) 227 if (pt1->pt_priority != pt2->pt_priority)
225 return pt1->pt_priority > pt2->pt_priority ? 1 : -1; 228 return pt1->pt_priority > pt2->pt_priority ? 1 : -1;
226 col1 = current_text_props[idx1].tp_col; 229 col1 = tp1->tp_col;
227 col2 = current_text_props[idx2].tp_col; 230 col2 = tp2->tp_col;
231 if (col1 == MAXCOL && col2 == MAXCOL)
232 {
233 int flags1 = 0;
234 int flags2 = 0;
235
236 // order on 0: after, 1: right, 2: below
237 if (tp1->tp_flags & TP_FLAG_ALIGN_RIGHT)
238 flags1 = 1;
239 if (tp1->tp_flags & TP_FLAG_ALIGN_BELOW)
240 flags1 = 2;
241 if (tp2->tp_flags & TP_FLAG_ALIGN_RIGHT)
242 flags2 = 1;
243 if (tp2->tp_flags & TP_FLAG_ALIGN_BELOW)
244 flags2 = 2;
245 if (flags1 != flags2)
246 return flags1 < flags2 ? 1 : -1;
247 }
228 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1; 248 return col1 == col2 ? 0 : col1 > col2 ? 1 : -1;
229 } 249 }
230 #endif 250 #endif
231 251
232 /* 252 /*
279 char_u *saved_p_extra = NULL; 299 char_u *saved_p_extra = NULL;
280 int saved_c_extra = 0; 300 int saved_c_extra = 0;
281 int saved_c_final = 0; 301 int saved_c_final = 0;
282 int saved_char_attr = 0; 302 int saved_char_attr = 0;
283 303
284 int n_attr = 0; // chars with special attr 304 int n_attr = 0; // chars with special attr
285 int saved_attr2 = 0; // char_attr saved for n_attr 305 int n_attr_skip = 0; // chars to skip before using extra_attr
286 int n_attr3 = 0; // chars with overruling special attr 306 int saved_attr2 = 0; // char_attr saved for n_attr
287 int saved_attr3 = 0; // char_attr saved for n_attr3 307 int n_attr3 = 0; // chars with overruling special attr
308 int saved_attr3 = 0; // char_attr saved for n_attr3
288 309
289 int n_skip = 0; // nr of chars to skip for 'nowrap' 310 int n_skip = 0; // nr of chars to skip for 'nowrap'
290 311
291 int fromcol = -10; // start of inverting 312 int fromcol = -10; // start of inverting
292 int tocol = MAXCOL; // end of inverting 313 int tocol = MAXCOL; // end of inverting
326 int text_props_active = 0; 347 int text_props_active = 0;
327 proptype_T *text_prop_type = NULL; 348 proptype_T *text_prop_type = NULL;
328 int text_prop_attr = 0; 349 int text_prop_attr = 0;
329 int text_prop_id = 0; // active property ID 350 int text_prop_id = 0; // active property ID
330 int text_prop_combine = FALSE; 351 int text_prop_combine = FALSE;
352 int text_prop_follows = FALSE; // another text prop to display
331 #endif 353 #endif
332 #ifdef FEAT_SPELL 354 #ifdef FEAT_SPELL
333 int has_spell = FALSE; // this buffer has spell checking 355 int has_spell = FALSE; // this buffer has spell checking
334 int can_spell = FALSE; 356 int can_spell = FALSE;
335 # define SPWORDLEN 150 357 # define SPWORDLEN 150
1470 // not on the next char yet, don't start another prop 1492 // not on the next char yet, don't start another prop
1471 --bcol; 1493 --bcol;
1472 # endif 1494 # endif
1473 // Add any text property that starts in this column. 1495 // Add any text property that starts in this column.
1474 while (text_prop_next < text_prop_count 1496 while (text_prop_next < text_prop_count
1475 && bcol >= text_props[text_prop_next].tp_col - 1) 1497 && (text_props[text_prop_next].tp_col == MAXCOL
1498 ? *ptr == NUL
1499 : bcol >= text_props[text_prop_next].tp_col - 1))
1476 { 1500 {
1477 if (bcol <= text_props[text_prop_next].tp_col - 1 1501 if (bcol <= text_props[text_prop_next].tp_col - 1
1478 + text_props[text_prop_next].tp_len) 1502 + text_props[text_prop_next].tp_len)
1479 text_prop_idxs[text_props_active++] = text_prop_next; 1503 text_prop_idxs[text_props_active++] = text_prop_next;
1480 ++text_prop_next; 1504 ++text_prop_next;
1482 1506
1483 text_prop_attr = 0; 1507 text_prop_attr = 0;
1484 text_prop_combine = FALSE; 1508 text_prop_combine = FALSE;
1485 text_prop_type = NULL; 1509 text_prop_type = NULL;
1486 text_prop_id = 0; 1510 text_prop_id = 0;
1487 if (text_props_active > 0) 1511 if (text_props_active > 0 && n_extra == 0)
1488 { 1512 {
1489 int used_tpi = -1; 1513 int used_tpi = -1;
1490 int used_attr = 0; 1514 int used_attr = 0;
1515 int other_tpi = -1;
1491 1516
1492 // Sort the properties on priority and/or starting last. 1517 // Sort the properties on priority and/or starting last.
1493 // Then combine the attributes, highest priority last. 1518 // Then combine the attributes, highest priority last.
1519 text_prop_follows = FALSE;
1494 current_text_props = text_props; 1520 current_text_props = text_props;
1495 current_buf = wp->w_buffer; 1521 current_buf = wp->w_buffer;
1496 qsort((void *)text_prop_idxs, (size_t)text_props_active, 1522 qsort((void *)text_prop_idxs, (size_t)text_props_active,
1497 sizeof(int), text_prop_compare); 1523 sizeof(int), text_prop_compare);
1498 1524
1509 text_prop_type = pt; 1535 text_prop_type = pt;
1510 text_prop_attr = 1536 text_prop_attr =
1511 hl_combine_attr(text_prop_attr, used_attr); 1537 hl_combine_attr(text_prop_attr, used_attr);
1512 text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE; 1538 text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE;
1513 text_prop_id = text_props[tpi].tp_id; 1539 text_prop_id = text_props[tpi].tp_id;
1540 other_tpi = used_tpi;
1514 used_tpi = tpi; 1541 used_tpi = tpi;
1515 } 1542 }
1516 } 1543 }
1517 if (n_extra == 0 && text_prop_id < 0 && used_tpi >= 0 1544 if (text_prop_id < 0 && used_tpi >= 0
1518 && -text_prop_id 1545 && -text_prop_id
1519 <= wp->w_buffer->b_textprop_text.ga_len) 1546 <= wp->w_buffer->b_textprop_text.ga_len)
1520 { 1547 {
1521 char_u *p = ((char_u **)wp->w_buffer 1548 char_u *p = ((char_u **)wp->w_buffer
1522 ->b_textprop_text.ga_data)[ 1549 ->b_textprop_text.ga_data)[
1523 -text_prop_id - 1]; 1550 -text_prop_id - 1];
1524 if (p != NULL) 1551 if (p != NULL)
1525 { 1552 {
1553 int right = (text_props[used_tpi].tp_flags
1554 & TP_FLAG_ALIGN_RIGHT);
1555 int below = (text_props[used_tpi].tp_flags
1556 & TP_FLAG_ALIGN_BELOW);
1557
1526 p_extra = p; 1558 p_extra = p;
1527 c_extra = NUL; 1559 c_extra = NUL;
1528 c_final = NUL; 1560 c_final = NUL;
1529 n_extra = (int)STRLEN(p); 1561 n_extra = (int)STRLEN(p);
1530 extra_attr = used_attr; 1562 extra_attr = used_attr;
1531 n_attr = n_extra; 1563 n_attr = n_extra;
1532 text_prop_attr = 0; 1564 text_prop_attr = 0;
1565 if (*ptr == NUL)
1566 // don't combine char attr after EOL
1567 text_prop_combine = FALSE;
1568
1569 // TODO: truncation if it doesn't fit
1570 if (right || below)
1571 {
1572 int added = wp->w_width - col;
1573 char_u *l;
1574
1575 // Right-align: fill with spaces
1576 // TODO: count screen columns
1577 if (right)
1578 added -= n_extra;
1579 if (added < 0 || (below && col == 0))
1580 added = 0;
1581 l = alloc(n_extra + added + 1);
1582 if (l != NULL)
1583 {
1584 vim_memset(l, ' ', added);
1585 STRCPY(l + added, p);
1586 vim_free(p_extra_free);
1587 p_extra = p_extra_free = l;
1588 n_extra += added;
1589 n_attr_skip = added;
1590 }
1591 }
1533 1592
1534 // If the cursor is on or after this position, 1593 // If the cursor is on or after this position,
1535 // move it forward. 1594 // move it forward.
1536 if (wp == curwin 1595 if (wp == curwin
1537 && lnum == curwin->w_cursor.lnum 1596 && lnum == curwin->w_cursor.lnum
1539 curwin->w_cursor.col += n_extra; 1598 curwin->w_cursor.col += n_extra;
1540 } 1599 }
1541 // reset the ID in the copy to avoid it being used 1600 // reset the ID in the copy to avoid it being used
1542 // again 1601 // again
1543 text_props[used_tpi].tp_id = -MAXCOL; 1602 text_props[used_tpi].tp_id = -MAXCOL;
1603
1604 // If another text prop follows the condition below at
1605 // the last window column must know.
1606 text_prop_follows = other_tpi != -1;
1544 } 1607 }
1545 } 1608 }
1546 } 1609 }
1547 #endif 1610 #endif
1548 1611
2639 curwin->w_flags &= ~(WFLAG_WCOL_OFF_ADDED | WFLAG_WROW_OFF_ADDED); 2702 curwin->w_flags &= ~(WFLAG_WCOL_OFF_ADDED | WFLAG_WROW_OFF_ADDED);
2640 # endif 2703 # endif
2641 } 2704 }
2642 #endif 2705 #endif
2643 2706
2644 // Don't override visual selection highlighting. 2707 // Use "extra_attr", but don't override visual selection highlighting.
2645 if (n_attr > 0 2708 // Don't use "extra_attr" until n_attr_skip is zero.
2709 if (n_attr_skip == 0 && n_attr > 0
2646 && draw_state == WL_LINE 2710 && draw_state == WL_LINE
2647 && !attr_pri) 2711 && !attr_pri)
2648 { 2712 {
2649 #ifdef LINE_ATTR 2713 #ifdef LINE_ATTR
2650 if (line_attr) 2714 if (line_attr)
3186 // restore attributes after "predeces" in 'listchars' 3250 // restore attributes after "predeces" in 'listchars'
3187 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) 3251 if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
3188 char_attr = saved_attr3; 3252 char_attr = saved_attr3;
3189 3253
3190 // restore attributes after last 'listchars' or 'number' char 3254 // restore attributes after last 'listchars' or 'number' char
3191 if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0) 3255 if (n_attr > 0 && draw_state == WL_LINE
3256 && n_attr_skip == 0 && --n_attr == 0)
3192 char_attr = saved_attr2; 3257 char_attr = saved_attr2;
3258 if (n_attr_skip > 0)
3259 --n_attr_skip;
3193 3260
3194 // At end of screen line and there is more to come: Display the line 3261 // At end of screen line and there is more to come: Display the line
3195 // so far. If there is no more to display it is caught above. 3262 // so far. If there is no more to display it is caught above.
3196 if (( 3263 if ((
3197 #ifdef FEAT_RIGHTLEFT 3264 #ifdef FEAT_RIGHTLEFT
3200 (col >= wp->w_width)) 3267 (col >= wp->w_width))
3201 && (draw_state != WL_LINE 3268 && (draw_state != WL_LINE
3202 || *ptr != NUL 3269 || *ptr != NUL
3203 #ifdef FEAT_DIFF 3270 #ifdef FEAT_DIFF
3204 || filler_todo > 0 3271 || filler_todo > 0
3272 #endif
3273 #ifdef FEAT_PROP_POPUP
3274 || text_prop_follows
3205 #endif 3275 #endif
3206 || (wp->w_p_list && wp->w_lcs_chars.eol != NUL 3276 || (wp->w_p_list && wp->w_lcs_chars.eol != NUL
3207 && p_extra != at_end_str) 3277 && p_extra != at_end_str)
3208 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL))) 3278 || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
3209 ) 3279 )
3221 3291
3222 // When not wrapping and finished diff lines, or when displayed 3292 // When not wrapping and finished diff lines, or when displayed
3223 // '$' and highlighting until last column, break here. 3293 // '$' and highlighting until last column, break here.
3224 if ((!wp->w_p_wrap 3294 if ((!wp->w_p_wrap
3225 #ifdef FEAT_DIFF 3295 #ifdef FEAT_DIFF
3226 && filler_todo <= 0 3296 && filler_todo <= 0
3297 #endif
3298 #ifdef FEAT_PROP_POPUP
3299 && !text_prop_follows
3227 #endif 3300 #endif
3228 ) || lcs_eol_one == -1) 3301 ) || lcs_eol_one == -1)
3229 break; 3302 break;
3230 3303
3231 // When the window is too narrow draw all "@" lines. 3304 // When the window is too narrow draw all "@" lines.
3248 } 3321 }
3249 3322
3250 if (screen_cur_row == screen_row - 1 3323 if (screen_cur_row == screen_row - 1
3251 #ifdef FEAT_DIFF 3324 #ifdef FEAT_DIFF
3252 && filler_todo <= 0 3325 && filler_todo <= 0
3326 #endif
3327 #ifdef FEAT_PROP_POPUP
3328 && !text_prop_follows
3253 #endif 3329 #endif
3254 && wp->w_width == Columns) 3330 && wp->w_width == Columns)
3255 { 3331 {
3256 // Remember that the line wraps, used for modeless copy. 3332 // Remember that the line wraps, used for modeless copy.
3257 LineWraps[screen_row - 1] = TRUE; 3333 LineWraps[screen_row - 1] = TRUE;