Skip to content

Commit

Permalink
refactor(blameStatusline)!: module and its config restructured
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisgrieser committed Feb 12, 2024
1 parent 8c9ed1f commit 407f4ac
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 97 deletions.
55 changes: 30 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ operations.
* [Push & PR](#push--pr)
* [Search File/Function History ("git pickaxe")](#search-filefunction-history-git-pickaxe)
* [Stash](#stash)
- [Status Line Components](#status-line-components)
* [Git Blame Status Line Component](#git-blame-status-line-component)
- [Other Features](#other-features)
* [Improved Highlighting of Interactive Rebase](#improved-highlighting-of-interactive-rebase)
* [Git Blame Status Line Component](#git-blame-status-line-component)
- [Configuration](#configuration)
- [Comparison to existing git plugins](#comparison-to-existing-git-plugins)
- [Credits](#credits)
Expand Down Expand Up @@ -219,6 +220,24 @@ require("tinygit").stashPush()
require("tinygit").stashPop()
```

## Status Line Components

### Git Blame Status Line Component
Shows the message and date (`git blame`) of the last commit that changed the
current *file* (not line), like at GitHub.

```lua
require("tinygit.statusline").blame()
```

> [!TIP]
> Some status line plugin also allow you to put components into the tabline or
> winbar. If your status line is too crowded, you can add the blame-component to
> the one of those bars instead.
The component can be configured with the `statusline.blame` options in the [plugin
configuration](#configuration).

## Other Features

### Improved Highlighting of Interactive Rebase
Expand All @@ -235,22 +254,6 @@ If you want to disable the modifications by `tinygit`, add this to your config:
vim.g.tinygit_no_rebase_ftplugin = true
```

### Git Blame Status Line Component
Shows the message and date (`git blame`) of the last commit that changed the
current *file* (not line), like at GitHub.

```lua
require("tinygit.gitblame").statusLine()
```

> [!TIP]
> Some status line plugin also allow you to put components into the tabline or
> winbar. If your status line is too crowded, you can add the blame-component to
> the one of those bars instead.
The component can be configured with the `blameStatusLine` options in the [plugin
configuration](#configuration).

## Configuration
The `setup` call is optional. These are the default settings:

Expand All @@ -261,7 +264,7 @@ local defaultConfig = {
mediumLen = 50,
maxLen = 72,

-- Shows diffstats of the changes that are going to be committed.
-- Shows diffstats of the changes that are going to be committed.
-- (requires nvim-notify)
commitPreview = true,

Expand Down Expand Up @@ -305,15 +308,17 @@ local defaultConfig = {
-- unshallow the repo by running `git fetch --unshallow`
autoUnshallowIfNeeded = false,
},
blameStatusLine = {
-- Any of these authors and the component is not shown (useful for bots)
ignoreAuthors = {},
statusline = {
blame = {
-- Any of these authors and the component is not shown (useful for bots)
ignoreAuthors = {},

-- show component, but leave out names (useful for your own name)
hideAuthorNames = {},
-- show component, but leave out names (useful for your own name)
hideAuthorNames = {},

maxMsgLen = 35,
icon = "",
maxMsgLen = 35,
icon = "",
},
},
}
```
Expand Down
5 changes: 4 additions & 1 deletion lua/tinygit/commands/commit-and-amend.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ local function hasNoChanges()
end

local function updateGitBlame()
if package.loaded["tinygit.gitblame"] then require("tinygit.gitblame").refreshBlame() end
-- conditation to avoid unnecessarily loading the module
if package.loaded["tinygit.statusline.blame"] then
require("tinygit.statusline.blame").refreshBlame()
end
end

---process a commit message: length, not empty, adheres to conventional commits
Expand Down
21 changes: 13 additions & 8 deletions lua/tinygit/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ local M = {}
---@field issueIcons issueIconConfig
---@field historySearch historySearchConfig
---@field push pushConfig
---@field blameStatusLine blameConfig
---@field statusline { branchState: branchStateConfig, blame: blameConfig }

---@class issueIconConfig
---@field closedIssue string
Expand Down Expand Up @@ -38,6 +38,8 @@ local M = {}
---@field maxMsgLen number
---@field icon string

---@class branchStateConfig

--------------------------------------------------------------------------------

---@type pluginConfig
Expand Down Expand Up @@ -91,15 +93,18 @@ local defaultConfig = {
-- unshallow the repo by running `git fetch --unshallow`
autoUnshallowIfNeeded = false,
},
blameStatusLine = {
-- Any of these authors and the component is not shown (useful for bots)
ignoreAuthors = {},
statusline = {
blame = {
-- Any of these authors and the component is not shown (useful for bots)
ignoreAuthors = {},

-- show component, but leave out names (useful for your own name)
hideAuthorNames = {},
-- show component, but leave out names (useful for your own name)
hideAuthorNames = {},

maxMsgLen = 35,
icon = "",
maxMsgLen = 35,
icon = "",
},
branchState = {}, -- TODO
},
}

Expand Down
80 changes: 17 additions & 63 deletions lua/tinygit/gitblame.lua
Original file line number Diff line number Diff line change
@@ -1,70 +1,24 @@
-- INFO This file is required nowhere but in the snippet the user uses. That
-- means non of this code will be executed, if the user does not decide to use
-- this feature.
--------------------------------------------------------------------------------
local M = {}

local config = require("tinygit.config").config.blameStatusLine
local trim = vim.trim
local fn = vim.fn
--------------------------------------------------------------------------------

---@param bufnr? number
---@return string blame lualine stringifys result, so need to return empty string instead of nil
---@nodiscard
local function getBlame(bufnr)
bufnr = bufnr or 0

-- GUARD valid buffer
if not vim.api.nvim_buf_is_valid(bufnr) then return "" end
if vim.api.nvim_buf_get_option(bufnr, "buftype") ~= "" then return "" end

local bufPath = vim.api.nvim_buf_get_name(bufnr)
local gitLogLine = trim(
vim.fn.system { "git", "log", "--format=%H\t%an\t%cr\t%s", "--max-count=1", "--", bufPath }
)
-- GUARD git log
if gitLogLine == "" or vim.v.shell_error ~= 0 then return "" end

local hash, author, relDate, msg = unpack(vim.split(gitLogLine, "\t"))
if vim.tbl_contains(config.ignoreAuthors, author) then return "" end

-- GUARD shallow and on first commit
-- get first commit: https://stackoverflow.com/a/5189296/22114136
local isOnFirstCommit = hash == trim(fn.system { "git", "rev-list", "--max-parents=0", "HEAD" })
local shallowRepo = require("tinygit.shared.utils").inShallowRepo()
if shallowRepo and isOnFirstCommit then return "" end

-- shorten the output
local shortRelDate = (relDate:match("%d+ %wi?n?") or "") -- 1 unit char (expect min)
:gsub("m$", "mo") -- month -> mo to be distinguishable from "min"
:gsub(" ", "")
:gsub("%d+s", "just now") -- secs -> just now
if not shortRelDate:find("just now") then shortRelDate = shortRelDate .. " ago" end
local trimmedMsg = #msg < config.maxMsgLen and msg or trim(msg:sub(1, config.maxMsgLen)) .. ""
local authorInitials = not (author:find("%s")) and author:sub(1, 2) -- "janedoe" -> "ja"
or author:sub(1, 1) .. author:match("%s(%S)") -- "Jane Doe" -> "JD"
local authorStr = vim.tbl_contains(config.hideAuthorNames, author) and ""
or " by " .. authorInitials

return config.icon .. ("%s [%s%s]"):format(trimmedMsg, shortRelDate, authorStr)
-- This module is only there for backwards compatibility. Will notify the user
-- to use the new module.

local notified = false

---@deprecated
function M.statusLine()
if not notified then
vim.defer_fn(function()
local msg = '`require("tinygit.gitblame").statusLine()` is deprecated.\n'
.. 'Please use `require("tinygit.statusline").blame()` instead.\n\n'
.. "Note that the config also changed from `blameStatusLine` to `statusline.blame`."
vim.notify(msg, vim.log.levels.WARN, { title = "tinygit" })
end, 3000)
notified = true
end
return require("tinygit.statusline").blame()
end

--------------------------------------------------------------------------------

---@param bufnr? number
function M.refreshBlame(bufnr) vim.b["tinygit_blame"] = getBlame(bufnr) end

vim.api.nvim_create_autocmd({ "BufEnter", "DirChanged", "FocusGained" }, {
callback = function(ctx)
-- so buftype is set before checking the buffer
vim.defer_fn(function() M.refreshBlame(ctx.buf) end, 1)
end,
})

M.refreshBlame() -- initialize in case of lazy-loading

function M.statusLine() return vim.b["tinygit_blame"] or "" end

--------------------------------------------------------------------------------
return M
9 changes: 9 additions & 0 deletions lua/tinygit/statusline.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
local M = {}
--------------------------------------------------------------------------------

function M.blame() return require("tinygit.statusline.blame").getBlame() end

function M.branchState() return require("tinygit.statusline.branch-state").getBranchState() end

--------------------------------------------------------------------------------
return M
70 changes: 70 additions & 0 deletions lua/tinygit/statusline/blame.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
-- INFO This file is required nowhere but in the snippet the user uses. That
-- means non of this code will be executed, if the user does not decide to use
-- this feature.
--------------------------------------------------------------------------------
local M = {}

local config = require("tinygit.config").config.statusline.blame
local trim = vim.trim
local fn = vim.fn
--------------------------------------------------------------------------------

---@param bufnr? number
---@return string blame lualine stringifys result, so need to return empty string instead of nil
---@nodiscard
local function getBlame(bufnr)
bufnr = bufnr or 0

-- GUARD valid buffer
if not vim.api.nvim_buf_is_valid(bufnr) then return "" end
if vim.api.nvim_buf_get_option(bufnr, "buftype") ~= "" then return "" end

local bufPath = vim.api.nvim_buf_get_name(bufnr)
local gitLogLine = trim(
vim.fn.system { "git", "log", "--format=%H\t%an\t%cr\t%s", "--max-count=1", "--", bufPath }
)
-- GUARD git log
if gitLogLine == "" or vim.v.shell_error ~= 0 then return "" end

local hash, author, relDate, msg = unpack(vim.split(gitLogLine, "\t"))
if vim.tbl_contains(config.ignoreAuthors, author) then return "" end

-- GUARD shallow and on first commit
-- get first commit: https://stackoverflow.com/a/5189296/22114136
local isOnFirstCommit = hash == trim(fn.system { "git", "rev-list", "--max-parents=0", "HEAD" })
local shallowRepo = require("tinygit.shared.utils").inShallowRepo()
if shallowRepo and isOnFirstCommit then return "" end

-- shorten the output
local shortRelDate = (relDate:match("%d+ %wi?n?") or "") -- 1 unit char (expect min)
:gsub("m$", "mo") -- month -> mo to be distinguishable from "min"
:gsub(" ", "")
:gsub("%d+s", "just now") -- secs -> just now
if not shortRelDate:find("just now") then shortRelDate = shortRelDate .. " ago" end
local trimmedMsg = #msg < config.maxMsgLen and msg or trim(msg:sub(1, config.maxMsgLen)) .. ""
local authorInitials = not (author:find("%s")) and author:sub(1, 2) -- "janedoe" -> "ja"
or author:sub(1, 1) .. author:match("%s(%S)") -- "Jane Doe" -> "JD"
local authorStr = vim.tbl_contains(config.hideAuthorNames, author) and ""
or " by " .. authorInitials

return config.icon .. ("%s [%s%s]"):format(trimmedMsg, shortRelDate, authorStr)
end

--------------------------------------------------------------------------------

---@param bufnr? number
function M.refreshBlame(bufnr) vim.b["tinygit_blame"] = getBlame(bufnr) end

vim.api.nvim_create_autocmd({ "BufEnter", "DirChanged", "FocusGained" }, {
callback = function(ctx)
-- so buftype is set before checking the buffer
vim.defer_fn(function() M.refreshBlame(ctx.buf) end, 1)
end,
})

M.refreshBlame() -- initialize in case of lazy-loading

function M.getBlame() return vim.b["tinygit_blame"] or "" end

--------------------------------------------------------------------------------
return M
Empty file.

0 comments on commit 407f4ac

Please sign in to comment.