*Automatically updates file metadata on save.*
headup_demo.mp4
- Automatic updates for header metadata on write
- Respects manual edits (won’t overwrite user changes)
- Per-filetype rules with globs, early-stop scanning, and exclusions
current_time: Current timestamp with customizable formatfile_size: Humanized file size (B / KB / MB / GB / TB)line_count: Number of lines in the bufferfile_name: Base filenamefile_path: Path relative to CWDfile_path_abs: Absolute path
See also: :help Utils.valid_contents.
Using lazy.nvim
{
"Fro-Q/headup.nvim",
config = function()
require("headup").setup()
end,
}Using packer.nvim
use {
"Fro-Q/headup.nvim",
config = function()
require("headup").setup()
end
}Minimal setup that updates something like -- Last Modified: x in Lua with current time in the specified format, stopping at the first empty line.
require("headup").setup({
enabled = true,
silent = true,
time_format = "%Y-%m-%d %H:%M:%S",
max_lines = 20,
end_pattern = "^%s*$", -- stop at first empty line
exclude_pattern = "",
{
pattern = "*.lua",
match_pattern = "^%s*%-%-%s*[Ll]ast[%s_%-][Mm]odified:%s(.-)%s*$",
content = "current_time",
},
})-
Global options (apply to all items unless overridden):
enabled(boolean, defaulttrue)silent(boolean, defaulttrue)time_format(string|"inherit")max_lines(number)end_pattern(string, Lua pattern; early stop when matched)exclude_pattern(string|string[]; file globs to skip)
-
Per-item options (each element is a rule):
pattern(string|string[]; file globs for autocmd)match_pattern(string; Lua pattern to capture the value to replace)content(string; one of supported content types)time_format(string|"inherit")max_lines(number)end_pattern(string)exclude_pattern(string|string[])
Note: items inherit unset values from global options (fallbacks).
:HeadupEnable/:HeadupDisable/:HeadupToggle:HeadupUpdate– force update current buffer (ignores previous cache and buffer state):HeadupClearCache– clear internal cache
Lua API (see :help Headup):
- Some commands have equivalent Lua functions:
require('headup').enable()/disable()/toggle()require('headup').update_current_buffer()require('headup').clear_cache()
- You can register custom content generators:
require('headup.func').register_generator(name, func)
See more in :help headup.nvim.
You can add your own content type by registering a generator. A generator is
fun(bufnr: integer, ctx?: { time_format?: string, old_content?: string }): string.
Register:
local func = require('headup.func')
func.register('my_branch', function(bufnr)
local file = vim.api.nvim_buf_get_name(bufnr)
local dir = file ~= '' and vim.fn.fnamemodify(file, ':h') or vim.fn.getcwd()
local out = vim.fn.systemlist({ 'git', '-C', dir, 'rev-parse', '--abbrev-ref', 'HEAD' })
local branch = (out and out[1]) or 'unknown'
return (branch or ''):gsub('%s+', '')
end)Use in config:
require('headup').setup({
{
pattern = '*.md',
match_pattern = 'branch:%s*(.-)%s*$',
content = 'my_branch',
},
})More templates:
-- Uppercase previous value
func.register('uppercase', function(_, ctx)
return ((ctx and ctx.old_content) or ''):upper()
end)
-- SHA256 of current buffer
func.register('file_sha256', function(bufnr)
local text = table.concat(vim.api.nvim_buf_get_lines(bufnr, 0, -1, false), '\n')
return vim.fn.sha256(text)
end)And share your useful generators in Discussions!
There is a most detailed help file included with the plugin. See in :help headup.nvim.
MIT - Copyright (c) 2025 Fro-Q