mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 02:34:59 -07:00
perf(extmarks): better track whether namespace has extmarks (#28615)
This avoids redraw when adding/removing an empty namespace for a window. This also avoids marktree traversal when clearing a namespace that has already been cleared, which is added as a benchmark.
This commit is contained in:
parent
cf9f002f31
commit
d44ed3a885
@ -129,13 +129,13 @@ function M.on_yank(opts)
|
||||
yank_cancel()
|
||||
end
|
||||
|
||||
vim.api.nvim_win_add_ns(winid, yank_ns)
|
||||
M.range(bufnr, yank_ns, higroup, "'[", "']", {
|
||||
regtype = event.regtype,
|
||||
inclusive = event.inclusive,
|
||||
priority = opts.priority or M.priorities.user,
|
||||
_scoped = true,
|
||||
})
|
||||
vim.api.nvim_win_add_ns(winid, yank_ns)
|
||||
|
||||
yank_cancel = function()
|
||||
yank_timer = nil
|
||||
|
@ -1234,7 +1234,9 @@ Boolean nvim_win_add_ns(Window window, Integer ns_id, Error *err)
|
||||
|
||||
set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
|
||||
|
||||
changed_window_setting(win);
|
||||
if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
|
||||
changed_window_setting(win);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1279,7 +1281,9 @@ Boolean nvim_win_remove_ns(Window window, Integer ns_id, Error *err)
|
||||
|
||||
set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id);
|
||||
|
||||
changed_window_setting(win);
|
||||
if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) {
|
||||
changed_window_setting(win);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -206,7 +206,9 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
|
||||
}
|
||||
}
|
||||
|
||||
bool marks_cleared = false;
|
||||
bool marks_cleared_any = false;
|
||||
bool marks_cleared_all = l_row == 0 && l_col == 0;
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, l_row, l_col, itr);
|
||||
while (true) {
|
||||
@ -214,16 +216,29 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r
|
||||
if (mark.pos.row < 0
|
||||
|| mark.pos.row > u_row
|
||||
|| (mark.pos.row == u_row && mark.pos.col > u_col)) {
|
||||
if (mark.pos.row >= 0) {
|
||||
marks_cleared_all = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (mark.ns == ns_id || all_ns) {
|
||||
marks_cleared = true;
|
||||
marks_cleared_any = true;
|
||||
extmark_del(buf, itr, mark, true);
|
||||
} else {
|
||||
marktree_itr_next(buf->b_marktree, itr);
|
||||
}
|
||||
}
|
||||
return marks_cleared;
|
||||
|
||||
if (marks_cleared_all) {
|
||||
if (all_ns) {
|
||||
map_destroy(uint32_t, buf->b_extmark_ns);
|
||||
*buf->b_extmark_ns = (Map(uint32_t, uint32_t)) MAP_INIT;
|
||||
} else {
|
||||
map_del(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return marks_cleared_any;
|
||||
}
|
||||
|
||||
/// @return the position of marks between a range,
|
||||
@ -315,10 +330,6 @@ MTPair extmark_from_id(buf_T *buf, uint32_t ns_id, uint32_t id)
|
||||
/// free extmarks from the buffer
|
||||
void extmark_free_all(buf_T *buf)
|
||||
{
|
||||
if (!map_size(buf->b_extmark_ns)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MarkTreeIter itr[1] = { 0 };
|
||||
marktree_itr_get(buf->b_marktree, 0, 0, itr);
|
||||
while (true) {
|
||||
|
@ -677,7 +677,7 @@ static int mf_trans_add(memfile_T *mfp, bhdr_T *hp)
|
||||
/// The old number When not found.
|
||||
blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr)
|
||||
{
|
||||
blocknr_T *num = map_ref(int64_t, int64_t)(&mfp->mf_trans, old_nr, false);
|
||||
blocknr_T *num = map_ref(int64_t, int64_t)(&mfp->mf_trans, old_nr, NULL);
|
||||
if (num == NULL) { // not found
|
||||
return old_nr;
|
||||
}
|
||||
|
45
test/benchmark/extmark_spec.lua
Normal file
45
test/benchmark/extmark_spec.lua
Normal file
@ -0,0 +1,45 @@
|
||||
local n = require('test.functional.testnvim')()
|
||||
|
||||
local clear = n.clear
|
||||
local exec_lua = n.exec_lua
|
||||
|
||||
describe('extmark perf', function()
|
||||
before_each(function()
|
||||
clear()
|
||||
|
||||
exec_lua([[
|
||||
out = {}
|
||||
function start()
|
||||
ts = vim.uv.hrtime()
|
||||
end
|
||||
function stop(name)
|
||||
out[#out+1] = ('%14.6f ms - %s'):format((vim.uv.hrtime() - ts) / 1000000, name)
|
||||
end
|
||||
]])
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
for _, line in ipairs(exec_lua([[return out]])) do
|
||||
print(line)
|
||||
end
|
||||
end)
|
||||
|
||||
it('repeatedly calling nvim_buf_clear_namespace #28615', function()
|
||||
exec_lua([[
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, true, { 'foo', 'bar' })
|
||||
local ns0 = vim.api.nvim_create_namespace('ns0')
|
||||
local ns1 = vim.api.nvim_create_namespace('ns1')
|
||||
|
||||
for _ = 1, 10000 do
|
||||
vim.api.nvim_buf_set_extmark(0, ns0, 0, 0, {})
|
||||
end
|
||||
vim.api.nvim_buf_set_extmark(0, ns1, 1, 0, {})
|
||||
|
||||
start()
|
||||
for _ = 1, 10000 do
|
||||
vim.api.nvim_buf_clear_namespace(0, ns1, 0, -1)
|
||||
end
|
||||
stop('nvim_buf_clear_namespace')
|
||||
]])
|
||||
end)
|
||||
end)
|
@ -1896,6 +1896,24 @@ describe('Extmarks buffer api with many marks', function()
|
||||
end
|
||||
eq(ns_marks[ns1], get_marks(ns1))
|
||||
eq(ns_marks[ns2], get_marks(ns2))
|
||||
|
||||
api.nvim_buf_clear_namespace(0, ns1, 0, 10)
|
||||
for id, mark in pairs(ns_marks[ns1]) do
|
||||
if mark[1] < 10 then
|
||||
ns_marks[ns1][id] = nil
|
||||
end
|
||||
end
|
||||
eq(ns_marks[ns1], get_marks(ns1))
|
||||
eq(ns_marks[ns2], get_marks(ns2))
|
||||
|
||||
api.nvim_buf_clear_namespace(0, ns1, 20, -1)
|
||||
for id, mark in pairs(ns_marks[ns1]) do
|
||||
if mark[1] >= 20 then
|
||||
ns_marks[ns1][id] = nil
|
||||
end
|
||||
end
|
||||
eq(ns_marks[ns1], get_marks(ns1))
|
||||
eq(ns_marks[ns2], get_marks(ns2))
|
||||
end)
|
||||
|
||||
it('can delete line', function()
|
||||
|
Loading…
Reference in New Issue
Block a user