Skip to content

fix(actions): don't stay in quickfix on edit actions#2673

Open
phanen wants to merge 1 commit intomainfrom
ignore-qf
Open

fix(actions): don't stay in quickfix on edit actions#2673
phanen wants to merge 1 commit intomainfrom
ignore-qf

Conversation

@phanen
Copy link
Copy Markdown
Collaborator

@phanen phanen commented Apr 16, 2026

This seems regression of abacb06.

Before that commit, we actually rely on an old vim behavior:
https://github.com/neovim/neovim/blob/5b0ad4a0607498616b984c63ae1a6903cb835c66/src/nvim/window.c#L3036

When close a window, vim try to avoid to focus a quickfix window:
(even your "last accessed window" is alraedy a quickfix window...)

If the cursor goes to the preview or the quickfix window, try
finding another window to go to.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed window context handling when executing commands from search results, ensuring proper cursor and window focus during command execution.

This seems regression of abacb06.

Before that commit, we actually rely on an old vim behavior:
https://github.com/neovim/neovim/blob/5b0ad4a0607498616b984c63ae1a6903cb835c66/src/nvim/window.c#L3036

When close a window, vim try to avoid to focus a quickfix window:
(even your "last accessed window" is alraedy a quickfix window...)
> If the cursor goes to the preview or the quickfix window, try
> finding another window to go to.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

A single line was added to M.vimcmd_entry function to forcibly set the current window context. The window selection logic prioritizes the quickfix buffer window if present, otherwise defaults to window 0, before processing selected entries.

Changes

Cohort / File(s) Summary
Window Context Handling
lua/fzf-lua/actions.lua
Added vim.api.nvim_set_current_win(...) call to establish window context before entry processing, with logic to detect and use quickfix buffer windows when available.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • PR #2667: Modifies the same M.vimcmd_entry function in lua/fzf-lua/actions.lua with related window/context handling changes.
  • PR #2666: Alters window and context handling logic within the vimcmd_entry function, affecting control flow for selected entry processing.

Poem

🐰 A window finds its proper place,
With quickfix held in fond embrace,
Or zero when none can be found,
Context set on hallowed ground!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main change: preventing the editor from staying in the quickfix window during edit actions, which matches the core fix in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ignore-qf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lua/fzf-lua/actions.lua`:
- 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.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d4e117a5-30d1-4936-82ed-1e50ff7482c0

📥 Commits

Reviewing files that changed from the base of the PR and between 69b0d5d and b0128cc.

📒 Files selected for processing (1)
  • lua/fzf-lua/actions.lua

Comment thread lua/fzf-lua/actions.lua
---@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.

@nenahp
Copy link
Copy Markdown

nenahp commented Apr 16, 2026

To elaborate, this fix: if we use picker when focus on a quickfix window, it will change the quickfix window's buffer.

I'm not sure anyone like this... if anyone want, this can be opt-in by custom something like vim._with({bo={bt=''}}, actions.file_edit)

@ibhagwan
Copy link
Copy Markdown
Owner

To elaborate, this fix: if we use picker when focus on a quickfix window, it will change the quickfix window's buffer.

I'm not sure anyone like this... if anyone want, this can be opt-in by custom something like vim._with({bo={bt=''}}, actions.file_edit)

I agree we shouldn’t change the quick fix buffer, more so we should match the behavior that existed before.

Maybe it’s better the fix should be in restore_last and do not run it at under most circumstances, only when it makes sense?

@phanen
Copy link
Copy Markdown
Collaborator Author

phanen commented Apr 18, 2026

Maybe it’s better the fix should be in restore_last and do not run it at under most circumstances, only when it makes sense?

I'll consider it, it work, but due to the vim behavior, when abort the picker with ctrl-c/esc, the cursor won't leave in quickfix window. I believe there should be a better way.

@phanen
Copy link
Copy Markdown
Collaborator Author

phanen commented Apr 19, 2026

Actually this is not only about quickfix and vim behavior.

I think we also don't want to override some other buffer like outline/file-explorer/codecompanion...

Currently I use this

      fa.vimcmd_entry = (function(orig)
        return function(...)
          api.nvim_set_current_win(vim.bo.bt ~= '' and fn.win_getid(fn.winnr('#')) or 0)
          return orig(...)
        end
      end)(fa.vimcmd_entry)

@ibhagwan
Copy link
Copy Markdown
Owner

I think we also don't want to override some other buffer like outline/file-explorer/codecompanion...

Agree, some buffers should remain

Currently I use this

if this works well for you we can use it, even if we have to add some hardcoded buffer types / filetypes for exclusion in the future that’s ok.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants