Patch 9.0.0067
Problem: Cannot show virtual text.
Solution: Initial changes for virtual text support, using text properties.
Files: runtime/doc/textprop.txt, src/beval.c, src/charset.c,
src/drawline.c, src/edit.c, src/errors.h, src/evalfunc.c,
src/getchar.c, src/indent.c, src/misc1.c, src/misc2.c,
src/mouse.c, src/ops.c, src/popupwin.c, src/proto/
charset.pro,
src/proto/
textprop.pro, src/regexp.c, src/regexp_bt.c,
src/regexp_nfa.c, src/register.c, src/structs.h, src/textprop.c,
src/testdir/test_textprop.vim,
src/testdir/dumps/Test_prop_inserts_text.dump
*** ../vim-9.0.0066/runtime/doc/textprop.txt 2022-06-28 11:21:06.000000000 +0100
--- runtime/doc/textprop.txt 2022-07-25 15:42:47.103101003 +0100
***************
*** 137,143 ****
bufnr buffer to add the property to; when omitted
the current buffer is used
id user defined ID for the property; must be a
! number; when omitted zero is used
type name of the text property type
All fields except "type" are optional.
--- 137,147 ----
bufnr buffer to add the property to; when omitted
the current buffer is used
id user defined ID for the property; must be a
! number, should be positive; when using "text"
! then "id" must not be present and will be set
! automatically to a negative number; otherwise
! zero is used
! text text to be displayed at {col}
type name of the text property type
All fields except "type" are optional.
***************
*** 157,162 ****
--- 161,177 ----
"type" will first be looked up in the buffer the property is
added to. When not found, the global property types are used.
If not found an error is given.
+ *virtual-text*
+ When "text" is used this text will be displayed at the start
+ location of the text property. The text of the buffer line
+ will be shifted to make room. This is called "virtual text".
+ The text will be displayed but it is not part of the actual
+ buffer line, the cursor cannot be placed on it. A mouse click
+ in the text will move the cursor to the first character after
+ the text.
+ A negative "id" will be chosen and is returned. Once a
+ property with "text" has been added for a buffer then using a
+ negative "id" for any other property will give an error.
Can also be used as a |method|: >
GetLnum()->prop_add(col, props)
***************
*** 181,186 ****
--- 196,204 ----
two items {end-lnum} and {end-col} specify the position just
after the text.
+ It is not possible to add a text property with a "text" field
+ here.
+
Example:
call prop_add_list(#{type: 'MyProp', id: 2},
\ [[1, 4, 1, 7],
*** ../vim-9.0.0066/src/beval.c 2022-05-27 17:18:23.000000000 +0100
--- src/beval.c 2022-07-25 15:42:47.103101003 +0100
***************
*** 47,53 ****
{
// Not past end of the file.
lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
! if (col <= win_linetabsize(wp, lbuf, (colnr_T)MAXCOL))
{
// Not past end of line.
if (getword)
--- 47,53 ----
{
// Not past end of the file.
lbuf = ml_get_buf(wp->w_buffer, lnum, FALSE);
! if (col <= win_linetabsize(wp, lnum, lbuf, (colnr_T)MAXCOL))
{
// Not past end of line.
if (getword)
*** ../vim-9.0.0066/src/charset.c 2022-05-22 19:57:32.000000000 +0100
--- src/charset.c 2022-07-25 16:54:09.730345955 +0100
***************
*** 12,19 ****
#if defined(HAVE_WCHAR_H)
# include <wchar.h> // for towupper() and towlower()
#endif
- static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp);
static unsigned nr2hex(unsigned c);
static int chartab_initialized = FALSE;
--- 12,19 ----
#if defined(HAVE_WCHAR_H)
# include <wchar.h> // for towupper() and towlower()
#endif
+ static int win_nolbr_chartabsize(chartabsize_T *cts, int *headp);
static unsigned nr2hex(unsigned c);
static int chartab_initialized = FALSE;
***************
*** 737,744 ****
#endif
/*
! * Return the number of characters the string 's' will take on the screen,
* taking into account the size of a tab.
*/
int
linetabsize(char_u *s)
--- 737,745 ----
#endif
/*
! * Return the number of characters the string "s" will take on the screen,
* taking into account the size of a tab.
+ * Does not handle text properties, since "s" is not a buffer line.
*/
int
linetabsize(char_u *s)
***************
*** 747,778 ****
}
/*
! * Like linetabsize(), but starting at column "startcol".
*/
int
linetabsize_col(int startcol, char_u *s)
{
! colnr_T col = startcol;
! char_u *line = s; // pointer to start of line, for breakindent
! while (*s != NUL)
! col += lbr_chartabsize_adv(line, &s, col);
! return (int)col;
}
/*
* Like linetabsize(), but for a given window instead of the current one.
*/
int
! win_linetabsize(win_T *wp, char_u *line, colnr_T len)
{
! colnr_T col = 0;
! char_u *s;
! for (s = line; *s != NUL && (len == MAXCOL || s < line + len);
! MB_PTR_ADV(s))
! col += win_lbr_chartabsize(wp, line, s, col, NULL);
! return (int)col;
}
/*
--- 748,781 ----
}
/*
! * Like linetabsize(), but "s" starts at column "startcol".
*/
int
linetabsize_col(int startcol, char_u *s)
{
! chartabsize_T cts;
! init_chartabsize_arg(&cts, curwin, 0, startcol, s, s);
! while (*cts.cts_ptr != NUL)
! cts.cts_vcol += lbr_chartabsize_adv(&cts);
! clear_chartabsize_arg(&cts);
! return (int)cts.cts_vcol;
}
/*
* Like linetabsize(), but for a given window instead of the current one.
*/
int
! win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len)
{
! chartabsize_T cts;
! init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
! for ( ; *cts.cts_ptr != NUL && (len == MAXCOL || cts.cts_ptr < line + len);
! MB_PTR_ADV(cts.cts_ptr))
! cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
! clear_chartabsize_arg(&cts);
! return (int)cts.cts_vcol;
}
/*
***************
*** 893,917 ****
}
/*
! * like chartabsize(), but also check for line breaks on the screen
*/
int
! lbr_chartabsize(
! char_u *line UNUSED, // start of the line
! unsigned char *s,
! colnr_T col)
{
! #ifdef FEAT_LINEBREAK
! if (!curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL
! && !curwin->w_p_bri)
{
#endif
if (curwin->w_p_wrap)
! return win_nolbr_chartabsize(curwin, s, col, NULL);
! RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
! #ifdef FEAT_LINEBREAK
}
! return win_lbr_chartabsize(curwin, line == NULL ? s : line, s, col, NULL);
#endif
}
--- 896,996 ----
}
/*
! * Prepare the structure passed to chartabsize functions.
! * "line" is the start of the line, "ptr" is the first relevant character.
! * When "lnum" is zero do not use text properties that insert text.
! */
! void
! init_chartabsize_arg(
! chartabsize_T *cts,
! win_T *wp,
! linenr_T lnum,
! colnr_T col,
! char_u *line,
! char_u *ptr)
! {
! cts->cts_win = wp;
! cts->cts_lnum = lnum;
! cts->cts_vcol = col;
! cts->cts_line = line;
! cts->cts_ptr = ptr;
! #ifdef FEAT_PROP_POPUP
! cts->cts_text_prop_count = 0;
! cts->cts_has_prop_with_text = FALSE;
! cts->cts_cur_text_width = 0;
! if (lnum > 0)
! {
! char_u *prop_start;
!
! cts->cts_text_prop_count = get_text_props(wp->w_buffer, lnum,
! &prop_start, FALSE);
! if (cts->cts_text_prop_count > 0)
! {
! // Make a copy of the properties, so that they are properly
! // aligned.
! cts->cts_text_props = ALLOC_MULT(textprop_T,
! cts->cts_text_prop_count);
! if (cts->cts_text_props == NULL)
! cts->cts_text_prop_count = 0;
! else
! {
! int i;
!
! mch_memmove(cts->cts_text_props, prop_start,
! cts->cts_text_prop_count * sizeof(textprop_T));
! for (i = 0; i < cts->cts_text_prop_count; ++i)
! if (cts->cts_text_props[i].tp_id < 0)
! {
! cts->cts_has_prop_with_text = TRUE;
! break;
! }
! if (!cts->cts_has_prop_with_text)
! {
! // won't use the text properties, free them
! vim_free(cts->cts_text_props);
! cts->cts_text_prop_count = 0;
! }
! }
! }
! }
! #endif
! }
!
! /*
! * Free any allocated item in "cts".
! */
! void
! clear_chartabsize_arg(chartabsize_T *cts)
! {
! if (cts->cts_text_prop_count > 0)
! vim_free(cts->cts_text_props);
! }
!
! /*
! * Like chartabsize(), but also check for line breaks on the screen and text
! * properties that insert text.
*/
int
! lbr_chartabsize(chartabsize_T *cts)
{
! #if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP)
! if (1
! # ifdef FEAT_LINEBREAK
! && !curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL
! && !curwin->w_p_bri
! # endif
! # ifdef FEAT_PROP_POPUP
! && !cts->cts_has_prop_with_text
! #endif
! )
{
#endif
if (curwin->w_p_wrap)
! return win_nolbr_chartabsize(cts, NULL);
! RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, cts->cts_ptr, cts->cts_vcol)
! #if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP)
}
! return win_lbr_chartabsize(cts, NULL);
#endif
}
***************
*** 919,937 ****
* Call lbr_chartabsize() and advance the pointer.
*/
int
! lbr_chartabsize_adv(
! char_u *line, // start of the line
! char_u **s,
! colnr_T col)
{
int retval;
! retval = lbr_chartabsize(line, *s, col);
! MB_PTR_ADV(*s);
return retval;
}
/*
* This function is used very often, keep it fast!!!!
*
* If "headp" not NULL, set *headp to the size of what we for 'showbreak'
--- 998,1016 ----
* Call lbr_chartabsize() and advance the pointer.
*/
int
! lbr_chartabsize_adv(chartabsize_T *cts)
{
int retval;
! retval = lbr_chartabsize(cts);
! MB_PTR_ADV(cts->cts_ptr);
return retval;
}
/*
+ * Return the screen size of the character indicated by "cts".
+ * "cts->cts_cur_text_width" is set to the extra size for a text property that
+ * inserts text.
* This function is used very often, keep it fast!!!!
*
* If "headp" not NULL, set *headp to the size of what we for 'showbreak'
***************
*** 940,956 ****
*/
int
win_lbr_chartabsize(
! win_T *wp,
! char_u *line UNUSED, // start of the line
! char_u *s,
! colnr_T col,
! int *headp UNUSED)
{
#ifdef FEAT_LINEBREAK
int c;
int size;
colnr_T col2;
! colnr_T col_adj = 0; // col + screen size of tab
colnr_T colmax;
int added;
int mb_added = 0;
--- 1019,1036 ----
*/
int
win_lbr_chartabsize(
! chartabsize_T *cts,
! int *headp UNUSED)
{
+ win_T *wp = cts->cts_win;
+ char_u *line = cts->cts_line; // start of the line
+ char_u *s = cts->cts_ptr;
+ colnr_T vcol = cts->cts_vcol;
#ifdef FEAT_LINEBREAK
int c;
int size;
colnr_T col2;
! colnr_T col_adj = 0; // vcol + screen size of tab
colnr_T colmax;
int added;
int mb_added = 0;
***************
*** 959,981 ****
int tab_corr = (*s == TAB);
int n;
char_u *sbr;
/*
! * No 'linebreak', 'showbreak' and 'breakindent': return quickly.
*/
! if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL)
#endif
{
if (wp->w_p_wrap)
! return win_nolbr_chartabsize(wp, s, col, headp);
! RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col)
}
! #ifdef FEAT_LINEBREAK
/*
! * First get normal size, without 'linebreak'
*/
! size = win_chartabsize(wp, s, col);
c = *s;
if (tab_corr)
col_adj = size - 1;
--- 1039,1104 ----
int tab_corr = (*s == TAB);
int n;
char_u *sbr;
+ #endif
+
+ #if defined(FEAT_PROP_POPUP)
+ cts->cts_cur_text_width = 0;
+ #endif
+ #if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP)
/*
! * No 'linebreak', 'showbreak', 'breakindent' and text properties that
! * insert text: return quickly.
*/
! if (1
! # ifdef FEAT_LINEBREAK
! && !wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL
! # endif
! # ifdef FEAT_PROP_POPUP
! && !cts->cts_has_prop_with_text
! # endif
! )
#endif
{
if (wp->w_p_wrap)
! return win_nolbr_chartabsize(cts, headp);
! RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, vcol)
}
! #if defined(FEAT_LINEBREAK) || defined(FEAT_PROP_POPUP)
/*
! * First get the normal size, without 'linebreak' or text properties
*/
! size = win_chartabsize(wp, s, vcol);
!
! # ifdef FEAT_PROP_POPUP
! if (cts->cts_has_prop_with_text)
! {
! int i;
! int col = (int)(s - line);
!
! for (i = 0; i < cts->cts_text_prop_count; ++i)
! {
! textprop_T *tp = cts->cts_text_props + i;
!
! if (tp->tp_id < 0
! && tp->tp_col - 1 >= col && tp->tp_col - 1 < col + size
! && -tp->tp_id <= wp->w_buffer->b_textprop_text.ga_len)
! {
! char_u *p = ((char_u **)wp->w_buffer->b_textprop_text.ga_data)[
! -tp->tp_id - 1];
! // TODO: count screen cells
! cts->cts_cur_text_width = STRLEN(p);
! size += cts->cts_cur_text_width;
! break;
! }
! if (tp->tp_col - 1 > col)
! break;
! }
! }
! # endif
!
! # ifdef FEAT_LINEBREAK
c = *s;
if (tab_corr)
col_adj = size - 1;
***************
*** 995,1008 ****
* non-blank after a blank.
*/
numberextra = win_col_off(wp);
! col2 = col;
colmax = (colnr_T)(wp->w_width - numberextra - col_adj);
! if (col >= colmax)
{
colmax += col_adj;
n = colmax + win_col_off2(wp);
if (n > 0)
! colmax += (((col - colmax) / n) + 1) * n - col_adj;
}
for (;;)
--- 1118,1131 ----
* non-blank after a blank.
*/
numberextra = win_col_off(wp);
! col2 = vcol;
colmax = (colnr_T)(wp->w_width - numberextra - col_adj);
! if (vcol >= colmax)
{
colmax += col_adj;
n = colmax + win_col_off2(wp);
if (n > 0)
! colmax += (((vcol - colmax) / n) + 1) * n - col_adj;
}
for (;;)
***************
*** 1013,1031 ****
if (!(c != NUL
&& (VIM_ISBREAK(c)
|| (!VIM_ISBREAK(c)
! && (col2 == col || !VIM_ISBREAK((int)*ps))))))
break;
col2 += win_chartabsize(wp, s, col2);
if (col2 >= colmax) // doesn't fit
{
! size = colmax - col + col_adj;
break;
}
}
}
else if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1
! && wp->w_p_wrap && in_win_border(wp, col))
{
++size; // Count the ">" in the last column.
mb_added = 1;
--- 1136,1154 ----
if (!(c != NUL
&& (VIM_ISBREAK(c)
|| (!VIM_ISBREAK(c)
! && (col2 == vcol || !VIM_ISBREAK((int)*ps))))))
break;
col2 += win_chartabsize(wp, s, col2);
if (col2 >= colmax) // doesn't fit
{
! size = colmax - vcol + col_adj;
break;
}
}
}
else if (has_mbyte && size == 2 && MB_BYTE2LEN(*s) > 1
! && wp->w_p_wrap && in_win_border(wp, vcol))
{
++size; // Count the ">" in the last column.
mb_added = 1;
***************
*** 1039,1071 ****
*/
added = 0;
sbr = c == NUL ? empty_option : get_showbreak_value(wp);
! if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && col != 0)
{
colnr_T sbrlen = 0;
int numberwidth = win_col_off(wp);
numberextra = numberwidth;
! col += numberextra + mb_added;
! if (col >= (colnr_T)wp->w_width)
{
! col -= wp->w_width;
numberextra = wp->w_width - (numberextra - win_col_off2(wp));
! if (col >= numberextra && numberextra > 0)
! col %= numberextra;
if (*sbr != NUL)
{
sbrlen = (colnr_T)MB_CHARLEN(sbr);
! if (col >= sbrlen)
! col -= sbrlen;
}
! if (col >= numberextra && numberextra > 0)
! col = col % numberextra;
! else if (col > 0 && numberextra > 0)
! col += numberwidth - win_col_off2(wp);
numberwidth -= win_col_off2(wp);
}
! if (col == 0 || col + size + sbrlen > (colnr_T)wp->w_width)
{
added = 0;
if (*sbr != NUL)
--- 1162,1194 ----
*/
added = 0;
sbr = c == NUL ? empty_option : get_showbreak_value(wp);
! if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0)
{
colnr_T sbrlen = 0;
int numberwidth = win_col_off(wp);
numberextra = numberwidth;
! vcol += numberextra + mb_added;
! if (vcol >= (colnr_T)wp->w_width)
{
! vcol -= wp->w_width;
numberextra = wp->w_width - (numberextra - win_col_off2(wp));
! if (vcol >= numberextra && numberextra > 0)
! vcol %= numberextra;
if (*sbr != NUL)
{
sbrlen = (colnr_T)MB_CHARLEN(sbr);
! if (vcol >= sbrlen)
! vcol -= sbrlen;
}
! if (vcol >= numberextra && numberextra > 0)
! vcol = vcol % numberextra;
! else if (vcol > 0 && numberextra > 0)
! vcol += numberwidth - win_col_off2(wp);
numberwidth -= win_col_off2(wp);
}
! if (vcol == 0 || vcol + size + sbrlen > (colnr_T)wp->w_width)
{
added = 0;
if (*sbr != NUL)
***************
*** 1074,1081 ****
{
// calculate effective window width
int width = (colnr_T)wp->w_width - sbrlen - numberwidth;
! int prev_width = col
! ? ((colnr_T)wp->w_width - (sbrlen + col)) : 0;
if (width <= 0)
width = (colnr_T)1;
--- 1197,1204 ----
{
// calculate effective window width
int width = (colnr_T)wp->w_width - sbrlen - numberwidth;
! int prev_width = vcol
! ? ((colnr_T)wp->w_width - (sbrlen + vcol)) : 0;
if (width <= 0)
width = (colnr_T)1;
***************
*** 1091,1118 ****
added += get_breakindent_win(wp, line);
size += added;
! if (col != 0)
added = 0;
}
}
if (headp != NULL)
*headp = added + mb_added;
return size;
#endif
}
/*
! * Like win_lbr_chartabsize(), except that we know 'linebreak' is off and
! * 'wrap' is on. This means we need to check for a double-byte character that
! * doesn't fit at the end of the screen line.
*/
static int
win_nolbr_chartabsize(
! win_T *wp,
! char_u *s,
! colnr_T col,
! int *headp)
{
int n;
if (*s == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1))
--- 1214,1245 ----
added += get_breakindent_win(wp, line);
size += added;
! if (vcol != 0)
added = 0;
}
}
if (headp != NULL)
*headp = added + mb_added;
return size;
+ # endif
#endif
}
/*
! * Like win_lbr_chartabsize(), except that we know 'linebreak' is off, 'wrap'
! * is on and there are no properties that insert text. This means we need to
! * check for a double-byte character that doesn't fit at the end of the screen
! * line.
! * Only uses "cts_win", "cts_ptr" and "cts_vcol" from "cts".
*/
static int
win_nolbr_chartabsize(
! chartabsize_T *cts,
! int *headp)
{
+ win_T *wp = cts->cts_win;
+ char_u *s = cts->cts_ptr;
+ colnr_T col = cts->cts_vcol;
int n;
if (*s == TAB && (!wp->w_p_list || wp->w_lcs_chars.tab1))
***************
*** 1187,1192 ****
--- 1314,1320 ----
#endif
int ts = wp->w_buffer->b_p_ts;
int c;
+ chartabsize_T cts;
vcol = 0;
line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
***************
*** 1209,1224 ****
posptr -= (*mb_head_off)(line, posptr);
}
/*
* This function is used very often, do some speed optimizations.
* When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set
! * use a simple loop.
* Also use this when 'list' is set but tabs take their normal size.
*/
if ((!wp->w_p_list || wp->w_lcs_chars.tab1 != NUL)
#ifdef FEAT_LINEBREAK
&& !wp->w_p_lbr && *get_showbreak_value(wp) == NUL && !wp->w_p_bri
#endif
)
{
for (;;)
--- 1337,1357 ----
posptr -= (*mb_head_off)(line, posptr);
}
+ init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line);
+
/*
* This function is used very often, do some speed optimizations.
* When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set
! * and there are no text properties with "text" use a simple loop.
* Also use this when 'list' is set but tabs take their normal size.
*/
if ((!wp->w_p_list || wp->w_lcs_chars.tab1 != NUL)
#ifdef FEAT_LINEBREAK
&& !wp->w_p_lbr && *get_showbreak_value(wp) == NUL && !wp->w_p_bri
#endif
+ #ifdef FEAT_PROP_POPUP
+ && !cts.cts_has_prop_with_text
+ #endif
)
{
for (;;)
***************
*** 1274,1302 ****
{
for (;;)
{
! // A tab gets expanded, depending on the current column
head = 0;
! incr = win_lbr_chartabsize(wp, line, ptr, vcol, &head);
// make sure we don't go past the end of the line
! if (*ptr == NUL)
{
incr = 1; // NUL at end of line only takes one column
break;
}
! if (posptr != NULL && ptr >= posptr) // character at pos->col
break;
! vcol += incr;
! MB_PTR_ADV(ptr);
}
}
if (start != NULL)
*start = vcol + head;
if (end != NULL)
*end = vcol + incr - 1;
if (cursor != NULL)
{
if (*ptr == TAB
&& (State & MODE_NORMAL)
&& !wp->w_p_list
--- 1407,1445 ----
{
for (;;)
{
! // A tab gets expanded, depending on the current column.
! // Other things also take up space.
head = 0;
! incr = win_lbr_chartabsize(&cts, &head);
// make sure we don't go past the end of the line
! if (*cts.cts_ptr == NUL)
{
incr = 1; // NUL at end of line only takes one column
break;
}
! if (posptr != NULL && cts.cts_ptr >= posptr)
! // character at pos->col
break;
! cts.cts_vcol += incr;
! MB_PTR_ADV(cts.cts_ptr);
}
+ vcol = cts.cts_vcol;
+ ptr = cts.cts_ptr;
}
+ clear_chartabsize_arg(&cts);
+
if (start != NULL)
*start = vcol + head;
if (end != NULL)
*end = vcol + incr - 1;
if (cursor != NULL)
{
+ #ifdef FEAT_PROP_POPUP
+ // cursor is after inserted text
+ vcol += cts.cts_cur_text_width;
+ #endif
if (*ptr == TAB
&& (State & MODE_NORMAL)
&& !wp->w_p_list
*** ../vim-9.0.0066/src/drawline.c 2022-07-09 04:56:12.522528981 +0100
--- src/drawline.c 2022-07-25 16:10:32.731049859 +0100
***************
*** 326,331 ****
--- 326,332 ----
int text_props_active = 0;
proptype_T *text_prop_type = NULL;
int text_prop_attr = 0;
+ int text_prop_id = 0; // active property ID
int text_prop_combine = FALSE;
#endif
#ifdef FEAT_SPELL
***************
*** 816,830 ****
v = wp->w_leftcol;
if (v > 0 && !number_only)
{
! char_u *prev_ptr = ptr;
!
! while (vcol < v && *ptr != NUL)
! {
! c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
! vcol += c;
! prev_ptr = ptr;
! MB_PTR_ADV(ptr);
! }
// When:
// - 'cuc' is set, or
--- 817,837 ----
v = wp->w_leftcol;
if (v > 0 && !number_only)
{
! char_u *prev_ptr = ptr;
! chartabsize_T cts;
! int charsize;
!
! init_chartabsize_arg(&cts, wp, lnum, vcol, line, ptr);
! while (cts.cts_vcol < v && *cts.cts_ptr != NUL)
! {
! charsize = win_lbr_chartabsize(&cts, NULL);
! cts.cts_vcol += charsize;
! prev_ptr = cts.cts_ptr;
! MB_PTR_ADV(cts.cts_ptr);
! }
! vcol = cts.cts_vcol;
! ptr = cts.cts_ptr;
! clear_chartabsize_arg(&cts);
// When:
// - 'cuc' is set, or
***************
*** 844,854 ****
// that character but skip the first few screen characters.
if (vcol > v)
{
! vcol -= c;
ptr = prev_ptr;
// If the character fits on the screen, don't need to skip it.
// Except for a TAB.
! if (( (*mb_ptr2cells)(ptr) >= c || *ptr == TAB) && col == 0)
n_skip = v - vcol;
}
--- 851,861 ----
// that character but skip the first few screen characters.
if (vcol > v)
{
! vcol -= charsize;
ptr = prev_ptr;
// If the character fits on the screen, don't need to skip it.
// Except for a TAB.
! if (( (*mb_ptr2cells)(ptr) >= charsize || *ptr == TAB) && col == 0)
n_skip = v - vcol;
}
***************
*** 1476,1483 ****
--- 1483,1494 ----
text_prop_attr = 0;
text_prop_combine = FALSE;
text_prop_type = NULL;
+ text_prop_id = 0;
if (text_props_active > 0)
{
+ int used_tpi;
+ int used_attr = 0;
+
// Sort the properties on priority and/or starting last.
// Then combine the attributes, highest priority last.
current_text_props = text_props;
***************
*** 1491,1505 ****
proptype_T *pt = text_prop_type_by_id(
wp->w_buffer, text_props[tpi].tp_type);
! if (pt != NULL && pt->pt_hl_id > 0)
{
! int pt_attr = syn_id2attr(pt->pt_hl_id);
!
text_prop_type = pt;
text_prop_attr =
! hl_combine_attr(text_prop_attr, pt_attr);
text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE;
}
}
}
}
--- 1502,1544 ----
proptype_T *pt = text_prop_type_by_id(
wp->w_buffer, text_props[tpi].tp_type);
! if (pt != NULL && pt->pt_hl_id > 0
! && text_props[tpi].tp_id != -MAXCOL)
{
! used_attr = syn_id2attr(pt->pt_hl_id);
text_prop_type = pt;
text_prop_attr =
! hl_combine_attr(text_prop_attr, used_attr);
text_prop_combine = pt->pt_flags & PT_FLAG_COMBINE;
+ text_prop_id = text_props[tpi].tp_id;
+ used_tpi = tpi;
+ }
+ }
+ if (n_extra == 0 && text_prop_id < 0
+ && -text_prop_id
+ <= wp->w_buffer->b_textprop_text.ga_len)
+ {
+ char_u *p = ((char_u **)wp->w_buffer
+ ->b_textprop_text.ga_data)[
+ -text_prop_id - 1];
+ if (p != NULL)
+ {
+ p_extra = p;
+ n_extra = STRLEN(p);
+ extra_attr = used_attr;
+ n_attr = n_extra;
+ text_prop_attr = 0;
+
+ // If the cursor is on or after this position,
+ // move it forward.
+ if (wp == curwin
+ && lnum == curwin->w_cursor.lnum
+ && curwin->w_cursor.col >= vcol)
+ curwin->w_cursor.col += n_extra;
}
+ // reset the ID in the copy to avoid it being used
+ // again
+ text_props[used_tpi].tp_id = -MAXCOL;
}
}
}
***************
*** 2025,2034 ****
int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1)
: 0;
char_u *p = ptr - (mb_off + 1);
! // TODO: is passing p for start of the line OK?
! n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol,
! NULL) - 1;
// We have just drawn the showbreak value, no need to add
// space for it again.
--- 2064,2073 ----
int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1)
: 0;
char_u *p = ptr - (mb_off + 1);
+ chartabsize_T cts;
! init_chartabsize_arg(&cts, wp, lnum, vcol, line, p);
! n_extra = win_lbr_chartabsize(&cts, NULL) - 1;
// We have just drawn the showbreak value, no need to add
// space for it again.
***************
*** 2069,2074 ****
--- 2108,2114 ----
if (!wp->w_p_list)
c = ' ';
}
+ clear_chartabsize_arg(&cts);
}
#endif
*** ../vim-9.0.0066/src/edit.c 2022-06-30 22:13:56.204846337 +0100
--- src/edit.c 2022-07-25 16:17:12.986522771 +0100
***************
*** 4905,4910 ****
--- 4905,4912 ----
colnr_T want_vcol, vcol;
int change_col = -1;
int save_list = curwin->w_p_list;
+ char_u *tab = (char_u *)"\t";
+ chartabsize_T cts;
/*
* Get the current line. For MODE_VREPLACE state, don't make real
***************
*** 4950,4961 ****
getvcol(curwin, &fpos, &vcol, NULL, NULL);
getvcol(curwin, cursor, &want_vcol, NULL, NULL);
// Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
// and 'linebreak' adding extra virtual columns.
while (VIM_ISWHITE(*ptr))
{
! i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
! if (vcol + i > want_vcol)
break;
if (*ptr != TAB)
{
--- 4952,4965 ----
getvcol(curwin, &fpos, &vcol, NULL, NULL);
getvcol(curwin, cursor, &want_vcol, NULL, NULL);
+ init_chartabsize_arg(&cts, curwin, 0, vcol, tab, tab);
+
// Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
// and 'linebreak' adding extra virtual columns.
while (VIM_ISWHITE(*ptr))
{
! i = lbr_chartabsize(&cts);
! if (cts.cts_vcol + i > want_vcol)
break;
if (*ptr != TAB)
{
***************
*** 4970,4990 ****
}
++fpos.col;
++ptr;
! vcol += i;
}
if (change_col >= 0)
{
! int repl_off = 0;
! char_u *line = ptr;
// Skip over the spaces we need.
! while (vcol < want_vcol && *ptr == ' ')
{
! vcol += lbr_chartabsize(line, ptr, vcol);
! ++ptr;
++repl_off;
}
if (vcol > want_vcol)
{
// Must have a char with 'showbreak' just before it.
--- 4974,5000 ----
}
++fpos.col;
++ptr;
! cts.cts_vcol += i;
}
+ vcol = cts.cts_vcol;
+ clear_chartabsize_arg(&cts);
if (change_col >= 0)
{
! int repl_off = 0;
// Skip over the spaces we need.
! init_chartabsize_arg(&cts, curwin, 0, vcol, ptr, ptr);
! while (cts.cts_vcol < want_vcol && *cts.cts_ptr == ' ')
{
! cts.cts_vcol += lbr_chartabsize(&cts);
! ++cts.cts_ptr;
++repl_off;
}
+ ptr = cts.cts_ptr;
+ vcol = cts.cts_vcol;
+ clear_chartabsize_arg(&cts);
+
if (vcol > want_vcol)
{
// Must have a char with 'showbreak' just before it.
***************
*** 5220,5229 ****
int
ins_copychar(linenr_T lnum)
{
! int c;
! int temp;
! char_u *ptr, *prev_ptr;
! char_u *line;
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
{
--- 5230,5239 ----
int
ins_copychar(linenr_T lnum)
{
! int c;
! char_u *ptr, *prev_ptr;
! char_u *line;
! chartabsize_T cts;
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
{
***************
*** 5233,5248 ****
// try to advance to the cursor column
validate_virtcol();
! temp = 0;
! line = ptr = ml_get(lnum);
! prev_ptr = ptr;
! while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
{
! prev_ptr = ptr;
! temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp);
}
! if ((colnr_T)temp > curwin->w_virtcol)
ptr = prev_ptr;
c = (*mb_ptr2char)(ptr);
if (c == NUL)
--- 5243,5261 ----
// try to advance to the cursor column
validate_virtcol();
! line = ml_get(lnum);
! prev_ptr = line;
! init_chartabsize_arg(&cts, curwin, lnum, 0, line, line);
! while (cts.cts_vcol < curwin->w_virtcol && *cts.cts_ptr != NUL)
{
! prev_ptr = cts.cts_ptr;
! cts.cts_vcol += lbr_chartabsize_adv(&cts);
}
! if (cts.cts_vcol > curwin->w_virtcol)
ptr = prev_ptr;
+ else
+ ptr = cts.cts_ptr;
+ clear_chartabsize_arg(&cts);
c = (*mb_ptr2char)(ptr);
if (c == NUL)
*** ../vim-9.0.0066/src/errors.h 2022-07-24 20:07:57.656416981 +0100
--- src/errors.h 2022-07-25 15:42:47.107100992 +0100
***************
*** 3310,3312 ****
--- 3310,3316 ----
EXTERN char e_cmdline_window_already_open[]
INIT(= N_("E1292: Command-line window is already open"));
#endif
+ #ifdef FEAT_PROP_POPUP
+ EXTERN char e_cannot_use_negative_id_after_adding_textprop_with_text[]
+ INIT(= N_("E1291: Cannot use a negative id after adding a textprop with text"));
+ #endif
*** ../vim-9.0.0066/src/evalfunc.c 2022-07-23 09:52:00.333814262 +0100
--- src/evalfunc.c 2022-07-25 15:42:47.107100992 +0100
***************
*** 2218,2224 ****
{"prompt_setprompt", 2, 2, FEARG_1, arg2_buffer_string,
ret_void, JOB_FUNC(f_prompt_setprompt)},
{"prop_add", 3, 3, FEARG_1, arg3_number_number_dict,
! ret_void, PROP_FUNC(f_prop_add)},
{"prop_add_list", 2, 2, FEARG_1, arg2_dict_any_list_any,
ret_void, PROP_FUNC(f_prop_add_list)},
{"prop_clear", 1, 3, FEARG_1, arg3_number_number_dict,
--- 2218,2224 ----
{"prompt_setprompt", 2, 2, FEARG_1, arg2_buffer_string,
ret_void, JOB_FUNC(f_prompt_setprompt)},
{"prop_add", 3, 3, FEARG_1, arg3_number_number_dict,
! ret_number, PROP_FUNC(f_prop_add)},
{"prop_add_list", 2, 2, FEARG_1, arg2_dict_any_list_any,
ret_void, PROP_FUNC(f_prop_add_list)},
{"prop_clear", 1, 3, FEARG_1, arg3_number_number_dict,
*** ../vim-9.0.0066/src/getchar.c 2022-07-23 06:24:56.405106035 +0100
--- src/getchar.c 2022-07-25 16:51:55.042379009 +0100
***************
*** 3210,3216 ****
&& (c = inchar(typebuf.tb_buf + typebuf.tb_off
+ typebuf.tb_len, 3, 25L)) == 0)
{
! colnr_T col = 0, vcol;
char_u *ptr;
if (mode_displayed)
--- 3210,3216 ----
&& (c = inchar(typebuf.tb_buf + typebuf.tb_off
+ typebuf.tb_len, 3, 25L)) == 0)
{
! colnr_T col = 0;
char_u *ptr;
if (mode_displayed)
***************
*** 3242,3265 ****
{
if (did_ai)
{
/*
* We are expecting to truncate the trailing
* white-space, so find the last non-white
* character -- webb
*/
! col = vcol = curwin->w_wcol = 0;
ptr = ml_get_curline();
! while (col < curwin->w_cursor.col)
{
! if (!VIM_ISWHITE(ptr[col]))
! curwin->w_wcol = vcol;
! vcol += lbr_chartabsize(ptr, ptr + col,
! vcol);
if (has_mbyte)
! col += (*mb_ptr2len)(ptr + col);
else
! ++col;
}
curwin->w_wrow = curwin->w_cline_row
+ curwin->w_wcol / curwin->w_width;
curwin->w_wcol %= curwin->w_width;
--- 3242,3271 ----
{
if (did_ai)
{
+ chartabsize_T cts;
+
/*
* We are expecting to truncate the trailing
* white-space, so find the last non-white
* character -- webb
*/
! curwin->w_wcol = 0;
ptr = ml_get_curline();
! init_chartabsize_arg(&cts, curwin,
! curwin->w_cursor.lnum, 0, ptr, ptr);
! while (cts.cts_ptr < ptr + curwin->w_cursor.col)
{
! if (!VIM_ISWHITE(*cts.cts_ptr))
! curwin->w_wcol = cts.cts_vcol;
! cts.cts_vcol += lbr_chartabsize(&cts);
if (has_mbyte)
! cts.cts_ptr +=
! (*mb_ptr2len)(cts.cts_ptr);
else
! ++cts.cts_ptr;
}
+ clear_chartabsize_arg(&cts);
+
curwin->w_wrow = curwin->w_cline_row
+ curwin->w_wcol / curwin->w_width;
curwin->w_wcol %= curwin->w_width;
*** ../vim-9.0.0066/src/indent.c 2022-07-01 13:15:31.556075437 +0100
--- src/indent.c 2022-07-25 17:49:44.798632658 +0100
***************
*** 1350,1375 ****
new_cursor_col = curwin->w_cursor.col;
else
{
// Compute the screen column where the cursor should be.
vcol = get_indent() - vcol;
curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
// Advance the cursor until we reach the right screen column.
! vcol = last_vcol = 0;
! new_cursor_col = -1;
ptr = ml_get_curline();
! while (vcol <= (int)curwin->w_virtcol)
{
! last_vcol = vcol;
! if (has_mbyte && new_cursor_col >= 0)
! new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
! else
! ++new_cursor_col;
! if (ptr[new_cursor_col] == NUL)
break;
! vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
}
vcol = last_vcol;
// May need to insert spaces to be able to position the cursor on
// the right screen column.
--- 1350,1377 ----
new_cursor_col = curwin->w_cursor.col;
else
{
+ chartabsize_T cts;
+
// Compute the screen column where the cursor should be.
vcol = get_indent() - vcol;
curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
// Advance the cursor until we reach the right screen column.
! last_vcol = 0;
ptr = ml_get_curline();
! init_chartabsize_arg(&cts, curwin, 0, 0, ptr, ptr);
! while (cts.cts_vcol <= (int)curwin->w_virtcol)
{
! last_vcol = cts.cts_vcol;
! if (cts.cts_vcol > 0)
! MB_PTR_ADV(cts.cts_ptr);
! if (*cts.cts_ptr == NUL)
break;
! cts.cts_vcol += lbr_chartabsize(&cts);
}
vcol = last_vcol;
+ new_cursor_col = cts.cts_ptr - cts.cts_line;
+ clear_chartabsize_arg(&cts);
// May need to insert spaces to be able to position the cursor on
// the right screen column.
***************
*** 2064,2077 ****
amount = 2;
else
{
! char_u *line = that;
! amount = 0;
! while (*that && col)
{
! amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
col--;
}
// Some keywords require "body" indenting rules (the
// non-standard-lisp ones are Scheme special forms):
--- 2066,2083 ----
amount = 2;
else
{
! char_u *line = that;
! chartabsize_T cts;
! init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line);
! while (*cts.cts_ptr != NUL && col > 0)
{
! cts.cts_vcol += lbr_chartabsize_adv(&cts);
col--;
}
+ amount = cts.cts_vcol;
+ that = cts.cts_ptr;
+ clear_chartabsize_arg(&cts);
// Some keywords require "body" indenting rules (the
// non-standard-lisp ones are Scheme special forms):
***************
*** 2091,2101 ****
}
firsttry = amount;
! while (VIM_ISWHITE(*that))
{
! amount += lbr_chartabsize(line, that, (colnr_T)amount);
! ++that;
}
if (*that && *that != ';') // not a comment line
{
--- 2097,2112 ----
}
firsttry = amount;
! init_chartabsize_arg(&cts, curwin, (colnr_T)(that - line),
! amount, line, that);
! while (VIM_ISWHITE(*cts.cts_ptr))
{
! cts.cts_vcol += lbr_chartabsize(&cts);
! ++cts.cts_ptr;
}
+ that = cts.cts_ptr;
+ amount = cts.cts_vcol;
+ clear_chartabsize_arg(&cts);
if (*that && *that != ';') // not a comment line
{
***************
*** 2107,2148 ****
parencount = 0;
quotecount = 0;
if (vi_lisp
|| (*that != '"'
&& *that != '\''
&& *that != '#'
&& (*that < '0' || *that > '9')))
{
! while (*that
! && (!VIM_ISWHITE(*that)
|| quotecount
|| parencount)
! && (!((*that == '(' || *that == '[')
&& !quotecount
&& !parencount
&& vi_lisp)))
{
! if (*that == '"')
quotecount = !quotecount;
! if ((*that == '(' || *that == '[')
&& !quotecount)
++parencount;
! if ((*that == ')' || *that == ']')
&& !quotecount)
--parencount;
! if (*that == '\\' && *(that+1) != NUL)
! amount += lbr_chartabsize_adv(
! line, &that, (colnr_T)amount);
! amount += lbr_chartabsize_adv(
! line, &that, (colnr_T)amount);
}
}
! while (VIM_ISWHITE(*that))
{
! amount += lbr_chartabsize(
! line, that, (colnr_T)amount);
! that++;
}
if (!*that || *that == ';')
amount = firsttry;
}
--- 2118,2164 ----
parencount = 0;
quotecount = 0;
+ init_chartabsize_arg(&cts, curwin,
+ (colnr_T)(that - line), amount, line, that);
if (vi_lisp
|| (*that != '"'
&& *that != '\''
&& *that != '#'
&& (*that < '0' || *that > '9')))
{
! while (*cts.cts_ptr
! && (!VIM_ISWHITE(*cts.cts_ptr)
|| quotecount
|| parencount)
! && (!((*cts.cts_ptr == '('
! || *cts.cts_ptr == '[')
&& !quotecount
&& !parencount
&& vi_lisp)))
{
! if (*cts.cts_ptr == '"')
quotecount = !quotecount;
! if ((*cts.cts_ptr == '(' || *cts.cts_ptr == '[')
&& !quotecount)
++parencount;
! if ((*cts.cts_ptr == ')' || *cts.cts_ptr == ']')
&& !quotecount)
--parencount;
! if (*cts.cts_ptr == '\\'
! && *(cts.cts_ptr+1) != NUL)
! cts.cts_vcol += lbr_chartabsize_adv(&cts);
! cts.cts_vcol += lbr_chartabsize_adv(&cts);
}
}
! while (VIM_ISWHITE(*cts.cts_ptr))
{
! cts.cts_vcol += lbr_chartabsize(&cts);
! ++cts.cts_ptr;
}
+ that = cts.cts_ptr;
+ amount = cts.cts_vcol;
+ clear_chartabsize_arg(&cts);
+
if (!*that || *that == ';')
amount = firsttry;
}
*** ../vim-9.0.0066/src/misc1.c 2022-07-02 17:36:27.332515941 +0100
--- src/misc1.c 2022-07-25 16:31:28.675129729 +0100
***************
*** 397,403 ****
s = ml_get_buf(wp->w_buffer, lnum, FALSE);
if (*s == NUL) // empty line
return 1;
! col = win_linetabsize(wp, s, (colnr_T)MAXCOL);
/*
* If list mode is on, then the '$' at the end of the line may take up one
--- 397,403 ----
s = ml_get_buf(wp->w_buffer, lnum, FALSE);
if (*s == NUL) // empty line
return 1;
! col = win_linetabsize(wp, lnum, s, (colnr_T)MAXCOL);
/*
* If list mode is on, then the '$' at the end of the line may take up one
***************
*** 427,436 ****
plines_win_col(win_T *wp, linenr_T lnum, long column)
{
long col;
- char_u *s;
int lines = 0;
int width;
char_u *line;
#ifdef FEAT_DIFF
// Check for filler lines above this buffer line. When folded the result
--- 427,436 ----
plines_win_col(win_T *wp, linenr_T lnum, long column)
{
long col;
int lines = 0;
int width;
char_u *line;
+ chartabsize_T cts;
#ifdef FEAT_DIFF
// Check for filler lines above this buffer line. When folded the result
***************
*** 444,468 ****
if (wp->w_width == 0)
return lines + 1;
! line = s = ml_get_buf(wp->w_buffer, lnum, FALSE);
! col = 0;
! while (*s != NUL && --column >= 0)
{
! col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL);
! MB_PTR_ADV(s);
}
/*
! * If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
! * MODE_INSERT state, then col must be adjusted so that it represents the
! * last screen position of the TAB. This only fixes an error when the TAB
! * wraps from one screen line to the next (when 'columns' is not a multiple
! * of 'ts') -- webb.
*/
! if (*s == TAB && (State & MODE_NORMAL)
&& (!wp->w_p_list || wp->w_lcs_chars.tab1))
! col += win_lbr_chartabsize(wp, line, s, (colnr_T)col, NULL) - 1;
/*
* Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
--- 444,470 ----
if (wp->w_width == 0)
return lines + 1;
! line = ml_get_buf(wp->w_buffer, lnum, FALSE);
! init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
! while (*cts.cts_ptr != NUL && --column >= 0)
{
! cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
! MB_PTR_ADV(cts.cts_ptr);
}
/*
! * If *cts.cts_ptr is a TAB, and the TAB is not displayed as ^I, and we're
! * not in MODE_INSERT state, then col must be adjusted so that it
! * represents the last screen position of the TAB. This only fixes an
! * error when the TAB wraps from one screen line to the next (when
! * 'columns' is not a multiple of 'ts') -- webb.
*/
! col = cts.cts_vcol;
! if (*cts.cts_ptr == TAB && (State & MODE_NORMAL)
&& (!wp->w_p_list || wp->w_lcs_chars.tab1))
! col += win_lbr_chartabsize(&cts, NULL) - 1;
! clear_chartabsize_arg(&cts);
/*
* Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
*** ../vim-9.0.0066/src/misc2.c 2022-05-16 19:32:27.000000000 +0100
--- src/misc2.c 2022-07-25 16:52:25.602379723 +0100
***************
*** 128,134 ****
{
colnr_T wcol = wcol_arg;
int idx;
- char_u *ptr;
char_u *line;
colnr_T col = 0;
int csize = 0;
--- 128,133 ----
***************
*** 158,163 ****
--- 157,163 ----
else
{
int width = curwin->w_width - win_col_off(curwin);
+ chartabsize_T cts;
if (finetune
&& curwin->w_p_wrap
***************
*** 180,198 ****
}
}
! ptr = line;
! while (col <= wcol && *ptr != NUL)
{
// Count a tab for what it's worth (if list mode not on)
#ifdef FEAT_LINEBREAK
! csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
! MB_PTR_ADV(ptr);
#else
! csize = lbr_chartabsize_adv(line, &ptr, col);
#endif
! col += csize;
}
! idx = (int)(ptr - line);
/*
* Handle all the special cases. The virtual_active() check
* is needed to ensure that a virtual position off the end of
--- 180,201 ----
}
}
! init_chartabsize_arg(&cts, curwin, pos->lnum, 0, line, line);
! while (cts.cts_vcol <= wcol && *cts.cts_ptr != NUL)
{
// Count a tab for what it's worth (if list mode not on)
#ifdef FEAT_LINEBREAK
! csize = win_lbr_chartabsize(&cts, &head);
! MB_PTR_ADV(cts.cts_ptr);
#else
! csize = lbr_chartabsize_adv(&cts);
#endif
! cts.cts_vcol += csize;
}
! col = cts.cts_vcol;
! idx = (int)(cts.cts_ptr - line);
! clear_chartabsize_arg(&cts);
!
/*
* Handle all the special cases. The virtual_active() check
* is needed to ensure that a virtual position off the end of
*** ../vim-9.0.0066/src/mouse.c 2022-07-09 04:56:12.522528981 +0100
--- src/mouse.c 2022-07-25 15:42:47.107100992 +0100
***************
*** 3101,3118 ****
int
vcol2col(win_T *wp, linenr_T lnum, int vcol)
{
! // try to advance to the specified column
! int count = 0;
! char_u *ptr;
! char_u *line;
! line = ptr = ml_get_buf(wp->w_buffer, lnum, FALSE);
! while (count < vcol && *ptr != NUL)
{
! count += win_lbr_chartabsize(wp, line, ptr, count, NULL);
! MB_PTR_ADV(ptr);
}
! return (int)(ptr - line);
}
#endif
--- 3101,3120 ----
int
vcol2col(win_T *wp, linenr_T lnum, int vcol)
{
! char_u *line;
! chartabsize_T cts;
! // try to advance to the specified column
! line = ml_get_buf(wp->w_buffer, lnum, FALSE);
! init_chartabsize_arg(&cts, wp, lnum, 0, line, line);
! while (cts.cts_vcol < vcol && *cts.cts_ptr != NUL)
{
! cts.cts_vcol += win_lbr_chartabsize(&cts, NULL);
! MB_PTR_ADV(cts.cts_ptr);
}
! clear_chartabsize_arg(&cts);
!
! return (int)(cts.cts_ptr - line);
}
#endif
*** ../vim-9.0.0066/src/ops.c 2022-06-30 22:13:56.204846337 +0100
--- src/ops.c 2022-07-25 17:25:27.982274054 +0100
***************
*** 307,313 ****
if (!left)
{
! int tabs = 0, spaces = 0;
/*
* 1. Get start vcol
--- 307,314 ----
if (!left)
{
! int tabs = 0, spaces = 0;
! chartabsize_T cts;
/*
* 1. Get start vcol
***************
*** 332,344 ****
else
++bd.textstart;
}
! for ( ; VIM_ISWHITE(*bd.textstart); )
{
! // TODO: is passing bd.textstart for start of the line OK?
! incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, bd.start_vcol);
total += incr;
! bd.start_vcol += incr;
}
// OK, now total=all the VWS reqd, and textstart points at the 1st
// non-ws char in the block.
#ifdef FEAT_VARTABS
--- 333,352 ----
else
++bd.textstart;
}
!
! // TODO: is passing bd.textstart for start of the line OK?
! init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum,
! bd.start_vcol, bd.textstart, bd.textstart);
! for ( ; VIM_ISWHITE(*cts.cts_ptr); )
{
! incr = lbr_chartabsize_adv(&cts);
total += incr;
! cts.cts_vcol += incr;
}
+ bd.textstart = cts.cts_ptr;
+ bd.start_vcol = cts.cts_vcol;
+ clear_chartabsize_arg(&cts);
+
// OK, now total=all the VWS reqd, and textstart points at the 1st
// non-ws char in the block.
#ifdef FEAT_VARTABS
***************
*** 381,386 ****
--- 389,395 ----
size_t shift_amount;
char_u *non_white = bd.textstart;
colnr_T non_white_col;
+ chartabsize_T cts;
/*
* Firstly, let's find the first non-whitespace character that is
***************
*** 399,409 ****
// The character's column is in "bd.start_vcol".
non_white_col = bd.start_vcol;
! while (VIM_ISWHITE(*non_white))
! {
! incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col);
! non_white_col += incr;
! }
block_space_width = non_white_col - oap->start_vcol;
// We will shift by "total" or "block_space_width", whichever is less.
--- 408,423 ----
// The character's column is in "bd.start_vcol".
non_white_col = bd.start_vcol;
! init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum,
! non_white_col, bd.textstart, non_white);
! while (VIM_ISWHITE(*cts.cts_ptr))
! {
! incr = lbr_chartabsize_adv(&cts);
! cts.cts_vcol += incr;
! }
! non_white_col = cts.cts_vcol;
! non_white = cts.cts_ptr;
! clear_chartabsize_arg(&cts);
block_space_width = non_white_col - oap->start_vcol;
// We will shift by "total" or "block_space_width", whichever is less.
***************
*** 423,440 ****
// column number.
if (bd.startspaces)
verbatim_copy_width -= bd.start_char_vcols;
! while (verbatim_copy_width < destination_col)
{
! char_u *line = verbatim_copy_end;
!
! // TODO: is passing verbatim_copy_end for start of the line OK?
! incr = lbr_chartabsize(line, verbatim_copy_end,
! verbatim_copy_width);
! if (verbatim_copy_width + incr > destination_col)
break;
! verbatim_copy_width += incr;
! MB_PTR_ADV(verbatim_copy_end);
}
// If "destination_col" is different from the width of the initial
// part of the line that will be copied, it means we encountered a tab
--- 437,455 ----
// column number.
if (bd.startspaces)
verbatim_copy_width -= bd.start_char_vcols;
! init_chartabsize_arg(&cts, curwin, 0, verbatim_copy_width,
! bd.textstart, verbatim_copy_end);
! while (cts.cts_vcol < destination_col)
{
! incr = lbr_chartabsize(&cts);
! if (cts.cts_vcol + incr > destination_col)
break;
! cts.cts_vcol += incr;
! MB_PTR_ADV(cts.cts_ptr);
}
+ verbatim_copy_width = cts.cts_vcol;
+ verbatim_copy_end = cts.cts_ptr;
+ clear_chartabsize_arg(&cts);
// If "destination_col" is different from the width of the initial
// part of the line that will be copied, it means we encountered a tab
***************
*** 703,710 ****
* Put deleted text into register 1 and shift number registers if the
* delete contains a line break, or when using a specific operator (Vi
* compatible)
- * Use the register name from before adjust_clip_reg() may have
- * changed it.
*/
if (oap->motion_type == MLINE || oap->line_count > 1
|| oap->use_reg_one)
--- 718,723 ----
***************
*** 2213,2218 ****
--- 2226,2232 ----
char_u *line;
char_u *prev_pstart;
char_u *prev_pend;
+ chartabsize_T cts;
#ifdef FEAT_LINEBREAK
int lbr_saved = curwin->w_p_lbr;
***************
*** 2232,2245 ****
bdp->start_char_vcols = 0;
line = ml_get(lnum);
- pstart = line;
prev_pstart = line;
! while (bdp->start_vcol < oap->start_vcol && *pstart)
{
// Count a tab for what it's worth (if list mode not on)
! incr = lbr_chartabsize(line, pstart, bdp->start_vcol);
! bdp->start_vcol += incr;
! if (VIM_ISWHITE(*pstart))
{
bdp->pre_whitesp += incr;
bdp->pre_whitesp_c++;
--- 2246,2259 ----
bdp->start_char_vcols = 0;
line = ml_get(lnum);
prev_pstart = line;
! init_chartabsize_arg(&cts, curwin, lnum, bdp->start_vcol, line, line);
! while (cts.cts_vcol < oap->start_vcol && *cts.cts_ptr != NUL)
{
// Count a tab for what it's worth (if list mode not on)
! incr = lbr_chartabsize(&cts);
! cts.cts_vcol += incr;
! if (VIM_ISWHITE(*cts.cts_ptr))
{
bdp->pre_whitesp += incr;
bdp->pre_whitesp_c++;
***************
*** 2249,2257 ****
bdp->pre_whitesp = 0;
bdp->pre_whitesp_c = 0;
}
! prev_pstart = pstart;
! MB_PTR_ADV(pstart);
}
bdp->start_char_vcols = incr;
if (bdp->start_vcol < oap->start_vcol) // line too short
{
--- 2263,2275 ----
bdp->pre_whitesp = 0;
bdp->pre_whitesp_c = 0;
}
! prev_pstart = cts.cts_ptr;
! MB_PTR_ADV(cts.cts_ptr);
}
+ bdp->start_vcol = cts.cts_vcol;
+ pstart = cts.cts_ptr;
+ clear_chartabsize_arg(&cts);
+
bdp->start_char_vcols = incr;
if (bdp->start_vcol < oap->start_vcol) // line too short
{
***************
*** 2295,2308 ****
}
else
{
prev_pend = pend;
! while (bdp->end_vcol <= oap->end_vcol && *pend != NUL)
{
! // Count a tab for what it's worth (if list mode not on)
! prev_pend = pend;
! incr = lbr_chartabsize_adv(line, &pend, bdp->end_vcol);
! bdp->end_vcol += incr;
! }
if (bdp->end_vcol <= oap->end_vcol
&& (!is_del
|| oap->op_type == OP_APPEND
--- 2313,2332 ----
}
else
{
+ init_chartabsize_arg(&cts, curwin, lnum, bdp->end_vcol,
+ line, pend);
prev_pend = pend;
! while (cts.cts_vcol <= oap->end_vcol && *cts.cts_ptr != NUL)
{
! // count a tab for what it's worth (if list mode not on)
! prev_pend = cts.cts_ptr;
! incr = lbr_chartabsize_adv(&cts);
! cts.cts_vcol += incr;
! }
! bdp->end_vcol = cts.cts_vcol;
! pend = cts.cts_ptr;
! clear_chartabsize_arg(&cts);
!
if (bdp->end_vcol <= oap->end_vcol
&& (!is_del
|| oap->op_type == OP_APPEND
*** ../vim-9.0.0066/src/popupwin.c 2022-07-23 09:52:00.337814264 +0100
--- src/popupwin.c 2022-07-25 15:42:47.111100981 +0100
***************
*** 1371,1377 ****
// "margin_width" is added to "len" where it matters.
if (wp->w_width < maxwidth)
wp->w_width = maxwidth;
! len = win_linetabsize(wp, ml_get_buf(wp->w_buffer, lnum, FALSE),
(colnr_T)MAXCOL);
wp->w_width = w_width;
--- 1371,1377 ----
// "margin_width" is added to "len" where it matters.
if (wp->w_width < maxwidth)
wp->w_width = maxwidth;
! len = win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum, FALSE),
(colnr_T)MAXCOL);
wp->w_width = w_width;
*** ../vim-9.0.0066/src/proto/
charset.pro 2022-06-27 23:14:58.000000000 +0100
--- src/proto/
charset.pro 2022-07-25 16:47:56.031024543 +0100
***************
*** 17,23 ****
int chartabsize(char_u *p, colnr_T col);
int linetabsize(char_u *s);
int linetabsize_col(int startcol, char_u *s);
! int win_linetabsize(win_T *wp, char_u *line, colnr_T len);
int vim_isIDc(int c);
int vim_isNormalIDc(int c);
int vim_iswordc(int c);
--- 17,23 ----
int chartabsize(char_u *p, colnr_T col);
int linetabsize(char_u *s);
int linetabsize_col(int startcol, char_u *s);
! int win_linetabsize(win_T *wp, linenr_T lnum, char_u *line, colnr_T len);
int vim_isIDc(int c);
int vim_isNormalIDc(int c);
int vim_iswordc(int c);
***************
*** 28,36 ****
int vim_isfilec_or_wc(int c);
int vim_isprintc(int c);
int vim_isprintc_strict(int c);
! int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col);
! int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col);
! int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp);
void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
colnr_T getvcol_nolist(pos_T *posp);
void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
--- 28,38 ----
int vim_isfilec_or_wc(int c);
int vim_isprintc(int c);
int vim_isprintc_strict(int c);
! void init_chartabsize_arg(chartabsize_T *cts, win_T *wp, linenr_T lnum, colnr_T col, char_u *line, char_u *ptr);
! void clear_chartabsize_arg(chartabsize_T *cts);
! int lbr_chartabsize(chartabsize_T *cts);
! int lbr_chartabsize_adv(chartabsize_T *cts);
! int win_lbr_chartabsize(chartabsize_T *cts, int *headp);
void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
colnr_T getvcol_nolist(pos_T *posp);
void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end);
*** ../vim-9.0.0066/src/proto/
textprop.pro 2022-06-27 23:15:26.000000000 +0100
--- src/proto/
textprop.pro 2022-07-25 16:48:05.562990867 +0100
***************
*** 2,8 ****
int find_prop_type_id(char_u *name, buf_T *buf);
void f_prop_add(typval_T *argvars, typval_T *rettv);
void f_prop_add_list(typval_T *argvars, typval_T *rettv);
! void prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict, buf_T *default_buf, typval_T *dict_arg);
int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
int count_props(linenr_T lnum, int only_starting);
int find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop, linenr_T *found_lnum);
--- 2,8 ----
int find_prop_type_id(char_u *name, buf_T *buf);
void f_prop_add(typval_T *argvars, typval_T *rettv);
void f_prop_add_list(typval_T *argvars, typval_T *rettv);
! int prop_add_common(linenr_T start_lnum, colnr_T start_col, dict_T *dict, buf_T *default_buf, typval_T *dict_arg);
int get_text_props(buf_T *buf, linenr_T lnum, char_u **props, int will_change);
int count_props(linenr_T lnum, int only_starting);
int find_visible_prop(win_T *wp, int type_id, int id, textprop_T *prop, linenr_T *found_lnum);
*** ../vim-9.0.0066/src/regexp.c 2022-07-07 22:20:28.441941352 +0100
--- src/regexp.c 2022-07-25 15:42:47.111100981 +0100
***************
*** 1303,1309 ****
rex.line = reg_getline(rex.lnum);
rex.input = rex.line + col;
! cols = win_linetabsize(wp, rex.line, col);
if (cols < start || cols > end - (*p_sel == 'e'))
return FALSE;
}
--- 1303,1309 ----
rex.line = reg_getline(rex.lnum);
rex.input = rex.line + col;
! cols = win_linetabsize(wp, rex.reg_firstlnum + rex.lnum, rex.line, col);
if (cols < start || cols > end - (*p_sel == 'e'))
return FALSE;
}
*** ../vim-9.0.0066/src/regexp_bt.c 2022-06-20 11:20:30.000000000 +0100
--- src/regexp_bt.c 2022-07-25 15:48:54.537761933 +0100
***************
*** 3441,3447 ****
case RE_VCOL:
if (!re_num_cmp((long_u)win_linetabsize(
rex.reg_win == NULL ? curwin : rex.reg_win,
! rex.line, (colnr_T)(rex.input - rex.line)) + 1, scan))
status = RA_NOMATCH;
break;
--- 3441,3449 ----
case RE_VCOL:
if (!re_num_cmp((long_u)win_linetabsize(
rex.reg_win == NULL ? curwin : rex.reg_win,
! rex.reg_firstlnum + rex.lnum,
! rex.line,
! (colnr_T)(rex.input - rex.line)) + 1, scan))
status = RA_NOMATCH;
break;
*** ../vim-9.0.0066/src/regexp_nfa.c 2022-06-20 11:20:50.000000000 +0100
--- src/regexp_nfa.c 2022-07-25 15:49:04.693808384 +0100
***************
*** 6775,6781 ****
}
if (!result)
result = nfa_re_num_cmp(t->state->val, op,
! (long_u)win_linetabsize(wp, rex.line, col) + 1);
if (result)
{
add_here = TRUE;
--- 6775,6783 ----
}
if (!result)
result = nfa_re_num_cmp(t->state->val, op,
! (long_u)win_linetabsize(wp,
! rex.reg_firstlnum + rex.lnum,
! rex.line, col) + 1);
if (result)
{
add_here = TRUE;
*** ../vim-9.0.0066/src/register.c 2022-06-30 12:30:13.823485781 +0100
--- src/register.c 2022-07-25 17:06:18.621161796 +0100
***************
*** 1820,1827 ****
bd.textcol = 0;
for (i = 0; i < y_size; ++i)
{
! int spaces = 0;
! char shortline;
bd.startspaces = 0;
bd.endspaces = 0;
--- 1820,1828 ----
bd.textcol = 0;
for (i = 0; i < y_size; ++i)
{
! int spaces = 0;
! char shortline;
! chartabsize_T cts;
bd.startspaces = 0;
bd.endspaces = 0;
***************
*** 1839,1851 ****
// get the old line and advance to the position to insert at
oldp = ml_get_curline();
oldlen = (int)STRLEN(oldp);
! for (ptr = oldp; vcol < col && *ptr; )
{
// Count a tab for what it's worth (if list mode not on)
! incr = lbr_chartabsize_adv(oldp, &ptr, vcol);
! vcol += incr;
}
bd.textcol = (colnr_T)(ptr - oldp);
shortline = (vcol < col) || (vcol == col && !*ptr) ;
--- 1840,1858 ----
// get the old line and advance to the position to insert at
oldp = ml_get_curline();
oldlen = (int)STRLEN(oldp);
! init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0,
! oldp, oldp);
!
! while (cts.cts_vcol < col && *cts.cts_ptr != NUL)
{
// Count a tab for what it's worth (if list mode not on)
! incr = lbr_chartabsize_adv(&cts);
! cts.cts_vcol += incr;
}
+ vcol = cts.cts_vcol;
+ ptr = cts.cts_ptr;
bd.textcol = (colnr_T)(ptr - oldp);
+ clear_chartabsize_arg(&cts);
shortline = (vcol < col) || (vcol == col && !*ptr) ;
***************
*** 1876,1883 ****
// calculate number of spaces required to fill right side of
// block
spaces = y_width + 1;
for (j = 0; j < yanklen; j++)
! spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
if (spaces < 0)
spaces = 0;
}
--- 1883,1897 ----
// calculate number of spaces required to fill right side of
// block
spaces = y_width + 1;
+ init_chartabsize_arg(&cts, curwin, 0, 0,
+ y_array[i], y_array[i]);
for (j = 0; j < yanklen; j++)
! {
! spaces -= lbr_chartabsize(&cts);
! ++cts.cts_ptr;
! cts.cts_vcol = 0;
! }
! clear_chartabsize_arg(&cts);
if (spaces < 0)
spaces = 0;
}
*** ../vim-9.0.0066/src/structs.h 2022-07-04 17:34:06.382292138 +0100
--- src/structs.h 2022-07-25 15:42:47.111100981 +0100
***************
*** 806,813 ****
int tp_flags; // TP_FLAG_ values
} textprop_T;
! #define TP_FLAG_CONT_NEXT 1 // property continues in next line
! #define TP_FLAG_CONT_PREV 2 // property was continued from prev line
/*
* Structure defining a property type.
--- 806,814 ----
int tp_flags; // TP_FLAG_ values
} textprop_T;
! #define TP_FLAG_CONT_NEXT 0x1 // property continues in next line
! #define TP_FLAG_CONT_PREV 0x2 // property was continued from prev line
! #define TP_VIRTUAL 0x4 // virtual text, uses tp_id
/*
* Structure defining a property type.
***************
*** 3074,3079 ****
--- 3075,3081 ----
#ifdef FEAT_PROP_POPUP
int b_has_textprop; // TRUE when text props were added
hashtab_T *b_proptypes; // text property types local to buffer
+ garray_T b_textprop_text; // stores text for props, index by (-id - 1)
#endif
#if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
***************
*** 4560,4562 ****
--- 4562,4579 ----
char_u *str;
int score;
} fuzmatch_str_T;
+
+ // Argument for lbr_chartabsize().
+ typedef struct {
+ win_T *cts_win;
+ linenr_T cts_lnum; // zero when not using text properties
+ char_u *cts_line; // start of the line
+ char_u *cts_ptr; // current position in line
+ #ifdef FEAT_PROP_POPUP
+ int cts_text_prop_count; // number of text props
+ textprop_T *cts_text_props; // text props (allocated) or NULL
+ char cts_has_prop_with_text; // TRUE if if a property inserts text
+ int cts_cur_text_width; // width of current inserted text
+ #endif
+ int cts_vcol; // virtual column at current position
+ } chartabsize_T;
*** ../vim-9.0.0066/src/textprop.c 2022-07-23 09:52:00.341814264 +0100
--- src/textprop.c 2022-07-25 16:53:22.590367803 +0100
***************
*** 150,156 ****
* prop_add({lnum}, {col}, {props})
*/
void
! f_prop_add(typval_T *argvars, typval_T *rettv UNUSED)
{
linenr_T start_lnum;
colnr_T start_col;
--- 150,156 ----
* prop_add({lnum}, {col}, {props})
*/
void
! f_prop_add(typval_T *argvars, typval_T *rettv)
{
linenr_T start_lnum;
colnr_T start_col;
***************
*** 174,193 ****
return;
}
! prop_add_common(start_lnum, start_col, argvars[2].vval.v_dict,
! curbuf, &argvars[2]);
}
/*
* Attach a text property 'type_name' to the text starting
* at [start_lnum, start_col] and ending at [end_lnum, end_col] in
! * the buffer 'buf' and assign identifier 'id'.
*/
static int
prop_add_one(
buf_T *buf,
char_u *type_name,
int id,
linenr_T start_lnum,
linenr_T end_lnum,
colnr_T start_col,
--- 174,195 ----
return;
}
! rettv->vval.v_number = prop_add_common(start_lnum, start_col,
! argvars[2].vval.v_dict, curbuf, &argvars[2]);
}
/*
* Attach a text property 'type_name' to the text starting
* at [start_lnum, start_col] and ending at [end_lnum, end_col] in
! * the buffer "buf" and assign identifier "id".
! * When "text" is not NULL add it to buf->b_textprop_text[-id - 1].
*/
static int
prop_add_one(
buf_T *buf,
char_u *type_name,
int id,
+ char_u *text_arg,
linenr_T start_lnum,
linenr_T end_lnum,
colnr_T start_col,
***************
*** 202,227 ****
char_u *newtext;
int i;
textprop_T tmp_prop;
type = lookup_prop_type(type_name, buf);
if (type == NULL)
! return FAIL;
if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_line_number_nr), (long)start_lnum);
! return FAIL;
}
if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_line_number_nr), (long)end_lnum);
! return FAIL;
}
if (buf->b_ml.ml_mfp == NULL)
{
emsg(_(e_cannot_add_text_property_to_unloaded_buffer));
! return FAIL;
}
for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
--- 204,246 ----
char_u *newtext;
int i;
textprop_T tmp_prop;
+ char_u *text = text_arg;
+ int res = FAIL;
type = lookup_prop_type(type_name, buf);
if (type == NULL)
! goto theend;
if (start_lnum < 1 || start_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_line_number_nr), (long)start_lnum);
! goto theend;
}
if (end_lnum < start_lnum || end_lnum > buf->b_ml.ml_line_count)
{
semsg(_(e_invalid_line_number_nr), (long)end_lnum);
! goto theend;
}
if (buf->b_ml.ml_mfp == NULL)
{
emsg(_(e_cannot_add_text_property_to_unloaded_buffer));
! goto theend;
! }
!
! if (text != NULL)
! {
! garray_T *gap = &buf->b_textprop_text;
!
! // double check we got the right ID
! if (-id - 1 != gap->ga_len)
! iemsg("text prop ID mismatch");
! if (gap->ga_growsize == 0)
! ga_init2(gap, sizeof(char *), 50);
! if (ga_grow(gap, 1) == FAIL)
! goto theend;
! ((char_u **)gap->ga_data)[gap->ga_len++] = text;
! text = NULL;
}
for (lnum = start_lnum; lnum <= end_lnum; ++lnum)
***************
*** 240,246 ****
if (col - 1 > (colnr_T)textlen)
{
semsg(_(e_invalid_column_number_nr), (long)start_col);
! return FAIL;
}
if (lnum == end_lnum)
--- 259,265 ----
if (col - 1 > (colnr_T)textlen)
{
semsg(_(e_invalid_column_number_nr), (long)start_col);
! goto theend;
}
if (lnum == end_lnum)
***************
*** 255,261 ****
// Allocate the new line with space for the new property.
newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
if (newtext == NULL)
! return FAIL;
// Copy the text, including terminating NUL.
mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
--- 274,280 ----
// Allocate the new line with space for the new property.
newtext = alloc(buf->b_ml.ml_line_len + sizeof(textprop_T));
if (newtext == NULL)
! goto theend;
// Copy the text, including terminating NUL.
mch_memmove(newtext, buf->b_ml.ml_line_ptr, textlen);
***************
*** 295,301 ****
}
changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
! return OK;
}
/*
--- 314,324 ----
}
changed_lines_buf(buf, start_lnum, end_lnum + 1, 0);
! res = OK;
!
! theend:
! vim_free(text);
! return res;
}
/*
***************
*** 367,373 ****
emsg(_(e_invalid_argument));
return;
}
! if (prop_add_one(buf, type_name, id, start_lnum, end_lnum,
start_col, end_col) == FAIL)
return;
}
--- 390,396 ----
emsg(_(e_invalid_argument));
return;
}
! if (prop_add_one(buf, type_name, id, NULL, start_lnum, end_lnum,
start_col, end_col) == FAIL)
return;
}
***************
*** 376,386 ****
}
/*
* Shared between prop_add() and popup_create().
* "dict_arg" is the function argument of a dict containing "bufnr".
* it is NULL for popup_create().
*/
! void
prop_add_common(
linenr_T start_lnum,
colnr_T start_col,
--- 399,420 ----
}
/*
+ * Get the next ID to use for a textprop with text in buffer "buf".
+ */
+ static int
+ get_textprop_id(buf_T *buf)
+ {
+ // TODO: recycle deleted entries
+ return -(buf->b_textprop_text.ga_len + 1);
+ }
+
+ /*
* Shared between prop_add() and popup_create().
* "dict_arg" is the function argument of a dict containing "bufnr".
* it is NULL for popup_create().
+ * Returns the "id" used for "text" or zero.
*/
! int
prop_add_common(
linenr_T start_lnum,
colnr_T start_col,
***************
*** 393,403 ****
char_u *type_name;
buf_T *buf = default_buf;
int id = 0;
if (dict == NULL || !dict_has_key(dict, "type"))
{
emsg(_(e_missing_property_type_name));
! return;
}
type_name = dict_get_string(dict, "type", FALSE);
--- 427,438 ----
char_u *type_name;
buf_T *buf = default_buf;
int id = 0;
+ char_u *text = NULL;
if (dict == NULL || !dict_has_key(dict, "type"))
{
emsg(_(e_missing_property_type_name));
! goto theend;
}
type_name = dict_get_string(dict, "type", FALSE);
***************
*** 407,413 ****
if (end_lnum < start_lnum)
{
semsg(_(e_invalid_value_for_argument_str), "end_lnum");
! return;
}
}
else
--- 442,448 ----
if (end_lnum < start_lnum)
{
semsg(_(e_invalid_value_for_argument_str), "end_lnum");
! goto theend;
}
}
else
***************
*** 420,426 ****
if (length < 0 || end_lnum > start_lnum)
{
semsg(_(e_invalid_value_for_argument_str), "length");
! return;
}
end_col = start_col + length;
}
--- 455,461 ----
if (length < 0 || end_lnum > start_lnum)
{
semsg(_(e_invalid_value_for_argument_str), "length");
! goto theend;
}
end_col = start_col + length;
}
***************
*** 430,436 ****
if (end_col <= 0)
{
semsg(_(e_invalid_value_for_argument_str), "end_col");
! return;
}
}
else if (start_lnum == end_lnum)
--- 465,471 ----
if (end_col <= 0)
{
semsg(_(e_invalid_value_for_argument_str), "end_col");
! goto theend;
}
}
else if (start_lnum == end_lnum)
***************
*** 441,457 ****
if (dict_has_key(dict, "id"))
id = dict_get_number(dict, "id");
if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
! return;
// This must be done _before_ we add the property because property changes
// trigger buffer (memline) reorganisation, which needs this flag to be
// correctly set.
buf->b_has_textprop = TRUE; // this is never reset
! prop_add_one(buf, type_name, id, start_lnum, end_lnum, start_col, end_col);
redraw_buf_later(buf, VALID);
}
/*
--- 476,515 ----
if (dict_has_key(dict, "id"))
id = dict_get_number(dict, "id");
+ if (dict_has_key(dict, "text"))
+ {
+ text = dict_get_string(dict, "text", TRUE);
+ if (text == NULL)
+ goto theend;
+ // use a default length of 1 to make multiple props show up
+ end_col = start_col + 1;
+ }
+
if (dict_arg != NULL && get_bufnr_from_arg(dict_arg, &buf) == FAIL)
! goto theend;
!
! if (id < 0 && buf->b_textprop_text.ga_len > 0)
! {
! emsg(_(e_cannot_use_negative_id_after_adding_textprop_with_text));
! goto theend;
! }
! if (text != NULL)
! id = get_textprop_id(buf);
// This must be done _before_ we add the property because property changes
// trigger buffer (memline) reorganisation, which needs this flag to be
// correctly set.
buf->b_has_textprop = TRUE; // this is never reset
! prop_add_one(buf, type_name, id, text,
! start_lnum, end_lnum, start_col, end_col);
! text = NULL;
redraw_buf_later(buf, VALID);
+
+ theend:
+ vim_free(text);
+ return id;
}
/*
***************
*** 954,962 ****
if ((prop_types == NULL
|| prop_type_or_id_in_list(prop_types, prop_types_len,
prop.tp_type))
! && (prop_ids == NULL ||
! prop_type_or_id_in_list(prop_ids, prop_ids_len,
! prop.tp_id)))
{
dict_T *d = dict_alloc();
--- 1012,1020 ----
if ((prop_types == NULL
|| prop_type_or_id_in_list(prop_types, prop_types_len,
prop.tp_type))
! && (prop_ids == NULL
! || prop_type_or_id_in_list(prop_ids, prop_ids_len,
! prop.tp_id)))
{
dict_T *d = dict_alloc();
*** ../vim-9.0.0066/src/testdir/test_textprop.vim 2022-05-24 21:22:09.000000000 +0100
--- src/testdir/test_textprop.vim 2022-07-25 18:09:17.168061181 +0100
***************
*** 2187,2190 ****
--- 2187,2213 ----
bwipe!
endfunc
+ func Test_prop_inserts_text()
+ CheckRunVimInTerminal
+
+ " Just a basic check for now
+ let lines =<< trim END
+ call setline(1, 'insert some text here and other text there and some more text after wrapping')
+ call prop_type_add('someprop', #{highlight: 'ErrorMsg'})
+ call prop_type_add('otherprop', #{highlight: 'Search'})
+ call prop_type_add('moreprop', #{highlight: 'DiffAdd'})
+ call prop_add(1, 18, #{type: 'someprop', text: 'SOME '})
+ call prop_add(1, 38, #{type: 'otherprop', text: 'OTHER '})
+ call prop_add(1, 69, #{type: 'moreprop', text: 'MORE '})
+ redraw
+ normal $
+ END
+ call writefile(lines, 'XscriptPropsWithText')
+ let buf = RunVimInTerminal('-S XscriptPropsWithText', #{rows: 6, cols: 60})
+ call VerifyScreenDump(buf, 'Test_prop_inserts_text', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XscriptPropsWithText')
+ endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
*** ../vim-9.0.0066/src/testdir/dumps/Test_prop_inserts_text.dump 2022-07-25 18:11:47.815151136 +0100
--- src/testdir/dumps/Test_prop_inserts_text.dump 2022-07-25 18:06:47.773105469 +0100
***************
*** 0 ****
--- 1,6 ----
+ |i+0&#ffffff0|n|s|e|r|t| |s|o|m|e| |t|e|x|t| |S+0#ffffff16#e000002|O|M|E| |h+0#0000000#ffffff0|e|r|e| |a|n|d| |o|t|h|e|r| |t|e|x|t| |O+0&#ffff4012|T|H|E|R| |t+0&#ffffff0|h|e|r|e| |a|n|d| |s|o
+ |m|e| |m|o|r|e| |t|e|x|t| |a|f|t|e|r| |M+0fd7ff255|O|R|E| |w+0&#ffffff0|r|a|p@1|i|n|g> @27
+ |~+0#4040ff13&| @58
+ |~| @58
+ |~| @58
+ | +0#0000000&@41|1|,|7@1|-|9|3| @6|A|l@1|
*** ../vim-9.0.0066/src/version.c 2022-07-25 12:28:05.844483996 +0100
--- src/version.c 2022-07-25 18:05:59.213482921 +0100
***************
*** 737,738 ****
--- 737,740 ----
{ /* Add new patch number below this line */
+ /**/
+ 67,
/**/
--
"A clear conscience is usually the sign of a bad memory."
-- Steven Wright
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///