diff options
-rw-r--r-- | src/nvim/api/buffer.c | 14 | ||||
-rw-r--r-- | src/nvim/ops.c | 27 | ||||
-rw-r--r-- | src/nvim/ops.h | 1 | ||||
-rw-r--r-- | test/functional/lua/buffer_updates_spec.lua | 23 |
4 files changed, 57 insertions, 8 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 915b99486d..a396693a61 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -27,6 +27,7 @@ #include "nvim/map_defs.h" #include "nvim/map.h" #include "nvim/mark.h" +#include "nvim/ops.h" #include "nvim/extmark.h" #include "nvim/decoration.h" #include "nvim/fileio.h" @@ -441,6 +442,8 @@ void nvim_buf_set_lines(uint64_t channel_id, goto end; } + bcount_t deleted_bytes = MAX(get_region_bytecount(start, end, 0, 0)-1, 0); + // If the size of the range is reducing (ie, new_len < old_len) we // need to delete some old_len. We do this at the start, by // repeatedly deleting line "start". @@ -460,6 +463,7 @@ void nvim_buf_set_lines(uint64_t channel_id, // new old_len. This is a more efficient operation, as it requires // less memory allocation and freeing. size_t to_replace = old_len < new_len ? old_len : new_len; + bcount_t inserted_bytes = 0; for (size_t i = 0; i < to_replace; i++) { int64_t lnum = start + (int64_t)i; @@ -472,6 +476,8 @@ void nvim_buf_set_lines(uint64_t channel_id, api_set_error(err, kErrorTypeException, "Failed to replace line"); goto end; } + + inserted_bytes += STRLEN(lines[i]) + 1; // Mark lines that haven't been passed to the buffer as they need // to be freed later lines[i] = NULL; @@ -491,6 +497,8 @@ void nvim_buf_set_lines(uint64_t channel_id, goto end; } + inserted_bytes += STRLEN(lines[i]) + 1; + // Same as with replacing, but we also need to free lines xfree(lines[i]); lines[i] = NULL; @@ -505,7 +513,11 @@ void nvim_buf_set_lines(uint64_t channel_id, (linenr_T)(end - 1), MAXLNUM, (long)extra, - kExtmarkUndo); + kExtmarkNOOP); + + extmark_splice(curbuf, (int)start-1, 0, (int)(end-start), 0, + deleted_bytes, (int)(end+extra-1), 0, inserted_bytes, + kExtmarkUndo); changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra, true); fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 10b8ebdc22..569ed167d2 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1676,17 +1676,14 @@ int op_delete(oparg_T *oap) curbuf_splice_pending++; pos_T startpos = curwin->w_cursor; // start position for delete - bcount_t deleted_bytes = (bcount_t)STRLEN( - ml_get(startpos.lnum)) + 1 - startpos.col; + bcount_t deleted_bytes = get_region_bytecount( + startpos.lnum, oap->end.lnum, startpos.col, + oap->end.col) - !oap->inclusive; truncate_line(true); // delete from cursor to end of line curpos = curwin->w_cursor; // remember curwin->w_cursor curwin->w_cursor.lnum++; - for (linenr_T i = 1; i <= oap->line_count - 2; i++) { - deleted_bytes += (bcount_t)STRLEN( - ml_get(startpos.lnum + i)) + 1; - } del_lines(oap->line_count - 2, false); // delete from start of line until op_end @@ -1694,7 +1691,6 @@ int op_delete(oparg_T *oap) curwin->w_cursor.col = 0; (void)del_bytes((colnr_T)n, !virtual_op, oap->op_type == OP_DELETE && !oap->is_VIsual); - deleted_bytes += n; curwin->w_cursor = curpos; // restore curwin->w_cursor (void)do_join(2, false, false, false, false); curbuf_splice_pending--; @@ -6303,3 +6299,20 @@ bool op_reg_set_previous(const char name) y_previous = &y_regs[i]; return true; } + +bcount_t get_region_bytecount(linenr_T start_lnum, linenr_T end_lnum, + colnr_T start_col, colnr_T end_col) +{ + const char *first = (const char *)ml_get(start_lnum); + bcount_t deleted_bytes = (bcount_t)STRLEN(first) - start_col + 1; + + if (start_lnum == end_lnum) { + return deleted_bytes - ((bcount_t)STRLEN(first) - end_col + 1); + } + + for (linenr_T i = 1; i <= end_lnum-start_lnum-1; i++) { + deleted_bytes += (bcount_t)STRLEN( + ml_get(start_lnum + i)) + 1; + } + return deleted_bytes + end_col + 1; +} diff --git a/src/nvim/ops.h b/src/nvim/ops.h index a8867e02ea..77d6b4435f 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -6,6 +6,7 @@ #include "nvim/macros.h" #include "nvim/ascii.h" #include "nvim/types.h" +#include "nvim/extmark.h" #include "nvim/eval/typval.h" #include "nvim/os/time.h" #include "nvim/normal.h" // for MotionType and oparg_T diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index d4c65eae5b..bd7f0b9cdd 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -958,6 +958,29 @@ describe('lua: nvim_buf_attach on_bytes', function() } end) + it("nvim_buf_set_lines", function() + local check_events = setup_eventcheck(verify, {"AAA", "BBB"}) + + -- delete + command("lua vim.api.nvim_buf_set_lines(0, 0, 1, true, {})") + + check_events { + { "test1", "bytes", 1, 3, 0, 0, 0, 1, 0, 4, 0, 0, 0 }; + } + + -- add + command("lua vim.api.nvim_buf_set_lines(0, 0, 0, true, {'asdf'})") + check_events { + { "test1", "bytes", 1, 4, 0, 0, 0, 0, 0, 0, 1, 0, 5 }; + } + + -- replace + command("lua vim.api.nvim_buf_set_lines(0, 0, 1, true, {'asdf', 'fdsa'})") + check_events { + { "test1", "bytes", 1, 5, 0, 0, 0, 1, 0, 5, 2, 0, 10 }; + } + end) + teardown(function() os.remove "Xtest-reload" os.remove "Xtest-undofile" |