SkillAgentSearch skills...

Qmk.nvim

Format qmk and zmk keymaps in neovim

Install / Use

/learn @codethread/Qmk.nvim
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

qmk.nvim

qmk.nvim is a 100% lua plugin for Neovim that formats QMK and ZMK keymaps, used in a large number of mechanical and hobbyist keyboards.

qmk

Features

  • automatically align your keymaps
  • create a comment string of your keymap
  • use inline JSON comments to make quick easy changes
  • supports QMK and ZMK* (though I highly recommend keymap-editor)
    • note any preprocessor macros must start with _ if they are to be identified as the start of a key, e.g
    #define _AS(keycode) &as LS(keycode) keycode
    // ...etc
    default_layer {
        &kp TAB        _AS(Q) SOME_OTHER
    }
    
    • ZMK is still experimental, please report any bugs

For a simple example of the following keymap

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  [_QWERTY] = LAYOUT_preonic_grid(
  KC_1 ,      K2,
      K3 , K4,     // notice the white space
    KC_5  , HERE_BE_A_LONG_KEY // and how this doesn't line up at all
  )
};

Setup your layout:

local qmk = require 'qmk'
qmk.setup {
    name = 'LAYOUT_preonic_grid', -- identify your layout name
    comment_preview = {
        keymap_overrides = {
            HERE_BE_A_LONG_KEY = 'Magic', -- replace any long key codes
        },
    },
    layout = { -- create a visual representation of your final layout
        'x ^xx', -- including keys that span multiple rows (with alignment left, center or right)
        '_ x x', -- pad empty cells
        '_ x x',
    },
}

Save the file and it will automatically be nicely aligned, with a pretty comment string

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
//    ┌───┬────────────┐
//    │ 1 │     K2     │
//    └───┼────┬───────┤
//        │ K3 │  K4   │
//        ├────┼───────┤
//        │ 5  │ Magic │
//        └────┴───────┘
[_QWERTY] = LAYOUT_preonic_grid(
  KC_1 , K2                       ,
         K3   , K4                ,
         KC_5 , HERE_BE_A_LONG_KEY
)
};

Requirements

  • Neovim >= 0.10
  • QMK: Treesitter c parser available (e.g through nvim-treesitter)
  • ZMK: Treesitter devicetree parser available (e.g through nvim-treesitter)
    • this can be used for .keymap files with set ft=dts

Installation

  • install with your favourite package manager, e.g packer
  • call setup with your layout name and your layout configuration

e.g:

use {
    'codethread/qmk.nvim',
    config = function()
        ---@type qmk.UserConfig
        local conf = {
            name = 'LAYOUT_preonic_grid',
            layout = {
                '_ x x x x x x _ x x x x x x',
                '_ x x x x x x _ x x x x x x',
                '_ x x x x x x _ x x x x x x',
                '_ x x x x x x _ x x x x x x',
                '_ x x x x x x _ x x x x x x',
            }
        }
        require('qmk').setup(conf)
    end
}

Configuration

qmk.nvim takes the following configuration (---@type qmk.UserConfig):

| setting | type | json | descritpion | |------------------------------------|---------------------------------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | name | string required | ✓ | the name of your layout, for example LAYOUT_preonic_grid for the preonic keyboard, for zmk this can just be anything, it won't be used | | layout | string[] required | ✓ | the keyboard key layout, see Layout for more details | | variant | qmk,zmk | | (default qmk) chooses the expected hardware target | | timeout | number | | (default 5000) duration of vim.notify timeout if using nvim-notify | | auto_format_pattern | string,string[] | | (default { '*keymap.c', '*.keymap' }) the autocommand file pattern to use when applying QMKFormat on save | | comment_preview | table | ✓ | table of properties for rendering a pretty comment string of each keymap | | comment_preview.position | top,bottom,inside, none | ✓ | (default top) control the position of the preview, set to none to disable (inside is only valid for variant=qmk) | | comment_preview.keymap_overrides | table<string, string> | ✓ | a dictionary of key codes to text replacements, any provided value will be merged with the existing dictionary, see key_map.lua for details | | comment_preview.symbols | table<string, string> | ✓ | a dictionary of symbols used for the preview comment border chars see default.lua for details |

examples

Here are some example configurations:

<details> <summary>Disabling most features</summary>
{
    name = 'Some_layout',
    layout = { { 'x', 'x' } },
    auto_format_pattern = nil,
    comment_preview = {
        position = 'none'
    }
}
</details> <details> <summary>Using Multiple Configurations</summary>

setup can be called multiple times without issue to apply different configuration options. This means you can use autocommands to apply different configurations for different boards, e.g:

local group = vim.api.nvim_create_augroup('MyQMK', {})

vim.api.nvim_create_autocmd('BufEnter', {
	desc = 'Format simple keymap',
	group = group,
	pattern = '*simple/keymap.c', -- this is a pattern to match the filepath of whatever board you wish to target
	callback = function()
		require('qmk').setup({
			name = 'LAYOUT_preonic_grid',
			auto_format_pattern = "*simple/keymap.c",
			layout = {
				'_ x x x x x x _ x x x x x x',
			},
         })
	end,
})

vim.api.nvim_create_autocmd('BufEnter', {
	desc = 'Format overlap keymap',
	group = group,
	pattern = '*overlap/keymap.c',
	callback = function()
		require('qmk').setup({
			name = 'LAYOUT_preonic_grid',
			auto_format_pattern = "*overlap/keymap.c",
			layout = {
				'x x x x x',
			},
		})
	end,
})
</details> <details> <summary>using ZMK</summary>
{
    name = 'meh',
    layout = { { 'x', 'x' } },
    variant = 'zmk'
}
</details> <details> <summary>Overriding a long key code</summary>

For the configuration

{
	name = 'Some_layout',
	layout = { 'x x' },
	comment_preview = {
		position = 'inside',
		keymap_overrides = {
            -- key codes are mapped literally against the entire key in your layout
            -- longer key codes are checked first, and these will replace the value displayed in the preview
            --
            -- lua magic patterns used to need escaping with `%` but not anymore
            -- old escaped patterns should still work thoug
            -- watch out for emojis as they are double width
			['LSG%(KC_GRAVE%)'] = 'Next Window',
			['LAG(KC_GRAVE)'] = 'Prev Window',
		},
	},
}

With keymap.c:

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_QWERTY] = Some_layout(
  KC_1
  ,
  LSG(KC_GRAVE)
)
}

Becomes:

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_QWERTY] = Some_layout(
//    ┌───┬─────────────┐
//    │ 1 │ Next Window │
//    └───┴─────────────┘
  KC_1 , LSG(KC_GRAVE)
)
}

Also if your key codes are quite long, you can define aliases in c

//Aliases for longer keycodes
#define NUMPAD  TG(_NUMPAD)
</details> <details> <summary>A pretty kinisis layout</summary>

for the configuration

{
    name = 'LAYOUT_pretty',
    layout = {
     
View on GitHub
GitHub Stars247
CategoryDevelopment
Updated6d ago
Forks12

Languages

Lua

Security Score

95/100

Audited on Mar 31, 2026

No findings