Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Close previously open code action windows #368

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
64 changes: 49 additions & 15 deletions lua/rust-tools/code_action_group.lua

Choose a reason for hiding this comment

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

Following the steps from #362, now the second code action picker doesn't open at all.

Copy link
Author

Choose a reason for hiding this comment

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

Do you mean that this is expected for you or you wanted a different behavior?

I tried to avoid multiple code actions opened, which has the consequence that when the LSP is still loading the stuck before trying to open the floats. Which leads to undetermined order of resolution for the handling of the cleanup state. For instance, during my tests I saw no code action windows opening, which to me is still better than the previous behavior.

Let me know if this approach is ok or if you would rather opt for something different ☺️.

Choose a reason for hiding this comment

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

It should follow the native neovim behavior of vim.lsp.buf.code_action?

  • Only once code action menu can be opened at once
  • If you move focus out of the action menu, it will close automatically
  • If you somehow trigger a new code action menu (when one is already open), the previous one will close and the new one will get opened.

🤔

Copy link
Author

Choose a reason for hiding this comment

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

Ok, I think I got your point: you should be able to close the previous code action instead of avoiding the opening of a new one, right?

I did not thing about this kind of situation because if you run vim.lsp.buf.code_action you natively don't get any window, you just get the input message to choose the code action, you cannot open a new action code without leaving (and making disappear) the current choice.

In any case, I simply did not realize that if you just focus out of the floating window (instead of quitting it), it will just be left there and if you try to open a new code action both are closed. But also think that the problem is I mainly related to your second point, not the third one. In other words, I think that it should not be possible to trigger a second code action without the first one already been closed.

Do we agree? As I said, I was not really understanding because "focusing out" was just "quitting" the floating window, now I also think that the issue is still there.

Copy link
Author

Choose a reason for hiding this comment

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

@MunifTanjim I added two events listener in order to detect when the code action windows are left, in order to close them. Interestingly enough, I started noticing a different issue if you try to repeatedly open a code action when the LSP is still not ready, maybe related to the fact that state.actions is cleared on cleanup (which I run in case when leaving the code action windows) but there are concurrent handling of pending code actions.

Let me know what you think, for both the change and the new issue. Said that, I noticed what you are doing for this project and I really appreciate it. So, thank you for your efforts.

Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ local function on_primary_quit()
M.cleanup()
end

local function cleanup_state(state)
if state.winnr then
utils.close_win(state.winnr)
state.clear()
end
end

local function on_code_action_results(results, ctx)
M.state.ctx = ctx

Expand All @@ -116,7 +123,7 @@ local function on_code_action_results(results, ctx)
return
end

M.state.primary.geometry = compute_width(action_tuples, true)
local geometry = compute_width(action_tuples, true)

M.state.actions.grouped = {}

Expand All @@ -139,10 +146,12 @@ local function on_code_action_results(results, ctx)
end
end

cleanup_state(M.state.primary)
M.state.primary.geometry = geometry
M.state.primary.bufnr = vim.api.nvim_create_buf(false, true)
M.state.primary.winnr = vim.api.nvim_open_win(M.state.primary.bufnr, true, {
relative = "cursor",
width = M.state.primary.geometry.width,
width = geometry.width,
height = vim.tbl_count(M.state.actions.grouped)
+ vim.tbl_count(M.state.actions.ungrouped),
focusable = true,
Expand Down Expand Up @@ -249,19 +258,13 @@ local function on_secondary_quit()
end

function M.cleanup()
if M.state.primary.winnr then
utils.close_win(M.state.primary.winnr)
M.state.primary.clear()
end

if M.state.secondary.winnr then
utils.close_win(M.state.secondary.winnr)
M.state.secondary.clear()
end
cleanup_state(M.state.primary)
cleanup_state(M.state.secondary)

M.state.actions = {}
M.state.active_group_index = nil
M.state.ctx = {}
M.state.left_buf = nil
end

function M.on_cursor_move()
Expand All @@ -276,14 +279,14 @@ function M.on_cursor_move()
M.state.secondary.clear()
end

M.state.secondary.geometry = compute_width(value.actions, false)
local geometry = compute_width(value.actions, false)

M.state.secondary.bufnr = vim.api.nvim_create_buf(false, true)
M.state.secondary.winnr =
vim.api.nvim_open_win(M.state.secondary.bufnr, false, {
relative = "win",
win = M.state.primary.winnr,
width = M.state.secondary.geometry.width,
width = geometry.width,
height = #value.actions,
focusable = true,
border = "rounded",
Expand Down Expand Up @@ -336,6 +339,38 @@ function M.on_cursor_move()
end
end

-- Handles win leave and enter in order to get if any code action win needs to be closed.
local close_on_exit_group = vim.api.nvim_create_augroup(
"rust-tools-code-actions-close-on-exit",
{ clear = true }
)

vim.api.nvim_create_autocmd("WinLeave", {
group = close_on_exit_group,
callback = function(args)
if args.buf == M.state.primary.bufnr or args.buf == M.state.secondary.bufnr then
M.state.left_buf = args.buf
else
M.state.left_buf = nil
end
end
})

vim.api.nvim_create_autocmd("WinEnter", {
group = close_on_exit_group,
callback = function(args)
if not M.state.left_buf then
return
end

if args.buf == M.state.primary.bufnr or args.buf == M.state.secondary.bufnr then
return;
end

M.cleanup()
end
})

M.state = {
ctx = {},
actions = {},
Expand All @@ -353,13 +388,12 @@ M.state = {
secondary = {
bufnr = nil,
winnr = nil,
geometry = nil,
clear = function()
M.state.secondary.geometry = nil
M.state.secondary.bufnr = nil
M.state.secondary.winnr = nil
end,
},
left_buf = nil,
}

function M.code_action_group()
Expand Down