Skip to content

Keep current file selected after staging #1760

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
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

Aitai
Copy link
Contributor

@Aitai Aitai commented Jun 7, 2025

This PR fixes #1448 where Diffview would jump back to the first file after saving.

To fix this in Neogit, I've updated the Diffview integration:

  1. When files are staged, I now capture the path of the file currently open in the active diff buffer.
  2. This is then passed to update_files, which then uses it to ensure the correct file remains selected.

Note on a related Diffview issue:
I also noticed that Diffview itself doesn't always handle writing edits to staged files correctly (changes made in the diff view to a staged file might not reflect in the worktree, appearing lost on refresh). I've fixed this in my fork of Diffview.

@Aitai Aitai force-pushed the diffview_write branch from 7fccff5 to 4ccbb92 Compare June 8, 2025 11:28
@CKolkey
Copy link
Member

CKolkey commented Jun 8, 2025

I'm going to do my best to review all your PR's soon, just bear in mind I have three kids, two of which are six months old 😅

@Aitai
Copy link
Contributor Author

Aitai commented Jun 8, 2025

No worries! Take your time, I know how demanding twins can be.

@@ -18,23 +17,33 @@ local function get_local_diff_view(section_name, item_name, opts)
section_name = "working"
end

local function update_files()
local function update_files(current_file_path)
Copy link
Member

Choose a reason for hiding this comment

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

it looks like this argument will always be nil? I don't see any callers passing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, that argument is never a file path as its name implied. My initial implementation incorrectly assumed I needed to manage the selected state during refreshes. I later realized diffview actually passes its view object to the update callback, and the old code was only working due to a subtle side-effect: the truthy view object prevented my fallback logic from running, which implicitly preserved the selection.

I've made a new commit which aligns correctly with the diffview API. The selected flag is now set only on the initial file list passed to the constructor. The update_files function acts as a pure data provider for refreshes, which properly leaves the selection management to diffview itself.

Comment on lines 23 to 31
git.repo:dispatch_refresh {
source = "diffview_update",
callback = function() end,
}

local repo_state = git.repo.state
if not repo_state then
return files
end
Copy link
Member

Choose a reason for hiding this comment

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

Not sure about this - the git repo should always have state at this point. How would you get here with an uninitialized repository?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was just defensive programming and isn't actually needed in this context. I've removed it.

Comment on lines 98 to 102
view:on_files_staged(function()
vim.schedule(function()
Watcher.instance():dispatch_refresh()
end)
end)
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain why this needs to be scheduled, instead of non-blocking async? Not sure I follow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I originally added vim.schedule because I was concerned about a potential race condition and thought I needed to manually defer the async refresh until after diffview's synchronous operations were complete.

However, I realized that dispatch_refresh already uses plenary.a.void internally.

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.

Diffviewer changes focus to first file after save
2 participants