mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
Merge pull request #27536 from bfredl/bufferarena
refactor(api): reduce temporary allocations when replacing lines
This commit is contained in:
commit
69bdcc6823
@ -325,7 +325,8 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
|
|||||||
/// @param replacement Array of lines to use as replacement
|
/// @param replacement Array of lines to use as replacement
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integer end,
|
void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integer end,
|
||||||
Boolean strict_indexing, ArrayOf(String) replacement, Error *err)
|
Boolean strict_indexing, ArrayOf(String) replacement, Arena *arena,
|
||||||
|
Error *err)
|
||||||
FUNC_API_SINCE(1)
|
FUNC_API_SINCE(1)
|
||||||
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
||||||
{
|
{
|
||||||
@ -360,14 +361,14 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
|
|||||||
size_t new_len = replacement.size;
|
size_t new_len = replacement.size;
|
||||||
size_t old_len = (size_t)(end - start);
|
size_t old_len = (size_t)(end - start);
|
||||||
ptrdiff_t extra = 0; // lines added to text, can be negative
|
ptrdiff_t extra = 0; // lines added to text, can be negative
|
||||||
char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL;
|
char **lines = (new_len != 0) ? arena_alloc(arena, new_len * sizeof(char *), true) : NULL;
|
||||||
|
|
||||||
for (size_t i = 0; i < new_len; i++) {
|
for (size_t i = 0; i < new_len; i++) {
|
||||||
const String l = replacement.items[i].data.string;
|
const String l = replacement.items[i].data.string;
|
||||||
|
|
||||||
// Fill lines[i] with l's contents. Convert NULs to newlines as required by
|
// Fill lines[i] with l's contents. Convert NULs to newlines as required by
|
||||||
// NL-used-for-NUL.
|
// NL-used-for-NUL.
|
||||||
lines[i] = xmemdupz(l.data, l.size);
|
lines[i] = arena_memdupz(arena, l.data, l.size);
|
||||||
memchrsub(lines[i], NUL, NL, l.size);
|
memchrsub(lines[i], NUL, NL, l.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,15 +413,12 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
|
|||||||
goto end;
|
goto end;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false) == FAIL) {
|
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
|
||||||
api_set_error(err, kErrorTypeException, "Failed to replace line");
|
api_set_error(err, kErrorTypeException, "Failed to replace line");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
||||||
// Mark lines that haven't been passed to the buffer as they need
|
|
||||||
// to be freed later
|
|
||||||
lines[i] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we may need to insert the remaining new old_len
|
// Now we may need to insert the remaining new old_len
|
||||||
@ -438,9 +436,6 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
|
|||||||
|
|
||||||
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
||||||
|
|
||||||
// Same as with replacing, but we also need to free lines
|
|
||||||
xfree(lines[i]);
|
|
||||||
lines[i] = NULL;
|
|
||||||
extra++;
|
extra++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,11 +458,6 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
|
|||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
for (size_t i = 0; i < new_len; i++) {
|
|
||||||
xfree(lines[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree(lines);
|
|
||||||
try_end(err);
|
try_end(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +490,8 @@ end:
|
|||||||
/// @param replacement Array of lines to use as replacement
|
/// @param replacement Array of lines to use as replacement
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, Integer start_col,
|
void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, Integer start_col,
|
||||||
Integer end_row, Integer end_col, ArrayOf(String) replacement, Error *err)
|
Integer end_row, Integer end_col, ArrayOf(String) replacement, Arena *arena,
|
||||||
|
Error *err)
|
||||||
FUNC_API_SINCE(7)
|
FUNC_API_SINCE(7)
|
||||||
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
||||||
{
|
{
|
||||||
@ -535,33 +526,31 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
char *str_at_start = NULL;
|
// Another call to ml_get_buf() may free the lines, so we make copies
|
||||||
char *str_at_end = NULL;
|
char *str_at_start = ml_get_buf(buf, (linenr_T)start_row);
|
||||||
|
|
||||||
// Another call to ml_get_buf() may free the line, so make a copy.
|
|
||||||
str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row));
|
|
||||||
size_t len_at_start = strlen(str_at_start);
|
size_t len_at_start = strlen(str_at_start);
|
||||||
|
str_at_start = arena_memdupz(arena, str_at_start, len_at_start);
|
||||||
start_col = start_col < 0 ? (int64_t)len_at_start + start_col + 1 : start_col;
|
start_col = start_col < 0 ? (int64_t)len_at_start + start_col + 1 : start_col;
|
||||||
VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", {
|
VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", {
|
||||||
goto early_end;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Another call to ml_get_buf() may free the line, so make a copy.
|
char *str_at_end = ml_get_buf(buf, (linenr_T)end_row);
|
||||||
str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row));
|
|
||||||
size_t len_at_end = strlen(str_at_end);
|
size_t len_at_end = strlen(str_at_end);
|
||||||
|
str_at_end = arena_memdupz(arena, str_at_end, len_at_end);
|
||||||
end_col = end_col < 0 ? (int64_t)len_at_end + end_col + 1 : end_col;
|
end_col = end_col < 0 ? (int64_t)len_at_end + end_col + 1 : end_col;
|
||||||
VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", {
|
VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", {
|
||||||
goto early_end;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
VALIDATE((start_row <= end_row && !(end_row == start_row && start_col > end_col)),
|
VALIDATE((start_row <= end_row && !(end_row == start_row && start_col > end_col)),
|
||||||
"%s", "'start' is higher than 'end'", {
|
"%s", "'start' is higher than 'end'", {
|
||||||
goto early_end;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
bool disallow_nl = (channel_id != VIML_INTERNAL_CALL);
|
bool disallow_nl = (channel_id != VIML_INTERNAL_CALL);
|
||||||
if (!check_string_array(replacement, "replacement string", disallow_nl, err)) {
|
if (!check_string_array(replacement, "replacement string", disallow_nl, err)) {
|
||||||
goto early_end;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t new_len = replacement.size;
|
size_t new_len = replacement.size;
|
||||||
@ -591,7 +580,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
if (replacement.size == 1) {
|
if (replacement.size == 1) {
|
||||||
firstlen += last_part_len;
|
firstlen += last_part_len;
|
||||||
}
|
}
|
||||||
char *first = xmallocz(firstlen);
|
char *first = arena_allocz(arena, firstlen);
|
||||||
char *last = NULL;
|
char *last = NULL;
|
||||||
memcpy(first, str_at_start, (size_t)start_col);
|
memcpy(first, str_at_start, (size_t)start_col);
|
||||||
memcpy(first + start_col, first_item.data, first_item.size);
|
memcpy(first + start_col, first_item.data, first_item.size);
|
||||||
@ -599,13 +588,13 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
if (replacement.size == 1) {
|
if (replacement.size == 1) {
|
||||||
memcpy(first + start_col + first_item.size, str_at_end + end_col, last_part_len);
|
memcpy(first + start_col + first_item.size, str_at_end + end_col, last_part_len);
|
||||||
} else {
|
} else {
|
||||||
last = xmallocz(last_item.size + last_part_len);
|
last = arena_allocz(arena, last_item.size + last_part_len);
|
||||||
memcpy(last, last_item.data, last_item.size);
|
memcpy(last, last_item.data, last_item.size);
|
||||||
memchrsub(last, NUL, NL, last_item.size);
|
memchrsub(last, NUL, NL, last_item.size);
|
||||||
memcpy(last + last_item.size, str_at_end + end_col, last_part_len);
|
memcpy(last + last_item.size, str_at_end + end_col, last_part_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
char **lines = xcalloc(new_len, sizeof(char *));
|
char **lines = arena_alloc(arena, new_len * sizeof(char *), true);
|
||||||
lines[0] = first;
|
lines[0] = first;
|
||||||
new_byte += (bcount_t)(first_item.size);
|
new_byte += (bcount_t)(first_item.size);
|
||||||
for (size_t i = 1; i < new_len - 1; i++) {
|
for (size_t i = 1; i < new_len - 1; i++) {
|
||||||
@ -613,7 +602,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
|
|
||||||
// Fill lines[i] with l's contents. Convert NULs to newlines as required by
|
// Fill lines[i] with l's contents. Convert NULs to newlines as required by
|
||||||
// NL-used-for-NUL.
|
// NL-used-for-NUL.
|
||||||
lines[i] = xmemdupz(l.data, l.size);
|
lines[i] = arena_memdupz(arena, l.data, l.size);
|
||||||
memchrsub(lines[i], NUL, NL, l.size);
|
memchrsub(lines[i], NUL, NL, l.size);
|
||||||
new_byte += (bcount_t)(l.size) + 1;
|
new_byte += (bcount_t)(l.size) + 1;
|
||||||
}
|
}
|
||||||
@ -665,13 +654,10 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
goto end;
|
goto end;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false) == FAIL) {
|
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) {
|
||||||
api_set_error(err, kErrorTypeException, "Failed to replace line");
|
api_set_error(err, kErrorTypeException, "Failed to replace line");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
// Mark lines that haven't been passed to the buffer as they need
|
|
||||||
// to be freed later
|
|
||||||
lines[i] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we may need to insert the remaining new old_len
|
// Now we may need to insert the remaining new old_len
|
||||||
@ -687,9 +673,6 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as with replacing, but we also need to free lines
|
|
||||||
xfree(lines[i]);
|
|
||||||
lines[i] = NULL;
|
|
||||||
extra++;
|
extra++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,15 +705,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
|
|||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
for (size_t i = 0; i < new_len; i++) {
|
|
||||||
xfree(lines[i]);
|
|
||||||
}
|
|
||||||
xfree(lines);
|
|
||||||
try_end(err);
|
try_end(err);
|
||||||
|
|
||||||
early_end:
|
|
||||||
xfree(str_at_start);
|
|
||||||
xfree(str_at_end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a range from the buffer.
|
/// Gets a range from the buffer.
|
||||||
|
@ -225,12 +225,12 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *er
|
|||||||
/// the end of the buffer.
|
/// the end of the buffer.
|
||||||
/// @param lines Array of lines
|
/// @param lines Array of lines
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void buffer_insert(Buffer buffer, Integer lnum, ArrayOf(String) lines, Error *err)
|
void buffer_insert(Buffer buffer, Integer lnum, ArrayOf(String) lines, Arena *arena, Error *err)
|
||||||
FUNC_API_DEPRECATED_SINCE(1)
|
FUNC_API_DEPRECATED_SINCE(1)
|
||||||
{
|
{
|
||||||
// "lnum" will be the index of the line after inserting,
|
// "lnum" will be the index of the line after inserting,
|
||||||
// no matter if it is negative or not
|
// no matter if it is negative or not
|
||||||
nvim_buf_set_lines(0, buffer, lnum, lnum, true, lines, err);
|
nvim_buf_set_lines(0, buffer, lnum, lnum, true, lines, arena, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a buffer line
|
/// Gets a buffer line
|
||||||
@ -272,13 +272,13 @@ String buffer_get_line(Buffer buffer, Integer index, Arena *arena, Error *err)
|
|||||||
/// @param index Line index
|
/// @param index Line index
|
||||||
/// @param line Contents of the new line
|
/// @param line Contents of the new line
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
|
void buffer_set_line(Buffer buffer, Integer index, String line, Arena *arena, Error *err)
|
||||||
FUNC_API_DEPRECATED_SINCE(1)
|
FUNC_API_DEPRECATED_SINCE(1)
|
||||||
{
|
{
|
||||||
Object l = STRING_OBJ(line);
|
Object l = STRING_OBJ(line);
|
||||||
Array array = { .items = &l, .size = 1 };
|
Array array = { .items = &l, .size = 1 };
|
||||||
index = convert_index(index);
|
index = convert_index(index);
|
||||||
nvim_buf_set_lines(0, buffer, index, index + 1, true, array, err);
|
nvim_buf_set_lines(0, buffer, index, index + 1, true, array, arena, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes a buffer line
|
/// Deletes a buffer line
|
||||||
@ -291,12 +291,12 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
|
|||||||
/// @param buffer buffer handle
|
/// @param buffer buffer handle
|
||||||
/// @param index line index
|
/// @param index line index
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void buffer_del_line(Buffer buffer, Integer index, Error *err)
|
void buffer_del_line(Buffer buffer, Integer index, Arena *arena, Error *err)
|
||||||
FUNC_API_DEPRECATED_SINCE(1)
|
FUNC_API_DEPRECATED_SINCE(1)
|
||||||
{
|
{
|
||||||
Array array = ARRAY_DICT_INIT;
|
Array array = ARRAY_DICT_INIT;
|
||||||
index = convert_index(index);
|
index = convert_index(index);
|
||||||
nvim_buf_set_lines(0, buffer, index, index + 1, true, array, err);
|
nvim_buf_set_lines(0, buffer, index, index + 1, true, array, arena, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves a line range from the buffer
|
/// Retrieves a line range from the buffer
|
||||||
@ -342,12 +342,13 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
|
|||||||
// array will delete the line range)
|
// array will delete the line range)
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean include_start,
|
void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean include_start,
|
||||||
Boolean include_end, ArrayOf(String) replacement, Error *err)
|
Boolean include_end, ArrayOf(String) replacement, Arena *arena,
|
||||||
|
Error *err)
|
||||||
FUNC_API_DEPRECATED_SINCE(1)
|
FUNC_API_DEPRECATED_SINCE(1)
|
||||||
{
|
{
|
||||||
start = convert_index(start) + !include_start;
|
start = convert_index(start) + !include_start;
|
||||||
end = convert_index(end) + include_end;
|
end = convert_index(end) + include_end;
|
||||||
nvim_buf_set_lines(0, buffer, start, end, false, replacement, err);
|
nvim_buf_set_lines(0, buffer, start, end, false, replacement, arena, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a buffer-scoped (b:) variable
|
/// Sets a buffer-scoped (b:) variable
|
||||||
|
@ -675,21 +675,21 @@ String nvim_get_current_line(Arena *arena, Error *err)
|
|||||||
///
|
///
|
||||||
/// @param line Line contents
|
/// @param line Line contents
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void nvim_set_current_line(String line, Error *err)
|
void nvim_set_current_line(String line, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(1)
|
FUNC_API_SINCE(1)
|
||||||
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
||||||
{
|
{
|
||||||
buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err);
|
buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, arena, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the current line.
|
/// Deletes the current line.
|
||||||
///
|
///
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
void nvim_del_current_line(Error *err)
|
void nvim_del_current_line(Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(1)
|
FUNC_API_SINCE(1)
|
||||||
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
|
||||||
{
|
{
|
||||||
buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err);
|
buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, arena, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a global (g:) variable.
|
/// Gets a global (g:) variable.
|
||||||
|
@ -4674,7 +4674,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
|
|||||||
snprintf(str, line_size, "|%*" PRIdLINENR "| %s", col_width - 3,
|
snprintf(str, line_size, "|%*" PRIdLINENR "| %s", col_width - 3,
|
||||||
next_linenr, line);
|
next_linenr, line);
|
||||||
if (linenr_preview == 0) {
|
if (linenr_preview == 0) {
|
||||||
ml_replace_buf(cmdpreview_buf, 1, str, true);
|
ml_replace_buf(cmdpreview_buf, 1, str, true, false);
|
||||||
} else {
|
} else {
|
||||||
ml_append_buf(cmdpreview_buf, linenr_preview, str, (colnr_T)line_size, false);
|
ml_append_buf(cmdpreview_buf, linenr_preview, str, (colnr_T)line_size, false);
|
||||||
}
|
}
|
||||||
|
@ -1626,7 +1626,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark
|
|||||||
STRCPY(newline + line_len + (p - cms) + markerlen, p + 2);
|
STRCPY(newline + line_len + (p - cms) + markerlen, p + 2);
|
||||||
added = markerlen + strlen(cms) - 2;
|
added = markerlen + strlen(cms) - 2;
|
||||||
}
|
}
|
||||||
ml_replace_buf(buf, lnum, newline, false);
|
ml_replace_buf(buf, lnum, newline, false, false);
|
||||||
if (added) {
|
if (added) {
|
||||||
extmark_splice_cols(buf, (int)lnum - 1, (int)line_len,
|
extmark_splice_cols(buf, (int)lnum - 1, (int)line_len,
|
||||||
0, (int)added, kExtmarkUndo);
|
0, (int)added, kExtmarkUndo);
|
||||||
@ -1690,7 +1690,7 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char *marker, size_t marker
|
|||||||
assert(p >= line);
|
assert(p >= line);
|
||||||
memcpy(newline, line, (size_t)(p - line));
|
memcpy(newline, line, (size_t)(p - line));
|
||||||
STRCPY(newline + (p - line), p + len);
|
STRCPY(newline + (p - line), p + len);
|
||||||
ml_replace_buf(buf, lnum, newline, false);
|
ml_replace_buf(buf, lnum, newline, false, false);
|
||||||
extmark_splice_cols(buf, (int)lnum - 1, (int)(p - line),
|
extmark_splice_cols(buf, (int)lnum - 1, (int)(p - line),
|
||||||
(int)len, 0, kExtmarkUndo);
|
(int)len, 0, kExtmarkUndo);
|
||||||
}
|
}
|
||||||
|
@ -1694,7 +1694,7 @@ void ml_sync_all(int check_file, int check_char, bool do_fsync)
|
|||||||
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL) {
|
if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL) {
|
||||||
continue; // no file
|
continue; // no file
|
||||||
}
|
}
|
||||||
ml_flush_line(buf); // flush buffered line
|
ml_flush_line(buf, false); // flush buffered line
|
||||||
// flush locked block
|
// flush locked block
|
||||||
ml_find_line(buf, 0, ML_FLUSH);
|
ml_find_line(buf, 0, ML_FLUSH);
|
||||||
if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
|
if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
|
||||||
@ -1745,7 +1745,7 @@ void ml_preserve(buf_T *buf, bool message, bool do_fsync)
|
|||||||
// before.
|
// before.
|
||||||
got_int = false;
|
got_int = false;
|
||||||
|
|
||||||
ml_flush_line(buf); // flush buffered line
|
ml_flush_line(buf, false); // flush buffered line
|
||||||
ml_find_line(buf, 0, ML_FLUSH); // flush locked block
|
ml_find_line(buf, 0, ML_FLUSH); // flush locked block
|
||||||
int status = mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0));
|
int status = mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0));
|
||||||
|
|
||||||
@ -1862,7 +1862,7 @@ static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change)
|
|||||||
siemsg(_(e_ml_get_invalid_lnum_nr), (int64_t)lnum);
|
siemsg(_(e_ml_get_invalid_lnum_nr), (int64_t)lnum);
|
||||||
recursive--;
|
recursive--;
|
||||||
}
|
}
|
||||||
ml_flush_line(buf);
|
ml_flush_line(buf, false);
|
||||||
errorret:
|
errorret:
|
||||||
STRCPY(questions, "???");
|
STRCPY(questions, "???");
|
||||||
buf->b_ml.ml_line_lnum = lnum;
|
buf->b_ml.ml_line_lnum = lnum;
|
||||||
@ -1881,7 +1881,7 @@ errorret:
|
|||||||
// Don't use the last used line when 'swapfile' is reset, need to load all
|
// Don't use the last used line when 'swapfile' is reset, need to load all
|
||||||
// blocks.
|
// blocks.
|
||||||
if (buf->b_ml.ml_line_lnum != lnum) {
|
if (buf->b_ml.ml_line_lnum != lnum) {
|
||||||
ml_flush_line(buf);
|
ml_flush_line(buf, false);
|
||||||
|
|
||||||
// Find the data block containing the line.
|
// Find the data block containing the line.
|
||||||
// This also fills the stack with the blocks from the root to the data
|
// This also fills the stack with the blocks from the root to the data
|
||||||
@ -1964,7 +1964,7 @@ int ml_append(linenr_T lnum, char *line, colnr_T len, bool newfile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (curbuf->b_ml.ml_line_lnum != 0) {
|
if (curbuf->b_ml.ml_line_lnum != 0) {
|
||||||
ml_flush_line(curbuf);
|
ml_flush_line(curbuf, false);
|
||||||
}
|
}
|
||||||
return ml_append_int(curbuf, lnum, line, len, newfile, false);
|
return ml_append_int(curbuf, lnum, line, len, newfile, false);
|
||||||
}
|
}
|
||||||
@ -1984,7 +1984,7 @@ int ml_append_buf(buf_T *buf, linenr_T lnum, char *line, colnr_T len, bool newfi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf->b_ml.ml_line_lnum != 0) {
|
if (buf->b_ml.ml_line_lnum != 0) {
|
||||||
ml_flush_line(buf);
|
ml_flush_line(buf, false);
|
||||||
}
|
}
|
||||||
return ml_append_int(buf, lnum, line, len, newfile, false);
|
return ml_append_int(buf, lnum, line, len, newfile, false);
|
||||||
}
|
}
|
||||||
@ -2423,7 +2423,7 @@ void ml_add_deleted_len_buf(buf_T *buf, char *ptr, ssize_t len)
|
|||||||
|
|
||||||
int ml_replace(linenr_T lnum, char *line, bool copy)
|
int ml_replace(linenr_T lnum, char *line, bool copy)
|
||||||
{
|
{
|
||||||
return ml_replace_buf(curbuf, lnum, line, copy);
|
return ml_replace_buf(curbuf, lnum, line, copy, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace line "lnum", with buffering, in current buffer.
|
/// Replace line "lnum", with buffering, in current buffer.
|
||||||
@ -2438,7 +2438,7 @@ int ml_replace(linenr_T lnum, char *line, bool copy)
|
|||||||
/// changed_lines(), unless update_screen(UPD_NOT_VALID) is used.
|
/// changed_lines(), unless update_screen(UPD_NOT_VALID) is used.
|
||||||
///
|
///
|
||||||
/// @return FAIL for failure, OK otherwise
|
/// @return FAIL for failure, OK otherwise
|
||||||
int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy)
|
int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy, bool noalloc)
|
||||||
{
|
{
|
||||||
if (line == NULL) { // just checking...
|
if (line == NULL) { // just checking...
|
||||||
return FAIL;
|
return FAIL;
|
||||||
@ -2450,12 +2450,13 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (copy) {
|
if (copy) {
|
||||||
|
assert(!noalloc);
|
||||||
line = xstrdup(line);
|
line = xstrdup(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf->b_ml.ml_line_lnum != lnum) {
|
if (buf->b_ml.ml_line_lnum != lnum) {
|
||||||
// another line is buffered, flush it
|
// another line is buffered, flush it
|
||||||
ml_flush_line(buf);
|
ml_flush_line(buf, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kv_size(buf->update_callbacks)) {
|
if (kv_size(buf->update_callbacks)) {
|
||||||
@ -2469,6 +2470,13 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy)
|
|||||||
buf->b_ml.ml_line_ptr = line;
|
buf->b_ml.ml_line_ptr = line;
|
||||||
buf->b_ml.ml_line_lnum = lnum;
|
buf->b_ml.ml_line_lnum = lnum;
|
||||||
buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
|
buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
|
||||||
|
if (noalloc) {
|
||||||
|
// TODO(bfredl): this is a bit of a hack. but replacing lines in a loop is really common,
|
||||||
|
// and allocating a separate scratch buffer for each line which is immediately freed adds
|
||||||
|
// a lot of noise. A more general refactor could be to use a _fixed_ scratch buffer for
|
||||||
|
// all lines up to $REASONABLE_SIZE .
|
||||||
|
ml_flush_line(buf, true);
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -2483,7 +2491,7 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy)
|
|||||||
/// @return FAIL for failure, OK otherwise
|
/// @return FAIL for failure, OK otherwise
|
||||||
int ml_delete(linenr_T lnum, bool message)
|
int ml_delete(linenr_T lnum, bool message)
|
||||||
{
|
{
|
||||||
ml_flush_line(curbuf);
|
ml_flush_line(curbuf, false);
|
||||||
return ml_delete_int(curbuf, lnum, message);
|
return ml_delete_int(curbuf, lnum, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2496,7 +2504,7 @@ int ml_delete(linenr_T lnum, bool message)
|
|||||||
/// @return FAIL for failure, OK otherwise
|
/// @return FAIL for failure, OK otherwise
|
||||||
int ml_delete_buf(buf_T *buf, linenr_T lnum, bool message)
|
int ml_delete_buf(buf_T *buf, linenr_T lnum, bool message)
|
||||||
{
|
{
|
||||||
ml_flush_line(buf);
|
ml_flush_line(buf, false);
|
||||||
return ml_delete_int(buf, lnum, message);
|
return ml_delete_int(buf, lnum, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2516,7 +2524,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
|
|||||||
set_keep_msg(_(no_lines_msg), 0);
|
set_keep_msg(_(no_lines_msg), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = ml_replace_buf(buf, 1, "", true);
|
int i = ml_replace_buf(buf, 1, "", true, false);
|
||||||
buf->b_ml.ml_flags |= ML_EMPTY;
|
buf->b_ml.ml_flags |= ML_EMPTY;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
@ -2724,7 +2732,7 @@ size_t ml_flush_deleted_bytes(buf_T *buf, size_t *codepoints, size_t *codeunits)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// flush ml_line if necessary
|
/// flush ml_line if necessary
|
||||||
static void ml_flush_line(buf_T *buf)
|
static void ml_flush_line(buf_T *buf, bool noalloc)
|
||||||
{
|
{
|
||||||
static bool entered = false;
|
static bool entered = false;
|
||||||
|
|
||||||
@ -2798,10 +2806,13 @@ static void ml_flush_line(buf_T *buf)
|
|||||||
ml_delete_int(buf, lnum, false);
|
ml_delete_int(buf, lnum, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xfree(new_line);
|
if (!noalloc) {
|
||||||
|
xfree(new_line);
|
||||||
|
}
|
||||||
|
|
||||||
entered = false;
|
entered = false;
|
||||||
} else if (buf->b_ml.ml_flags & ML_ALLOCATED) {
|
} else if (buf->b_ml.ml_flags & ML_ALLOCATED) {
|
||||||
|
assert(!noalloc); // caller must set ML_LINE_DIRTY with noalloc, handled above
|
||||||
xfree(buf->b_ml.ml_line_ptr);
|
xfree(buf->b_ml.ml_line_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3903,7 +3914,7 @@ int ml_find_line_or_offset(buf_T *buf, linenr_T lnum, int *offp, bool no_ff)
|
|||||||
// was never cached to start with anyway).
|
// was never cached to start with anyway).
|
||||||
bool can_cache = (lnum != 0 && !ffdos && buf->b_ml.ml_line_lnum == lnum);
|
bool can_cache = (lnum != 0 && !ffdos && buf->b_ml.ml_line_lnum == lnum);
|
||||||
if (lnum == 0 || buf->b_ml.ml_line_lnum < lnum || !no_ff) {
|
if (lnum == 0 || buf->b_ml.ml_line_lnum < lnum || !no_ff) {
|
||||||
ml_flush_line(curbuf);
|
ml_flush_line(curbuf, false);
|
||||||
} else if (can_cache && buf->b_ml.ml_line_offset > 0) {
|
} else if (can_cache && buf->b_ml.ml_line_offset > 0) {
|
||||||
return (int)buf->b_ml.ml_line_offset;
|
return (int)buf->b_ml.ml_line_offset;
|
||||||
}
|
}
|
||||||
@ -4030,7 +4041,7 @@ void goto_byte(int cnt)
|
|||||||
{
|
{
|
||||||
int boff = cnt;
|
int boff = cnt;
|
||||||
|
|
||||||
ml_flush_line(curbuf); // cached line may be dirty
|
ml_flush_line(curbuf, false); // cached line may be dirty
|
||||||
setpcmark();
|
setpcmark();
|
||||||
if (boff) {
|
if (boff) {
|
||||||
boff--;
|
boff--;
|
||||||
|
@ -667,14 +667,20 @@ void arena_mem_free(ArenaMem mem)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *arena_memdupz(Arena *arena, const char *buf, size_t size)
|
char *arena_allocz(Arena *arena, size_t size)
|
||||||
{
|
{
|
||||||
char *mem = arena_alloc(arena, size + 1, false);
|
char *mem = arena_alloc(arena, size + 1, false);
|
||||||
memcpy(mem, buf, size);
|
|
||||||
mem[size] = NUL;
|
mem[size] = NUL;
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *arena_memdupz(Arena *arena, const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
char *mem = arena_allocz(arena, size);
|
||||||
|
memcpy(mem, buf, size);
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(EXITFREE)
|
#if defined(EXITFREE)
|
||||||
|
|
||||||
# include "nvim/autocmd.h"
|
# include "nvim/autocmd.h"
|
||||||
|
@ -581,7 +581,7 @@ Array runtime_inspect(Arena *arena)
|
|||||||
|
|
||||||
for (size_t i = 0; i < kv_size(path); i++) {
|
for (size_t i = 0; i < kv_size(path); i++) {
|
||||||
SearchPathItem *item = &kv_A(path, i);
|
SearchPathItem *item = &kv_A(path, i);
|
||||||
Array entry = ARRAY_DICT_INIT;
|
Array entry = arena_array(arena, 3);
|
||||||
ADD_C(entry, CSTR_AS_OBJ(item->path));
|
ADD_C(entry, CSTR_AS_OBJ(item->path));
|
||||||
ADD_C(entry, BOOLEAN_OBJ(item->after));
|
ADD_C(entry, BOOLEAN_OBJ(item->after));
|
||||||
if (item->has_lua != kNone) {
|
if (item->has_lua != kNone) {
|
||||||
|
Loading…
Reference in New Issue
Block a user