vim-patch:9.1.0151: ml_get_buf_len() does not consider text properties (#37094)

Problem:  ml_get_buf_len() does not consider text properties
          (zeertzj)
Solution: Store text length excluding text properties length
          in addition in the memline

related vim/vim#14123
closes: vim/vim#14133

a72d1be5a9

--------

Replace ml_line_len with ml_line_textlen to be explicit
that Nvim doesn't currently support Vim's text properties
and Nvim doesn't support lines with "ambiguous" length.

--------

vim-patch:9.1.0153: Text properties corrupted with fo+=aw and backspace

Problem:  Text properties corrupted with fo+=aw and backspace
Solution: Allocate line and move text properties
          (zeertzjq)

closes: vim/vim#14147

7ac1145fbe

vim-patch:9.1.0163: Calling STRLEN() to compute ml_line_textlen when not needed

Problem:  Calling STRLEN() to compute ml_line_textlen when not needed.
Solution: Use 0 when STRLEN() will be required and call STRLEN() later.
          (zeertzjq)

closes: vim/vim#14155

82e079df81

Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
Jan Edmund Lazo
2025-12-25 02:38:45 -05:00
committed by GitHub
parent 1cde71233f
commit 60a0e3d0a0
5 changed files with 34 additions and 21 deletions

View File

@@ -937,14 +937,14 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen);
newp = oldp; // use same allocated memory
} else { // need to allocate a new line
newp = xmalloc((size_t)newlen + 1);
newp = xmallocz((size_t)newlen);
memmove(newp, oldp, (size_t)col);
}
memmove(newp + col, oldp + col + count, (size_t)movelen);
if (alloc_newp) {
ml_replace(lnum, newp, false);
} else {
curbuf->b_ml.ml_line_len -= count;
curbuf->b_ml.ml_line_textlen = newlen + 1;
}
// mark the buffer as changed and prepare for displaying

View File

@@ -3386,11 +3386,17 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
// again when auto-formatting.
if (has_format_option(FO_AUTO)
&& has_format_option(FO_WHITE_PAR)) {
char *ptr = ml_get_buf_mut(curbuf, curwin->w_cursor.lnum);
const char *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum);
int len = get_cursor_line_len();
if (len > 0 && ptr[len - 1] == ' ') {
ptr[len - 1] = NUL;
curbuf->b_ml.ml_line_len--;
char *newp = xmemdupz(ptr, (size_t)(len - 1));
if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) {
xfree(curbuf->b_ml.ml_line_ptr);
}
curbuf->b_ml.ml_line_ptr = newp;
curbuf->b_ml.ml_line_textlen--;
curbuf->b_ml.ml_flags |= ML_LINE_DIRTY;
}
}
@@ -4038,17 +4044,18 @@ static bool ins_tab(void)
int i = cursor->col - fpos.col;
if (i > 0) {
if (!(State & VREPLACE_FLAG)) {
char *newp = xmalloc((size_t)(curbuf->b_ml.ml_line_len - i));
const colnr_T newp_len = curbuf->b_ml.ml_line_textlen - i;
char *newp = xmalloc((size_t)newp_len);
ptrdiff_t col = ptr - curbuf->b_ml.ml_line_ptr;
if (col > 0) {
memmove(newp, ptr - col, (size_t)col);
}
memmove(newp + col, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - col - i));
memmove(newp + col, ptr + i, (size_t)(newp_len - col));
if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) {
xfree(curbuf->b_ml.ml_line_ptr);
}
curbuf->b_ml.ml_line_ptr = newp;
curbuf->b_ml.ml_line_len -= i;
curbuf->b_ml.ml_line_textlen = newp_len;
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
inserted_bytes(fpos.lnum, change_col,
cursor->col - change_col, fpos.col - change_col);

View File

@@ -1804,6 +1804,7 @@ theend:
/// On failure an error message is given and IObuff is returned (to avoid
/// having to check for error everywhere).
char *ml_get(linenr_T lnum)
FUNC_ATTR_NONNULL_RET
{
return ml_get_buf_impl(curbuf, lnum, false);
}
@@ -1813,6 +1814,7 @@ char *ml_get(linenr_T lnum)
/// This is the same as ml_get(), but taking in the buffer
/// as an argument.
char *ml_get_buf(buf_T *buf, linenr_T lnum)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
return ml_get_buf_impl(buf, lnum, false);
}
@@ -1824,6 +1826,7 @@ char *ml_get_buf(buf_T *buf, linenr_T lnum)
///
/// @return a pointer to a line in the buffer
char *ml_get_buf_mut(buf_T *buf, linenr_T lnum)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
return ml_get_buf_impl(buf, lnum, true);
}
@@ -1850,11 +1853,14 @@ colnr_T ml_get_pos_len(pos_T *pos)
/// @return length (excluding the NUL) of the given line in the given buffer.
colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum)
{
if (*ml_get_buf(buf, lnum) == NUL) {
const char *line = ml_get_buf(buf, lnum);
if (*line == NUL) {
return 0;
}
return buf->b_ml.ml_line_len - 1;
assert(buf->b_ml.ml_line_textlen > 0);
return buf->b_ml.ml_line_textlen - 1;
}
/// @return codepoint at pos. pos must be either valid or have col set to MAXCOL!
@@ -1872,13 +1878,13 @@ int gchar_pos(pos_T *pos)
///
/// @return a pointer to a line in a specific buffer
static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change)
FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
static int recursive = 0;
static char questions[4];
if (buf->b_ml.ml_mfp == NULL) { // there are no lines
buf->b_ml.ml_line_len = 1;
buf->b_ml.ml_line_textlen = 1;
return "";
}
@@ -1893,7 +1899,7 @@ static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change)
ml_flush_line(buf, false);
errorret:
STRCPY(questions, "???");
buf->b_ml.ml_line_len = 4;
buf->b_ml.ml_line_textlen = 4;
buf->b_ml.ml_line_lnum = lnum;
return questions;
}
@@ -1933,7 +1939,7 @@ errorret:
unsigned end = idx == 0 ? dp->db_txt_end : (dp->db_index[idx - 1] & DB_INDEX_MASK);
buf->b_ml.ml_line_ptr = (char *)dp + start;
buf->b_ml.ml_line_len = (colnr_T)(end - start);
buf->b_ml.ml_line_textlen = (colnr_T)(end - start);
buf->b_ml.ml_line_lnum = lnum;
buf->b_ml.ml_flags &= ~(ML_LINE_DIRTY | ML_ALLOCATED);
}
@@ -1952,7 +1958,7 @@ errorret:
if ((buf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) == 0) {
// make sure the text is in allocated memory
buf->b_ml.ml_line_ptr = xmemdup(buf->b_ml.ml_line_ptr,
(size_t)buf->b_ml.ml_line_len);
(size_t)buf->b_ml.ml_line_textlen);
buf->b_ml.ml_flags |= ML_ALLOCATED;
if (will_change) {
// can't make the change in the data block
@@ -2526,7 +2532,6 @@ int ml_replace_buf_len(buf_T *buf, linenr_T lnum, char *line_arg, size_t len_arg
FUNC_ATTR_NONNULL_ARG(1)
{
char *line = line_arg;
colnr_T len = (colnr_T)len_arg;
if (line == NULL) { // just checking...
return FAIL;
@@ -2556,7 +2561,7 @@ int ml_replace_buf_len(buf_T *buf, linenr_T lnum, char *line_arg, size_t len_arg
}
buf->b_ml.ml_line_ptr = line;
buf->b_ml.ml_line_len = len + 1;
buf->b_ml.ml_line_textlen = (colnr_T)len_arg + 1;
buf->b_ml.ml_line_lnum = lnum;
buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
if (noalloc) {
@@ -2875,7 +2880,7 @@ static void ml_flush_line(buf_T *buf, bool noalloc)
} else { // text of previous line follows
old_len = (int)(dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
}
colnr_T new_len = buf->b_ml.ml_line_len;
colnr_T new_len = buf->b_ml.ml_line_textlen;
int extra = new_len - old_len; // negative if lines gets smaller
// if new line fits in data block, replace directly
@@ -3833,7 +3838,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, int len, int updtype)
// First line in empty buffer from ml_flush_line() -- reset
buf->b_ml.ml_usedchunks = 1;
buf->b_ml.ml_chunksize[0].mlcs_numlines = 1;
buf->b_ml.ml_chunksize[0].mlcs_totalsize = buf->b_ml.ml_line_len;
buf->b_ml.ml_chunksize[0].mlcs_totalsize = buf->b_ml.ml_line_textlen;
return;
}

View File

@@ -56,7 +56,8 @@ typedef struct {
#define ML_ALLOCATED 0x10 // ml_line_ptr is an allocated copy
int ml_flags;
colnr_T ml_line_len; // length of the cached line + NUL
// colnr_T ml_line_len;
colnr_T ml_line_textlen; // length of the cached line + NUL
linenr_T ml_line_lnum; // line number of cached line, 0 if not valid
char *ml_line_ptr; // pointer to cached line
size_t ml_line_offset; // cached byte offset of ml_line_lnum

View File

@@ -1053,7 +1053,7 @@ static void pbyte(pos_T lp, int c)
{
assert(c <= UCHAR_MAX);
char *p = ml_get_buf_mut(curbuf, lp.lnum);
colnr_T len = curbuf->b_ml.ml_line_len;
colnr_T len = curbuf->b_ml.ml_line_textlen;
// safety check
if (lp.col >= len) {