mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 11:28:22 +00:00
Merge pull request #19069 from neovim/backport-19056-to-release-0.7
[Backport release-0.7] fix(api): check for inclusive buffer line index out of bounds correctly
This commit is contained in:
@@ -554,13 +554,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, false, &oob);
|
||||
if (oob || start_row == buf->b_ml.ml_line_count + 1) {
|
||||
if (oob) {
|
||||
api_set_error(err, kErrorTypeValidation, "start_row out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
end_row = normalize_index(buf, end_row, false, &oob);
|
||||
if (oob || end_row == buf->b_ml.ml_line_count + 1) {
|
||||
if (oob) {
|
||||
api_set_error(err, kErrorTypeValidation, "end_row out of bounds");
|
||||
return;
|
||||
}
|
||||
@@ -1488,14 +1488,15 @@ static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
|
||||
// Normalizes 0-based indexes to buffer line numbers
|
||||
static int64_t normalize_index(buf_T *buf, int64_t index, bool end_exclusive, bool *oob)
|
||||
{
|
||||
int64_t line_count = buf->b_ml.ml_line_count;
|
||||
assert(buf->b_ml.ml_line_count > 0);
|
||||
int64_t max_index = buf->b_ml.ml_line_count + (int)end_exclusive - 1;
|
||||
// Fix if < 0
|
||||
index = index < 0 ? line_count + index + (int)end_exclusive : index;
|
||||
index = index < 0 ? max_index + index + 1 : index;
|
||||
|
||||
// Check for oob
|
||||
if (index > line_count) {
|
||||
if (index > max_index) {
|
||||
*oob = true;
|
||||
index = line_count;
|
||||
index = max_index;
|
||||
} else if (index < 0) {
|
||||
*oob = true;
|
||||
index = 0;
|
||||
|
@@ -227,8 +227,8 @@ describe('api/buf', function()
|
||||
it('can get a single line with strict indexing', function()
|
||||
set_lines(0, 1, true, {'line1.a'})
|
||||
eq(1, line_count()) -- sanity
|
||||
eq(false, pcall(get_lines, 1, 2, true))
|
||||
eq(false, pcall(get_lines, -3, -2, true))
|
||||
eq('Index out of bounds', pcall_err(get_lines, 1, 2, true))
|
||||
eq('Index out of bounds', pcall_err(get_lines, -3, -2, true))
|
||||
end)
|
||||
|
||||
it('can get a single line with non-strict indexing', function()
|
||||
@@ -240,11 +240,11 @@ describe('api/buf', function()
|
||||
|
||||
it('can set and delete a single line with strict indexing', function()
|
||||
set_lines(0, 1, true, {'line1.a'})
|
||||
eq(false, pcall(set_lines, 1, 2, true, {'line1.b'}))
|
||||
eq(false, pcall(set_lines, -3, -2, true, {'line1.c'}))
|
||||
eq('Index out of bounds', pcall_err(set_lines, 1, 2, true, {'line1.b'}))
|
||||
eq('Index out of bounds', pcall_err(set_lines, -3, -2, true, {'line1.c'}))
|
||||
eq({'line1.a'}, get_lines(0, -1, true))
|
||||
eq(false, pcall(set_lines, 1, 2, true, {}))
|
||||
eq(false, pcall(set_lines, -3, -2, true, {}))
|
||||
eq('Index out of bounds', pcall_err(set_lines, 1, 2, true, {}))
|
||||
eq('Index out of bounds', pcall_err(set_lines, -3, -2, true, {}))
|
||||
eq({'line1.a'}, get_lines(0, -1, true))
|
||||
end)
|
||||
|
||||
@@ -302,9 +302,9 @@ describe('api/buf', function()
|
||||
set_lines(0, -1, true, {'a', 'b', 'c'})
|
||||
eq({'a', 'b', 'c'}, get_lines(0, -1, true)) --sanity
|
||||
|
||||
eq(false, pcall(get_lines, 3, 4, true))
|
||||
eq(false, pcall(get_lines, 3, 10, true))
|
||||
eq(false, pcall(get_lines, -5, -5, true))
|
||||
eq('Index out of bounds', pcall_err(get_lines, 3, 4, true))
|
||||
eq('Index out of bounds', pcall_err(get_lines, 3, 10, true))
|
||||
eq('Index out of bounds', pcall_err(get_lines, -5, -5, true))
|
||||
-- empty or inverted ranges are not errors
|
||||
eq({}, get_lines(3, -1, true))
|
||||
eq({}, get_lines(-3, -4, true))
|
||||
@@ -316,10 +316,10 @@ describe('api/buf', function()
|
||||
|
||||
eq({'c'}, get_lines(-2, 5, false))
|
||||
eq({'a', 'b', 'c'}, get_lines(0, 6, false))
|
||||
eq(false, pcall(set_lines, 4, 6, true, {'d'}))
|
||||
eq('Index out of bounds', pcall_err(set_lines, 4, 6, true, {'d'}))
|
||||
set_lines(4, 6, false, {'d'})
|
||||
eq({'a', 'b', 'c', 'd'}, get_lines(0, -1, true))
|
||||
eq(false, pcall(set_lines, -6, -6, true, {'e'}))
|
||||
eq('Index out of bounds', pcall_err(set_lines, -6, -6, true, {'e'}))
|
||||
set_lines(-6, -6, false, {'e'})
|
||||
eq({'e', 'a', 'b', 'c', 'd'}, get_lines(0, -1, true))
|
||||
end)
|
||||
@@ -392,7 +392,7 @@ describe('api/buf', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_buf_get_lines, nvim_buf_set_text', function()
|
||||
describe('nvim_buf_set_text', function()
|
||||
local get_lines, set_text = curbufmeths.get_lines, curbufmeths.set_text
|
||||
|
||||
it('works', function()
|
||||
@@ -430,6 +430,10 @@ describe('api/buf', function()
|
||||
|
||||
set_text(-1, 0, -1, 0, {'text'})
|
||||
eq({'goodbye bar', 'text'}, get_lines(0, 2, true))
|
||||
|
||||
-- can append to a line
|
||||
set_text(1, 4, -1, 4, {' and', 'more'})
|
||||
eq({'goodbye bar', 'text and', 'more'}, get_lines(0, 3, true))
|
||||
end)
|
||||
|
||||
it('works with undo', function()
|
||||
@@ -513,12 +517,12 @@ describe('api/buf', function()
|
||||
eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id2, {}))
|
||||
eq({0, 6}, curbufmeths.get_extmark_by_id(ns, id3, {}))
|
||||
|
||||
-- marks should be shifted over by the correct number of bytes for multibyte
|
||||
-- chars
|
||||
set_text(0, 0, 0, 0, {'Ø'})
|
||||
eq({0, 3}, curbufmeths.get_extmark_by_id(ns, id1, {}))
|
||||
eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id2, {}))
|
||||
eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id3, {}))
|
||||
-- marks should be shifted over by the correct number of bytes for multibyte
|
||||
-- chars
|
||||
set_text(0, 0, 0, 0, {'Ø'})
|
||||
eq({0, 3}, curbufmeths.get_extmark_by_id(ns, id1, {}))
|
||||
eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id2, {}))
|
||||
eq({0, 8}, curbufmeths.get_extmark_by_id(ns, id3, {}))
|
||||
end)
|
||||
|
||||
it("correctly marks changed region for redraw #13890", function()
|
||||
@@ -540,18 +544,39 @@ describe('api/buf', function()
|
||||
|
|
||||
|
||||
]])
|
||||
end)
|
||||
|
||||
it('errors on out-of-range', function()
|
||||
insert([[
|
||||
hello foo!
|
||||
text]])
|
||||
eq('start_row out of bounds', pcall_err(set_text, 2, 0, 3, 0, {}))
|
||||
eq('start_row out of bounds', pcall_err(set_text, -3, 0, 0, 0, {}))
|
||||
eq('end_row out of bounds', pcall_err(set_text, 0, 0, 2, 0, {}))
|
||||
eq('end_row out of bounds', pcall_err(set_text, 0, 0, -3, 0, {}))
|
||||
eq('start_col out of bounds', pcall_err(set_text, 1, 5, 1, 5, {}))
|
||||
eq('end_col out of bounds', pcall_err(set_text, 1, 0, 1, 5, {}))
|
||||
end)
|
||||
|
||||
it('errors when start is greater than end', function()
|
||||
insert([[
|
||||
hello foo!
|
||||
text]])
|
||||
eq('start is higher than end', pcall_err(set_text, 1, 0, 0, 0, {}))
|
||||
eq('start is higher than end', pcall_err(set_text, 0, 1, 0, 0, {}))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_buf_get_text', function()
|
||||
local get_text = curbufmeths.get_text
|
||||
|
||||
it('works', function()
|
||||
before_each(function()
|
||||
insert([[
|
||||
hello foo!
|
||||
text]])
|
||||
end)
|
||||
|
||||
it('works', function()
|
||||
eq({'hello'}, get_text(0, 0, 0, 5, {}))
|
||||
eq({'hello foo!'}, get_text(0, 0, 0, 42, {}))
|
||||
eq({'foo!'}, get_text(0, 6, 0, 10, {}))
|
||||
@@ -562,13 +587,17 @@ describe('api/buf', function()
|
||||
end)
|
||||
|
||||
it('errors on out-of-range', function()
|
||||
eq(false, pcall(get_text, 2, 0, 3, 0, {}))
|
||||
eq(false, pcall(get_text, 0, 0, 4, 0, {}))
|
||||
eq('Index out of bounds', pcall_err(get_text, 2, 0, 3, 0, {}))
|
||||
eq('Index out of bounds', pcall_err(get_text, -3, 0, 0, 0, {}))
|
||||
eq('Index out of bounds', pcall_err(get_text, 0, 0, 2, 0, {}))
|
||||
eq('Index out of bounds', pcall_err(get_text, 0, 0, -3, 0, {}))
|
||||
-- no ml_get errors should happen #19017
|
||||
eq('', meths.get_vvar('errmsg'))
|
||||
end)
|
||||
|
||||
it('errors when start is greater than end', function()
|
||||
eq(false, pcall(get_text, 1, 0, 0, 0, {}))
|
||||
eq(false, pcall(get_text, 0, 1, 0, 0, {}))
|
||||
eq('start is higher than end', pcall_err(get_text, 1, 0, 0, 0, {}))
|
||||
eq('start_col must be less than end_col', pcall_err(get_text, 0, 1, 0, 0, {}))
|
||||
end)
|
||||
end)
|
||||
|
||||
|
Reference in New Issue
Block a user