Skip to content

Commit 9363b46

Browse files
committed
feat(commit): commit preview window now also displays last log lines
1 parent fd4aff8 commit 9363b46

2 files changed

Lines changed: 64 additions & 28 deletions

File tree

lua/tinygit/commands/commit/preview.lua

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ local state = {
1010
--------------------------------------------------------------------------------
1111

1212
---@param mode "stage-all-and-commit"|"commit"
13-
---@param statsWidth number
13+
---@param width number
1414
---@return string[] cleanedOutput
1515
---@return string summary
16+
---@return number stagedLinesCount
1617
---@nodiscard
17-
function M.getDiffStats(mode, statsWidth)
18+
function M.getDiffStats(mode, width)
1819
---@type fun(args: string[]): string[], string
1920
local function runGitStatsAndCleanUp(args)
2021
local output = vim.split(u.syncShellCmd(args), "\n")
@@ -39,34 +40,59 @@ function M.getDiffStats(mode, statsWidth)
3940
return cleanedOutput, summary
4041
end
4142

42-
local gitStatsArgs = { "git", "diff", "--compact-summary", "--stat=" .. statsWidth }
43+
local gitStatsArgs = { "git", "diff", "--compact-summary", "--stat=" .. width }
4344

4445
if mode == "stage-all-and-commit" then
4546
u.intentToAddUntrackedFiles() -- include new files in diff stats
46-
return runGitStatsAndCleanUp(gitStatsArgs)
47+
local staged, summary = runGitStatsAndCleanUp(gitStatsArgs)
48+
return staged, summary, #staged
4749
end
4850

4951
local notStaged, _ = runGitStatsAndCleanUp(gitStatsArgs)
5052
local staged, summary = runGitStatsAndCleanUp(vim.list_extend(gitStatsArgs, { "--staged" }))
51-
if #notStaged > 0 then notStaged = vim.list_extend({ "", "not staged:" }, notStaged) end
52-
return vim.list_extend(staged, notStaged), summary
53+
local stagedLinesCount = #staged -- save, since `list_extend` mutates
54+
return vim.list_extend(staged, notStaged), summary, stagedLinesCount
5355
end
5456

55-
function M.diffStatsHighlights()
56-
local hlGroups = require("tinygit.config").config.appearance.hlGroups
57-
vim.fn.matchadd(hlGroups.addedText, [[ \zs+\+]]) -- color the plus/minus like in the terminal
58-
vim.fn.matchadd(hlGroups.removedText, [[-\+\ze\s*$]])
59-
60-
vim.fn.matchadd("Keyword", [[(new.*)]])
61-
vim.fn.matchadd("Keyword", [[(gone.*)]])
57+
---@param width number
58+
---@return string[] logLines
59+
function M.getGitLog(width)
60+
local args = { "git", "log", "--max-count=3", "--format=%s (%cr)" }
61+
local lines = vim.split(u.syncShellCmd(args), "\n")
62+
return vim.tbl_map(function(line)
63+
if #line > width then return line:sub(1, width - 1) .. "" end
64+
return line
65+
end, lines)
66+
end
6267

63-
vim.fn.matchadd("Function", ".*/") -- directory of a file
64-
vim.fn.matchadd("WarningMsg", "/") -- path separator
68+
---@param bufnr number
69+
---@param stagedLines number
70+
---@param diffstatLines number
71+
local function highlightPreviewWin(bufnr, stagedLines, diffstatLines)
72+
-- highlight diffstat for staged lines
73+
local hlGroups = require("tinygit.config").config.appearance.hlGroups
74+
local highlights = {
75+
{ hlGroups.addedText, [[ \zs+\+]] }, -- added lines
76+
{ hlGroups.removedText, [[-\+\ze *]] }, -- removed lines
77+
{ "Keyword", [[(new.*)]] },
78+
{ "Keyword", [[(gone.*)]] },
79+
{ "Function", ".*/" }, -- directory of a file
80+
{ "WarningMsg", "/" }, -- path separator
81+
{ "Comment", "" }, -- path separator
82+
}
83+
local endToken = "\\%<" .. stagedLines + 1 .. "l" -- limit pattern to range, see :help \%<l
84+
for _, hl in ipairs(highlights) do
85+
local pattern = hl[2] .. endToken
86+
vim.fn.matchadd(hl[1], pattern)
87+
end
6588

66-
vim.fn.matchadd("Comment", "") -- vertical separator
89+
-- highlight diffstat for UNstaged lines
90+
local ns = vim.api.nvim_create_namespace("tinygit.commitPreview")
91+
vim.hl.range(bufnr, ns, "Comment", { stagedLines, 0 }, { diffstatLines, 0 }, { priority = 1000 })
6792

68-
-- starting with "not staged", color rest of buffer (`\_.` matches any char, inc. \n)
69-
vim.fn.matchadd("Comment", [[^not staged:\_.*]])
93+
-- highlight log lines
94+
require("tinygit.shared.highlights").commitType(stagedLines) -- subject
95+
vim.fn.matchadd("Comment", [[(.*)$]]) -- date at the end via `git log --format="%s (%cr)"`
7096
end
7197

7298
--------------------------------------------------------------------------------
@@ -75,11 +101,16 @@ end
75101
---@param inputWinid number
76102
function M.createWin(mode, inputWinid)
77103
local inputWin = vim.api.nvim_win_get_config(inputWinid)
78-
local diffStats, summary = M.getDiffStats(mode, inputWin.width - 2)
104+
local textWidth = inputWin.width - 2
105+
local diffStatLines, summary, stagedLinesCount = M.getDiffStats(mode, textWidth)
106+
local diffstatLineCount = #diffStatLines -- save, since `list_extend` mutates
107+
table.insert(diffStatLines, "") -- line break
108+
local logLines = M.getGitLog(textWidth)
109+
local previewLines = vim.list_extend(diffStatLines, logLines)
79110

80111
-- CREATE WINDOW
81112
local bufnr = vim.api.nvim_create_buf(false, true)
82-
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, diffStats)
113+
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, previewLines)
83114
local winid = vim.api.nvim_open_win(bufnr, false, {
84115
relative = "win",
85116
win = inputWinid,
@@ -90,19 +121,22 @@ function M.createWin(mode, inputWinid)
90121
border = inputWin.border,
91122
style = "minimal",
92123
focusable = false,
93-
footer = #diffStats > 1 and " " .. summary .. " " or "",
124+
footer = #diffStatLines > 1 and " " .. summary .. " " or "",
94125
footer_pos = "right",
95126
})
96127
state.bufnr = bufnr
97128
state.winid = winid
98-
state.diffHeight = #diffStats
129+
state.diffHeight = #previewLines
99130
M.adaptWinPosition(inputWin)
100131

101132
vim.bo[bufnr].filetype = "tinygit.diffstats"
102133
vim.wo[winid].statuscolumn = " " -- = left-padding
103134

104135
vim.wo[winid].winhighlight = "FloatFooter:NonText,FloatBorder:Comment,Normal:Normal"
105-
vim.api.nvim_win_call(winid, M.diffStatsHighlights)
136+
vim.api.nvim_win_call(
137+
winid,
138+
function() highlightPreviewWin(bufnr, stagedLinesCount, diffstatLineCount) end
139+
)
106140
end
107141

108142
---@param inputWin vim.api.keyset.win_config

lua/tinygit/shared/highlights.lua

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ function M.inlineCodeAndIssueNumbers()
66
vim.fn.matchadd("@markup.raw.markdown_inline", [[`.\{-}`]]) -- .\{-} = non-greedy quantifier
77
end
88

9-
function M.commitType()
9+
---@param startingFromLine? number
10+
function M.commitType(startingFromLine)
11+
local prefix = startingFromLine and "\\%>" .. startingFromLine .. "l" or ""
12+
1013
-- not restricted to start of string, so prefixes like the numbering from the
1114
-- snacks-ui-select do not prevent the highlight
1215
local commitTypePattern = [[\v\w+(\(.{-}\))?!?]]
1316

14-
local type = commitTypePattern .. [[\ze: ]] -- `\ze`: end of match
15-
local colonAfterType = commitTypePattern .. [[\zs: ]] -- `\zs`: start of match
16-
vim.fn.matchadd("Title", type)
17+
local type = prefix .. commitTypePattern .. [[\ze: ]] -- `\ze`: end of match
18+
local colonAfterType = prefix .. commitTypePattern .. [[\zs: ]] -- `\zs`: start of match
19+
vim.fn.matchadd("Keyword", type)
1720
vim.fn.matchadd("Comment", colonAfterType)
18-
vim.fn.matchadd("WarningMsg", [[\v(fixup|squash)!]])
1921
end
2022

2123
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)