Skip to content

Conversation

@christiandesantis
Copy link

Changes

Untracked file support

  • Single-pane mode for untracked files: the left (original) pane is hidden since there is no previous version to compare against
  • Auto-skip navigation: moving past the hidden pane redirects to the explorer or file pane automatically

Hunk-level staging and unstaging

  • S stages the hunk under the cursor to the git index (git apply --cached)
  • U unstages the hunk under the cursor from the git index (git apply --cached --reverse)
  • Diff view auto-refreshes after each operation
  • When the last hunk is staged/unstaged, automatically switches to the opposite view (staged/unstaged)

Explorer file actions

  • a / s stages the file under the cursor (git add)
  • u unstages the file under the cursor (git restore --staged)
  • d discards file changes or deletes untracked files (with confirmation prompt)
  • o opens the file under the cursor (alias for <CR>)
  • l jumps to the modified (right) pane if the file is already open, otherwise opens it

Bug fixes

  • Fixed git C-quoted paths: filenames with spaces and special characters are now parsed correctly
  • Fixed filetype detection for virtual buffers (e.g. .ts files now get proper syntax highlighting)
  • Fixed q keymap not working in single-pane mode for untracked files

Display untracked files (status ??) in a single pane without diff
highlighting, since there's nothing to compare against. When switching
to tracked files, the two-pane layout is automatically restored.

- Add update_windows() and is_single_pane_mode() to lifecycle module
- Handle untracked file selection in explorer to close original window
- Add single-pane recovery logic in view.update() for layout restoration
Instead of closing the original window (which corrupts session state),
show an empty scratch buffer with a message in the left pane while
displaying the untracked file in the right pane. This keeps the
session state consistent and allows switching back to tracked files.
When viewing untracked files:
- Shrink left pane to 1 column (effectively hidden)
- Auto-skip the hidden pane when navigating with Ctrl+H/L
- Restore equal window widths when switching to tracked files
Move the placeholder window restoration code to run synchronously
after buffer loading, rather than inside the async render_everything
callback. This ensures window widths are restored reliably.
- Use bufadd/bufload/nvim_win_set_buf instead of :edit to reuse buffers
- Get old buffers from session before clearing highlights
- Update all session state (buffers, paths, revisions, diff_result)
  after opening untracked file to keep state consistent
- This fixes issues when switching between untracked and tracked files
- Create separate scratch buffers for each window in explorer mode
  so the initial tabnew buffer can be properly deleted
- Capture scratch buffer before loading new buffers in view.update
- Clean up old scratch buffers (buftype='nofile') in view.update
- This fixes empty buffer accumulation and improves restoration
  when switching between untracked and tracked files
Keep the explorer scratch buffer fix (prevents empty buffer
accumulation) but revert the changes to view.update that broke
untracked→tracked file switching.
The :edit! command to load virtual files can fail in a 1-column window.
Move the placeholder restoration code (window resizing) to run BEFORE
buffer loading, so the window is a proper size when loading content.
@christiandesantis christiandesantis force-pushed the feat/staging-and-explorer-actions branch from 2d63f70 to 9e0fee7 Compare January 30, 2026 04:48
@christiandesantis
Copy link
Author

I'm sorry I was working on this without having pulled the latest changes from the main branch, hope I didn't break anything during rebase

@christiandesantis
Copy link
Author

I'm sorry I was working on this without having pulled the latest changes from the main branch, hope I didn't break anything during rebase

It did broke during rebase, I'll push a fix soon

@esmuellert esmuellert dismissed a stale review February 1, 2026 19:38

remove

Copy link
Owner

@esmuellert esmuellert left a comment

Choose a reason for hiding this comment

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

Basically, some keymaps seems lke to be existing, and the new implementation is duplicate? If so we might want to remove them first. The hunk level stage support is good and requested by many issues. I will take a look at it

old_path = parts[2]
path = parts[3]
end
-- For revision comparison, we treat everything as "unstaged" for explorer compatibility
Copy link
Owner

Choose a reason for hiding this comment

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

Can you run make format to format the code before submission?

Copy link
Author

Choose a reason for hiding this comment

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

Will do

},
explorer = {
select = "<CR>",
open = "o", -- Alias for select (open file or toggle group)
Copy link
Owner

Choose a reason for hiding this comment

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

I feel if user wants an alias, they can setup their own keymap locally, so it might not be necessary for us to have one?

explorer = {
select = "<CR>",
open = "o", -- Alias for select (open file or toggle group)
focus_file = "l", -- Jump to modified pane if file is open, otherwise open file
Copy link
Owner

Choose a reason for hiding this comment

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

To confirm the behavior, if a file was not selected, it will select that file first, then focus the modified pane, right?

Copy link
Author

@christiandesantis christiandesantis Feb 1, 2026

Choose a reason for hiding this comment

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

Using 'l' would open the file if not selected already, and move the cursor straight to the right pane so you can start scrolling and reviewing immediately. In case that you use 'l' and the file was already open, it just takes the cursor to the right pane the same way. When using 'o' it opens the file without moving the cursor from the file explorer, I thought it to be a good default, maybe I should've not call it "alias" in the comment next to it

refresh = "R",
toggle_view_mode = "i", -- Toggle between 'list' and 'tree' views
toggle_view_mode = "i", -- Toggle between 'list' and 'tree' views
stage_file = "a", -- Stage file under cursor (git add)
Copy link
Owner

Choose a reason for hiding this comment

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

These keymaps for stage/unstage/discard the file under cursor in explorer seem to be already implemented by - and X keymaps, so are they duplicated? If so, we might want to remove them

Copy link
Author

Choose a reason for hiding this comment

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

Yeah maybe, I just found these more intuitive. I still don't know if this previously had a key binding for staging the file, since '-' works for unstaging, I tried using '+' to stage but didn't work

Copy link
Owner

Choose a reason for hiding this comment

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

Yes, - not only works for unstaging but also can stage unstaged if you click. It is basically a toggle. So the stage/unstage features seem to be duplicated

Copy link
Author

Choose a reason for hiding this comment

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

Ohh gotcha!

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.

2 participants