From 15004473b531e37a6ff3aeca9e3bfeaaa1487d9e Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 23 Feb 2022 15:19:47 -0700 Subject: [PATCH] fix(api)!: correctly handle negative line numbers for nvim_buf_set_text (#17498) nvim_buf_set_text does not handle negative row numbers correctly: for example, nvim_buf_set_text(0, -2, 0, -1, 20, {"Hello", "world"}) should replace the 2nd to last line in the buffer with "Hello" and the first 20 characters of the last line with "world". Instead, it reports "start_row out of bounds". This happens because when negative line numbers are used, they are incremented by one additional number to make the non-negative line numbers end-exclusive. However, the line numbers for nvim_buf_set_text should be end-inclusive. In #15181 we handled this for nvim_buf_get_text by adding a new parameter to `normalize_index`. We can solve the problem with nvim_buf_set_text by simply availing ourselves of this new argument. This is a breaking change, but makes the semantics of negative line numbers much clearer and more obvious (as well as matching nvim_buf_get_text). BREAKING CHANGE: Existing usages of nvim_buf_set_text that use negative line numbers will be off-by-one. --- src/nvim/api/buffer.c | 4 ++-- test/functional/api/buffer_spec.lua | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 02bd294c74..922d288da1 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -553,13 +553,13 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // check range is ordered and everything! // start_row, end_row within buffer len (except add text past the end?) - start_row = normalize_index(buf, start_row, true, &oob); + start_row = normalize_index(buf, start_row, false, &oob); if (oob || start_row == buf->b_ml.ml_line_count + 1) { api_set_error(err, kErrorTypeValidation, "start_row out of bounds"); return; } - end_row = normalize_index(buf, end_row, true, &oob); + end_row = normalize_index(buf, end_row, false, &oob); if (oob || end_row == buf->b_ml.ml_line_count + 1) { api_set_error(err, kErrorTypeValidation, "end_row out of bounds"); return; diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index dac3324a0f..dd3af8c28f 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -423,6 +423,13 @@ describe('api/buf', function() -- will join multiple lines if needed set_text(0, 6, 3, 4, {'bar'}) eq({'hello bar'}, get_lines(0, 1, true)) + + -- can use negative line numbers + set_text(-2, 0, -2, 5, {'goodbye'}) + eq({'goodbye bar', ''}, get_lines(0, -1, true)) + + set_text(-1, 0, -1, 0, {'text'}) + eq({'goodbye bar', 'text'}, get_lines(0, 2, true)) end) it('works with undo', function()