When navigating large or new codebases, sometimes it is nice to see what has recently changed, versus what code has been around for a long time.
Visualize the relative age of each line of code, by git blame in Neovim's
sign column. Newer code gets a thicker, greener bar; older code fades to a
thin red sliver. Ages are log-scaled and anchored to the file's newest line,
so a wide spread of commit dates stays readable.
█ function greet(name) -- recent (green, full block)
▌ return "hello " .. name -- months old (yellow, half block)
▏ end -- years old (red, thin)
- Per-line age heatmap in the sign column
- Color gradient: green (new) → yellow → red (old)
- Two styles:
thickness(default): single glyph per line, scaled from▏to█. No signcolumn config needed.stack: 1–N copies of a bar character, stacked across sign slots.
- Log-scaled ages so a file with both 2-day-old and 5-year-old lines stays distinguishable.
- Anchored to the file's newest line — shows relative age within the file, not absolute.
- Neovim ≥ 0.10 (uses
vim.system) gitinPATH- The buffer's file must be tracked by git
{
"markmarkoh/code-age.nvim",
cmd = "CodeAge",
opts = {
-- defaults shown; omit `opts` entirely to accept them
style = "thickness",
tiers = 3,
},
}use({
"markmarkoh/code-age.nvim",
config = function()
require("code_age").setup({})
end,
})Plug 'markmarkoh/code-age.nvim'Then in your init.lua:
require("code_age").setup({})add({ source = "markmarkoh/code-age.nvim" })
require("code_age").setup({})git clone https://github.com/markmarkoh/code-age.nvim \
~/.local/share/nvim/site/pack/plugins/start/code-age.nvim| Command | Action |
|---|---|
:CodeAge |
Toggle the heatmap on the current buffer |
:CodeAge show |
Enable |
:CodeAge hide |
Disable |
All options with their defaults:
require("code_age").setup({
style = "thickness", -- "thickness" | "stack"
bar = "▌", -- glyph used in "stack" mode
tiers = 3, -- number of age buckets (also stack height)
})Single glyph per line, sampled evenly from ▏ ▎ ▍ ▌ ▋ ▊ ▉ █ based on
tiers. Fits in the default signcolumn=yes — no extra setup required.
Try tiers = 5 or tiers = 8 for a finer-grained ramp.
Repeats bar once per tier; new code stacks to tiers bars, old code
collapses to one. Each sign slot is two cells, so you need to widen the
sign column:
vim.opt.signcolumn = "yes:3" -- match your `tiers` value- Runs
git blame --line-porcelain -M -Con the buffer's file. - For each line, computes
age_days = newest_in_file - author_time. - Log-scales (
log(1 + age_days)) and normalizes tot ∈ [0, 1]. - Maps
tto a color (two-segment green→yellow→red lerp) and to a glyph weight (1..tiers).
The anchor is the newest line in this file, not "today". So a file untouched for five years still shows its internal age structure.
- Works on the on-disk version of the file — unsaved buffer edits can
misalign line numbers until you save and re-run
:CodeAge. - No autorefresh on
BufWritePostyet. - Uncommitted lines are treated as "newest" (no blame info).