Skip to content

Commit

Permalink
perf: avoid copying buffer/window variables to lua
Browse files Browse the repository at this point in the history
Problem:
Calling vim.fn.{getbufinfo,getwininfo} in lua can be slow because it has
to convert potentially big and cyclic data structures stored in vim
buffer/window variables into lua values.

Solution:
Remove buffer/window variables from the result before passing it to lua.
  • Loading branch information
tomtomjhj committed Apr 5, 2024
1 parent f430c5b commit edfaf03
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 14 deletions.
22 changes: 22 additions & 0 deletions autoload/fzf_lua.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
" Calling vim.fn.getbufinfo in lua can be expensive because it has to convert
" all the buffer variables into lua values. Since fzf-lua does not access
" buffer variables, this cost can be avoided by clearing the entry before
" passing the info to lua.
function! fzf_lua#getbufinfo(bufnr) abort
let info = getbufinfo(a:bufnr)
if empty(info)
return v:false " there is no way to return `nil` from vimscript
endif
unlet! info[0].variables
return info[0]
endfunction

" Similar to fzf_lua#getbufinfo, but for getwininfo.
function! fzf_lua#getwininfo(winid) abort
let info = getwininfo(a:winid)
if empty(info)
return v:false
endif
unlet! info[0].variables
return info[0]
endfunction
10 changes: 5 additions & 5 deletions lua/fzf-lua/previewer/builtin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ end

function Previewer.base:preview_is_terminal()
if not self.win or not self.win:validate_preview() then return end
return vim.fn.getwininfo(self.win.preview_winid)[1].terminal == 1
return vim.fn["fzf_lua#getwininfo"](self.win.preview_winid).terminal == 1
end

function Previewer.base:get_tmp_buffer()
Expand Down Expand Up @@ -368,10 +368,10 @@ function Previewer.base:scroll(direction)
-- user scrolls, the highlight is no longer relevant (#462).
-- Conditionally toggle 'cursorline' based on cursor position
if self.orig_pos and self.winopts.cursorline then
local wininfo = vim.fn.getwininfo(preview_winid)
if wininfo and wininfo[1] and
self.orig_pos[1] >= wininfo[1].topline and
self.orig_pos[1] <= wininfo[1].botline then
local wininfo = vim.fn["fzf_lua#getwininfo"](preview_winid)
if wininfo and
self.orig_pos[1] >= wininfo.topline and
self.orig_pos[1] <= wininfo.botline then
-- reset cursor pos even when it's already there, no bigggie
-- local curpos = vim.api.nvim_win_get_cursor(preview_winid)
vim.api.nvim_win_set_cursor(preview_winid, self.orig_pos)
Expand Down
2 changes: 1 addition & 1 deletion lua/fzf-lua/providers/buffers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ local populate_buffer_entries = function(opts, bufnrs, tabh)
local element = {
bufnr = bufnr,
flag = flag,
info = vim.fn.getbufinfo(bufnr)[1],
info = vim.fn["fzf_lua#getbufinfo"](bufnr),
readonly = vim.bo[bufnr].readonly
}

Expand Down
12 changes: 6 additions & 6 deletions lua/fzf-lua/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -805,17 +805,17 @@ function M.is_term_buffer(bufnr)
bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr
local winid = vim.fn.bufwinid(bufnr)
if tonumber(winid) > 0 and vim.api.nvim_win_is_valid(winid) then
return vim.fn.getwininfo(winid)[1].terminal == 1
return vim.fn["fzf_lua#getwininfo"](winid).terminal == 1
end
local bufname = vim.api.nvim_buf_is_valid(bufnr) and vim.api.nvim_buf_get_name(bufnr)
return M.is_term_bufname(bufname)
end

function M.buffer_is_dirty(bufnr, warn, only_if_last_buffer)
bufnr = tonumber(bufnr) or vim.api.nvim_get_current_buf()
local info = bufnr and vim.fn.getbufinfo(bufnr)[1]
local info = bufnr and vim.fn["fzf_lua#getbufinfo"](bufnr)
if info and info.changed ~= 0 then
if only_if_last_buffer and 1 < M.tbl_length(vim.fn.win_findbuf(bufnr)) then
if only_if_last_buffer and 1 < #vim.fn.win_findbuf(bufnr) then
return false
end
if warn then
Expand All @@ -829,7 +829,7 @@ end

function M.save_dialog(bufnr)
bufnr = tonumber(bufnr) or vim.api.nvim_get_current_buf()
local info = bufnr and vim.fn.getbufinfo(bufnr)[1]
local info = bufnr and vim.fn["fzf_lua#getbufinfo"](bufnr)
if not info.name or #info.name == 0 then
-- unnamed buffers can't be saved
M.warn(string.format("buffer %d has unsaved changes", bufnr))
Expand All @@ -854,7 +854,7 @@ end
-- 2 for loc list
function M.win_is_qf(winid, wininfo)
wininfo = wininfo or
(vim.api.nvim_win_is_valid(winid) and vim.fn.getwininfo(winid)[1])
(vim.api.nvim_win_is_valid(winid) and vim.fn["fzf_lua#getwininfo"](winid))
if wininfo and wininfo.quickfix == 1 then
return wininfo.loclist == 1 and 2 or 1
end
Expand All @@ -863,7 +863,7 @@ end

function M.buf_is_qf(bufnr, bufinfo)
bufinfo = bufinfo or
(vim.api.nvim_buf_is_valid(bufnr) and vim.fn.getbufinfo(bufnr)[1])
(vim.api.nvim_buf_is_valid(bufnr) and vim.fn["fzf_lua#getbufinfo"](bufnr))
if bufinfo and bufinfo.variables and
bufinfo.variables.current_syntax == "qf" and
not vim.tbl_isempty(bufinfo.windows) then
Expand Down
4 changes: 2 additions & 2 deletions lua/fzf-lua/win.lua
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ end

function FzfWin:preview_layout()
if self.winopts.split and self.previewer_is_builtin then
local wininfo = fn.getwininfo(self.fzf_winid)[1]
local wininfo = fn["fzf_lua#getwininfo"](self.fzf_winid)
-- unlike floating win popups, split windows inherit the global
-- 'signcolumn' setting which affects the available width for fzf
-- 'generate_layout' will then use the sign column available width
Expand Down Expand Up @@ -1144,7 +1144,7 @@ function FzfWin:update_scrollbar(hide)
local buf = api.nvim_win_get_buf(self.preview_winid)

local o = {}
o.wininfo = fn.getwininfo(self.preview_winid)[1]
o.wininfo = fn["fzf_lua#getwininfo"](self.preview_winid)
o.line_count = api.nvim_buf_line_count(buf)

local topline, height = o.wininfo.topline, o.wininfo.height
Expand Down

0 comments on commit edfaf03

Please sign in to comment.