comparison src/charset.c @ 29678:fc0f93590fd4 v9.0.0179

patch 9.0.0179: cursor pos wrong with wrapping virtual text in empty line Commit: https://github.com/vim/vim/commit/49a90792d950c51608d0459ef8699fe921070718 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Aug 9 18:25:23 2022 +0100 patch 9.0.0179: cursor pos wrong with wrapping virtual text in empty line Problem: Cursor position wrong with wrapping virtual text in empty line. Solution: Adjust handling of an empty line. (closes https://github.com/vim/vim/issues/10875)
author Bram Moolenaar <Bram@vim.org>
date Tue, 09 Aug 2022 19:30:03 +0200
parents b4fea827c20a
children 538204fce2a4
comparison
equal deleted inserted replaced
29677:d8ad7b1e9116 29678:fc0f93590fd4
757 chartabsize_T cts; 757 chartabsize_T cts;
758 758
759 init_chartabsize_arg(&cts, curwin, 0, startcol, s, s); 759 init_chartabsize_arg(&cts, curwin, 0, startcol, s, s);
760 while (*cts.cts_ptr != NUL) 760 while (*cts.cts_ptr != NUL)
761 cts.cts_vcol += lbr_chartabsize_adv(&cts); 761 cts.cts_vcol += lbr_chartabsize_adv(&cts);
762 #ifdef FEAT_PROP_POPUP
763 if (cts.cts_has_prop_with_text && cts.cts_ptr == cts.cts_line)
764 {
765 // check for virtual text in an empty line
766 (void)lbr_chartabsize_adv(&cts);
767 cts.cts_vcol += cts.cts_cur_text_width;
768 }
769 #endif
762 clear_chartabsize_arg(&cts); 770 clear_chartabsize_arg(&cts);
763 return (int)cts.cts_vcol; 771 return (int)cts.cts_vcol;
764 } 772 }
765 773
766 /* 774 /*
770 win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len) 778 win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len)
771 { 779 {
772 chartabsize_T cts; 780 chartabsize_T cts;
773 781
774 init_chartabsize_arg(&cts, wp, lnum, 0, line, line); 782 init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
775 #ifdef FEAT_PROP_POPUP 783 win_linetabsize_cts(&cts, len);
776 cts.cts_with_trailing = len == MAXCOL;
777 #endif
778 for ( ; *cts.cts_ptr != NUL && (len == MAXCOL || cts.cts_ptr < line + len);
779 MB_PTR_ADV(cts.cts_ptr))
780 cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
781 clear_chartabsize_arg(&cts); 784 clear_chartabsize_arg(&cts);
782 return (int)cts.cts_vcol; 785 return (int)cts.cts_vcol;
786 }
787
788 void
789 win_linetabsize_cts(chartabsize_T *cts, colnr_T len)
790 {
791 #ifdef FEAT_PROP_POPUP
792 cts->cts_with_trailing = len == MAXCOL;
793 #endif
794 for ( ; *cts->cts_ptr != NUL && (len == MAXCOL || cts->cts_ptr < cts->cts_line + len);
795 MB_PTR_ADV(cts->cts_ptr))
796 cts->cts_vcol += win_lbr_chartabsize(cts, NULL);
797 #ifdef FEAT_PROP_POPUP
798 // check for a virtual text on an empty line
799 if (cts->cts_has_prop_with_text && *cts->cts_ptr == NUL
800 && cts->cts_ptr == cts->cts_line)
801 {
802 (void)win_lbr_chartabsize(cts, NULL);
803 cts->cts_vcol += cts->cts_cur_text_width;
804 }
805 #endif
783 } 806 }
784 807
785 /* 808 /*
786 * Return TRUE if 'c' is a normal identifier character: 809 * Return TRUE if 'c' is a normal identifier character:
787 * Letters and characters from the 'isident' option. 810 * Letters and characters from the 'isident' option.
1126 * First get the normal size, without 'linebreak' or text properties 1149 * First get the normal size, without 'linebreak' or text properties
1127 */ 1150 */
1128 size = win_chartabsize(wp, s, vcol); 1151 size = win_chartabsize(wp, s, vcol);
1129 1152
1130 # ifdef FEAT_PROP_POPUP 1153 # ifdef FEAT_PROP_POPUP
1131 if (cts->cts_has_prop_with_text && *line != NUL) 1154 if (cts->cts_has_prop_with_text)
1132 { 1155 {
1133 int tab_size = size; 1156 int tab_size = size;
1134 int charlen = mb_ptr2len(s); 1157 int charlen = *s == NUL ? 1 : mb_ptr2len(s);
1135 int i; 1158 int i;
1136 int col = (int)(s - line); 1159 int col = (int)(s - line);
1137 garray_T *gap = &wp->w_buffer->b_textprop_text; 1160 garray_T *gap = &wp->w_buffer->b_textprop_text;
1138 1161
1139 for (i = 0; i < cts->cts_text_prop_count; ++i) 1162 for (i = 0; i < cts->cts_text_prop_count; ++i)
1410 int *vts = wp->w_buffer->b_p_vts_array; 1433 int *vts = wp->w_buffer->b_p_vts_array;
1411 #endif 1434 #endif
1412 int ts = wp->w_buffer->b_p_ts; 1435 int ts = wp->w_buffer->b_p_ts;
1413 int c; 1436 int c;
1414 chartabsize_T cts; 1437 chartabsize_T cts;
1438 #ifdef FEAT_PROP_POPUP
1439 int on_NUL = FALSE;
1440 #endif
1415 1441
1416 vcol = 0; 1442 vcol = 0;
1417 line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE); 1443 line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
1418 if (pos->col == MAXCOL) 1444 if (pos->col == MAXCOL)
1419 posptr = NULL; // continue until the NUL 1445 posptr = NULL; // continue until the NUL
1510 incr = win_lbr_chartabsize(&cts, &head); 1536 incr = win_lbr_chartabsize(&cts, &head);
1511 // make sure we don't go past the end of the line 1537 // make sure we don't go past the end of the line
1512 if (*cts.cts_ptr == NUL) 1538 if (*cts.cts_ptr == NUL)
1513 { 1539 {
1514 incr = 1; // NUL at end of line only takes one column 1540 incr = 1; // NUL at end of line only takes one column
1541 #ifdef FEAT_PROP_POPUP
1542 if (cts.cts_cur_text_width > 0)
1543 incr = cts.cts_cur_text_width;
1544 on_NUL = TRUE;
1545 #endif
1515 break; 1546 break;
1516 } 1547 }
1517 1548
1518 if (posptr != NULL && cts.cts_ptr >= posptr) 1549 if (posptr != NULL && cts.cts_ptr >= posptr)
1519 // character at pos->col 1550 // character at pos->col
1542 ) 1573 )
1543 *cursor = vcol + incr - 1; // cursor at end 1574 *cursor = vcol + incr - 1; // cursor at end
1544 else 1575 else
1545 { 1576 {
1546 #ifdef FEAT_PROP_POPUP 1577 #ifdef FEAT_PROP_POPUP
1547 if ((State & MODE_INSERT) == 0) 1578 if ((State & MODE_INSERT) == 0 && !on_NUL)
1548 // cursor is after inserted text 1579 // cursor is after inserted text, unless on the NUL
1549 vcol += cts.cts_cur_text_width; 1580 vcol += cts.cts_cur_text_width;
1550 #endif 1581 #endif
1551 *cursor = vcol + head; // cursor at start 1582 *cursor = vcol + head; // cursor at start
1552 } 1583 }
1553 } 1584 }