Skip to content

willothy/macro-lab.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

macro-lab.nvim

Record, view, edit, and replay Vim macros — sanely.

Vim macros are powerful but opaque: a register full of raw keystrokes you can't read, can't fix, and can't trust. macro-lab.nvim opens any macro in a lab window where it's broken down into human-readable steps, editable as plain notation, replayable with a dry-run preview, and savable under a name.

╭─────────────────────── Macro Lab  @a ───────────────────────╮
│                                                             │
│  @a    3 keys · 18 bytes                                    │
│                                                             │
│  NOTATION                                                   │
│  │ ciwHello<Esc>jA<Space>world<Esc>                         │
│                                                             │
│  STEPS                                                      │
│  │  1  INS  ciwHello<Esc>       Change inner word, typing…  │
│  │  2       j                   Move down one line          │
│  │  3  INS  A<Space>world<Esc>  Append at end of line: …    │
│                                                             │
╰──── e edit  r replay  p preview  s step  w save  q quit ────╯

Special keys, literal text, mode badges (INS/CMD/VIS/…) and section headers are all themed via overridable MacroLab* highlight groups, so the lab matches your colourscheme.

Features

  • View a macro as readable steps — a mode-aware interpreter groups the raw keystrokes into logical actions (ciwfoo<Esc>Change inner word, typing "foo") instead of a wall of bytes.
  • Edit a macro — open the macro as :map-style notation, fix it by hand, and :w to write it straight back into the register. Round-trips losslessly.
  • Replay with preview — dry-run the macro against a throwaway copy of the buffer and see a before/after diff before you commit, or step through it one action at a time.
  • Save named macros — persist macros to disk with a name and description, and load them back into any register.
  • Convert repeated edits to a macro — after you've done the same edit a few times by hand, :MacroLabFromHistory detects the repeated keystroke pattern and lifts it into a reusable macro.

Install

Using lazy.nvim:

{
  "willothy/macro-lab.nvim",
  config = function()
    require("macro-lab").setup()
  end,
}

setup() is optional — the :MacroLab* commands work as soon as the plugin loads. Calling setup() additionally arms keystroke capture so :MacroLabFromHistory works.

Requires Neovim 0.8+ (for keytrans()).

Usage

The typical "messy macro" flow:

  1. Record a macro the normal way: qaq.
  2. :MacroLab a — open the lab and read what you actually recorded.
  3. Press p to preview it on the current buffer (no changes made).
  4. Press e to fix the broken step, :w to save it back.
  5. Press r to run it, or w to save it under a name for later.

Commands

Command Description
:MacroLab [reg] Open the lab for a register (default q).
:MacroLabEdit [reg] Edit the register's macro as notation.
:MacroLabReplay [reg] [count] Replay the macro on the current buffer.
:MacroLabPreview [reg] Dry-run preview as a diff.
:MacroLabStep [reg] Step through the macro interactively.
:MacroLabSave <name> [reg] Save the register's macro under a name.
:MacroLabLoad <name> [reg] Load a saved macro into a register.
:MacroLabList List saved macros.
:MacroLabDelete <name> Delete a saved macro.
:MacroLabRecord [reg] Toggle native recording, then open the lab.
:MacroLabFromHistory [reg] Lift a repeated edit into a macro.

Lab window keys

Key Action
e Edit the macro as notation
r Replay on the current buffer
p Preview (dry-run diff)
s Step through interactively
w Save as a named macro
l Load a saved macro
L List saved macros
<C-r> Refresh
q Quit

Configuration

Defaults shown:

require("macro-lab").setup({
  default_register = "q",   -- register opened when none is given
  record_register = "q",    -- register :MacroLabRecord uses by default
  storage_path = vim.fn.stdpath("data") .. "/macro-lab/macros.json",
  history_size = 256,       -- keystrokes kept for repeated-edit detection
  min_pattern_repeats = 2,  -- repeats required to detect a repeated edit
  window = {
    width = 0.6,            -- <=1 is a fraction of the editor, >1 is columns
    height = 0.7,
    border = "rounded",
    title_pos = "center",
  },
  keymaps = {               -- buffer-local keys inside the lab window
    edit = "e", replay = "r", preview = "p", step = "s",
    save = "w", load = "l", list = "L", quit = "q",
    help = "?", refresh = "<C-r>",
  },
})

Highlights

Every colour in the lab is an overridable highlight group linked to a standard group by default. Override any of them to taste:

Group Default link Used for
MacroLabRegister Title The @a register heading
MacroLabMeta Comment Key/byte counts
MacroLabSection Statement NOTATION / STEPS headers
MacroLabGutter NonText The gutter
MacroLabKeys Identifier Literal keys
MacroLabSpecialKey Special <...> special keys
MacroLabIndex LineNr Step numbers
MacroLabDesc Normal Step descriptions
MacroLabBadgeInsert Added INS badge
MacroLabBadgeReplace Removed REP badge
MacroLabBadgeVisual Changed VIS badge
MacroLabBadgeCmdline / MacroLabBadgeSearch Special CMD / FND badges
MacroLabDiffAdd / MacroLabDiffDelete DiffAdd / DiffDelete Preview diff
vim.api.nvim_set_hl(0, "MacroLabSection", { fg = "#7aa2f7", bold = true })

Lua API

local ml = require("macro-lab")

ml.open("a")            -- open the lab for register a
ml.steps("a")           -- get readable steps as a table
ml.notation("a")        -- get the macro as :map notation
ml.replay("a", 3)       -- run it 3 times
ml.preview("a")         -- dry-run preview
ml.save("name", "a", "description")
ml.load("name", "a")
ml.list()
ml.delete("name")
ml.from_history("a")    -- lift a repeated edit into register a

How it works

A macro is just the raw bytes of a register. macro-lab converts those bytes to readable :map notation with Vim's own keytrans(), tokenizes the notation with a hand-written scanner, and runs the tokens through a small mode-aware command grouper that recognises the shape of normal-mode commands (operators, motions, text objects, insert/replace, ex and search lines, visual selections). Editing goes the other way: notation is turned back into raw bytes with nvim_replace_termcodes(), which round-trips cleanly with keytrans().

Development

Run the test suite (no external dependencies) from the repo root:

nvim --headless -l tests/run.lua

License

MIT

About

Record, view, edit, and replay Vim macros - sanely. (WIP)

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages