|
1 | | -# A Neovim Plugin Template |
| 1 | +--- |
| 2 | +last_modified: 2025-11-03 17:39:38 |
| 3 | +--- |
| 4 | + |
| 5 | +# headup.nvim |
2 | 6 |
|
3 | | - |
4 | 7 |  |
5 | 8 |
|
6 | | -A template repository for Neovim plugins. |
| 9 | +A Neovim plugin that automatically updates file header metadata when files are saved. |
| 10 | + |
| 11 | +## Features |
| 12 | + |
| 13 | +- **Automatic Updates**: Automatically updates metadata in file headers when saving |
| 14 | +- **Respects Manual Edits**: Won't overwrite user manual changes to metadata |
| 15 | +- **Configurable**: Support multiple file types with different patterns |
| 16 | + |
| 17 | +## Supported Content |
| 18 | + |
| 19 | +- `current_time`: Current timestamp |
| 20 | +- `file_size`: File size with automatic unit conversion (B, KB, MB, GB, TB) |
| 21 | +- `line_count`: Number of lines in the file |
| 22 | +- `file_name`: The base filename of the buffer |
| 23 | +- `file_path`: File path relative to current working directory |
| 24 | +- `file_path_abs`: Absolute file path |
| 25 | + |
| 26 | +## Installation |
| 27 | + |
| 28 | +### Using [lazy.nvim](https://github.com/folke/lazy.nvim) |
| 29 | + |
| 30 | +```lua |
| 31 | +{ |
| 32 | + "Fro-Q/headup.nvim", |
| 33 | + config = function() |
| 34 | + require("headup").setup({ |
| 35 | + -- your configuration here |
| 36 | + }) |
| 37 | + end, |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +### Using [packer.nvim](https://github.com/wbthomason/packer.nvim) |
7 | 42 |
|
8 | | -## Using it |
| 43 | +```lua |
| 44 | +use { |
| 45 | + "Fro-Q/headup.nvim", |
| 46 | + config = function() |
| 47 | + require("headup").setup({ |
| 48 | + -- your configuration here |
| 49 | + }) |
| 50 | + end |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +## Configuration |
| 55 | + |
| 56 | +headup.nvim uses a simplified configuration format where you pass global settings and configuration items directly in the setup table, without needing a `configs` wrapper key. |
9 | 57 |
|
10 | | -Via `gh`: |
| 58 | +### Basic Structure |
11 | 59 |
|
| 60 | +```lua |
| 61 | +require("headup").setup({ |
| 62 | + -- Global settings |
| 63 | + enabled = true, |
| 64 | + silent = true, |
| 65 | + |
| 66 | + -- Configuration items (array elements) |
| 67 | + { |
| 68 | + pattern = "*.md", -- file name glob(s) for autocmd |
| 69 | + match_pattern = "...", -- Lua pattern to capture value in file content |
| 70 | + content = "current_time", -- what to write |
| 71 | + -- other options... |
| 72 | + }, |
| 73 | + { |
| 74 | + pattern = {"*.py", "*.pyi"}, |
| 75 | + match_pattern = "...", |
| 76 | + content = "current_time", |
| 77 | + -- other options... |
| 78 | + }, |
| 79 | + -- Add more configuration items as needed... |
| 80 | +}) |
12 | 81 | ``` |
13 | | -$ gh repo create my-plugin -p ellisonleao/nvim-plugin-template |
| 82 | + |
| 83 | +### Default Configuration |
| 84 | + |
| 85 | +```lua |
| 86 | +require("headup").setup({ |
| 87 | + enabled = true, |
| 88 | + silent = true, -- Set to false to show notifications when updating |
| 89 | + |
| 90 | + -- Global fallbacks (used when an item doesn't set its own value) |
| 91 | + time_format = "inherit", |
| 92 | + max_lines = 20, |
| 93 | + end_pattern = "^---%s*$", -- Stop scanning at end of YAML front matter |
| 94 | + -- exclude_pattern = "*/archive/*", -- optional global exclude |
| 95 | + |
| 96 | + { |
| 97 | + pattern = "*.md", |
| 98 | + match_pattern = "last_modified:%s*(.-)%s*$", |
| 99 | + content = "current_time", |
| 100 | + -- This item will use the global fallbacks above |
| 101 | + }, |
| 102 | +}) |
14 | 103 | ``` |
15 | 104 |
|
16 | | -Via github web page: |
| 105 | +### Configuration Options |
17 | 106 |
|
18 | | -Click on `Use this template` |
| 107 | +#### Global Options |
| 108 | +- `enabled` (boolean): Whether the plugin is enabled globally (default: `true`) |
| 109 | +- `silent` (boolean): Whether to suppress notification messages (default: `true`) |
| 110 | +- `time_format` (string|"inherit"): Global fallback for time format when `content = "current_time"` |
| 111 | +- `max_lines` (number): Global fallback for maximum number of lines to scan from the beginning |
| 112 | +- `end_pattern` (string): Global fallback Lua pattern; stop scanning when matched (prevents over-scanning) |
| 113 | +- `exclude_pattern` (string|string[]): Global fallback filename glob(s) to exclude from processing |
19 | 114 |
|
20 | | - |
| 115 | +#### Per-Config Options (as array items) |
| 116 | +Each configuration item should be a table with the following fields: |
| 117 | +- `pattern` (string|string[]): File name glob(s) for autocmd (e.g., `"*.md"` or `{ "*.md", "*.markdown" }`) |
| 118 | +- `match_pattern` (string): Lua pattern to capture the content to update |
| 119 | +- `content` (string): What to write (`"current_time"`, `"file_size"`, `"line_count"`, `"file_name"`, `"file_path"`, `"file_path_abs"`) |
| 120 | +- `time_format` (string): Time format string for `current_time`, use `"inherit"` to keep original format |
| 121 | +- `max_lines` (number): Maximum number of lines to search from the beginning (default: 20) |
| 122 | +- `end_pattern` (string, optional): Lua pattern that, when matched, stops scanning further lines (prevents over-scanning) |
| 123 | +- `exclude_pattern` (string|string[], optional): File name glob(s) to exclude from processing |
21 | 124 |
|
22 | | -## Features and structure |
| 125 | +Note: For `time_format`, `max_lines`, `end_pattern`, and `exclude_pattern`, if an item doesn't provide a value, it will fall back to the corresponding global value when set. |
23 | 126 |
|
24 | | -- 100% Lua |
25 | | -- Github actions for: |
26 | | - - running tests using [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) and [busted](https://olivinelabs.com/busted/) |
27 | | - - check for formatting errors (Stylua) |
28 | | - - vimdocs autogeneration from README.md file |
29 | | - - luarocks release (LUAROCKS_API_KEY secret configuration required) |
| 127 | +### Example Configurations |
30 | 128 |
|
31 | | -### Plugin structure |
| 129 | +#### Markdown with YAML Front Matter |
32 | 130 |
|
| 131 | +```lua |
| 132 | +{ |
| 133 | + pattern = "*.md", |
| 134 | + match_pattern = "last_modified:%s*(.-)%s*$", |
| 135 | + content = "current_time", |
| 136 | + time_format = "inherit", |
| 137 | + max_lines = 20, |
| 138 | + end_pattern = "^---%s*$", |
| 139 | +} |
33 | 140 | ``` |
34 | | -. |
35 | | -├── lua |
36 | | -│ ├── plugin_name |
37 | | -│ │ └── module.lua |
38 | | -│ └── plugin_name.lua |
39 | | -├── Makefile |
40 | | -├── plugin |
41 | | -│ └── plugin_name.lua |
42 | | -├── README.md |
43 | | -├── tests |
44 | | -│ ├── minimal_init.lua |
45 | | -│ └── plugin_name |
46 | | -│ └── plugin_name_spec.lua |
| 141 | + |
| 142 | +#### Multiple File Types with Different Patterns |
| 143 | + |
| 144 | +```lua |
| 145 | +require("headup").setup({ |
| 146 | + enabled = true, |
| 147 | + silent = false, -- Show notifications |
| 148 | + |
| 149 | + -- Markdown files |
| 150 | + { |
| 151 | + pattern = {"*.md", "*.markdown"}, |
| 152 | + match_pattern = "last_modified:%s*(.-)%s*$", |
| 153 | + content = "current_time", |
| 154 | + time_format = "%Y-%m-%d %H:%M:%S", |
| 155 | + max_lines = 20, |
| 156 | + end_pattern = "^---%s*$", |
| 157 | + exclude_pattern = "*/archive/*", -- skip archived notes |
| 158 | + }, |
| 159 | + |
| 160 | + -- Text files with file size |
| 161 | + { |
| 162 | + pattern = "*.txt", |
| 163 | + match_pattern = "Size:%s*(.-)%s*$", |
| 164 | + content = "file_size", |
| 165 | + max_lines = 10, |
| 166 | + }, |
| 167 | + |
| 168 | + -- Any file type with line count |
| 169 | + { |
| 170 | + pattern = "*", |
| 171 | + match_pattern = "Lines:%s*(.-)%s*$", |
| 172 | + content = "line_count", |
| 173 | + max_lines = 15, |
| 174 | + }, |
| 175 | +}) |
47 | 176 | ``` |
| 177 | + |
| 178 | +## Commands |
| 179 | + |
| 180 | +- `:HeadupEnable` / `:HeadupDisable` / `:HeadupToggle` — control plugin state |
| 181 | +- `:HeadupUpdate` — manually update current buffer |
| 182 | +- `:HeadupClearCache` — clear internal cache |
| 183 | +- `:HeadupShowConfig` — show current effective configuration (formatted table) |
| 184 | + |
| 185 | +The plugin provides the following commands: |
| 186 | + |
| 187 | +- `:HeadupEnable` - Enable the plugin |
| 188 | +- `:HeadupDisable` - Disable the plugin |
| 189 | +- `:HeadupToggle` - Toggle plugin on/off |
| 190 | +- `:HeadupUpdate` - Manually update metadata in current buffer |
| 191 | +- `:HeadupClearCache` - Clear internal cache |
| 192 | + |
| 193 | +## How It Works |
| 194 | + |
| 195 | +1. **File Loading**: When a file is opened, the plugin scans for patterns and caches the matched content |
| 196 | +2. **Content Detection**: On save, it checks if the file content has actually changed |
| 197 | +3. **Manual Edit Respect**: If you manually edited the metadata, the plugin won't overwrite it |
| 198 | +4. **Smart Update**: Only updates metadata when file content changed but metadata wasn't manually modified |
| 199 | +5. **Cache Update**: Updates the internal cache after successful updates |
| 200 | + |
| 201 | +## Example Usage |
| 202 | + |
| 203 | +For a Markdown file with YAML front matter: |
| 204 | + |
| 205 | +```markdown |
| 206 | +--- |
| 207 | +title: My Document |
| 208 | +last_modified: 2024-01-01 12:00:00 |
| 209 | +--- |
| 210 | + |
| 211 | +# My Document |
| 212 | + |
| 213 | +Content here... |
| 214 | +``` |
| 215 | + |
| 216 | +When you edit and save the file, `last_modified` will automatically update to the current timestamp while preserving the original time format. |
| 217 | + |
| 218 | +## Silent Mode |
| 219 | + |
| 220 | +By default, the plugin operates silently. To see notifications when metadata is updated, set `silent = false` in your configuration: |
| 221 | + |
| 222 | +```lua |
| 223 | +require("headup").setup({ |
| 224 | + silent = false, -- Show notifications |
| 225 | + -- other config... |
| 226 | +}) |
| 227 | +``` |
| 228 | + |
| 229 | +When `silent = false`, you'll see notifications like: |
| 230 | +- "headup.nvim: Auto-updated timestamp to: 2024-11-02 15:30:45" |
| 231 | +- "headup.nvim: Updated file size to: 2.1 KB" |
| 232 | + |
| 233 | +## License |
| 234 | + |
| 235 | +MIT License - see [LICENSE](LICENSE) file for details. |
0 commit comments