diff --git a/doc/neogit.txt b/doc/neogit.txt index 646481e2a..328fcb0e7 100644 --- a/doc/neogit.txt +++ b/doc/neogit.txt @@ -56,6 +56,7 @@ CONTENTS *neogit_contents* 7. Buffers |neogit_buffers| • Status |neogit_status_buffer| + • Editor |neogit_editor_buffer| • Log |neogit_log_buffer| • Reflog |neogit_reflog_buffer| • Commit |neogit_commit_buffer| @@ -1428,9 +1429,11 @@ Actions: *neogit_worktree_popup_actions* 7. Buffers *neogit_buffers* • Status |neogit_status_buffer| +• Editor |neogit_editor_buffer| • Log |neogit_log_buffer| • Reflog |neogit_reflog_buffer| • Commit |neogit_commit_buffer| +• Rebase Todo |neogit_rebase_todo_buffer| ============================================================================== Status Buffer *neogit_status_buffer* @@ -1441,6 +1444,47 @@ Untracked Files *neogit_status_buffer_untracked* untracked files entirely, "normal" to show files and directories (default), or "all" to show all files in all directories. +============================================================================== +Editor Buffer *neogit_editor_buffer* + +Commands: *neogit_editor_commands* + • Close *neogit_editor_close* + Default key: `q` + + Closes the editor buffer. If there are unsaved changes, user will be + prompted to save them. Discarding the changes will abort. + + • Submit *neogit_editor_submit* + Default key: `` + + Writes and closes the editor. + + • Abort *neogit_editor_abort* + Default key: `` + + Closes the editor buffer, discarding any changes that might have been + written. + + • PrevMessage *neogit_editor_prev_message* + Default key: `` + + Replaces the current commit message with the previously used one, via + reflog. Messages that have been discarded via reset will be included as + well. Any changes a user makes to a message will be stored while the + editor is open. + + • NextMessage *neogit_editor_next_message* + Default key: `` + + Replaces the current commit message with the next used one, via + reflog. Same semantics as |neogit_editor_prev_message| apply. + + • ResetMessage *neogit_editor_reset_message* + Default key: `` + + If a user has changed a message that was found via reflog, reset it to how + it appeared in reflog. + ============================================================================== Log Buffer *neogit_log_buffer* (TODO) diff --git a/lua/neogit/buffers/editor/init.lua b/lua/neogit/buffers/editor/init.lua index ab4ef9a4d..9bc9e43f0 100644 --- a/lua/neogit/buffers/editor/init.lua +++ b/lua/neogit/buffers/editor/init.lua @@ -2,6 +2,7 @@ local Buffer = require("neogit.lib.buffer") local config = require("neogit.config") local input = require("neogit.lib.input") local util = require("neogit.lib.util") +local git = require("neogit.lib.git") local pad = util.pad_right @@ -42,6 +43,25 @@ function M:open(kind) local mapping = config.get_reversed_commit_editor_maps() local aborted = false + local message_index = 1 + local message_buffer = { { "" } } + local footer + + local function reflog_message(index) + return git.log.reflog_message(index - 2) + end + + local function commit_message() + return message_buffer[message_index] or reflog_message(message_index) + end + + local function current_message(buffer) + local message = buffer:get_lines(0, -1) + message = util.slice(message, 1, math.max(1, #message - #footer)) + + return message + end + self.buffer = Buffer.create { name = self.filename, filetype = filetypes[self.filename:match("[%u_]+$")] or "NeogitEditor", @@ -64,6 +84,9 @@ function M:open(kind) string.format("# %s Close", pad_mapping("Close")), string.format("# %s Submit", pad_mapping("Submit")), string.format("# %s Abort", pad_mapping("Abort")), + string.format("# %s Previous Message", pad_mapping("PrevMessage")), + string.format("# %s Next Message", pad_mapping("NextMessage")), + string.format("# %s Reset Message", pad_mapping("ResetMessage")), } help_lines = util.filter_map(help_lines, function(line) @@ -77,6 +100,8 @@ function M:open(kind) buffer:write() buffer:move_cursor(1) + footer = buffer:get_lines(1, -1) + -- Start insert mode if user has configured it local disable_insert = config.values.disable_insert_on_commit if @@ -127,6 +152,31 @@ function M:open(kind) buffer:write() buffer:close(true) end, + [mapping["PrevMessage"]] = function(buffer) + local message = current_message(buffer) + message_buffer[message_index] = message + + message_index = message_index + 1 + + buffer:set_lines(0, #message, false, commit_message()) + buffer:move_cursor(1) + end, + [mapping["NextMessage"]] = function(buffer) + local message = current_message(buffer) + + if message_index > 1 then + message_buffer[message_index] = message + message_index = message_index - 1 + end + + buffer:set_lines(0, #message, false, commit_message()) + buffer:move_cursor(1) + end, + [mapping["ResetMessage"]] = function(buffer) + local message = current_message(buffer) + buffer:set_lines(0, #message, false, reflog_message(message_index)) + buffer:move_cursor(1) + end, }, }, } diff --git a/lua/neogit/config.lua b/lua/neogit/config.lua index 011e39c6e..9c3a420ac 100644 --- a/lua/neogit/config.lua +++ b/lua/neogit/config.lua @@ -114,7 +114,7 @@ end ---@alias NeogitConfigMappingsRebaseEditor "Pick" | "Reword" | "Edit" | "Squash" | "Fixup" | "Execute" | "Drop" | "Break" | "MoveUp" | "MoveDown" | "Close" | "OpenCommit" | "Submit" | "Abort" | false | fun() --- ----@alias NeogitConfigMappingsCommitEditor "Close" | "Submit" | "Abort" | false | fun() +---@alias NeogitConfigMappingsCommitEditor "Close" | "Submit" | "Abort" | "PrevMessage" | "ResetMessage" | "NextMessage" | false | fun() ---@class NeogitConfigMappings Consult the config file or documentation for values ---@field finder? { [string]: NeogitConfigMappingsFinder } A dictionary that uses finder commands to set multiple keybinds @@ -301,6 +301,9 @@ function M.get_default_values() ["q"] = "Close", [""] = "Submit", [""] = "Abort", + [""] = "PrevMessage", + [""] = "NextMessage", + [""] = "ResetMessage", }, rebase_editor = { ["p"] = "Pick", diff --git a/lua/neogit/lib/buffer.lua b/lua/neogit/lib/buffer.lua index bb7dbcc1a..cfbd6eed3 100644 --- a/lua/neogit/lib/buffer.lua +++ b/lua/neogit/lib/buffer.lua @@ -81,7 +81,7 @@ function Buffer:write() end function Buffer:get_lines(first, last, strict) - return api.nvim_buf_get_lines(self.handle, first, last, strict) + return api.nvim_buf_get_lines(self.handle, first, last, strict or false) end function Buffer:get_line(line) @@ -148,13 +148,7 @@ function Buffer:set_text(first_line, last_line, first_col, last_col, lines) end function Buffer:move_cursor(line) - if line < 0 then - self:focus() - vim.cmd("norm! G") - else - self:focus() - vim.cmd("norm! " .. line .. "G") - end + api.nvim_win_set_cursor(0, { line, 0 }) end function Buffer:close(force) diff --git a/lua/neogit/lib/git/log.lua b/lua/neogit/lib/git/log.lua index 3d5da4c5c..a1cbd1ef6 100644 --- a/lua/neogit/lib/git/log.lua +++ b/lua/neogit/lib/git/log.lua @@ -535,4 +535,12 @@ M.branch_info = util.memoize(function(ref, remotes) return result end) +function M.reflog_message(skip) + return cli.log + .format("%B") + .max_count(1) + .args("--reflog", "--no-merges", "--skip=" .. tostring(skip)) + .call_sync({ ignore_error = true }).stdout +end + return M diff --git a/lua/neogit/lib/util.lua b/lua/neogit/lib/util.lua index d9bb00fd1..bab107485 100644 --- a/lua/neogit/lib/util.lua +++ b/lua/neogit/lib/util.lua @@ -193,20 +193,20 @@ function M.str_min_width(str, len, sep) return str .. string.rep(sep or " ", len - length) end --- function M.slice(tbl, s, e) --- local pos, new = 1, {} --- --- if e == nil then --- e = #tbl --- end --- --- for i = s, e do --- new[pos] = tbl[i] --- pos = pos + 1 --- end --- --- return new --- end +function M.slice(tbl, s, e) + local pos, new = 1, {} + + if e == nil then + e = #tbl + end + + for i = s, e do + new[pos] = tbl[i] + pos = pos + 1 + end + + return new +end -- function M.str_count(str, target) -- local count = 0