diff --git a/lua/fzfx/config.lua b/lua/fzfx/config.lua index e9cff75d9..19dc83c43 100644 --- a/lua/fzfx/config.lua +++ b/lua/fzfx/config.lua @@ -178,12 +178,26 @@ local Defaults = { "--no-height", { "--preview-window", "right,50%" }, }, + + -- popup window opts + -- please check: https://neovim.io/doc/user/api.html#nvim_open_win() win_opts = { + -- popup window height/width + -- if 0 <= h/w <= 1, evaluate as the ratio based on editor window's lines and columns + -- if h/w > 1, pass it directly to nvim_open_win api height = 0.85, width = 0.85, + -- popup window row/col position + -- if 0 < r/c < 1, evaluate as the ratio based on editor window's lines and columns + -- if r/c >= 1 or r/c <= -1, pass it directly to nvim_open_win api + -- Note: r/c cannot be in range [-1, 0), it makes no sense. + row = -vim.o.cmdheight, -- 0.5 + col = 0.5, + anchor = "NW", border = "none", zindex = 51, }, + env = { nvim = nil, }, diff --git a/lua/fzfx/popup.lua b/lua/fzfx/popup.lua index 04feaa4c3..f968309e3 100644 --- a/lua/fzfx/popup.lua +++ b/lua/fzfx/popup.lua @@ -117,7 +117,7 @@ local PopupWindowOpts = { --- @param win_opts Config --- @return PopupWindowOpts -local function new_popup_window_layout(win_opts) +local function new_popup_window_opts(win_opts) --- @type integer local columns = vim.o.columns --- @type integer @@ -127,7 +127,7 @@ local function new_popup_window_layout(win_opts) math.max( 3, win_opts.width > 1 and win_opts.width - or math.floor(columns * win_opts.width) + or math.floor(columns * win_opts.width) ), columns ) @@ -136,22 +136,55 @@ local function new_popup_window_layout(win_opts) math.max( 3, win_opts.height > 1 and win_opts.height - or math.floor(lines * win_opts.height) + or math.floor(lines * win_opts.height) ), lines ) --- @type integer - local row = - math.min(math.max(math.floor((lines - height) / 2), 0), lines - height) + local row = math.min( + math.max(0, math.floor((lines - height) * 0.5)), + lines - height + ) + if win_opts.row >= -1 and win_opts.row < 0 then + log.err( + "error! invalid win_opts.row '%s' option!", + vim.inspect(win_opts.row) + ) + else + row = math.min( + math.max( + 0, + win_opts.row > 1 and win_opts.row + or math.floor((lines - height) * win_opts.row) + ), + lines - height + ) + end --- @type integer local col = math.min( - math.max(math.floor((columns - width) / 2), 0), + math.max(0, math.floor((columns - width) * 0.5)), columns - width ) + if win_opts.col >= -1 and win_opts.col < 0 then + log.err( + "error! invalid win_opts.col '%s' option!", + vim.inspect(win_opts.col) + ) + else + col = math.min( + math.max( + 0, + win_opts.col > 1 and win_opts.col + or math.floor((columns - width) * win_opts.col) + ), + columns - width + ) + end --- @type PopupWindowOpts local popup_win_opts = vim.tbl_deep_extend("force", vim.deepcopy(PopupWindowOpts), { + anchor = win_opts.anchor, relative = "editor", width = width, height = height, @@ -163,7 +196,8 @@ local function new_popup_window_layout(win_opts) zindex = win_opts.zindex, }) log.debug( - "|fzfx.popup - new_window_layout| win_layout:%s", + "|fzfx.popup - new_popup_window_opts| (origin) win_opts:%s, popup_win_opts:%s", + vim.inspect(win_opts), vim.inspect(popup_win_opts) ) return popup_win_opts @@ -190,7 +224,7 @@ local function new_popup_window() vim.api.nvim_set_option_value("filetype", "fzf", { buf = bufnr }) --- @type PopupWindowOpts - local popup_win_opts = new_popup_window_layout(win_opts) + local popup_win_opts = new_popup_window_opts(win_opts) --- @type integer local winnr = vim.api.nvim_open_win(bufnr, true, popup_win_opts) --- set winhighlight='Pmenu:,Normal:Normal' @@ -310,10 +344,6 @@ end local function new_popup_fzf(popup_win, source, fzf_opts, actions) local result = path.tempname() local fzf_command = make_fzf_command(fzf_opts, actions, result) - log.debug( - "|fzfx.popup - new_popup_fzf| fzf_command:%s", - vim.inspect(fzf_command) - ) local function on_fzf_exit(jobid2, exitcode, event) log.debug( @@ -369,15 +399,25 @@ local function new_popup_fzf(popup_win, source, fzf_opts, actions) if type(action_key) == "string" and string.len(action_key) == 0 then action_key = "enter" end - local action_callback = actions[action_key] - if type(action_callback) ~= "function" then - log.err("error! wrong action type: %s", action_key) - else - action_callback(action_lines) + if not tostring(action_key):match("v:null") then + local action_callback = actions[action_key] + if type(action_callback) ~= "function" then + log.err("error! wrong action type: %s", action_key) + else + action_callback(action_lines) + end end end local prev_fzf_default_command = vim.env.FZF_DEFAULT_COMMAND vim.env.FZF_DEFAULT_COMMAND = source + log.debug( + "|fzfx.popup - new_popup_fzf| $FZF_DEFAULT_COMMAND:%s", + vim.inspect(vim.env.FZF_DEFAULT_COMMAND) + ) + log.debug( + "|fzfx.popup - new_popup_fzf| fzf_command:%s", + vim.inspect(fzf_command) + ) local jobid = vim.fn.termopen(fzf_command, { on_exit = on_fzf_exit }) --[[@as integer ]] vim.env.FZF_DEFAULT_COMMAND = prev_fzf_default_command vim.cmd([[ startinsert ]]) diff --git a/lua/fzfx/utils.lua b/lua/fzfx/utils.lua index c65d6f930..b2dbf9765 100644 --- a/lua/fzfx/utils.lua +++ b/lua/fzfx/utils.lua @@ -135,29 +135,29 @@ end --- @return FileSwitch local function new_file_switch(name, current_value, next_value) local init = env.debug_enable() - and { - value = string.format( - "%s%sfzfx.nvim%s%s_current_swapable", - vim.fn.stdpath("data"), - path.sep(), - path.sep(), - name - ), - next = string.format( - "%s%sfzfx.nvim%s%s_next_swapable", - vim.fn.stdpath("data"), - path.sep(), - path.sep(), - name - ), - swap = string.format( - "%s%sfzfx.nvim%s%s_swap_swapable", - vim.fn.stdpath("data"), - path.sep(), - path.sep(), - name - ), - } + and { + value = string.format( + "%s%sfzfx.nvim%s%s_value", + vim.fn.stdpath("data"), + path.sep(), + path.sep(), + name + ), + next = string.format( + "%s%sfzfx.nvim%s%s_next", + vim.fn.stdpath("data"), + path.sep(), + path.sep(), + name + ), + swap = string.format( + "%s%sfzfx.nvim%s%s_swap", + vim.fn.stdpath("data"), + path.sep(), + path.sep(), + name + ), + } or { value = path.tempname(), next = path.tempname(),