{"id":13412410,"url":"https://github.com/chrisgrieser/nvim-recorder","last_synced_at":"2025-04-12T21:33:48.480Z","repository":{"id":65820108,"uuid":"576877052","full_name":"chrisgrieser/nvim-recorder","owner":"chrisgrieser","description":"Enhance the usage of macros in Neovim.","archived":false,"fork":false,"pushed_at":"2025-04-12T09:36:18.000Z","size":129,"stargazers_count":249,"open_issues_count":1,"forks_count":7,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-12T10:34:32.850Z","etag":null,"topics":["breakpoints","macros","nvim-lua","nvim-plugin"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chrisgrieser.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":"https://www.paypal.me/ChrisGrieser","ko_fi":"pseudometa"}},"created_at":"2022-12-11T09:26:45.000Z","updated_at":"2025-04-12T09:36:21.000Z","dependencies_parsed_at":"2024-04-12T04:44:41.667Z","dependency_job_id":"c0dab59b-4537-426b-a953-1354b8109caa","html_url":"https://github.com/chrisgrieser/nvim-recorder","commit_stats":{"total_commits":184,"total_committers":5,"mean_commits":36.8,"dds":0.03804347826086951,"last_synced_commit":"68a75f97967e909116c282bedc211a6bd078a4d2"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-recorder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-recorder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-recorder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chrisgrieser%2Fnvim-recorder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chrisgrieser","download_url":"https://codeload.github.com/chrisgrieser/nvim-recorder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248636075,"owners_count":21137369,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["breakpoints","macros","nvim-lua","nvim-plugin"],"created_at":"2024-07-30T20:01:24.340Z","updated_at":"2025-04-12T21:33:48.457Z","avatar_url":"https://github.com/chrisgrieser.png","language":"Lua","funding_links":["https://www.paypal.me/ChrisGrieser","https://ko-fi.com/pseudometa","https://ko-fi.com/Y8Y86SQ91'"],"categories":["Utility","Lua","Keybinding"],"sub_categories":["Cursorline","Tree-sitter Based"],"readme":"\u003c!-- LTeX: enabled=false --\u003e\n# nvim-recorder 📹\n\u003c!-- LTeX: enabled=true --\u003e\n\u003ca href=\"https://dotfyle.com/plugins/chrisgrieser/nvim-recorder\"\u003e\n\u003cimg alt=\"badge\" src=\"https://dotfyle.com/plugins/chrisgrieser/nvim-recorder/shield\"/\u003e\u003c/a\u003e\n\nEnhance the usage of macros in Neovim.\n\n\u003c!-- toc --\u003e\n\n- [Features](#features)\n- [Setup](#setup)\n\t* [Installation](#installation)\n\t* [Configuration](#configuration)\n\t* [Status Line Components](#status-line-components)\n- [Basic Usage](#basic-usage)\n- [Advanced Usage](#advanced-usage)\n\t* [Performance Optimizations](#performance-optimizations)\n\t* [Macro Breakpoints](#macro-breakpoints)\n\t* [Lazy-loading the plugin](#lazy-loading-the-plugin)\n- [About the developer](#about-the-developer)\n\n\u003c!-- tocstop --\u003e\n\n## Features\n- __Simplified controls__: One key to start and stop recording, a second key for\n  playing the macro. Instead of `qa … q @a @@`, you just do `q … q Q Q`.[^1]\n- __Macro Breakpoints__ for easier debugging of macros. Breakpoints can also be\n  set after the recording and are automatically ignored when triggering a macro\n  with a count.\n- __Status line components__: Particularly useful if you use `cmdheight=0` where\n  the recording status is not visible.\n- __Macro-to-Mapping__: Copy a macro, so you can save it as a mapping.\n- __Various quality-of-life features__: notifications with macro content, the\n  ability to cancel a recording, a command to edit macros,\n- __Performance Optimizations for large macros__: When the macro is triggered\n  with a high count, temporarily enable some performance improvements.\n- Uses up-to-date nvim features like `vim.notify`. This means you can get\n  confirmation notices with plugins like\n  [nvim-notify](https://github.com/rcarriga/nvim-notify).\n\n## Setup\n\n### Installation\n\n```lua\n-- lazy.nvim\n{\n\t\"chrisgrieser/nvim-recorder\",\n\tdependencies = \"rcarriga/nvim-notify\", -- optional\n\topts = {}, -- required even with default settings, since it calls `setup()`\n},\n\n-- packer\nuse {\n\t\"chrisgrieser/nvim-recorder\",\n\trequires = \"rcarriga/nvim-notify\", -- optional\n\tconfig = function() require(\"recorder\").setup() end,\n}\n```\n\nCalling `setup()` (or `lazy`'s `opts`) is __required__.\n\n### Configuration\n\n```lua\n-- default values\nrequire(\"recorder\").setup {\n\t-- Named registers where macros are saved (single lowercase letters only).\n\t-- The first register is the default register used as macro-slot after\n\t-- startup.\n\tslots = { \"a\", \"b\" },\n\n    -- specify one of options: \n    -- [static]   -\u003e use static slots, this is default behaviour\n    -- [rotate]   -\u003e rotates through letters specified in slots[]\n    dynamicSlots = \"static\",\n\n\tmapping = {\n\t\tstartStopRecording = \"q\",\n\t\tplayMacro = \"Q\",\n\t\tswitchSlot = \"\u003cC-q\u003e\",\n\t\teditMacro = \"cq\",\n\t\tdeleteAllMacros = \"dq\",\n\t\tyankMacro = \"yq\",\n\t\t-- ⚠️ this should be a string you don't use in insert mode during a macro\n\t\taddBreakPoint = \"##\",\n\t},\n\n\t-- Clears all macros-slots on startup.\n\tclear = false,\n\n\t-- Log level used for non-critical notifications; mostly relevant for nvim-notify.\n\t-- (Note that by default, nvim-notify does not show the levels `trace` \u0026 `debug`.)\n\tlogLevel = vim.log.levels.INFO, -- :help vim.log.levels\n\n\t-- If enabled, only essential notifications are sent.\n\t-- If you do not use a plugin like nvim-notify, set this to `true`\n\t-- to remove otherwise annoying messages.\n\tlessNotifications = false,\n\n\t-- Use nerdfont icons in the status bar components and keymap descriptions\n\tuseNerdfontIcons = true,\n\n\t-- Performance optimizations for macros with high count. When `playMacro` is\n\t-- triggered with a count higher than the threshold, nvim-recorder\n\t-- temporarily changes changes some settings for the duration of the macro.\n\tperformanceOpts = {\n\t\tcountThreshold = 100,\n\t\tlazyredraw = true, -- enable lazyredraw (see `:h lazyredraw`)\n\t\tnoSystemClipboard = true, -- remove `+`/`*` from clipboard option\n\t\tautocmdEventsIgnore = { -- temporarily ignore these autocmd events\n\t\t\t\"TextChangedI\",\n\t\t\t\"TextChanged\",\n\t\t\t\"InsertLeave\",\n\t\t\t\"InsertEnter\",\n\t\t\t\"InsertCharPre\",\n\t\t},\n\t},\n\n\t-- [experimental] partially share keymaps with nvim-dap.\n\t-- (See README for further explanations.)\n\tdapSharedKeymaps = false,\n}\n```\n\nIf you want to handle multiple macros or use `cmdheight=0`, it is recommended to\nalso set up the status line components:\n\n### Status Line Components\n\n```lua\n-- Indicates whether you are currently recording. Useful if you are using\n-- `cmdheight=0`, where recording-status is not visible.\nrequire(\"recorder\").recordingStatus()\n\n-- Displays non-empty macro-slots (registers) and indicates the selected ones.\n-- Only displayed when *not* recording. Slots with breakpoints get an extra `#`.\nrequire(\"recorder\").displaySlots()\n```\n\n\u003e [!TIP]\n\u003e Use with the config `clear = true` to see recordings you made this session.\n\nExample for adding the status line components to [lualine](https://github.com/nvim-lualine/lualine.nvim):\n\n```lua\nlualine_y = {\n\t{ require(\"recorder\").displaySlots },\n},\nlualine_z = {\n\t{ require(\"recorder\").recordingStatus },\n},\n```\n\n\u003e [!TIP]\n\u003e Put the components in different status line segments, so they have\n\u003e a different color, making the recording status more distinguishable\n\u003e from saved recordings\n\n## Basic Usage\n- `startStopRecording`: Starts recording to the current macro slot (so you do\n  not need to specify a register). Press again to end the recording.\n- `playMacro`: Plays the macro in the current slot (without the need to specify\n  a register).\n- `switchSlot`: Cycles through the registers you specified in the configuration.\n  Also show a notification with the slot and its content. (The currently\n  selected slot can be seen in the [status line\n  component](#status-line-components).)\n- `editMacro`: Edit the macro recorded in the active slot. (Be aware that these\n  are the keystrokes in \"encoded\" form.)\n- `yankMacro`: Copies the current macro in decoded form that can be used to\n  create a mapping from it. Breakpoints are removed from the copied macro.\n- `deleteAllMacros`: Copies the current macro in decoded form that can be used to\n\n\u003e [!TIP]\n\u003e For recursive macros (playing a macro inside a macro), you can still use\n\u003e the default command `@a`.\n\n## Advanced Usage\n\n### Performance Optimizations\nRunning macros with a high count can be demanding on the system and result in\nlags. For this reason, `nvim-recorder` provides some performance optimizations\nthat are temporarily enabled when a macro with a high count is run.\n\nNote that these optimizations do have some potential drawbacks.\n- [`lazyredraw`](https://neovim.io/doc/user/options.html#'lazyredraw') disables\n  redrawing of the screen, which makes it harder to notice edge cases not\n  considered in the macro. It may also appear as if the screen is frozen for a\n  while.\n- Disabling the system clipboard is mostly safe, if you do not intend to copy\n  content to it with the macro.\n- Ignoring auto-commands is not recommended, when you rely on certain plugin\n  functionality during the macro, since it can potentially disrupt those\n  plugins' effect.\n\n### Macro Breakpoints\n`nvim-recorder` allows you to set breakpoints in your macros which can be\nhelpful for debugging macros. Breakpoints are automatically ignored when you\ntrigger the macro with a count.\n\n__Setting Breakpoints__  \n- *During a recording:* press the `addBreakPoint` key (default: `##`) in normal\n   mode\n- *After a recording:* use `editMacro` and add or remove the `##` manually.\n\n__Playing Macros with Breakpoints__  \n- Using the `playMacro` key, the macro automatically stops at the next\n  breakpoint. The next time you press `playMacro`, the next segment of the macro\n  is played.\n- Starting a new recording, editing a macro, yanking a macro, or switching macro\n  slot all reset the sequence, meaning that `playMacro` starts from the\n  beginning again.\n\n\u003e [!TIP]\n\u003e You can do other things in between playing segments of the macro, like\n\u003e moving a few characters to the left or right. That way you can also use\n\u003e breakpoints to manually correct irregularities.\n\n__Ignoring Breakpoints__  \nWhen you play the macro with a *count* (for example `50Q`), breakpoints are\nautomatically ignored.\n\n\u003e [!TIP]\n\u003e Add a count of 1 (`1Q`) to play a macro once and still ignore breakpoints.\n\n__Shared Keybindings with `nvim-dap`__  \nIf you are using [nvim-dap](https://github.com/mfussenegger/nvim-dap), you can\nuse `dapSharedKeymaps = true` to set up the following shared keybindings:\n1. `addBreakPoint` maps to `dap.toggle_breakpoint()` outside\na recording. During a recording, it adds a macro breakpoint instead.\n2. `playMacro` maps to `dap.continue()` if there is at least one\nDAP-breakpoint. If there is no DAP-breakpoint, plays the current\nmacro-slot instead.\n\nNote that this feature is experimental, since the [respective API from nvim-dap\nis non-public and can be changed without deprecation\nnotice](https://github.com/mfussenegger/nvim-dap/discussions/810#discussioncomment-4623606).\n\n### Lazy-loading the plugin\n`nvim-recorder` is best lazy-loaded on the mappings for `startStopRecording` and\n`playMacro`. However, adding the status line components to `lualine` will cause the\nplugin to load before you start or play a recording.\n\nTo avoid this, the statusline components need to be loaded only in the plugin's\n`config`. The drawback of this method is that no component is shown when until\nyou start or play a recording (which you can completely disregard when you set\n`clear = true`, though).\n\nNonetheless, the plugin is pretty lightweight (~400 lines of code), so not\nlazy-loading it should not have a big impact.\n\n```lua\n-- minimal config for lazy-loading with lazy.nvim\n{\n\t\"chrisgrieser/nvim-recorder\",\n\tdependencies = \"rcarriga/nvim-notify\",\n\tkeys = {\n\t\t-- these must match the keys in the mapping config below\n\t\t{ \"q\", desc = \" Start Recording\" },\n\t\t{ \"Q\", desc = \" Play Recording\" },\n\t},\n\tconfig = function()\n\t\trequire(\"recorder\").setup({\n\t\t\tmapping = {\n\t\t\t\tstartStopRecording = \"q\",\n\t\t\t\tplayMacro = \"Q\",\n\t\t\t},\n\t\t})\n\n\t\t\tlocal lualineZ = require(\"lualine\").get_config().sections.lualine_z or {}\n\t\t\tlocal lualineY = require(\"lualine\").get_config().sections.lualine_y or {}\n\t\t\ttable.insert(lualineZ, { require(\"recorder\").recordingStatus })\n\t\t\ttable.insert(lualineY, { require(\"recorder\").displaySlots })\n\n\t\t\trequire(\"lualine\").setup {\n\t\t\t\ttabline = {\n\t\t\t\t\tlualine_y = lualineY,\n\t\t\t\t\tlualine_z = lualineZ,\n\t\t\t\t},\n\t\t\t}\n\tend,\n},\n```\n\n## About the developer\nIn my day job, I am a sociologist studying the social mechanisms underlying the\ndigital economy. For my PhD project, I investigate the governance of the app\neconomy and how software ecosystems manage the tension between innovation and\ncompatibility. If you are interested in this subject, feel free to get in touch.\n\nI also occasionally blog about vim: [Nano Tips for Vim](https://nanotipsforvim.prose.sh)\n\n- [Website](https://chris-grieser.de/)\n- [Mastodon](https://pkm.social/@pseudometa)\n- [ResearchGate](https://www.researchgate.net/profile/Christopher-Grieser)\n- [LinkedIn](https://www.linkedin.com/in/christopher-grieser-ba693b17a/)\n\n\u003ca href='https://ko-fi.com/Y8Y86SQ91' target='_blank'\u003e \u003cimg height='36'\nstyle='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3'\nborder='0' alt='Buy Me a Coffee at ko-fi.com' /\u003e\u003c/a\u003e\n\n[^1]: As opposed to vim, Neovim already allows you to use `Q` to [play the last\n\trecorded macro](https://neovim.io/doc/user/repeat.html#Q). Considering this,\n\tthe simplified controls really only save you one keystroke for one-off\n\tmacros. However, as opposed to Neovim's built-in controls, you can still\n\tkeep using `Q` for playing the not-most-recently recorded macro.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisgrieser%2Fnvim-recorder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchrisgrieser%2Fnvim-recorder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchrisgrieser%2Fnvim-recorder/lists"}