mirror of
https://github.com/neovim/neovim
synced 2025-07-16 17:21:49 +00:00
fix(lua): avoid internal error when :luado deletes lines (#27262)
This commit is contained in:
@ -1732,10 +1732,15 @@ void ex_luado(exarg_T *const eap)
|
|||||||
nlua_error(lstate, _("E5110: Error executing lua: %.*s"));
|
nlua_error(lstate, _("E5110: Error executing lua: %.*s"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf_T *const was_curbuf = curbuf;
|
||||||
|
|
||||||
for (linenr_T l = eap->line1; l <= eap->line2; l++) {
|
for (linenr_T l = eap->line1; l <= eap->line2; l++) {
|
||||||
|
// Check the line number, the command may have deleted lines.
|
||||||
if (l > curbuf->b_ml.ml_line_count) {
|
if (l > curbuf->b_ml.ml_line_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pushvalue(lstate, -1);
|
lua_pushvalue(lstate, -1);
|
||||||
const char *const old_line = ml_get_buf(curbuf, l);
|
const char *const old_line = ml_get_buf(curbuf, l);
|
||||||
// Get length of old_line here as calling Lua code may free it.
|
// Get length of old_line here as calling Lua code may free it.
|
||||||
@ -1746,6 +1751,13 @@ void ex_luado(exarg_T *const eap)
|
|||||||
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
|
nlua_error(lstate, _("E5111: Error calling lua: %.*s"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Catch the command switching to another buffer.
|
||||||
|
// Check the line number, the command may have deleted lines.
|
||||||
|
if (curbuf != was_curbuf || l > curbuf->b_ml.ml_line_count) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (lua_isstring(lstate, -1)) {
|
if (lua_isstring(lstate, -1)) {
|
||||||
size_t new_line_len;
|
size_t new_line_len;
|
||||||
const char *const new_line = lua_tolstring(lstate, -1, &new_line_len);
|
const char *const new_line = lua_tolstring(lstate, -1, &new_line_len);
|
||||||
@ -1760,6 +1772,7 @@ void ex_luado(exarg_T *const eap)
|
|||||||
}
|
}
|
||||||
lua_pop(lstate, 1);
|
lua_pop(lstate, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pop(lstate, 1);
|
lua_pop(lstate, 1);
|
||||||
check_cursor();
|
check_cursor();
|
||||||
redraw_curbuf_later(UPD_NOT_VALID);
|
redraw_curbuf_later(UPD_NOT_VALID);
|
||||||
|
@ -247,20 +247,30 @@ describe(':luado command', function()
|
|||||||
eq('', exec_capture('luado return ("<%02x>"):format(line:byte())'))
|
eq('', exec_capture('luado return ("<%02x>"):format(line:byte())'))
|
||||||
eq({ '<31>', '<32>', '<33>' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
eq({ '<31>', '<32>', '<33>' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('stops processing lines when suddenly out of lines', function()
|
it('stops processing lines when suddenly out of lines', function()
|
||||||
api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' })
|
api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' })
|
||||||
eq('', exec_capture('2,$luado runs = ((runs or 0) + 1) vim.api.nvim_command("%d")'))
|
eq('', exec_capture('2,$luado runs = ((runs or 0) + 1) vim.api.nvim_command("%d")'))
|
||||||
eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
||||||
eq(1, fn.luaeval('runs'))
|
eq(1, fn.luaeval('runs'))
|
||||||
end)
|
|
||||||
it('works correctly when changing lines out of range', function()
|
api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' })
|
||||||
api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' })
|
eq('', exec_capture('luado vim.api.nvim_command("%d")'))
|
||||||
eq(
|
|
||||||
'Vim(luado):E322: Line number out of range: 1 past the end',
|
|
||||||
pcall_err(command, '2,$luado vim.api.nvim_command("%d") return linenr')
|
|
||||||
)
|
|
||||||
eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
eq({ '' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
||||||
|
|
||||||
|
api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' })
|
||||||
|
eq('', exec_capture('luado vim.api.nvim_command("1,2d")'))
|
||||||
|
eq({ 'three' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
||||||
|
|
||||||
|
api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' })
|
||||||
|
eq('', exec_capture('luado vim.api.nvim_command("2,3d"); return "REPLACED"'))
|
||||||
|
eq({ 'REPLACED' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
||||||
|
|
||||||
|
api.nvim_buf_set_lines(0, 0, -1, false, { 'one', 'two', 'three' })
|
||||||
|
eq('', exec_capture('2,3luado vim.api.nvim_command("1,2d"); return "REPLACED"'))
|
||||||
|
eq({ 'three' }, api.nvim_buf_get_lines(0, 0, -1, false))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails on errors', function()
|
it('fails on errors', function()
|
||||||
eq(
|
eq(
|
||||||
[[Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unexpected symbol near ')']],
|
[[Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unexpected symbol near ')']],
|
||||||
@ -271,9 +281,11 @@ describe(':luado command', function()
|
|||||||
pcall_err(command, 'luado return liness + 1')
|
pcall_err(command, 'luado return liness + 1')
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with NULL errors', function()
|
it('works with NULL errors', function()
|
||||||
eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=], exc_exec('luado error(nil)'))
|
eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=], exc_exec('luado error(nil)'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('fails in sandbox when needed', function()
|
it('fails in sandbox when needed', function()
|
||||||
api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' })
|
api.nvim_buf_set_lines(0, 0, 1, false, { 'ABC', 'def', 'gHi' })
|
||||||
eq(
|
eq(
|
||||||
@ -282,6 +294,7 @@ describe(':luado command', function()
|
|||||||
)
|
)
|
||||||
eq(NIL, fn.luaeval('runs'))
|
eq(NIL, fn.luaeval('runs'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with long strings', function()
|
it('works with long strings', function()
|
||||||
local s = ('x'):rep(100500)
|
local s = ('x'):rep(100500)
|
||||||
|
|
||||||
@ -332,6 +345,7 @@ describe(':luafile', function()
|
|||||||
remove_trace(exc_exec('luafile ' .. fname))
|
remove_trace(exc_exec('luafile ' .. fname))
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with NULL errors', function()
|
it('works with NULL errors', function()
|
||||||
write_file(fname, 'error(nil)')
|
write_file(fname, 'error(nil)')
|
||||||
eq(
|
eq(
|
||||||
|
Reference in New Issue
Block a user