Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lua/fzf-lua/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ end
---@param bufedit boolean?
---@return string?
M.vimcmd_entry = function(vimcmd, selected, opts, bufedit)
vim.api.nvim_set_current_win(vim.bo.bt == "quickfix" and vim.fn.win_getid(vim.fn.winnr("#")) or 0)
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Window fallback still allows preview/quickfix targets

Line 207 only checks whether the current window is quickfix, then blindly switches to winnr("#"). If the alternate window is preview/quickfix (or not a good edit target), edit actions can still run in the wrong window.

💡 Suggested fix
-  vim.api.nvim_set_current_win(vim.bo.bt == "quickfix" and vim.fn.win_getid(vim.fn.winnr("#")) or 0)
+  local function is_edit_target(winid)
+    if not winid or winid == 0 or not vim.api.nvim_win_is_valid(winid) then
+      return false
+    end
+    local buf = vim.api.nvim_win_get_buf(winid)
+    local bt = vim.api.nvim_get_option_value("buftype", { buf = buf })
+    local is_preview = vim.api.nvim_get_option_value("previewwindow", { win = winid })
+    return bt ~= "quickfix" and not is_preview
+  end
+
+  if vim.bo.bt == "quickfix" or vim.wo.previewwindow then
+    local target = vim.fn.win_getid(vim.fn.winnr("#"))
+    if not is_edit_target(target) then
+      for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
+        if is_edit_target(winid) then
+          target = winid
+          break
+        end
+      end
+    end
+    if is_edit_target(target) then
+      vim.api.nvim_set_current_win(target)
+    end
+  end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
vim.api.nvim_set_current_win(vim.bo.bt == "quickfix" and vim.fn.win_getid(vim.fn.winnr("#")) or 0)
local function is_edit_target(winid)
if not winid or winid == 0 or not vim.api.nvim_win_is_valid(winid) then
return false
end
local buf = vim.api.nvim_win_get_buf(winid)
local bt = vim.api.nvim_get_option_value("buftype", { buf = buf })
local is_preview = vim.api.nvim_get_option_value("previewwindow", { win = winid })
return bt ~= "quickfix" and not is_preview
end
if vim.bo.bt == "quickfix" or vim.wo.previewwindow then
local target = vim.fn.win_getid(vim.fn.winnr("#"))
if not is_edit_target(target) then
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
if is_edit_target(winid) then
target = winid
break
end
end
end
if is_edit_target(target) then
vim.api.nvim_set_current_win(target)
end
end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lua/fzf-lua/actions.lua` at line 207, The current fallback blindly sets the
current window using vim.fn.winnr("#") via vim.api.nvim_set_current_win even if
that alternate window is a quickfix/preview or otherwise unsuitable; change the
logic in the block using vim.api.nvim_set_current_win(...) to validate the
target window first: resolve the candidate window id (from
vim.fn.winnr("#")/win_getid), check the associated buffer's buftype
(vim.api.nvim_buf_get_option(buf, "buftype")) and window properties
(vim.api.nvim_win_get_config or win_gettype) to reject quickfix/preview/floating
windows, and if rejected iterate through vim.api.nvim_list_wins() to pick the
first suitable edit window (buftype == "" and not preview/quickfix/floating)
before calling vim.api.nvim_set_current_win; if no suitable window is found, do
not switch windows. Ensure you update the code around
vim.api.nvim_set_current_win, vim.bo.bt, vim.fn.winnr, and win_getid references.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Literally rewrite in lua...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we need that complex.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phanen Fair point — Neovim's own window selection logic (referenced in the PR description via window.c) already avoids landing on preview/quickfix windows when resolving the alternate window, so reimplementing those heuristics in Lua is redundant overhead. The one-liner is the right call.

(∩^o^)⊃━☆゚.*・。゚


✏️ Learnings added
Learnt from: phanen
Repo: ibhagwan/fzf-lua PR: 2673
File: lua/fzf-lua/actions.lua:207-207
Timestamp: 2026-04-16T16:45:08.605Z
Learning: In fzf-lua (lua/fzf-lua/actions.lua), `M.vimcmd_entry` uses `vim.fn.win_getid(vim.fn.winnr("#"))` to resolve the alternate window when the current window is quickfix. Do not suggest reimplementing window-avoidance heuristics (skip preview/quickfix) in Lua — Neovim's own C-level window selection logic already handles this. Trust the built-in behavior.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: ibhagwan
Repo: ibhagwan/fzf-lua PR: 2634
File: lua/fzf-lua/win.lua:240-277
Timestamp: 2026-03-27T17:15:12.021Z
Learning: In fzf-lua (lua/fzf-lua/win.lua), the SIGWINCH handler registered via `FzfWin.on_SIGWINCH` and `toggle_preview()` operate in completely separate async phases across separate processes (Neovim and fzf). The SIGWINCH callback only returns a fzf action string to the external fzf process — it never calls `toggle_preview()`. Conversely, `toggle_preview()` only sends POSIX signal 28 asynchronously via `self:SIGWINCH(...)`; fzf receives the signal later, fires its `resize` event, and then the handler runs. There is no synchronous re-entry path between these two sides. Do not flag double-apply / re-entry bugs in this flow.

for i, sel in ipairs(selected) do
(function()
-- Lua 5.1 goto compatiblity hack (function wrap)
Expand Down
Loading