-
Notifications
You must be signed in to change notification settings - Fork 62
fix: discussion window teardown and a recursion guard #581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
seflue
wants to merge
3
commits into
harrisoncramer:develop
Choose a base branch
from
seflue:fix/discussion-window-teardown
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| -- Without the nil-parent guard this test does not fail, it hangs, and the suite stops here. | ||
|
|
||
| local NuiTree = require("nui.tree") | ||
| local common = require("gitlab.actions.common") | ||
|
|
||
| describe("actions/common.get_root_node", function() | ||
| it("Gives up on a top level node that is not marked as a root", function() | ||
| local bufnr = vim.api.nvim_create_buf(false, true) | ||
| local tree = NuiTree({ | ||
| bufnr = bufnr, | ||
| nodes = { NuiTree.Node({ id = "a", text = "a", type = "note" }) }, | ||
| }) | ||
| tree:render() | ||
| -- The loop only forms if NuiTree can answer `get_node(nil)`, which it does from the | ||
| -- cursor of a window showing the buffer. | ||
| vim.api.nvim_win_set_buf(0, bufnr) | ||
|
|
||
| assert.is_nil( | ||
| common.get_root_node(tree, tree:get_node("-a")), | ||
| "get_root_node claimed a root for a note node that has no parent" | ||
| ) | ||
|
|
||
| vim.api.nvim_buf_delete(bufnr, { force = true }) | ||
| end) | ||
| end) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| -- close() closes the window itself instead of leaving that to NuiSplit, which gives up on | ||
| -- the last window of a session and ignores every later unmount once one has failed. These | ||
| -- tests check that the window is gone afterwards and that `split_visible` says so. | ||
|
|
||
| local discussions = require("gitlab.actions.discussions") | ||
| local draft_notes = require("gitlab.actions.draft_notes") | ||
| local winbar = require("gitlab.actions.discussions.winbar") | ||
| local state = require("gitlab.state") | ||
|
|
||
| ---Register a split with the given unmount behaviour, in a window of its own. | ||
| ---@param unmount fun(split: table) | ||
| ---@return integer winid | ||
| local function arrange(unmount) | ||
| vim.cmd("tabnew") | ||
| vim.cmd("split") | ||
| local winid = vim.api.nvim_get_current_win() | ||
| discussions.split = { winid = winid, unmount = unmount } | ||
| discussions.split_visible = true | ||
| return winid | ||
| end | ||
|
|
||
| describe("actions/discussions.close", function() | ||
| after_each(function() | ||
| discussions.split = nil | ||
| discussions.split_visible = false | ||
| discussions.discussion_tree = nil | ||
| discussions.linked_bufnr = nil | ||
| discussions.unlinked_bufnr = nil | ||
| winbar.cleanup_timer() | ||
| state.DISCUSSION_DATA = nil | ||
| vim.cmd("tabnew") | ||
| vim.cmd("silent! tabonly") | ||
| vim.cmd("silent! only") | ||
| end) | ||
|
|
||
| it("Closes the window itself when a poisoned split ignores unmount", function() | ||
| local winid = arrange(function() end) | ||
|
|
||
| discussions.close() | ||
|
|
||
| assert.is_false(vim.api.nvim_win_is_valid(winid), ("window %d survived close()"):format(winid)) | ||
| assert.is_false(discussions.split_visible) | ||
| end) | ||
|
|
||
| it("Closes the window itself when unmounting raises", function() | ||
| local winid = arrange(function() | ||
| error("nui teardown failed") | ||
| end) | ||
|
|
||
| discussions.close() | ||
|
|
||
| assert.is_false(vim.api.nvim_win_is_valid(winid), ("window %d survived close()"):format(winid)) | ||
| assert.is_false(discussions.split_visible) | ||
| end) | ||
|
|
||
| it("Closes the window when it is the last one in the session", function() | ||
| vim.cmd("silent! tabonly") | ||
| vim.cmd("silent! only") | ||
| -- Neovim refuses to close the last window, so close() has to open a sibling first. That | ||
| -- sibling shows the tree buffer, which is wiped a moment later. | ||
| local winid = vim.api.nvim_get_current_win() | ||
| local bufnr = vim.api.nvim_create_buf(true, false) | ||
| vim.api.nvim_win_set_buf(winid, bufnr) | ||
| discussions.split = { winid = winid, unmount = function() end } | ||
| discussions.split_visible = true | ||
| discussions.linked_bufnr = bufnr | ||
|
|
||
| discussions.close() | ||
|
|
||
| assert.is_false(vim.api.nvim_win_is_valid(winid), ("window %d survived close()"):format(winid)) | ||
| assert.is_false(vim.api.nvim_buf_is_valid(bufnr), ("buffer %d survived close()"):format(bufnr)) | ||
| assert.is_false(discussions.split_visible) | ||
| end) | ||
|
|
||
| it("Tears the split down when the user closes the window by hand", function() | ||
| -- M.open calls draft_notes.rebuild_view, which talks to the Go server these tests | ||
| -- cannot connect to. | ||
| local original_rebuild_view = draft_notes.rebuild_view | ||
| draft_notes.rebuild_view = function() end | ||
| vim.cmd("tabnew") | ||
| discussions.open() | ||
| local winid = discussions.split.winid | ||
|
|
||
| vim.api.nvim_win_close(winid, true) | ||
|
|
||
| local torn_down = vim.wait(200, function() | ||
| return discussions.split_visible == false | ||
| end, 10) | ||
|
|
||
| assert.is_true(torn_down, "split_visible is still set 200ms after the window closed") | ||
| draft_notes.rebuild_view = original_rebuild_view | ||
| end) | ||
| end) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| -- The linked and unlinked buffers belong to one open, not to the session, so close() owns | ||
| -- their release. | ||
|
|
||
| local discussions = require("gitlab.actions.discussions") | ||
| local draft_notes = require("gitlab.actions.draft_notes") | ||
| local winbar = require("gitlab.actions.discussions.winbar") | ||
| local state = require("gitlab.state") | ||
|
|
||
| -- Without this precondition the deletion asserts below would also pass if open() never | ||
| -- created the buffers in the first place. | ||
| local function assert_buffers_created(linked, unlinked) | ||
| assert.is_true(linked ~= nil and vim.api.nvim_buf_is_valid(linked), "open() created no linked buffer") | ||
| assert.is_true(unlinked ~= nil and vim.api.nvim_buf_is_valid(unlinked), "open() created no unlinked buffer") | ||
| end | ||
|
|
||
| describe("actions/discussions buffers", function() | ||
| local original_rebuild_view | ||
|
|
||
| before_each(function() | ||
| -- M.open tails into draft_notes.rebuild_view, which talks to the Go server these tests | ||
| -- have no connection to. | ||
| original_rebuild_view = draft_notes.rebuild_view | ||
| draft_notes.rebuild_view = function() end | ||
| end) | ||
|
|
||
| after_each(function() | ||
| draft_notes.rebuild_view = original_rebuild_view | ||
| discussions.split = nil | ||
| discussions.split_visible = false | ||
| discussions.discussion_tree = nil | ||
| discussions.linked_bufnr = nil | ||
| discussions.unlinked_bufnr = nil | ||
| winbar.cleanup_timer() | ||
| state.DISCUSSION_DATA = nil | ||
| vim.cmd("tabnew") | ||
| vim.cmd("silent! tabonly") | ||
| vim.cmd("silent! only") | ||
| end) | ||
|
|
||
| it("Deletes both buffers when the window is closed", function() | ||
| vim.cmd("tabnew") | ||
| discussions.open() | ||
| local linked, unlinked = discussions.linked_bufnr, discussions.unlinked_bufnr | ||
| assert_buffers_created(linked, unlinked) | ||
|
|
||
| discussions.close() | ||
|
|
||
| assert.is_false(vim.api.nvim_buf_is_valid(linked), ("linked buffer %d was not deleted"):format(linked)) | ||
| assert.is_false(vim.api.nvim_buf_is_valid(unlinked), ("unlinked buffer %d was not deleted"):format(unlinked)) | ||
| end) | ||
|
|
||
| it("Leaves no buffer behind over an open/close cycle", function() | ||
| vim.cmd("tabnew") | ||
| discussions.open() | ||
| local first_linked, first_unlinked = discussions.linked_bufnr, discussions.unlinked_bufnr | ||
| assert_buffers_created(first_linked, first_unlinked) | ||
| discussions.close() | ||
|
|
||
| discussions.open() | ||
|
|
||
| assert.are_not.equal(first_linked, discussions.linked_bufnr) | ||
| assert.is_false( | ||
| vim.api.nvim_buf_is_valid(first_linked), | ||
| ("linked buffer %d of the first open leaked"):format(first_linked) | ||
| ) | ||
| assert.is_false( | ||
| vim.api.nvim_buf_is_valid(first_unlinked), | ||
| ("unlinked buffer %d of the first open leaked"):format(first_unlinked) | ||
| ) | ||
| discussions.close() | ||
| end) | ||
| end) | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.