Skip to content
Merged
Show file tree
Hide file tree
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
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ Resolve a Git conflict:
:DiffBanditMerge path/to/conflicted-file
```

Close the DiffBandit view in the current tab (same as `q`):

```vim
:DiffBanditClose
```

## Editor Integration

DiffBandit uses real editable buffers for the right-side target in file,
Expand Down Expand Up @@ -277,11 +283,12 @@ Inside a diff view:
| `]d` | Align both panes to the bottom of the documents |
| `]s` | Snap the other pane to the cursor line |
| `C` | Open or focus the commit panel for the current Git file |
| `gzp` | Show or hide the commit panel |
| `<Space>` | Toggle stage for the active Git hunk |
| `>>` | Apply the left side to the right target |
| `<<` | Apply the right side to the left target |
| `u` | Undo the last DiffBandit hunk action |
| `q` | Close the diff session |
| `q` | Close the diff session (`navigation.close_key`) |

At a file boundary, `]c` and `[c` first notify that the next press will move to
the next or previous file. This keeps hunk navigation deliberate while still
Expand Down Expand Up @@ -332,7 +339,16 @@ opened by `:DiffBanditGit`.
| `<Space>` in the commit message window | Toggle amend mode |
| `:w` in the commit message window | Commit staged changes |
| `R` | Refresh the panel |
| `q` | Close the panel |
| `gzp` | Hide the panel, keeping the diff open |
| `q` | Close the whole view (diff, merge resolver, or standalone panel) |

`q` closes the view the same way from the panel and the diff panes, as does
`:DiffBanditClose`. An unfinished commit message is kept: closing the view
saves it for the repository, and the next commit panel opened there restores
it. Committing clears it.

Moving the panel selection between a merge conflict and a changed file swaps
the view in place, in the same tab.

The panel validates empty commit messages and missing staged changes before
committing, and rejects commits while merge conflicts remain unresolved. In
Expand Down
23 changes: 21 additions & 2 deletions doc/diffbandit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ COMMANDS *diffbandit-commands*
Open a three-pane resolver for an unmerged Git conflict. If [path] is
omitted, the current buffer path is used.

*:DiffBanditClose*
:DiffBanditClose
Close the DiffBandit view in the current tab: a diff, merge, or folder
session together with its tab page, or a standalone commit panel.
Equivalent to pressing `q`.

*:DiffBanditLaunch*
:DiffBanditLaunch
Entry point for the `bin/diffbandit` launcher; see
Expand Down Expand Up @@ -204,7 +210,11 @@ Diff view mappings:
u Undo the last DiffBandit hunk action for the current file.

*diffbandit-q*
q Close the diff session.
*diffbandit-gzp*
gzp Show or hide the commit panel for a Git diff.

q Close the diff session. Set by `navigation.close_key`;
false disables it.

At a file boundary, |diffbandit-]c| and |diffbandit-[c| first notify that the
next press will move to the next or previous file. This keeps file navigation
Expand Down Expand Up @@ -329,7 +339,14 @@ Panel mappings:
a Open file actions for the selected file.
cc Focus the commit message window.
R Refresh the panel.
q Close the panel.
gzp Hide the panel, keeping the diff open.
q Close the whole view: the diff or merge resolver with its
tab page, or the standalone panel. Same as |:DiffBanditClose|.

Closing a view keeps an unfinished commit message: it is saved for the
repository and restored by the next commit panel opened there. Committing
clears it. Moving the panel selection between a merge conflict and a changed
file swaps the view in place, in the same tab page.

Commit message window mappings:

Expand Down Expand Up @@ -414,6 +431,7 @@ Common configuration:
bottom = "]d",
},
snap_key = "]s",
close_key = "q",
},
git = {
default_mode = "all",
Expand All @@ -435,6 +453,7 @@ Common configuration:
file_actions = "a",
toggle_amend = "<Space>",
refresh = "R",
toggle_panel = "gzp",
close = "q",
},
},
Expand Down
2 changes: 2 additions & 0 deletions doc/tags
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
:DiffBanditApplyLeftHunk diffbandit.txt /*:DiffBanditApplyLeftHunk*
:DiffBanditApplyRightHunk diffbandit.txt /*:DiffBanditApplyRightHunk*
:DiffBanditBuffers diffbandit.txt /*:DiffBanditBuffers*
:DiffBanditClose diffbandit.txt /*:DiffBanditClose*
:DiffBanditCommitPanel diffbandit.txt /*:DiffBanditCommitPanel*
:DiffBanditDiscardHunk diffbandit.txt /*:DiffBanditDiscardHunk*
:DiffBanditFolderDiff diffbandit.txt /*:DiffBanditFolderDiff*
Expand Down Expand Up @@ -35,6 +36,7 @@ diffbandit-commit-panel diffbandit.txt /*diffbandit-commit-panel*
diffbandit-configuration diffbandit.txt /*diffbandit-configuration*
diffbandit-folder-diff diffbandit.txt /*diffbandit-folder-diff*
diffbandit-git diffbandit.txt /*diffbandit-git*
diffbandit-gzp diffbandit.txt /*diffbandit-gzp*
diffbandit-hunk-actions diffbandit.txt /*diffbandit-hunk-actions*
diffbandit-installation diffbandit.txt /*diffbandit-installation*
diffbandit-launcher diffbandit.txt /*diffbandit-launcher*
Expand Down
2 changes: 2 additions & 0 deletions lua/diffbandit/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ local defaults = {
bottom = "]d",
},
snap_key = "]s",
close_key = "q",
prompt_message = "Reached final change in this diff. Open next file with changes?",
on_request_next_file = nil,
},
Expand Down Expand Up @@ -155,6 +156,7 @@ local defaults = {
file_actions = "a",
toggle_amend = "<Space>",
refresh = "R",
toggle_panel = "gzp",
close = "q",
},
},
Expand Down
24 changes: 24 additions & 0 deletions lua/diffbandit/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -598,4 +598,28 @@ function M.undo()
return call_current_session("undo_action")
end

-- Close the DiffBandit view in the current tab: a diff, merge, or folder
-- session (with its tabpage) and/or a standalone commit panel. Under the
-- bin/diffbandit launcher this quits nvim, matching the panel's close key.
function M.close()
local tab = vim.api.nvim_get_current_tabpage()
local session = live_session(tab)
local panel = live_panel(tab)
if not session and not panel then
nvim.notify_info("no DiffBandit view in this tab")
return false
end
if state.quit_on_close then
pcall(vim.cmd, "confirm qall")
return true
end
if panel then
panel:close()
end
if session then
session:close()
end
return true
end

return M
6 changes: 6 additions & 0 deletions lua/diffbandit/merge/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1919,6 +1919,11 @@ function Merge:goto_queue_file(index, chunk_position, opts)
return false
end
state.register(session)
-- Replace this merge view rather than stacking a tab per switch (issue #20).
self:close()
if session.tabpage and vim.api.nvim_tabpage_is_valid(session.tabpage) then
pcall(vim.api.nvim_set_current_tabpage, session.tabpage)
end
return true
end

Expand Down Expand Up @@ -2157,6 +2162,7 @@ function Merge:close(from_autocmd)
if self.disposed then
return
end
panel_mod.save_draft(self)
self.disposed = true
kitty.detach(self)
self:clear_keymaps()
Expand Down
2 changes: 2 additions & 0 deletions lua/diffbandit/panel/commit_host.lua
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ function CommitPanel:close()
if self.disposed then
return
end
panel_mod.save_draft(self)
self:hide_commit_panel()
self.disposed = true
panel_mod.delete_buffers(self)
state.unregister_panel(self.tabpage)
end

Expand Down
73 changes: 69 additions & 4 deletions lua/diffbandit/panel/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,41 @@ function M.capture_message_lines(session)
return panel.message_lines or { "" }
end

local function has_text(lines)
return vim.trim(table.concat(lines or {}, "\n")) ~= ""
end

local function draft_root(session)
if is_review_panel(session) then
return nil
end
local queue = (session or {}).file_queue
return queue and queue.kind == "git" and queue.root or nil
end

-- Remember an unfinished commit message per repository, so closing the view
-- (q, :DiffBanditClose, :tabclose) never throws it away; the next panel
-- opened for that repository restores it. A panel that never rendered its
-- message (and carries none) leaves the saved draft alone, and so does amend
-- mode, whose message is the amended commit's rather than a draft.
function M.save_draft(session)
local panel = (session or {}).panel
local root = draft_root(session)
if not (panel and root) or panel.amend then
return
end
local lines
if panel.message_initialized and panel.commit_buf and vim.api.nvim_buf_is_valid(panel.commit_buf) then
lines = commit_message_lines_from_buffer(panel.commit_buf)
else
lines = panel.message_lines
if not has_text(lines) then
return
end
end
state.commit_drafts[root] = has_text(lines) and vim.deepcopy(lines) or nil
end

function M.clear_amend_opts(opts)
local clean = vim.tbl_extend("force", {}, opts or {})
clean.stage_base = nil
Expand Down Expand Up @@ -671,6 +706,11 @@ function M.render_commit(session)
end
if not panel.message_initialized then
panel.message_initialized = true
local root = draft_root(session)
local draft = root and state.commit_drafts[root]
if draft and not panel.amend and not has_text(panel.message_lines) then
panel.message_lines = vim.deepcopy(draft)
end
if #(panel.message_lines or {}) == 0 then
panel.message_lines = { "" }
end
Expand Down Expand Up @@ -929,6 +969,10 @@ function M.commit(session)
nvim.notify_warn(panel.validation_message)
return false, err
end
local root = draft_root(session)
if root then
state.commit_drafts[root] = nil
end
panel.message_lines = { "" }
panel.message_initialized = false
panel.validation_message = nil
Expand All @@ -943,11 +987,25 @@ function M.commit(session)
return true, nil
end

function M.close(session)
if is_review_panel(session) and panel_api.has(session, "close") then
panel_api.close(session)
-- Delete a closed host's panel buffers. The commit buffer is an acwrite
-- buffer that is usually modified, so leaving it loaded would make :qa fail
-- with E37; its text is already saved as a draft by save_draft().
function M.delete_buffers(session)
local panel = (session or {}).panel
if not panel then
return
end
for _, buf in ipairs({ panel.nav_buf, panel.commit_buf }) do
if buf and vim.api.nvim_buf_is_valid(buf) then
pcall(vim.api.nvim_set_option_value, "modified", false, { buf = buf })
pcall(vim.api.nvim_buf_delete, buf, { force = true })
end
end
end

-- Hide the panel windows. Closing the whole view is the host's close(), which
-- the panel's close key calls directly.
function M.close(session)
local panel = session.panel
if not panel then
return
Expand Down Expand Up @@ -1011,7 +1069,14 @@ function M.setup_keymaps(session)
pcall(vim.cmd, "confirm qall")
return
end
M.close(session)
-- q closes the whole view (diff, merge, or standalone panel), the same
-- as q in the diff panes and :DiffBanditClose; the toggle_panel key
-- hides only the panel.
if panel_api.has(session, "close") then
panel_api.close(session)
else
M.close(session)
end
end

-- lhs = nil/false skips the map (unset config key or failed condition);
Expand Down
Loading
Loading