[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\ncharset = utf-8\n"
  },
  {
    "path": ".github/.release-please-manifest.json",
    "content": "{\n  \".\": \"3.17.0\"\n}\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug Report\ndescription: File a bug/issue\ntitle: \"bug: \"\nlabels: [bug]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        **Before** reporting an issue, make sure to read the [documentation](https://github.com/folke/which-key.nvim)\n        and search [existing issues](https://github.com/folke/which-key.nvim/issues).\n\n        Usage questions such as ***\"How do I...?\"*** belong in [Discussions](https://github.com/folke/which-key.nvim/discussions) and will be closed.\n  - type: checkboxes\n    attributes:\n      label: Did you check docs and existing issues?\n      description: Make sure you checked all of the below before submitting an issue\n      options:\n        - label: I have read all the which-key.nvim docs\n          required: true\n        - label: I have updated the plugin to the latest version before submitting this issue\n          required: true\n        - label: I have searched the existing issues of which-key.nvim\n          required: true\n        - label: I have searched the existing issues of plugins related to this issue\n          required: true\n  - type: input\n    attributes:\n      label: \"Neovim version (nvim -v)\"\n      placeholder: \"0.8.0 commit db1b0ee3b30f\"\n    validations:\n      required: true\n  - type: input\n    attributes:\n      label: \"Operating system/version\"\n      placeholder: \"MacOS 11.5\"\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Describe the bug\n      description: A clear and concise description of what the bug is. Please include any related errors you see in Neovim.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Steps To Reproduce\n      description: Steps to reproduce the behavior.\n      placeholder: |\n        1.\n        2. \n        3.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Expected Behavior\n      description: A concise description of what you expected to happen.\n    validations:\n      required: true\n  - type: textarea\n    attributes:\n      label: Health\n      description: Attach the output of `:checkhealth which-key` here\n      render: log\n  - type: textarea\n    attributes:\n      label: Log\n      description: Please enable logging with `opts.debug = true` and attach the contents of `./wk.log` here\n      render: log\n  - type: textarea\n    attributes:\n      label: Repro\n      description: Minimal `init.lua` to reproduce this issue. Save as `repro.lua` and run with `nvim -u repro.lua`\n      value: |\n        vim.env.LAZY_STDPATH = \".repro\"\n        load(vim.fn.system(\"curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua\"))()\n\n        require(\"lazy.minit\").repro({\n          spec = {\n            { \"folke/which-key.nvim\", opts = {} },\n            -- add any other plugins here\n          },\n        })\n      render: lua\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Ask a question\n    url: https://github.com/folke/which-key.nvim/discussions\n    about: Use Github discussions instead\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature Request\ndescription: Suggest a new feature\ntitle: \"feature: \"\nlabels: [enhancement]\nbody:\n  - type: checkboxes\n    attributes:\n      label: Did you check the docs?\n      description: Make sure you read all the docs before submitting a feature request\n      options:\n        - label: I have read all the which-key.nvim docs\n          required: true\n  - type: textarea\n    validations:\n      required: true\n    attributes:\n      label: Is your feature request related to a problem? Please describe.\n      description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n  - type: textarea\n    validations:\n      required: true\n    attributes:\n      label: Describe the solution you'd like\n      description: A clear and concise description of what you want to happen.\n  - type: textarea\n    validations:\n      required: true\n    attributes:\n      label: Describe alternatives you've considered\n      description: A clear and concise description of any alternative solutions or features you've considered.\n  - type: textarea\n    validations:\n      required: false\n    attributes:\n      label: Additional context\n      description: Add any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## Description\n\n<!-- Describe the big picture of your changes to communicate to the maintainers\n  why we should accept this pull request. -->\n\n## Related Issue(s)\n\n<!--\n  If this PR fixes any issues, please link to the issue here.\n  - Fixes #<issue_number>\n-->\n\n## Screenshots\n\n<!-- Add screenshots of the changes if applicable. -->\n\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n"
  },
  {
    "path": ".github/release-please-config.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json\",\n  \"packages\": {\n    \".\": {\n      \"release-type\": \"simple\",\n      \"extra-files\": [\"lua/which-key/config.lua\"]\n    }\n  }\n}\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [main, master]\n  pull_request:\n\njobs:\n  ci:\n    uses: folke/github/.github/workflows/ci.yml@main\n    secrets: inherit\n    with:\n      plugin: which-key.nvim\n      repo: folke/which-key.nvim\n"
  },
  {
    "path": ".github/workflows/labeler.yml",
    "content": "name: \"PR Labeler\"\non:\n  - pull_request_target\n\njobs:\n  labeler:\n    uses: folke/github/.github/workflows/labeler.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/pr.yml",
    "content": "name: PR Title\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - synchronize\n      - reopened\n      - ready_for_review\n\npermissions:\n  pull-requests: read\n\njobs:\n  pr-title:\n    uses: folke/github/.github/workflows/pr.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/stale.yml",
    "content": "name: Stale Issues & PRs\n\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n\njobs:\n  stale:\n    if: contains(fromJSON('[\"folke\", \"LazyVim\"]'), github.repository_owner)\n    uses: folke/github/.github/workflows/stale.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/update.yml",
    "content": "name: Update Repo\n\non:\n  workflow_dispatch:\n  schedule:\n    # Run every hour\n    - cron: \"0 * * * *\"\n\njobs:\n  update:\n    if: contains(fromJSON('[\"folke\", \"LazyVim\"]'), github.repository_owner)\n    uses: folke/github/.github/workflows/update.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".gitignore",
    "content": "*.log\n/.repro\n/.tests\n/build\n/debug\n/doc/tags\nfoo.*\nnode_modules\ntt.*\n"
  },
  {
    "path": ".lua-format",
    "content": "# https://github.com/Koihik/LuaFormatter/blob/master/docs/Style-Config.md\ncolumn_limit: 100\nindent_width: 2\ncontinuation_indent_width: 2\nuse_tab: false\nchop_down_parameter: true\nchop_down_table: true\nchop_down_kv_table: true\nsingle_quote_to_double_quote: true\nspaces_inside_table_braces: true\nalign_parameter: true\nkeep_simple_control_block_one_line: true\nextra_sep_at_table_end: true\n"
  },
  {
    "path": ".markdownlint-cli2.yaml",
    "content": "config:\n  MD013: false\n  MD033: false\n"
  },
  {
    "path": ".neoconf.json",
    "content": "{\n  \"lspconfig\": {\n    \"sumneko_lua\": {\n      \"Lua.format.defaultConfig\": {\n        \"indent_style\": \"space\",\n        \"indent_size\": \"2\",\n        \"continuation_indent_size\": \"2\"\n      },\n      \"Lua.diagnostics.neededFileStatus\": {\n        // \"codestyle-check\": \"Any\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [3.17.0](https://github.com/folke/which-key.nvim/compare/v3.16.0...v3.17.0) (2025-02-14)\n\n\n### Features\n\n* **mappings:** allow flagging a mapping as `real`. It will be hidden if there's no real keymap. ([bcfe1e4](https://github.com/folke/which-key.nvim/commit/bcfe1e4596dc0c6cc25a5b14b32f60a81d18c08d))\n* **preset:** some extra win keymaps ([ff61f4f](https://github.com/folke/which-key.nvim/commit/ff61f4fe0d21de199c44a9d893395b5005e96270))\n\n## [3.16.0](https://github.com/folke/which-key.nvim/compare/v3.15.0...v3.16.0) (2025-01-05)\n\n\n### Features\n\n* **icons:** add refactoring ([#923](https://github.com/folke/which-key.nvim/issues/923)) ([7b7e3d0](https://github.com/folke/which-key.nvim/commit/7b7e3d0788957592e12970bbb9e0e14c4cd143d4))\n\n\n### Bug Fixes\n\n* **mappings:** add missing keybinds for g; & g, ([#924](https://github.com/folke/which-key.nvim/issues/924)) ([57f4438](https://github.com/folke/which-key.nvim/commit/57f4438158e93be6856317e999758ed77f286dd9))\n\n## [3.15.0](https://github.com/folke/which-key.nvim/compare/v3.14.1...v3.15.0) (2024-12-15)\n\n\n### Features\n\n* **icons:** icons for snacks and profiler ([d533d8a](https://github.com/folke/which-key.nvim/commit/d533d8a2e0da3444986500ecc2fb0528062d6003))\n\n\n### Bug Fixes\n\n* **config:** load early when executing WhichKey command. Fixes [#912](https://github.com/folke/which-key.nvim/issues/912) ([c890020](https://github.com/folke/which-key.nvim/commit/c8900201501ab6f0dcfabd55c70f6ba03ada3bd8))\n\n## [3.14.1](https://github.com/folke/which-key.nvim/compare/v3.14.0...v3.14.1) (2024-11-28)\n\n\n### Bug Fixes\n\n* **state:** do proper redraw that works on nightly and on stable ([3a9b162](https://github.com/folke/which-key.nvim/commit/3a9b162026a4ad4b9ee7b09009b8bbe69ba19520))\n\n## [3.14.0](https://github.com/folke/which-key.nvim/compare/v3.13.3...v3.14.0) (2024-11-28)\n\n\n### Features\n\n* **icons:** add grapple icon ([#838](https://github.com/folke/which-key.nvim/issues/838)) ([c21b71f](https://github.com/folke/which-key.nvim/commit/c21b71ff0bc4e516705811ec6916131e880cb882))\n\n\n### Bug Fixes\n\n* **state:** use redraw flush to prevent issues with selecting visual line etc. Fixes [#898](https://github.com/folke/which-key.nvim/issues/898) ([3974c2d](https://github.com/folke/which-key.nvim/commit/3974c2d21b117236ec4f5be4e61a9e4f02aa4c46))\n* **triggers:** when in macro defer re-checking suspended for 100ms. Fixes [#864](https://github.com/folke/which-key.nvim/issues/864) ([f46556b](https://github.com/folke/which-key.nvim/commit/f46556b2b1bb7dbbd3b1086eaa24ca5db52b1986))\n\n\n### Performance Improvements\n\n* **state:** only redraw when waiting for a key longer than 200ms ([1c5aeba](https://github.com/folke/which-key.nvim/commit/1c5aeba42861a2cd446156ec8cbb7e7a5b5a9dfd))\n* **tree:** small perf optims ([5610eb6](https://github.com/folke/which-key.nvim/commit/5610eb6bd7193e78d31eb399effacd2dfc25dedf))\n\n## [3.13.3](https://github.com/folke/which-key.nvim/compare/v3.13.2...v3.13.3) (2024-09-18)\n\n\n### Bug Fixes\n\n* **config:** disable wk by default  for terminal mode ([#825](https://github.com/folke/which-key.nvim/issues/825)) ([e7b415c](https://github.com/folke/which-key.nvim/commit/e7b415cc1d9ac9aee180ee5c8e46ca1484ebda78))\n* **triggers:** never attach when macro is recording / executing. Fixes [#851](https://github.com/folke/which-key.nvim/issues/851). Fixes [#822](https://github.com/folke/which-key.nvim/issues/822). Fixes [#807](https://github.com/folke/which-key.nvim/issues/807) ([6b023b4](https://github.com/folke/which-key.nvim/commit/6b023b4c29ecc0aad06a51dd14bd2754b43bb0c8))\n* **view:** display actual scroll up/down keys in help ([#821](https://github.com/folke/which-key.nvim/issues/821)) ([dafe27a](https://github.com/folke/which-key.nvim/commit/dafe27a06919bc5077db2ee97feec54d0932450e))\n\n## [3.13.2](https://github.com/folke/which-key.nvim/compare/v3.13.1...v3.13.2) (2024-07-24)\n\n\n### Bug Fixes\n\n* **view:** fix epanded keys. Fixes [#795](https://github.com/folke/which-key.nvim/issues/795) ([f5e0cd5](https://github.com/folke/which-key.nvim/commit/f5e0cd5c7712ac63d8e6184785fb7bdac3b7b50d))\n\n## [3.13.1](https://github.com/folke/which-key.nvim/compare/v3.13.0...v3.13.1) (2024-07-24)\n\n\n### Bug Fixes\n\n* **state:** better current buf/mode check ([711453b](https://github.com/folke/which-key.nvim/commit/711453bb945433362636e918a5238172ffd21e43))\n* **state:** deal with the fact that ModeChanged doesn't always seems to trigger. Fixes [#787](https://github.com/folke/which-key.nvim/issues/787) ([388bd3f](https://github.com/folke/which-key.nvim/commit/388bd3f83de06d1a1758ea6a342cf3ae614401f1))\n\n## [3.13.0](https://github.com/folke/which-key.nvim/compare/v3.12.1...v3.13.0) (2024-07-24)\n\n\n### Features\n\n* **debug:** add git info to log when using lazy ([550338d](https://github.com/folke/which-key.nvim/commit/550338dc292c014d83687afccb0afb06e3e769f2))\n\n## [3.12.1](https://github.com/folke/which-key.nvim/compare/v3.12.0...v3.12.1) (2024-07-24)\n\n\n### Bug Fixes\n\n* **node:** dynamic mappings only support functions as rhs. Fixes [#790](https://github.com/folke/which-key.nvim/issues/790) ([ba91db7](https://github.com/folke/which-key.nvim/commit/ba91db72ffc745983f06ca4e7d969101287a9afe))\n* **state:** use cached mode. Fixes [#787](https://github.com/folke/which-key.nvim/issues/787). Closes [#789](https://github.com/folke/which-key.nvim/issues/789) ([c1b062a](https://github.com/folke/which-key.nvim/commit/c1b062ae95c3ca3e6eb87c075da991523605d79b))\n* **triggers:** check for existing keymaps in the correct buffer. Fixes [#783](https://github.com/folke/which-key.nvim/issues/783) ([977fa23](https://github.com/folke/which-key.nvim/commit/977fa23622425e3c8ae837b9f7c710d9c78bdeab))\n* **triggers:** nil error ([dae3bd2](https://github.com/folke/which-key.nvim/commit/dae3bd271826887771a7fb6deec231d2eb344f02))\n\n## [3.12.0](https://github.com/folke/which-key.nvim/compare/v3.11.1...v3.12.0) (2024-07-22)\n\n\n### Features\n\n* **api:** allow overriding delay. Closes [#778](https://github.com/folke/which-key.nvim/issues/778) ([e6fea48](https://github.com/folke/which-key.nvim/commit/e6fea4889c20f22a7c6267cf1f1d091bc96f8ca0))\n\n\n### Bug Fixes\n\n* dont expand nodes without children. Fixes [#782](https://github.com/folke/which-key.nvim/issues/782) ([53a1d2a](https://github.com/folke/which-key.nvim/commit/53a1d2a674df5fb667497fe3bbda625c39a2c0e1))\n\n## [3.11.1](https://github.com/folke/which-key.nvim/compare/v3.11.0...v3.11.1) (2024-07-21)\n\n\n### Bug Fixes\n\n* **config:** keys can be any case. Fixes [#771](https://github.com/folke/which-key.nvim/issues/771) ([0a44d55](https://github.com/folke/which-key.nvim/commit/0a44d55d3bcdf75a134ec57c90aaec1055731014))\n* **config:** normalize keys ([c96be9b](https://github.com/folke/which-key.nvim/commit/c96be9bd54ffbc2ec7fc818001cad712119d778c))\n\n## [3.11.0](https://github.com/folke/which-key.nvim/compare/v3.10.0...v3.11.0) (2024-07-20)\n\n\n### Features\n\n* **icons:** icon for grug-far ([b2a2a0c](https://github.com/folke/which-key.nvim/commit/b2a2a0c9486211da23acdf18087f8203bfbca0e4))\n* **state:** detect recursion by users mapping wk manually. Closes [#761](https://github.com/folke/which-key.nvim/issues/761) ([55fa07f](https://github.com/folke/which-key.nvim/commit/55fa07fbbd8a4c6d75399b1d1f9005d146cda22c))\n* **view:** expand recursively. Closes [#767](https://github.com/folke/which-key.nvim/issues/767) ([5ae87af](https://github.com/folke/which-key.nvim/commit/5ae87af42914afe8b478ad6cdb3cb179fb73a62b))\n\n\n### Bug Fixes\n\n* **config:** disable wk by default for insert/command mode ([9d2b2e7](https://github.com/folke/which-key.nvim/commit/9d2b2e7059547c0481db2e93fd98547b26c7c05a))\n* **config:** more checks in validate ([bdcc429](https://github.com/folke/which-key.nvim/commit/bdcc429afaecc5896b462b0b07c2b3a9e9c1c60f))\n* **mappings:** preset descriptions should not override existing keymap descriptions. Fixes [#769](https://github.com/folke/which-key.nvim/issues/769) ([82d628f](https://github.com/folke/which-key.nvim/commit/82d628f4cfa397cf4bb233bd500e9cd9a018ded1))\n* **state:** don't feed count in insert mode. Fixes [#770](https://github.com/folke/which-key.nvim/issues/770) ([63690ff](https://github.com/folke/which-key.nvim/commit/63690ff34a8921c2de44fad289e2e04ee324b031))\n* **util:** better `&lt;nop&gt;` check. Fixes [#766](https://github.com/folke/which-key.nvim/issues/766) ([b7b3bd1](https://github.com/folke/which-key.nvim/commit/b7b3bd1b609524472f67e4a69d2bc14b80ea997f))\n* **view:** dont set title when no border. Fixes [#764](https://github.com/folke/which-key.nvim/issues/764) ([6e61b09](https://github.com/folke/which-key.nvim/commit/6e61b0904e9c038b6c511c43591ae2d811b4975e))\n\n\n### Performance Improvements\n\n* prevent expanding nodes when not needed ([78cc92c](https://github.com/folke/which-key.nvim/commit/78cc92c6cb7da88df60227bc334a598a7e772e51))\n\n## [3.10.0](https://github.com/folke/which-key.nvim/compare/v3.9.0...v3.10.0) (2024-07-18)\n\n\n### Features\n\n* **view:** expand all nodes by default when filter.global = false ([c168905](https://github.com/folke/which-key.nvim/commit/c168905d62d9b8859b261de69910dfb7e3438996))\n\n\n### Bug Fixes\n\n* **buf:** always use nowait. Fixes [#755](https://github.com/folke/which-key.nvim/issues/755) ([ae1a235](https://github.com/folke/which-key.nvim/commit/ae1a235c53233c58a2f7cc14e5cdd09346cf27ed))\n* **buf:** early exit to determine if a trigger is safe to create. Fixes [#754](https://github.com/folke/which-key.nvim/issues/754) ([27e4716](https://github.com/folke/which-key.nvim/commit/27e47163165fee8e45b43d340db9335001403d2f))\n* **icons:** added frontier pattern for `ai` ([#760](https://github.com/folke/which-key.nvim/issues/760)) ([6fe0657](https://github.com/folke/which-key.nvim/commit/6fe065716e08550328c471689e6f8c1e42a0effc))\n* list_contains doesn't exists in Neovim &lt; 0.10. Fixes [#758](https://github.com/folke/which-key.nvim/issues/758) ([7e4eae8](https://github.com/folke/which-key.nvim/commit/7e4eae8836e4ad28d478fedc421700b1138d1e0c))\n* **node:** allow custom mappings to override proxy/plugin/expand mappings ([9820900](https://github.com/folke/which-key.nvim/commit/982090080fa11da06038cf8e71af90d3a4fbd05a))\n* **node:** is_local check now also includes children ([fdd27f9](https://github.com/folke/which-key.nvim/commit/fdd27f9b6a991586943eb865275b279fb411ff0b))\n* **registers:** don't try to get `+*` registers when no clipboard is available. Fixes [#754](https://github.com/folke/which-key.nvim/issues/754) ([ae4ec03](https://github.com/folke/which-key.nvim/commit/ae4ec030489d7ecda908e473aea096a7594f84e8))\n* **state:** always honor defer. Fixes [#690](https://github.com/folke/which-key.nvim/issues/690) ([c512d13](https://github.com/folke/which-key.nvim/commit/c512d135531be81e17c85e254994cc755d3016c5))\n* **state:** redraw cursor before getchar ([cf6cbf2](https://github.com/folke/which-key.nvim/commit/cf6cbf2fd8f0c6497f130d07f6c88a2833c15d80))\n* **triggers:** prevent creating triggers for single upper-case alpha keys expect for Z. Fixes [#756](https://github.com/folke/which-key.nvim/issues/756) ([d19fa07](https://github.com/folke/which-key.nvim/commit/d19fa07b6e818ab55c34815784470a6d5f023524))\n\n## [3.9.0](https://github.com/folke/which-key.nvim/compare/v3.8.0...v3.9.0) (2024-07-18)\n\n\n### Features\n\n* **config:** simplified config. Some options are now deprecated ([8ddf2da](https://github.com/folke/which-key.nvim/commit/8ddf2da5a6aa76f5b3cec976f1d61e7c7fea42b5))\n* **view:** show and expand localleader mappings with filter.global = false ([ed5f762](https://github.com/folke/which-key.nvim/commit/ed5f7622771d0b5c0ac3a5e286ec6cd17b6be131))\n\n\n### Bug Fixes\n\n* **ui:** remove deprecated opts.layout.align option. (wasn't used). Closes [#752](https://github.com/folke/which-key.nvim/issues/752) ([db32ac6](https://github.com/folke/which-key.nvim/commit/db32ac67abb36789a43fe497ff7d0b8ab7e8109e))\n\n## [3.8.0](https://github.com/folke/which-key.nvim/compare/v3.7.0...v3.8.0) (2024-07-17)\n\n\n### Features\n\n* **mappings:** added health check for invalid modes ([640724a](https://github.com/folke/which-key.nvim/commit/640724a541af75e6bbfe98f78cdebbec701d23a8))\n\n\n### Bug Fixes\n\n* **buf:** never create proxy/plugin mappings when a keymap exists. Fixes [#738](https://github.com/folke/which-key.nvim/issues/738) ([b4c4e36](https://github.com/folke/which-key.nvim/commit/b4c4e3648261399a97bfdc44bb8fa31b485fd3b9))\n* **registers:** use x instead of v ([#742](https://github.com/folke/which-key.nvim/issues/742)) ([5c3b3e8](https://github.com/folke/which-key.nvim/commit/5c3b3e834852a44efb26725f9c08917145f2c0c6))\n* **state:** schedule redraw. Fixes [#740](https://github.com/folke/which-key.nvim/issues/740) ([09f21a1](https://github.com/folke/which-key.nvim/commit/09f21a133104b66a5cede8fc0a8082b85b0eee9b))\n* **triggers:** allow overriding keymaps with empty rhs or &lt;Nop&gt;. Fixes [#748](https://github.com/folke/which-key.nvim/issues/748) ([843a93f](https://github.com/folke/which-key.nvim/commit/843a93fac6bca58167aafa392e6f7fd5a77633c9))\n* **triggers:** make sure no keymaps exists for triggers ([e8b454f](https://github.com/folke/which-key.nvim/commit/e8b454fb03e3cab398c894e5d462c84595ee57ca))\n* **typo:** replace 'exras' for 'extras' in README. ([#745](https://github.com/folke/which-key.nvim/issues/745)) ([af48cdc](https://github.com/folke/which-key.nvim/commit/af48cdc4bb8f1982a6124bf6bb5570349f690822))\n\n## [3.7.0](https://github.com/folke/which-key.nvim/compare/v3.6.0...v3.7.0) (2024-07-17)\n\n\n### Features\n\n* added `expand` property to create dynamic mappings. An example for `buf` and `win` is included ([02f6e6f](https://github.com/folke/which-key.nvim/commit/02f6e6f4951ff993ad1d5c699784e6847a6c7b4c))\n* proxy mappings ([c3cfc2b](https://github.com/folke/which-key.nvim/commit/c3cfc2bdb03c1b87943a6d02485ad50b86567341))\n* **state:** allow defering on certain operators. Closes [#733](https://github.com/folke/which-key.nvim/issues/733) ([984d930](https://github.com/folke/which-key.nvim/commit/984d930711341ac118e6712804e8e22e575ba9d3))\n\n\n### Bug Fixes\n\n* **buf:** create triggers for xo anyway. Fixes [#728](https://github.com/folke/which-key.nvim/issues/728) ([96b2e93](https://github.com/folke/which-key.nvim/commit/96b2e93979373744056c921f82b0c356e6f900de))\n* **icons:** added frontier pattern for `git`. Fixes [#727](https://github.com/folke/which-key.nvim/issues/727) ([bb4e82b](https://github.com/folke/which-key.nvim/commit/bb4e82bdaff50a4a93867e4c90938d18e7615af6))\n* **state:** dont popup when switching between v and V mode. Fixes [#729](https://github.com/folke/which-key.nvim/issues/729) ([8ddb527](https://github.com/folke/which-key.nvim/commit/8ddb527bcffc6957a59518f11c34a84d91e075f9))\n* **view:** always show a group as a group ([96a9eb3](https://github.com/folke/which-key.nvim/commit/96a9eb3f0b3299dffc241cf0f9ee5cf0509e6cd2))\n* **view:** empty icons ([e2cacc6](https://github.com/folke/which-key.nvim/commit/e2cacc6f1e4ba77e82e7a34e0dc6b2ad69cf075b))\n\n## [3.6.0](https://github.com/folke/which-key.nvim/compare/v3.5.0...v3.6.0) (2024-07-16)\n\n\n### Features\n\n* added icons for &lt;D mappings ([aaf71ab](https://github.com/folke/which-key.nvim/commit/aaf71ab078d86a48a26fafb5d451af609fd19c64))\n* added option to disable all mapping icons. Fixes [#721](https://github.com/folke/which-key.nvim/issues/721) ([33f6ac0](https://github.com/folke/which-key.nvim/commit/33f6ac04bdbce855ce43eecacb4c421876e246d7))\n* make which-key work without setup or calling add/register ([9ca5f4a](https://github.com/folke/which-key.nvim/commit/9ca5f4ab7cb541ef48dcaa4f03d3cd914a5e62fb))\n* **presets:** added some missing mappings ([6e1b3f2](https://github.com/folke/which-key.nvim/commit/6e1b3f290a3f89ffca68148aa639c866c24e2b77))\n* **state:** improve trigger/mode logic. Fixes [#715](https://github.com/folke/which-key.nvim/issues/715) ([3617e47](https://github.com/folke/which-key.nvim/commit/3617e47673d027989e9c3caa645edb6412c7fa30))\n\n\n### Bug Fixes\n\n* **config:** replacement for plug mappings ([495f9d9](https://github.com/folke/which-key.nvim/commit/495f9d953a86d630ef308f555ed452e332f417ee))\n* **icons:** get icons from parent nodes when needed ([3f0a7ed](https://github.com/folke/which-key.nvim/commit/3f0a7ed4401b98764740cbe8e1b954ac6adeca1b))\n* **icons:** use nerdfont symbol for BS. Fixes [#722](https://github.com/folke/which-key.nvim/issues/722) ([18c1ff5](https://github.com/folke/which-key.nvim/commit/18c1ff5ccb813d95c86f4ead6dac7e6cc5728f08))\n* **mode:** never create triggers for xo mode ([15d3a70](https://github.com/folke/which-key.nvim/commit/15d3a70304607417b2dc1df3da4992d5b8ce077a))\n* **presets:** motions in normal mode ([e2ffc26](https://github.com/folke/which-key.nvim/commit/e2ffc263fc05bf20f090ccaae7a06f88fd6e2fee))\n* tmp fix for op mode ([91641e2](https://github.com/folke/which-key.nvim/commit/91641e2a3af116ffaf739302a65cdb2865fb2415))\n* **view:** fix format for keymaps with 3+ keys ([#723](https://github.com/folke/which-key.nvim/issues/723)) ([0db7896](https://github.com/folke/which-key.nvim/commit/0db7896057d046576c829a87e2ff2de37c49e0fe))\n\n## [3.5.0](https://github.com/folke/which-key.nvim/compare/v3.4.0...v3.5.0) (2024-07-15)\n\n\n### Features\n\n* **api:** using wk.show() always assumes you want to see the group, and not the actual mapping in case of overlap. Fixes [#714](https://github.com/folke/which-key.nvim/issues/714) ([f5067d2](https://github.com/folke/which-key.nvim/commit/f5067d2b244c19eca38b5b495b6eb3e361ac565d))\n\n\n### Bug Fixes\n\n* **state:** attach on BufNew as well. Fixes [#681](https://github.com/folke/which-key.nvim/issues/681) ([0f58176](https://github.com/folke/which-key.nvim/commit/0f581764dc2c89c0ac3d8363369152735ae265ab))\n* **state:** make sure mode always exists even when not safe. See [#681](https://github.com/folke/which-key.nvim/issues/681) ([7915964](https://github.com/folke/which-key.nvim/commit/7915964e73c30ba5657e9a762c6570925dad421b))\n\n\n### Performance Improvements\n\n* **plugin:** only expand plugins when needed ([1fcfc72](https://github.com/folke/which-key.nvim/commit/1fcfc72374c705d68f0607a1dcbbbce13873b4e2))\n* **view:** set buf/win opts with eventignore ([e81e55b](https://github.com/folke/which-key.nvim/commit/e81e55b647a781f306453734834eb543e1f43c20))\n\n## [3.4.0](https://github.com/folke/which-key.nvim/compare/v3.3.0...v3.4.0) (2024-07-15)\n\n\n### Features\n\n* added icons for function keys ([9222280](https://github.com/folke/which-key.nvim/commit/9222280970e8a7d74b4e0f6dab06c2f7a54d668d))\n* **mode:** allow certain modes to start hidden and only show after keypress. See [#690](https://github.com/folke/which-key.nvim/issues/690) ([b4fa48f](https://github.com/folke/which-key.nvim/commit/b4fa48f473796f5d9e3c9c31e6c9d7d509e51ca6))\n* **presets:** added gw ([09b80a6](https://github.com/folke/which-key.nvim/commit/09b80a68085c1fc792b595a851f702bc071d6310))\n* **presets:** better padding defaults for helix preset ([4c36b9b](https://github.com/folke/which-key.nvim/commit/4c36b9b8c722bcf51d038dcfba8b967f0ee818b8))\n* **presets:** increase default height for helix ([df0ad20](https://github.com/folke/which-key.nvim/commit/df0ad205ebd661ef101666ae21a62b77b3024a83))\n* simplified/documented/fixed mappings sorting. Closes [#694](https://github.com/folke/which-key.nvim/issues/694) ([eb73f7c](https://github.com/folke/which-key.nvim/commit/eb73f7c05785a83e07f1ea155b3b2833d8bbb532))\n* **state:** skip mouse keys in debug ([5f85b77](https://github.com/folke/which-key.nvim/commit/5f85b770c386c9435eb8da5db3081aa19078211a))\n* **ui:** show keys/help in an overlay and added scrolling hint ([50b2c43](https://github.com/folke/which-key.nvim/commit/50b2c43532e6ea5cca3ef4c2838d5a8bb535757f))\n* **view:** get parent icon if possible ([b9de927](https://github.com/folke/which-key.nvim/commit/b9de9278bdc57adfa69a67d8a3309f07c83951d0))\n\n\n### Bug Fixes\n\n* **buf:** always detach \" when executing keys. Fixes [#689](https://github.com/folke/which-key.nvim/issues/689) ([d36f722](https://github.com/folke/which-key.nvim/commit/d36f722f114dfdafc8098496e9b5dcbd9f8fc3e8))\n* **config:** set expand=0 by default. Fixes [#693](https://github.com/folke/which-key.nvim/issues/693) ([89434aa](https://github.com/folke/which-key.nvim/commit/89434aa356abd4a694d2b89eccb203e0742bc0d7))\n* **config:** warn when deprecated config options were used. Fixes [#696](https://github.com/folke/which-key.nvim/issues/696) ([81413ef](https://github.com/folke/which-key.nvim/commit/81413ef02dffbe6e4c73f418e4acc920e68b3aa7))\n* **health:** move deprecated option check to health ([af7a30f](https://github.com/folke/which-key.nvim/commit/af7a30fa24ce0a13dba00cbd7b836330facf9f1a))\n* **mappings:** allow creating keymaps without desc. Fixes [#695](https://github.com/folke/which-key.nvim/issues/695) ([c442aaa](https://github.com/folke/which-key.nvim/commit/c442aaa6aafe2742c2e92df7ee127df90099ce17))\n* **plugins:** add existing keymaps to plugin view. Fixes [#681](https://github.com/folke/which-key.nvim/issues/681) ([26f6fd2](https://github.com/folke/which-key.nvim/commit/26f6fd258b66e9656bb86c7269c6497a9ce8a5fa))\n* **presets:** don't override title setting for classic. See [#649](https://github.com/folke/which-key.nvim/issues/649) ([9a53c1f](https://github.com/folke/which-key.nvim/commit/9a53c1ff46421450b5563baab1599591d81de111))\n* **presets:** shorter descriptions ([20600e4](https://github.com/folke/which-key.nvim/commit/20600e422277b383e8c921feec2111a281935217))\n* **state:** always do full update on BufReadPost since buffer-local keymaps would be deleted. Fixes [#709](https://github.com/folke/which-key.nvim/issues/709) ([6068887](https://github.com/folke/which-key.nvim/commit/60688872f4ecc552a5e2bcbd01e7629a155f377f))\n* **state:** don't show when coming from cmdline mode. Fixes [#692](https://github.com/folke/which-key.nvim/issues/692) ([8cba66b](https://github.com/folke/which-key.nvim/commit/8cba66b5a1a0ea8fe8dd5d3d55a42755924e47d8))\n* **state:** honor timeoutlen and nowait. Fixes [#648](https://github.com/folke/which-key.nvim/issues/648). Closes [#697](https://github.com/folke/which-key.nvim/issues/697) ([80f20ee](https://github.com/folke/which-key.nvim/commit/80f20ee62311505fe6d675212f7b246900570450))\n* **state:** properly disable which-key when recording macros. Fixes [#702](https://github.com/folke/which-key.nvim/issues/702) ([b506275](https://github.com/folke/which-key.nvim/commit/b506275acfb4383f678b9ba3aa8db88787c24680))\n* **state:** scrolling ([dce9167](https://github.com/folke/which-key.nvim/commit/dce9167025a0801e4bab146a2856508a9af52ea2))\n* **tree:** rawget for existing plugin node children ([c77cda8](https://github.com/folke/which-key.nvim/commit/c77cda8cd2f54965e4316699f1d124a2b3bf9d49))\n* **util:** when no clipboard provider exists, use the \" register as default. Fixes [#687](https://github.com/folke/which-key.nvim/issues/687) ([d077a3f](https://github.com/folke/which-key.nvim/commit/d077a3f36d4b4d29eccc7feb1ba8e78a421df920))\n* **view:** disable footer on Neovim &lt; 0.10 ([6d544a4](https://github.com/folke/which-key.nvim/commit/6d544a43a21a228482155d65c3ca18fd7038b422))\n* **view:** ensure highlights get set for title padding ([#684](https://github.com/folke/which-key.nvim/issues/684)) ([2e4f7af](https://github.com/folke/which-key.nvim/commit/2e4f7afa4aa444483d8ade5989d524c7f4131368))\n* **view:** hide existing title/footer when no trail ([4f589a1](https://github.com/folke/which-key.nvim/commit/4f589a1368e100a6e33aabd904f34716b75360f6))\n* **view:** include group keymaps in expand results. See [#682](https://github.com/folke/which-key.nvim/issues/682) ([39e703c](https://github.com/folke/which-key.nvim/commit/39e703ceaa9a05dcc664e0ab0ea88c03c3b6bf90))\n* **view:** overlap protection should keep at least 4 lines ([0d89475](https://github.com/folke/which-key.nvim/commit/0d89475f87756199efc2bc52537fc4d11b0f695a))\n* **view:** padding & column spacing. Fixes [#704](https://github.com/folke/which-key.nvim/issues/704) ([11eec49](https://github.com/folke/which-key.nvim/commit/11eec49509490c023bf0272efef955f86f18c1d2))\n* **view:** spacing when more than one box ([89568f3](https://github.com/folke/which-key.nvim/commit/89568f3438f1fbc6c340a8af05ea67feac494c46))\n* **view:** special handling of `&lt;NL&gt;/<C-J>`. Fixes [#706](https://github.com/folke/which-key.nvim/issues/706) ([f8c91b2](https://github.com/folke/which-key.nvim/commit/f8c91b2b4a2d239d3b1d49f901a393e7326a5da8))\n\n## [3.3.0](https://github.com/folke/which-key.nvim/compare/v3.2.0...v3.3.0) (2024-07-14)\n\n\n### Features\n\n* **expand:** allow expand to be a function. Closes [#670](https://github.com/folke/which-key.nvim/issues/670) ([dfaa10c](https://github.com/folke/which-key.nvim/commit/dfaa10cd24badb321a4667fb9135f242393e5680))\n* **mappings:** mapping `desc` and `icon` can now be a function that is evaluated when which-key is show. Fixes [#666](https://github.com/folke/which-key.nvim/issues/666) ([c634af1](https://github.com/folke/which-key.nvim/commit/c634af1295512dc2062fbec38f563f5793de245c))\n* **mappings:** opts.filter to exclude certain mappings from showing up in which-key. ([763ea00](https://github.com/folke/which-key.nvim/commit/763ea000cce9589124515ba34f6d9a6347a02891))\n* **view:** add operator to trail in op mode ([5a6eaaa](https://github.com/folke/which-key.nvim/commit/5a6eaaa4ebc072625b9fc906943e3798028bd817))\n* **view:** when in visual mode, propagate esc. See [#656](https://github.com/folke/which-key.nvim/issues/656) ([30ef44a](https://github.com/folke/which-key.nvim/commit/30ef44a13065a157f97d3fb5bbf23a5c23e513eb))\n\n\n### Bug Fixes\n\n* default preset ([38987d3](https://github.com/folke/which-key.nvim/commit/38987d3f18a8ffc5eaa404d746fd8ee4017b5f37))\n* **mappings:** don't show `&lt;SNR&gt;` mappings ([d700244](https://github.com/folke/which-key.nvim/commit/d700244acc1f1474b34737e14a45df2aa3a324ba))\n* **presets:** max 1 column in helix mode. Fixes [#665](https://github.com/folke/which-key.nvim/issues/665) ([b2a6910](https://github.com/folke/which-key.nvim/commit/b2a6910e9e97526f2327327d2751834049cbd334))\n* **presets:** shorter descriptions ([9a73d6a](https://github.com/folke/which-key.nvim/commit/9a73d6a0b0d5f456a9768d434a83d6d4cdb83efa))\n* **state:** cooldown till next tick when not safe to open which-key. Fixes [#672](https://github.com/folke/which-key.nvim/issues/672) ([bdf3b27](https://github.com/folke/which-key.nvim/commit/bdf3b272ea34ac137af3cb1ebcd5cf8c9745abbb))\n* **util:** nt mode should map to n ([969afc9](https://github.com/folke/which-key.nvim/commit/969afc95d374bc0d6ce397d3d2357d8faa38041a))\n* **view:** set nowrap for the which-key window ([6e1c098](https://github.com/folke/which-key.nvim/commit/6e1c0987024adf63ab91f281f8f9c355abf3f3d8))\n* **view:** set winhl groups. Fixes [#661](https://github.com/folke/which-key.nvim/issues/661) ([baff8ea](https://github.com/folke/which-key.nvim/commit/baff8ea846cbb613dee79333aad7a1d2b912a5bc))\n\n## [3.2.0](https://github.com/folke/which-key.nvim/compare/v3.1.0...v3.2.0) (2024-07-13)\n\n\n### Features\n\n* added `opts.debug` that writes to wk.log in the current directory ([c23df71](https://github.com/folke/which-key.nvim/commit/c23df711884d97963d0c17ed29f5d8c1064d4adc))\n* hydra mode. will document later ([65f2e72](https://github.com/folke/which-key.nvim/commit/65f2e7236a3bc278dd163d7c98c9ea5d9ab6e42e))\n* **icons:** add telescope icon ([#643](https://github.com/folke/which-key.nvim/issues/643)) ([fca3d9e](https://github.com/folke/which-key.nvim/commit/fca3d9eaef57ddb3ce438d208ebc32e23c9f290a))\n\n\n### Bug Fixes\n\n* layout stuff ([7423096](https://github.com/folke/which-key.nvim/commit/742309697cff6aa7f377b72e2f54d34afef09ee1))\n* **mappings:** always use mapping even when it's creating a keymap. Fixes [#637](https://github.com/folke/which-key.nvim/issues/637) ([2d744cb](https://github.com/folke/which-key.nvim/commit/2d744cb824c0f310be420bf33688bc005f164f46))\n* **mappings:** make replace_keycodes default to false in v1 spec ([6ec0a1e](https://github.com/folke/which-key.nvim/commit/6ec0a1ef89209680c799269227b4d0c28de1d877))\n* **state:** dont start which-key during dot repeat. Fixes [#636](https://github.com/folke/which-key.nvim/issues/636) ([5971ecd](https://github.com/folke/which-key.nvim/commit/5971ecdf4465425d6bc6e2277101c6fc896cbe06))\n* **state:** dont start which-key more than once during the same tick in xo mode. Fixes [#635](https://github.com/folke/which-key.nvim/issues/635) ([0218fce](https://github.com/folke/which-key.nvim/commit/0218fce1c3d54307217391215db28e63de9b8980))\n* **state:** dont start wk when chars are pending. Fixes [#658](https://github.com/folke/which-key.nvim/issues/658). Fixes [#655](https://github.com/folke/which-key.nvim/issues/655). Fixes [#648](https://github.com/folke/which-key.nvim/issues/648) ([877ce16](https://github.com/folke/which-key.nvim/commit/877ce163d764bbe7c82a7fec5671c32188607754))\n* **state:** only hide on focus lost when still hidden after 1s. Fixes [#638](https://github.com/folke/which-key.nvim/issues/638) ([649a51b](https://github.com/folke/which-key.nvim/commit/649a51bc81b09443c326d390e3d182e0cdf98c15))\n* **types:** spec field types ([#645](https://github.com/folke/which-key.nvim/issues/645)) ([c6ffb1c](https://github.com/folke/which-key.nvim/commit/c6ffb1ce63959d5f1effe5924712f36eac1e940e))\n* **util:** set local window opts for notify. Fixes [#641](https://github.com/folke/which-key.nvim/issues/641) ([63f2112](https://github.com/folke/which-key.nvim/commit/63f2112361a53b0cf68245868977773f210bb5cd))\n* **view:** check for real overlap instead of just row overlap. See [#649](https://github.com/folke/which-key.nvim/issues/649) ([0427e91](https://github.com/folke/which-key.nvim/commit/0427e91dbbd9c37eb20e6fbc2386f890dc0d7e2a))\n* **view:** disable folds. Fixes [#99](https://github.com/folke/which-key.nvim/issues/99) ([6860e3b](https://github.com/folke/which-key.nvim/commit/6860e3b681b40e3620049f714ae53a6bad594701))\n\n## [3.1.0](https://github.com/folke/which-key.nvim/compare/v3.0.0...v3.1.0) (2024-07-12)\n\n\n### Features\n\n* allow disabling any trigger ([94b7951](https://github.com/folke/which-key.nvim/commit/94b795154fb213db6ed8aeba3d7f53cbce7c147c))\n\n\n### Bug Fixes\n\n* added support for vim.loop ([54db192](https://github.com/folke/which-key.nvim/commit/54db1928c17ac420e897a40f5ad560ee9f28b186))\n* automatically do setup if setup wasn't called within 500ms. Fixes [#630](https://github.com/folke/which-key.nvim/issues/630) ([632ad41](https://github.com/folke/which-key.nvim/commit/632ad41b5fcf60fac897d0b6530a699eb980748d))\n* **buf:** buffer-local mappings were broken (not keymaps). Fixes [#629](https://github.com/folke/which-key.nvim/issues/629) ([58d7f82](https://github.com/folke/which-key.nvim/commit/58d7f822ecc80ca4b43e9c14fd6ec962483e2168))\n* **colors:** compat with older Neovim vesions. Fixes [#631](https://github.com/folke/which-key.nvim/issues/631) ([4516dc9](https://github.com/folke/which-key.nvim/commit/4516dc9422f571c9e189ff6696853d445a3058d6))\n\n## [3.0.0](https://github.com/folke/which-key.nvim/compare/v2.1.0...v3.0.0) (2024-07-12)\n\n\n### ⚠ BREAKING CHANGES\n\n* v3 release\n\n### Features\n\n* added health check back with better wording on what actually gets checked ([97e6e41](https://github.com/folke/which-key.nvim/commit/97e6e4166134aad826454588ae764c7a54f5d298))\n* added WhichKey command ([7c12ab9](https://github.com/folke/which-key.nvim/commit/7c12ab9c2569a7459932bc19a4e52ea5a48437b2))\n* automatically use nowait based on delay and timeoutlen ([110ed72](https://github.com/folke/which-key.nvim/commit/110ed728bedd0182e4d11726194f7eb5db63e2fb))\n* bring config back and create mappings when needed ([add7ab9](https://github.com/folke/which-key.nvim/commit/add7ab92163399c47f7149c96387d382e9d8996b))\n* buffer-local sort & refactor API ([14309d0](https://github.com/folke/which-key.nvim/commit/14309d0446dcc6a24421c56e914e06b1fe2d4f41))\n* close which-key on FocusLost ([aa99460](https://github.com/folke/which-key.nvim/commit/aa99460e117d0348c7f1f77ab669398c04fcba6b))\n* config, and presets ([541989d](https://github.com/folke/which-key.nvim/commit/541989db167e04eb3db24ba57decab0326614f0f))\n* expand groups with less than n mappings. Closes [#374](https://github.com/folke/which-key.nvim/issues/374). Fixes [#90](https://github.com/folke/which-key.nvim/issues/90). Closes [#208](https://github.com/folke/which-key.nvim/issues/208) ([5caf057](https://github.com/folke/which-key.nvim/commit/5caf057b3a204a94d53b4b0200ce915463b4a922))\n* fancy key icons ([e4d0134](https://github.com/folke/which-key.nvim/commit/e4d01347434b31e8a90720463076bbbeebbef199))\n* fix hidden and empty groups ([afc4aa9](https://github.com/folke/which-key.nvim/commit/afc4aa96ae5671f5d4d14f332789dec72dd5db02))\n* **health:** duplicate mappings check ([4762e06](https://github.com/folke/which-key.nvim/commit/4762e06f9dc45b3470ab5b2efa0a4b3de6148298))\n* **health:** icon providers & overlapping keys ([dcbf29a](https://github.com/folke/which-key.nvim/commit/dcbf29ae337bd4d621e326b6f1caad66cfe0770a))\n* initial rewrite ([eb3ad2e](https://github.com/folke/which-key.nvim/commit/eb3ad2eb062392497d0fed3489e2582d4e5bc289))\n* keep track of virtual mappings ([4537d3e](https://github.com/folke/which-key.nvim/commit/4537d3ea52b2b11b96ca2fdde2bb4573f0ca7c73))\n* key/desc replacements ([cf34ffe](https://github.com/folke/which-key.nvim/commit/cf34ffe9384941dc833ed2a3bb2a3bf3aa050373))\n* layout ([347288a](https://github.com/folke/which-key.nvim/commit/347288acd8398ae7c641bd6159261e98f9a6b929))\n* manual sorting. Closes [#131](https://github.com/folke/which-key.nvim/issues/131), Closes [#362](https://github.com/folke/which-key.nvim/issues/362), Closes [#264](https://github.com/folke/which-key.nvim/issues/264) ([c2daf9d](https://github.com/folke/which-key.nvim/commit/c2daf9dcf48e8c8cca61cfc27b1731272b9bc2c6))\n* **mappings:** added support for lazy.nvim style mappings ([6f7a945](https://github.com/folke/which-key.nvim/commit/6f7a945f1dc679ce2c35064e12e4dc531ebf2c3c))\n* **mappings:** added support for setting custom icons from the spec ([951ae7a](https://github.com/folke/which-key.nvim/commit/951ae7a89d164f39f8aa49f51da424539370f6c4))\n* new spec and migration recommendation for health ([41374bc](https://github.com/folke/which-key.nvim/commit/41374bcae462d897fa98c904a44127e258c0438c))\n* option to disable icon colors ([79c8ac8](https://github.com/folke/which-key.nvim/commit/79c8ac87139dcb816072c1a5ca1800d9ce5d64aa))\n* option to disable notify ([4cc46ff](https://github.com/folke/which-key.nvim/commit/4cc46ffa57b8a6ebf6ca7a07128d353f5569a802))\n* play nice with macros ([1abc2bf](https://github.com/folke/which-key.nvim/commit/1abc2bf96472e7816252719de06d60e9b09035dc))\n* plugins partially working again ([b925b31](https://github.com/folke/which-key.nvim/commit/b925b31bab1f91507d15a96f226f7f7423c4fced))\n* **registers:** show non-printable with keytrans ([1832197](https://github.com/folke/which-key.nvim/commit/183219772d01e0ea744c0ff8bf656895f7d7c8d3))\n* spec parser rewrite & proper typings ([07065fe](https://github.com/folke/which-key.nvim/commit/07065fe345bc9dd20aff11ab9a6a3b078aacd42e))\n* state management ([e2ee1fa](https://github.com/folke/which-key.nvim/commit/e2ee1fae13f7a6c38652994dedb0cb34e2608918))\n* state management ([e6beb88](https://github.com/folke/which-key.nvim/commit/e6beb8845e80558194c6027b7a985e1211e76878))\n* title trail ([aef2e53](https://github.com/folke/which-key.nvim/commit/aef2e535c5b7c8f100b534a4b781a82e36f20e39))\n* **ui:** added scrolling ([5f1ab35](https://github.com/folke/which-key.nvim/commit/5f1ab35d099a252f204e2806747980c192a9c265))\n* **ui:** keymap icons ([21d7108](https://github.com/folke/which-key.nvim/commit/21d71081d86872189a3ce90b7c13593f15b78459))\n* **ui:** sorters ([ffeea79](https://github.com/folke/which-key.nvim/commit/ffeea7933249d5ce33b2b3838171cc5299ef1893))\n* update ui when new mappings become available ([a8f66f5](https://github.com/folke/which-key.nvim/commit/a8f66f5ebd9b94f409a88c4a77244167f6edd05f))\n* v3 release ([da258a8](https://github.com/folke/which-key.nvim/commit/da258a89a700916ad0e6af1ad8f9889ff0308253))\n* **view:** nerd font icons for cmd keys ([2787dbd](https://github.com/folke/which-key.nvim/commit/2787dbd158184af67ead5af5bcc0cbdb17856c31))\n\n\n### Bug Fixes\n\n* **api:** show view immediately when opened through the API ([b0e0af0](https://github.com/folke/which-key.nvim/commit/b0e0af0957a648735a43fae52ef34059721f7b42))\n* autmatically blacklist all single key hooks except for z and g ([87c5a4b](https://github.com/folke/which-key.nvim/commit/87c5a4b1be1f882c8b27252464d777a76ea15839))\n* **icons:** check that mini icons hl groups exist in the current colorscheme. If not use which-key default groups ([2336350](https://github.com/folke/which-key.nvim/commit/233635039bf828e341f5ca9b4b8444ac3c56b974))\n* **icons:** proper icons check ([2eaed99](https://github.com/folke/which-key.nvim/commit/2eaed99585f08787d6b5060c89184973eb5aa276))\n* **keys:** delete nop keymaps with a description ([ccf0276](https://github.com/folke/which-key.nvim/commit/ccf027625df6c4e22febfdd786c5e1f7521c2ccb))\n* **layout:** display vs multibyte ellipsis ([0442a73](https://github.com/folke/which-key.nvim/commit/0442a7340cebe13cc5a5fd70dd6cdc989f9086fe))\n* **layout:** empty columns ([600881a](https://github.com/folke/which-key.nvim/commit/600881a9b0cf8119819a97d8900d99fd7a406d36))\n* op-mode, count and reg ([e4d54d1](https://github.com/folke/which-key.nvim/commit/e4d54d11cc247edd0ed4bde7a501caa8e119c1ff))\n* pcall keymap.del ([e47ee13](https://github.com/folke/which-key.nvim/commit/e47ee139b6a082deab16e436cbd2711923e01625))\n* plugin actions & spelling ([e7da411](https://github.com/folke/which-key.nvim/commit/e7da411b45415e8d0d6a5e14b9c1bd5207d09869))\n* presets ([bcf52ba](https://github.com/folke/which-key.nvim/commit/bcf52ba08a57a90e85d4397245a0350c34f2b9d1))\n* readme ([5fe6c91](https://github.com/folke/which-key.nvim/commit/5fe6c91e6f2d7d6dd1a8473ac0cd9bbe311512d9))\n* respect mappings with `&lt;esc&gt;` and close on cursor moved ([22deda5](https://github.com/folke/which-key.nvim/commit/22deda5458b15a10b02b516c68dd409cbaeb53f4))\n* set check debounce to 50 ([754bcc7](https://github.com/folke/which-key.nvim/commit/754bcc7be77b9f9ecac02598121eb97a243b7efa))\n* **state:** dont return or autocmd will cancel ([9a77986](https://github.com/folke/which-key.nvim/commit/9a779869ef557ff6fa84a8b0b478a0f84781c67e))\n* **state:** keyboard interrupts ([1ed9182](https://github.com/folke/which-key.nvim/commit/1ed91823d47f34ce5c52da9ca14e202606caf215))\n* **state:** make sure the buffer mode exists when changing modes ([df64366](https://github.com/folke/which-key.nvim/commit/df64366d8633ac13ba2da7134cc6bbe242a97237))\n* stuff ([f67eb19](https://github.com/folke/which-key.nvim/commit/f67eb192ca6d579add84086d4d1b4ce6ce8732ac))\n* **tree:** check for which_key_ignore in existing keymaps ([f17d78b](https://github.com/folke/which-key.nvim/commit/f17d78bdf8a0afce5bec97c70e68203a6cddf2b7))\n* **ui:** box height ([528fc43](https://github.com/folke/which-key.nvim/commit/528fc43b87cfc29bbc1dddc17051a99cdfdf9ad2))\n* **ui:** make sure the which-key window never overlaps the user's cursor position ([1bb30a7](https://github.com/folke/which-key.nvim/commit/1bb30a7a6901aa842f31c96af7009ef645b29edd))\n* **ui:** scroll and topline=1 on refresh ([28b648d](https://github.com/folke/which-key.nvim/commit/28b648daeabfd2aad8496ffc7a2096bf7d2441b5))\n* which_key_ignore ([ab5ffa8](https://github.com/folke/which-key.nvim/commit/ab5ffa83b4f10ea2360a32d855b016f72a2be6b6))\n* which-key ignore and cleanup ([aeae826](https://github.com/folke/which-key.nvim/commit/aeae826f948cbaeb3a89d9025c423e8300cb5dd3))\n\n## [2.1.0](https://github.com/folke/which-key.nvim/compare/v2.0.1...v2.1.0) (2024-06-06)\n\n\n### Features\n\n* **presets:** add descriptions for fold deletion ([#504](https://github.com/folke/which-key.nvim/issues/504)) ([53b6085](https://github.com/folke/which-key.nvim/commit/53b6085367a92740664783330583facd958dbceb))\n\n\n### Bug Fixes\n\n* black hole z= replacements ([#602](https://github.com/folke/which-key.nvim/issues/602)) ([f5b9124](https://github.com/folke/which-key.nvim/commit/f5b912451f33fd19e52230e73617ad099ffd3ab1))\n* **keys:** fix nested operators. See [#600](https://github.com/folke/which-key.nvim/issues/600). Fixes [#609](https://github.com/folke/which-key.nvim/issues/609) ([25d5b9e](https://github.com/folke/which-key.nvim/commit/25d5b9e9b5775525248b8d5c95271ba28f75d326))\n* restore win view after rendering buffer ([#516](https://github.com/folke/which-key.nvim/issues/516)) ([ea4a17d](https://github.com/folke/which-key.nvim/commit/ea4a17d63571c81f529669a373d20c855b9b351d)), closes [#515](https://github.com/folke/which-key.nvim/issues/515)\n* support nested operators ([#600](https://github.com/folke/which-key.nvim/issues/600)) ([476f4ca](https://github.com/folke/which-key.nvim/commit/476f4cacb15da81dcebe68ea45333e660409612d))\n\n## [2.0.1](https://github.com/folke/which-key.nvim/compare/v2.0.0...v2.0.1) (2024-06-06)\n\n\n### Bug Fixes\n\n* label -&gt; desc ([b8eb534](https://github.com/folke/which-key.nvim/commit/b8eb5348a749e214dfd08d38654a736d91191918))\n\n## [2.0.0](https://github.com/folke/which-key.nvim/compare/v1.6.1...v2.0.0) (2024-06-06)\n\n\n### ⚠ BREAKING CHANGES\n\n* which-key now requires Neovim >= 0.9\n\n### Features\n\n* **keys:** `desc` in `\"&lt;nop&gt;\"` or `\"\"` keymaps can now become prefix label ([#522](https://github.com/folke/which-key.nvim/issues/522)) ([c1958e2](https://github.com/folke/which-key.nvim/commit/c1958e2529433ef096e924c72315733790ca7f88))\n* **mappings:** check if desc exists when parsing mappings ([#589](https://github.com/folke/which-key.nvim/issues/589)) ([a7ced9f](https://github.com/folke/which-key.nvim/commit/a7ced9f00a309418865ec2e3c272113147d167fe))\n* which-key now requires Neovim &gt;= 0.9 ([53ba0ac](https://github.com/folke/which-key.nvim/commit/53ba0accc2d607ef3f2b4f6e40aa9ac75e611dee))\n\n\n### Bug Fixes\n\n* **ignore_missing:** not showing key maps with desc field ([#577](https://github.com/folke/which-key.nvim/issues/577)) ([928c6c8](https://github.com/folke/which-key.nvim/commit/928c6c8fb62df55fa640399b7d76410c037b5f55))\n* **is_enabled:** disable whichkey in cmdline-window ([#581](https://github.com/folke/which-key.nvim/issues/581)) ([26ff0e6](https://github.com/folke/which-key.nvim/commit/26ff0e6084a4e957fc13ffe00bafd7c0c5ab81cc))\n* **keys:** fix buffer-local mapping groups ([d87c01c](https://github.com/folke/which-key.nvim/commit/d87c01c9bbcc7c1c2d248dca1b11285259d66be8))\n* **mappings:** dont remove desc ([4a7d732](https://github.com/folke/which-key.nvim/commit/4a7d7328b26d3f3355a43af4d8dc5ffd33cbd793))\n\n## [1.6.1](https://github.com/folke/which-key.nvim/compare/v1.6.0...v1.6.1) (2024-05-31)\n\n\n### Bug Fixes\n\n* **reg:** Added check for OSC 52 to disable related register previews ([#604](https://github.com/folke/which-key.nvim/issues/604)) ([8063a7f](https://github.com/folke/which-key.nvim/commit/8063a7f33bfea6a6387907c93a30a5877aa02633))\n* small typo in operator description ([#528](https://github.com/folke/which-key.nvim/issues/528)) ([d65087b](https://github.com/folke/which-key.nvim/commit/d65087b892c45d3722b6511c83a029671d6290e5))\n\n## [1.6.0](https://github.com/folke/which-key.nvim/compare/v1.5.1...v1.6.0) (2023-10-17)\n\n\n### Features\n\n* **presets:** added gt and gT. Fixes [#457](https://github.com/folke/which-key.nvim/issues/457) ([3ba77f0](https://github.com/folke/which-key.nvim/commit/3ba77f0b0961b3fe685397b8d8f34f231b9350a6))\n\n\n### Bug Fixes\n\n* call config in issue template ([#489](https://github.com/folke/which-key.nvim/issues/489)) ([09a8188](https://github.com/folke/which-key.nvim/commit/09a8188224dc890618dfbc961436b106d912c2c1))\n* **view:** set modifiable flag for view buffer ([#506](https://github.com/folke/which-key.nvim/issues/506)) ([1d17760](https://github.com/folke/which-key.nvim/commit/1d1776012eda4258985f6f1f0c02b78594a3f37b))\n\n## [1.5.1](https://github.com/folke/which-key.nvim/compare/v1.5.0...v1.5.1) (2023-07-15)\n\n\n### Bug Fixes\n\n* revert: never overwrite actual keymaps with group names. Fixes [#478](https://github.com/folke/which-key.nvim/issues/478) Fixes [#479](https://github.com/folke/which-key.nvim/issues/479) Fixes [#480](https://github.com/folke/which-key.nvim/issues/480) ([fc25407](https://github.com/folke/which-key.nvim/commit/fc25407a360d27c36a30a90ff36861aa20ef2e54))\n\n## [1.5.0](https://github.com/folke/which-key.nvim/compare/v1.4.3...v1.5.0) (2023-07-14)\n\n\n### Features\n\n* **marks:** show filename as label when no label ([25babc6](https://github.com/folke/which-key.nvim/commit/25babc6add21c17d6391a585302aee5632266622))\n\n\n### Bug Fixes\n\n* **keys:** don't show empty groups ([8503c0d](https://github.com/folke/which-key.nvim/commit/8503c0d725420b37ac31e44753657cde91435597))\n* never overwrite actual keymaps with group names ([f61da3a](https://github.com/folke/which-key.nvim/commit/f61da3a3a6143b7a42b4b16e983004856ec26bd1))\n* **registers:** dont trigger on @. Fixes [#466](https://github.com/folke/which-key.nvim/issues/466) ([65b36cc](https://github.com/folke/which-key.nvim/commit/65b36cc258e857dea92fc11cdc0d6e2bb01d3e87))\n\n## [1.4.3](https://github.com/folke/which-key.nvim/compare/v1.4.2...v1.4.3) (2023-05-22)\n\n\n### Bug Fixes\n\n* **health:** dont show duplicates between global and buffer-local. It's too confusing ([015fdf3](https://github.com/folke/which-key.nvim/commit/015fdf3e3e052d4a9fee997ca0aa387c2dd3731c))\n\n## [1.4.2](https://github.com/folke/which-key.nvim/compare/v1.4.1...v1.4.2) (2023-05-10)\n\n\n### Bug Fixes\n\n* **health:** update the deprecated function ([#453](https://github.com/folke/which-key.nvim/issues/453)) ([12d3b11](https://github.com/folke/which-key.nvim/commit/12d3b11a67b94d65483f10c6ba0a47474039543a))\n\n## [1.4.1](https://github.com/folke/which-key.nvim/compare/v1.4.0...v1.4.1) (2023-05-04)\n\n\n### Bug Fixes\n\n* **keys:** dont overwrite existing keymaps with a callback. Fixes [#449](https://github.com/folke/which-key.nvim/issues/449) ([4db6bb0](https://github.com/folke/which-key.nvim/commit/4db6bb080b269ac155e5aa1696d26f2376c749ab))\n\n## [1.4.0](https://github.com/folke/which-key.nvim/compare/v1.3.0...v1.4.0) (2023-04-18)\n\n\n### Features\n\n* **view:** ensure it's above other floating windows ([#442](https://github.com/folke/which-key.nvim/issues/442)) ([9443778](https://github.com/folke/which-key.nvim/commit/94437786a0d0fde61284f8476ac142896878c2d7))\n\n## [1.3.0](https://github.com/folke/which-key.nvim/compare/v1.2.3...v1.3.0) (2023-04-17)\n\n\n### Features\n\n* **health:** move health check to separate health file ([b56c512](https://github.com/folke/which-key.nvim/commit/b56c5126752fcd498a81c6d8d1e7f51f251166eb))\n* **preset:** add `z&lt;CR&gt;` preset ([#346](https://github.com/folke/which-key.nvim/issues/346)) ([ed37330](https://github.com/folke/which-key.nvim/commit/ed3733059ffa281c8144e44f1b4819a771ddf4de))\n* **preset:** added `zi` and `CTRL-W_o` ([#378](https://github.com/folke/which-key.nvim/issues/378)) ([5e8e6b1](https://github.com/folke/which-key.nvim/commit/5e8e6b1c70d3fcbe2712453ef3ebbf07d0d2aff4))\n* **view:** allow percentages for margins. Fixes [#436](https://github.com/folke/which-key.nvim/issues/436) ([0b5a653](https://github.com/folke/which-key.nvim/commit/0b5a6537b66ee37d03c6c3f0e21fd147f817422d))\n\n\n### Bug Fixes\n\n* **health:** add OK output to check_health fn ([#375](https://github.com/folke/which-key.nvim/issues/375)) ([c9c430a](https://github.com/folke/which-key.nvim/commit/c9c430ab19a3bf8dd394dd9925a3a219063276b9))\n* **keys:** allow keymap desc to override preset labels. Fixes [#386](https://github.com/folke/which-key.nvim/issues/386) ([6aa1b2f](https://github.com/folke/which-key.nvim/commit/6aa1b2fa93a2a26a1bd752080ec6a51beb009e75))\n* **tree:** don't cache plugin nodes. Fixes [#441](https://github.com/folke/which-key.nvim/issues/441) ([20fcd7b](https://github.com/folke/which-key.nvim/commit/20fcd7b602a2c58d634eaa1f1d28b16a6acbfad3))\n* **util:** clear cache when leader changes ([df3597f](https://github.com/folke/which-key.nvim/commit/df3597f7dc0f379bda865e3c9dd6303fa6e4c959))\n* **util:** missing return statement ([f6bb21c](https://github.com/folke/which-key.nvim/commit/f6bb21c8c1d72008783466e80e0c993ef056a3a9))\n* **util:** nil check ([6ab25e2](https://github.com/folke/which-key.nvim/commit/6ab25e24ec2b2a8fb88f43eb13feb21e5042c280))\n\n\n### Performance Improvements\n\n* **keys:** optimized `update_keymaps` ([476d137](https://github.com/folke/which-key.nvim/commit/476d13754db0da7831fc3581fb243cd7f0d3e581))\n* **tree:** added fast nodes lookup ([8e5e012](https://github.com/folke/which-key.nvim/commit/8e5e0126aaff9bd73eb25a6d5568f6b5bdff58f0))\n* **util:** cache parse_keys ([8649bf5](https://github.com/folke/which-key.nvim/commit/8649bf5c66b8fa1fa6ee879b9af78e89f886d13c))\n* **util:** cache replace termcodes ([eaa8027](https://github.com/folke/which-key.nvim/commit/eaa80272ef488c68cd51698c64e795767c6e0624))\n\n## [1.2.3](https://github.com/folke/which-key.nvim/compare/v1.2.2...v1.2.3) (2023-04-17)\n\n\n### Bug Fixes\n\n* **util:** dont parse empty lhs ([8d5ab76](https://github.com/folke/which-key.nvim/commit/8d5ab76836d89be1c761a4ed61bf700d98c71e5d))\n* **util:** only collect valid &lt;&gt; keys ([#438](https://github.com/folke/which-key.nvim/issues/438)) ([4bd6dca](https://github.com/folke/which-key.nvim/commit/4bd6dcaa6d7e1650590303f0066d32aa6762d8f3))\n* **util:** replace `&lt;lt&gt;` by `<` before parsing ([789ac71](https://github.com/folke/which-key.nvim/commit/789ac718ee7a2b49dd82409e3d7cf45b52ea95ce))\n* **view:** allow deviating paddings per side ([#400](https://github.com/folke/which-key.nvim/issues/400)) ([3090eaf](https://github.com/folke/which-key.nvim/commit/3090eafb780da76eb4876986081551db80bf35cd))\n\n\n### Performance Improvements\n\n* **util:** simplify and optimize parsers ([#435](https://github.com/folke/which-key.nvim/issues/435)) ([b0ebb67](https://github.com/folke/which-key.nvim/commit/b0ebb6722c77dda1ab1e3ce13521fe7db20cbc79))\n\n## [1.2.2](https://github.com/folke/which-key.nvim/compare/v1.2.1...v1.2.2) (2023-04-16)\n\n\n### Performance Improvements\n\n* **mappings:** avoid computing error string on hot path ([#429](https://github.com/folke/which-key.nvim/issues/429)) ([6892f16](https://github.com/folke/which-key.nvim/commit/6892f165bb984561f8cac298a6747da338d04668))\n\n## [1.2.1](https://github.com/folke/which-key.nvim/compare/v1.2.0...v1.2.1) (2023-03-26)\n\n\n### Bug Fixes\n\n* **icons:** fixed obsolete icons with nerdfix ([151f21d](https://github.com/folke/which-key.nvim/commit/151f21d34d50fc53506ddc9d8ec58234202df795))\n* **view:** wrong window position when statusline is not set ([#363](https://github.com/folke/which-key.nvim/issues/363)) ([e14f8dc](https://github.com/folke/which-key.nvim/commit/e14f8dc6304e774ce005d09f7feebbd191fe20f9))\n\n## [1.2.0](https://github.com/folke/which-key.nvim/compare/v1.1.1...v1.2.0) (2023-03-01)\n\n\n### Features\n\n* enable spelling plugin by default ([6d886f4](https://github.com/folke/which-key.nvim/commit/6d886f4dcaa25d1fe20e332f779fe1edb726d063))\n* make delay configurable for marks/registers/spelling. Fixes [#379](https://github.com/folke/which-key.nvim/issues/379). Fixes [#152](https://github.com/folke/which-key.nvim/issues/152), Fixes [#220](https://github.com/folke/which-key.nvim/issues/220), Fixes [#334](https://github.com/folke/which-key.nvim/issues/334) ([5649320](https://github.com/folke/which-key.nvim/commit/56493205745597abdd8d3ceb22f502ffe74784f5))\n\n## [1.1.1](https://github.com/folke/which-key.nvim/compare/v1.1.0...v1.1.1) (2023-02-10)\n\n\n### Bug Fixes\n\n* remove duplicate kaymap ([#361](https://github.com/folke/which-key.nvim/issues/361)) ([9a4680e](https://github.com/folke/which-key.nvim/commit/9a4680e95b7026c58f0a377de0f13ee2507ece7a))\n\n## [1.1.0](https://github.com/folke/which-key.nvim/compare/v1.0.0...v1.1.0) (2023-01-10)\n\n\n### Features\n\n* Hide mapping when `desc = \"which_key_ignore\"` ([#391](https://github.com/folke/which-key.nvim/issues/391)) ([fd07b61](https://github.com/folke/which-key.nvim/commit/fd07b6137f1e362a66df04f7c7055b99319e3a4d))\n\n\n### Bug Fixes\n\n* visual-multi compatibility ([#389](https://github.com/folke/which-key.nvim/issues/389)) ([#385](https://github.com/folke/which-key.nvim/issues/385)) ([01334bb](https://github.com/folke/which-key.nvim/commit/01334bb48c53231fc8b2e2932215bfee05474904))\n\n## 1.0.0 (2023-01-04)\n\n\n### Features\n\n* add &lt;C-w&gt;_ to misc ([#296](https://github.com/folke/which-key.nvim/issues/296)) ([03b8c1d](https://github.com/folke/which-key.nvim/commit/03b8c1dde8c02f187869c56a6019d5e2578f7af7))\n* add preset key to mappings for API usage ([ed7d6c5](https://github.com/folke/which-key.nvim/commit/ed7d6c523ae8ef7b8059d2fee0836009e71bcd0c))\n* added a winblend option for the floating window ([#161](https://github.com/folke/which-key.nvim/issues/161)) ([d3032b6](https://github.com/folke/which-key.nvim/commit/d3032b6d3e0adb667975170f626cb693bfc66baa))\n* added duplicate mapping checks to checkhealth [#34](https://github.com/folke/which-key.nvim/issues/34) ([710c5f8](https://github.com/folke/which-key.nvim/commit/710c5f81da2c34e6e0f361d87cfca27207e1b994))\n* added healthcheck to check for conflicting keymaps ([44d3c3f](https://github.com/folke/which-key.nvim/commit/44d3c3f9307930ce8c877383d51fca1a353982d8))\n* added ignore_missing option to hide any keymap for which no label exists [#60](https://github.com/folke/which-key.nvim/issues/60) ([1ccba9d](https://github.com/folke/which-key.nvim/commit/1ccba9d0b553b08feaca9f432386f9c33bd1656f))\n* added operators plugin ([c7f8496](https://github.com/folke/which-key.nvim/commit/c7f84968e44f1a9ab9687ddf0b3dc5465e48bc75))\n* added option to configure scroll bindings inside the popup ([#175](https://github.com/folke/which-key.nvim/issues/175)) ([a54ef5f](https://github.com/folke/which-key.nvim/commit/a54ef5f5db5819ee65a5ec3dea9bae64476c5017))\n* added options to align columns left, center or right [#82](https://github.com/folke/which-key.nvim/issues/82) ([2467fb1](https://github.com/folke/which-key.nvim/commit/2467fb15e8775928fba3d7d20a68b64852f44122))\n* added settings to disable the WhichKey popup for certain buftypes and filetyes ([fb276a0](https://github.com/folke/which-key.nvim/commit/fb276a07c7dc305e48ecc2683e4bd28cda49499a))\n* added support for expr mappings ([9d2785c](https://github.com/folke/which-key.nvim/commit/9d2785c4d44b4a8ca1095856cb4ee34a32497cf6))\n* added triggers_blacklist to blacklist certain whichkey hooks [#73](https://github.com/folke/which-key.nvim/issues/73) ([ec1474b](https://github.com/folke/which-key.nvim/commit/ec1474bb0c373eb583962deff20860c2af54f932))\n* added WhichKeyBorder highlight group ([9c190ea](https://github.com/folke/which-key.nvim/commit/9c190ea91939eba8c2d45660127e0403a5300b5a))\n* allow functions to be passed to create keybindings. Implements [#31](https://github.com/folke/which-key.nvim/issues/31) ([cf644cd](https://github.com/folke/which-key.nvim/commit/cf644cd9a0e989ad3e0a6dffb98beced742f3297))\n* allow manual setup of triggers [#30](https://github.com/folke/which-key.nvim/issues/30) ([423a50c](https://github.com/folke/which-key.nvim/commit/423a50cccfeb8b812e0e89f156316a4bd9d2673a))\n* allow mapping to have multiple modes as a table ([0d559fa](https://github.com/folke/which-key.nvim/commit/0d559fa5573aa48c4822e8874315316bd075e17e))\n* allow mode to be set on a single mapping ([2a08d58](https://github.com/folke/which-key.nvim/commit/2a08d58658e1de0fae3b44e21e8ed72399465701))\n* allow overriding key labels [#77](https://github.com/folke/which-key.nvim/issues/77) ([2be929e](https://github.com/folke/which-key.nvim/commit/2be929e34b2f2b982e6b978c0bd94cd2e1d500e6))\n* allow to close popup with &lt;c-c&gt; [#33](https://github.com/folke/which-key.nvim/issues/33) ([410523a](https://github.com/folke/which-key.nvim/commit/410523a6d7bcbcab73f8c7b0fc567893d7cd8c44))\n* better logging ([c39df95](https://github.com/folke/which-key.nvim/commit/c39df95881a6cd8ac27fce5926dc2dc1b4597df9))\n* better support for plugin actions with custom lua function ([222a8ee](https://github.com/folke/which-key.nvim/commit/222a8eeaf727f9b1b767424198f7c71274c04d43))\n* builtin key mappings ([0063ceb](https://github.com/folke/which-key.nvim/commit/0063ceb161475097885d567500fe764358983c62))\n* check for rogue existsing WhichKey mappings and show error. WK handles triggers automatically, no need to define them ([db97a30](https://github.com/folke/which-key.nvim/commit/db97a301fb7691b61cd6c975e3cc060fb53fd980))\n* easily reset WK with plenary for development of WK ([55b4dab](https://github.com/folke/which-key.nvim/commit/55b4dabab649d59e657917eb17c9d57716817719))\n* expose registers to customize order ([2b83fe7](https://github.com/folke/which-key.nvim/commit/2b83fe74dee00763e4c037d198c88ff11c843914))\n* for nvim 0.7.0 or higher, use native keymap callbacks instead of which key functions ([5e96cf9](https://github.com/folke/which-key.nvim/commit/5e96cf950a864a4600512c90f2080b0b6f0eacb7))\n* group symbol ([5e02b66](https://github.com/folke/which-key.nvim/commit/5e02b66b9e7add373967b798552a7cc9a427efb4))\n* handle [count] with motion. Implements [#11](https://github.com/folke/which-key.nvim/issues/11) ([d93ef0f](https://github.com/folke/which-key.nvim/commit/d93ef0f2f1a9a6288016a3a82f70399e350a574f))\n* hide mapping boilerplate ([#6](https://github.com/folke/which-key.nvim/issues/6)) ([b3357de](https://github.com/folke/which-key.nvim/commit/b3357de005f27a3cc6aabe922e8ee308470d9343))\n* honor timeoutlen when typing an operator followed by i or a instead of showing immediately ([54d1b3a](https://github.com/folke/which-key.nvim/commit/54d1b3ab3ed9132142f2139964cfa68d018b38c5))\n* initial commit ([970e79f](https://github.com/folke/which-key.nvim/commit/970e79f7016f6cc2a89dad8c50e2e89657684f55))\n* keyamp functions ([801cc81](https://github.com/folke/which-key.nvim/commit/801cc810f4d57eca029261f383b2483ec21e5824))\n* make custom operators configurable (fixes [#9](https://github.com/folke/which-key.nvim/issues/9)) ([81875d8](https://github.com/folke/which-key.nvim/commit/81875d875f7428c7a087e0d051744c7b3f9dc1b3))\n* make help message configurable ([7b1c6aa](https://github.com/folke/which-key.nvim/commit/7b1c6aa23061a9ed1acdfec3d20dc5e361ec01a3))\n* Make keypress message configuratble ([#351](https://github.com/folke/which-key.nvim/issues/351)) ([fd2422f](https://github.com/folke/which-key.nvim/commit/fd2422fb7030510cf9c3304047e653e8adcd8f20))\n* motions plugin ([f989fcf](https://github.com/folke/which-key.nvim/commit/f989fcfeafd4fd333a8e87617fce39a449ae81ca))\n* new keymap dsl ([#352](https://github.com/folke/which-key.nvim/issues/352)) Docs to come ([fbf0381](https://github.com/folke/which-key.nvim/commit/fbf038110edb5e2cbecaac57570aae2c9fa2939c))\n* option to make some triggers show immediately, regardless of timeoutlen ([3a52dc0](https://github.com/folke/which-key.nvim/commit/3a52dc02b6e542d5cd216381ccfa108943bab17c))\n* plugin for registers ([5415832](https://github.com/folke/which-key.nvim/commit/541583280fab4ea96900f35fb6b5ffb8de103a4c))\n* plugin support + first builtin marks plugin ([9d5e631](https://github.com/folke/which-key.nvim/commit/9d5e6311c20970741eaaf7a3950c1a33de5eedaa))\n* prefer `desc` to `cmd` as the fallback label ([#253](https://github.com/folke/which-key.nvim/issues/253)) ([bd4411a](https://github.com/folke/which-key.nvim/commit/bd4411a2ed4dd8bb69c125e339d837028a6eea71))\n* preset with misc keybindings ([e610338](https://github.com/folke/which-key.nvim/commit/e61033858b8d5208a49c24d70eb9576cbd22e887))\n* set keymap desc when creating new mappings based on the WhichKey labels ([f4518ca](https://github.com/folke/which-key.nvim/commit/f4518ca50193a545681ba65ba0c5bb8a8479c5b5))\n* set popup filetype to WhichKey and buftype to nofile [#86](https://github.com/folke/which-key.nvim/issues/86) ([20682f1](https://github.com/folke/which-key.nvim/commit/20682f189a0c452203f6365f66eccb0407b20936))\n* show a warning if &lt;leader&gt; is already mapped, even if it's <nop> ([ac56f45](https://github.com/folke/which-key.nvim/commit/ac56f45095e414c820f621423611aac4027f74bd))\n* show breadcrumb and help on command line ([c27535c](https://github.com/folke/which-key.nvim/commit/c27535ca085c05ade1e23b3b347e39e53c24d33a))\n* show keys and help in float when cmdheight == 0 ([f645017](https://github.com/folke/which-key.nvim/commit/f64501787bebe9ff28c10dbe470ffad5dd017769))\n* show/hide a fake cursor when WK is open ([0f53f40](https://github.com/folke/which-key.nvim/commit/0f53f40c1b827d35771c82a5c47c5a54d9408f7c))\n* spelling suggestion plugin ([4b74f21](https://github.com/folke/which-key.nvim/commit/4b74f218f4541991a40719286f96cce9447a89c4))\n* support for custom text object completion. Fixes [#10](https://github.com/folke/which-key.nvim/issues/10) ([394ff5a](https://github.com/folke/which-key.nvim/commit/394ff5a37bab051857de4216ee25db2284de2196))\n* support opts.remap for keymap ([#339](https://github.com/folke/which-key.nvim/issues/339)) ([6885b66](https://github.com/folke/which-key.nvim/commit/6885b669523ff4238de99a7c653d47b081b5506d))\n* support using lua function for expr ([#110](https://github.com/folke/which-key.nvim/issues/110)) ([e0dce15](https://github.com/folke/which-key.nvim/commit/e0dce1552ea37964ae6ac7144709867544eae7f3))\n* text objects ([d255b71](https://github.com/folke/which-key.nvim/commit/d255b71992494ce4998caae7fe281144fb669abb))\n* WhichKey vim command to show arbitrary keymaps ([df615d4](https://github.com/folke/which-key.nvim/commit/df615d44987a8bfe8910c618164f696e227ecfd4))\n\n\n### Bug Fixes\n\n* :norm .. commands keep feeding &lt;esc&gt; at the end of the command [#58](https://github.com/folke/which-key.nvim/issues/58) ([d66ffdd](https://github.com/folke/which-key.nvim/commit/d66ffdd5a845c713f581ac6da36173e88096e0fa))\n* add delay option to macro key ([#152](https://github.com/folke/which-key.nvim/issues/152)) ([#156](https://github.com/folke/which-key.nvim/issues/156)) ([bd226c4](https://github.com/folke/which-key.nvim/commit/bd226c4d02d7f360747364a59cc5f0da50524f2c))\n* add remaining &lt;esc&gt; to pending in case there's no other characters ([29a82b5](https://github.com/folke/which-key.nvim/commit/29a82b575b9752a45b005327030948ce8cb513a0))\n* add triggers for other modes in marks and register plugin ([#116](https://github.com/folke/which-key.nvim/issues/116)) ([bbfc640](https://github.com/folke/which-key.nvim/commit/bbfc640c44612d705f4b0670ec1387c8a6ff2c7c))\n* added @ trigger for showing registers ([01b6676](https://github.com/folke/which-key.nvim/commit/01b66769480fac14f6efa7c31327234398d05837))\n* added builtin plugins to config ([6e461ca](https://github.com/folke/which-key.nvim/commit/6e461caec3d3aa43f1fa2b7890b299705bccfe8d))\n* added hidden option to disable the popup on motion counts (motions.count) ([ea975ef](https://github.com/folke/which-key.nvim/commit/ea975ef254f10c4938cd663a7c4fb14e2d7514c0))\n* added support for operator pending keymaps ([1f6b510](https://github.com/folke/which-key.nvim/commit/1f6b510f6ef0c223b51f3599200bbf6abc30f909))\n* added z= for spelling correction ([59603de](https://github.com/folke/which-key.nvim/commit/59603dee2f67f623a520148d60c634f6f56f6017))\n* always escape &lt;leader&gt; when it's a backslash ([41636a3](https://github.com/folke/which-key.nvim/commit/41636a3be909af5d20d811f8ce6a304a5ee3cc21))\n* always execute keys with remap, but unhook / hook WK triggers (Fixes [#8](https://github.com/folke/which-key.nvim/issues/8)) ([bf329df](https://github.com/folke/which-key.nvim/commit/bf329df0ee11d6c80c7208b40eab74368e963245))\n* always map &lt;leader&gt;, even without register ([512631c](https://github.com/folke/which-key.nvim/commit/512631c1bdce96dd048115cb139ea3a8452a931a))\n* always unhook and ignore errors ([01a60cd](https://github.com/folke/which-key.nvim/commit/01a60cd5929b395042c8ba3d872f6f25ccd55ecb))\n* always use noremap=false for &lt;plug&gt; commands ([9b9cece](https://github.com/folke/which-key.nvim/commit/9b9cece006b78ff7527a35285a4b5c1359d70fd8))\n* always use word under the cursor for spelling suggestions ([c5b19ec](https://github.com/folke/which-key.nvim/commit/c5b19ecf4d1d8f8c77ee982caf9792740f6d5e53))\n* better handling of weird norm and getchar endless &lt;esc&gt; bug [#68](https://github.com/folke/which-key.nvim/issues/68) ([bfd37e9](https://github.com/folke/which-key.nvim/commit/bfd37e93761d622328c673828b537d5671389413))\n* better sorting ([99e8940](https://github.com/folke/which-key.nvim/commit/99e894032afbe2543dbbf9bba05518d96b852aa0))\n* center alignemnt should be an integer ([db85198](https://github.com/folke/which-key.nvim/commit/db851981595fc360e9b6196a7c3995611aceac3b))\n* check for FloatBorder before setting winhighlight ([af6b91d](https://github.com/folke/which-key.nvim/commit/af6b91dc09e4ed830d8cd4a3652a5b3f80ccefac))\n* check is hook exists before unhooking ([f6cf3a2](https://github.com/folke/which-key.nvim/commit/f6cf3a2e49c09aba739c0f6fc85d3aebf2b96cb6))\n* cmd can be nil ([060a574](https://github.com/folke/which-key.nvim/commit/060a574c228433e9b17960fa0eafca0a975381e8))\n* **colors:** Separator links to DiffAdd ([#302](https://github.com/folke/which-key.nvim/issues/302)) ([a2749c5](https://github.com/folke/which-key.nvim/commit/a2749c5b039ad34734c98f8752b9fb5da7ceac55))\n* Compatibility with Visual Multi plug ([#278](https://github.com/folke/which-key.nvim/issues/278)) ([92916b6](https://github.com/folke/which-key.nvim/commit/92916b6cede0ffd7d5c1ce9abad93ec0c4d9635e))\n* convert trings with strtrans to properly render non printable characters ([d85ce36](https://github.com/folke/which-key.nvim/commit/d85ce3627f4060f622e4c0a9657f26c0151829de))\n* correct floating window position in Neovim 0.6 nightly ([#176](https://github.com/folke/which-key.nvim/issues/176)) ([a35a910](https://github.com/folke/which-key.nvim/commit/a35a910d28683294fd23d35dd03c06f6f7c37b17))\n* correctly handle counts before commands [#17](https://github.com/folke/which-key.nvim/issues/17) ([4feb319](https://github.com/folke/which-key.nvim/commit/4feb319ff89fb8659efa2a788f808bc390afa490))\n* correctly unhook buffer local mappings before executing keys ([4f98b47](https://github.com/folke/which-key.nvim/commit/4f98b4713ea9d4534662ceb7b542b0626eeb9ea8))\n* disable folding on whichkey popup. Fixes [#99](https://github.com/folke/which-key.nvim/issues/99) ([78821de](https://github.com/folke/which-key.nvim/commit/78821de0b633275d6934660e67989639bc7a784c))\n* disable operator pending maps for now ([#2](https://github.com/folke/which-key.nvim/issues/2)) ([0cd66a8](https://github.com/folke/which-key.nvim/commit/0cd66a84520fc0e7e3eec81f081157541cb48dbd))\n* do feedkeys in correct mode when dealing with operator pending commands. Fixes [#8](https://github.com/folke/which-key.nvim/issues/8) ([cf30788](https://github.com/folke/which-key.nvim/commit/cf307886b68ed53334ffdcee809a751376269e33))\n* don't show &lt;esc&gt; mappings since <esc> closes the popup ([09db756](https://github.com/folke/which-key.nvim/commit/09db756b5d357767a635a4d169e2e820b2962ea8))\n* don't show spelling when the command was started with a count [#80](https://github.com/folke/which-key.nvim/issues/80) ([20a85bd](https://github.com/folke/which-key.nvim/commit/20a85bd8bc54a11cf040aafa5d60f8a735eecfbd))\n* dont do feedkeys when user uses WhichKey command with non existing prefix ([f9537ce](https://github.com/folke/which-key.nvim/commit/f9537ce0f7457665e3b90d82c5f3f2c37fe0506f))\n* dont pass zero counts ([0c3cfb0](https://github.com/folke/which-key.nvim/commit/0c3cfb0064ceec5b182bac580033e0654d9575e6))\n* dont show errors about loading order of setup and register ([2adbc17](https://github.com/folke/which-key.nvim/commit/2adbc17e00061073f2c2a40b6420ee2a80ea458d))\n* explicitely check if we try to execute an auto which-key mapping. shouldn't happen, but still safer to check ([30fdd46](https://github.com/folke/which-key.nvim/commit/30fdd465433d48cab3b1f894daf52fa0005cf7ac))\n* expose presets so one can change them if needed [#70](https://github.com/folke/which-key.nvim/issues/70) ([46ea686](https://github.com/folke/which-key.nvim/commit/46ea686c6cc9bfc96bc492c76a76d43548a587c4))\n* feed CTRL-O again if called from CTRL-O ([#145](https://github.com/folke/which-key.nvim/issues/145)) ([833b5ea](https://github.com/folke/which-key.nvim/commit/833b5ea1a0d4b3bddf4b5c68fc89f1234960edec))\n* feed the keys as typed ([#333](https://github.com/folke/which-key.nvim/issues/333)) ([33b4e72](https://github.com/folke/which-key.nvim/commit/33b4e72a07546bc4798b4bafb99ae06df47bd790))\n* fix flickering on tmux ([f112602](https://github.com/folke/which-key.nvim/commit/f11260251ad942ba1635db9bc25c2efaf75caf0a))\n* fix issue when cmdheight=0 [#301](https://github.com/folke/which-key.nvim/issues/301) ([#305](https://github.com/folke/which-key.nvim/issues/305)) ([9cd09ca](https://github.com/folke/which-key.nvim/commit/9cd09ca6bbe5acfbce86ca023fdc720f6aa132d6))\n* fixed 0 after an operator. Wrongly assumed any number to be a count for following op mode, but not the case for 0 [#59](https://github.com/folke/which-key.nvim/issues/59) [#61](https://github.com/folke/which-key.nvim/issues/61) ([36616ca](https://github.com/folke/which-key.nvim/commit/36616cacba5d9eb716017bf23b7bbbe4cb4a6822))\n* fixed possible nil error when showing marks ([b44fc09](https://github.com/folke/which-key.nvim/commit/b44fc095f6d0144278f3413533ad2d40ae664229))\n* for sporadic loss of lua function for mapping ([#216](https://github.com/folke/which-key.nvim/issues/216)) ([312c386](https://github.com/folke/which-key.nvim/commit/312c386ee0eafc925c27869d2be9c11ebdb807eb))\n* formatting of text-objects plugin ([442d2d3](https://github.com/folke/which-key.nvim/commit/442d2d383284390c5ee1b922036fc10fff530b2d))\n* get value of register '=' with getreg('=',1) ([#114](https://github.com/folke/which-key.nvim/issues/114)) ([6224ea8](https://github.com/folke/which-key.nvim/commit/6224ea81f505c66a9644f89129149b108f722e56))\n* handle backslash as localleader [#47](https://github.com/folke/which-key.nvim/issues/47) ([cd23fdc](https://github.com/folke/which-key.nvim/commit/cd23fdc1b0cbdb22769bed5cb275a6d1c4bd9bfc))\n* handle baskslashes when leader or localleader isn't set ([d155ab3](https://github.com/folke/which-key.nvim/commit/d155ab3bef11a8156995b47d5552586e5c9f66a3))\n* handle keymaps with a &lt;nop&gt; rhs as non existing and possibly overwrite them with WK hooks [#35](https://github.com/folke/which-key.nvim/issues/35) ([402be18](https://github.com/folke/which-key.nvim/commit/402be18dc656897b1dc68c88fab4ffe8635b8209))\n* handle nvim_{buf_}get_keymap return no rhs due to 'callback' mapping ([#223](https://github.com/folke/which-key.nvim/issues/223)) ([28d2bd1](https://github.com/folke/which-key.nvim/commit/28d2bd129575b5e9ebddd88506601290bb2bb221))\n* handle possible errors when getting last expression register [#64](https://github.com/folke/which-key.nvim/issues/64) ([7a1be6f](https://github.com/folke/which-key.nvim/commit/7a1be6ff950c7fb94a4f9e9bdb428a514e569503))\n* highlighting of line number in marks ([9997d93](https://github.com/folke/which-key.nvim/commit/9997d93e5adcf0352aa73c42d3c395ba775600e9))\n* immediately show registers and marks. Fixes [#144](https://github.com/folke/which-key.nvim/issues/144) ([653ce71](https://github.com/folke/which-key.nvim/commit/653ce711e6c27416ac79c4811ff814e9a38fddcf))\n* link default WhichKeyBorder to FloatBorder. Fixes [#331](https://github.com/folke/which-key.nvim/issues/331) ([1698d6d](https://github.com/folke/which-key.nvim/commit/1698d6d0ff0b00b8499d9aea8715d120dc526900))\n* make register selection work in INSERT mode ([d4315f8](https://github.com/folke/which-key.nvim/commit/d4315f8991da816c30e9387a891c02774552dc36))\n* make spelling suggestions also work for correctly spelled words ([d02dc34](https://github.com/folke/which-key.nvim/commit/d02dc344bdaf273dfde7672f3f8e70a307593f62))\n* make sure we never accidentally show WK triggers ([197b4d3](https://github.com/folke/which-key.nvim/commit/197b4d3403c04c0045e8d541e8cd2504aba5f168))\n* make which-key's lazy loading work when it is also lazy-loaded ([7d929b9](https://github.com/folke/which-key.nvim/commit/7d929b96e2588fe9710ad795402eaead1aa0f70f))\n* manual command now uses proper escaping for prefix ([334fcca](https://github.com/folke/which-key.nvim/commit/334fcca64611dbca8c0c669260f4fb2a8ff81509))\n* mapleader=\\ ([b5c8985](https://github.com/folke/which-key.nvim/commit/b5c89851d580459c1dd33ecbda611ae06e22eec4))\n* mapping when right-hand side is `nil` ([#323](https://github.com/folke/which-key.nvim/issues/323)) ([1d449d4](https://github.com/folke/which-key.nvim/commit/1d449d44e01787ef17dc7b0672eec01a8121b36e))\n* never hook in SELECT mode and properly handle v, x, s [#45](https://github.com/folke/which-key.nvim/issues/45) [#46](https://github.com/folke/which-key.nvim/issues/46) ([2844e1c](https://github.com/folke/which-key.nvim/commit/2844e1cbf298129afa58c13a90f91be907232dbf))\n* never hook j and k in INSERT mode automatcally to prevent jk kj &lt;ESC&gt; mappings to work as intended ([9a2faed](https://github.com/folke/which-key.nvim/commit/9a2faed055459d3226634344468f78bf85d77fa8))\n* never hook numbers. locks up due to v:count. Fixes [#118](https://github.com/folke/which-key.nvim/issues/118) ([2d2954a](https://github.com/folke/which-key.nvim/commit/2d2954a1d05b4f074e022e64db9aa6093d439bb0))\n* never hook on &lt;esc&gt; ([fd08322](https://github.com/folke/which-key.nvim/commit/fd0832233bd0c733618fab1c3df92f261c13d6b3))\n* never hook q [#63](https://github.com/folke/which-key.nvim/issues/63) ([95ae9d2](https://github.com/folke/which-key.nvim/commit/95ae9d2d00e8714379e64994e69ae17fc540a7d6))\n* never hook to operators in visual mode [#61](https://github.com/folke/which-key.nvim/issues/61) ([43d799a](https://github.com/folke/which-key.nvim/commit/43d799ad0e6218964e802ff342ca5f9352105175))\n* nil in health check ([5c018ae](https://github.com/folke/which-key.nvim/commit/5c018ae412b235abe17e24b46057564db0944dc4))\n* nvim_win_close force = true ([ca73a0e](https://github.com/folke/which-key.nvim/commit/ca73a0e03f142067a16891b712c7ea73ac646dff))\n* nvim-0.7.0 check ([#338](https://github.com/folke/which-key.nvim/issues/338)) ([1491c35](https://github.com/folke/which-key.nvim/commit/1491c355ec9bb0ec4c8e71c8625bc5f55a54b925))\n* only create mappings for builtin operators. plugings will always have their own mappings ([1b2ec76](https://github.com/folke/which-key.nvim/commit/1b2ec760d65ce9eda473879bec5c31c4771079e7))\n* only enable plugins that are specified in the configuration ([b8ed0e8](https://github.com/folke/which-key.nvim/commit/b8ed0e8e675b747ce21aa830c38ddf4fb2458e05))\n* only show message about existing &lt;leader&gt; mapping in NORMAL mode [#75](https://github.com/folke/which-key.nvim/issues/75) ([bcc8297](https://github.com/folke/which-key.nvim/commit/bcc829775b7d366f61bd2db1753e2c6b3d1ec4d3))\n* only show up/down when scrolling is posible (fixes [#4](https://github.com/folke/which-key.nvim/issues/4)) ([9e7986d](https://github.com/folke/which-key.nvim/commit/9e7986d8726291ee93ef448ae8c452981f1fc75f))\n* override &lt;leader&gt; if it's mapped to <nop> ([928288b](https://github.com/folke/which-key.nvim/commit/928288b543d77c38ade936ee8bdef32a769ebe3a))\n* pass + and * regsiters to feedkeys [#36](https://github.com/folke/which-key.nvim/issues/36) ([ce37f41](https://github.com/folke/which-key.nvim/commit/ce37f41641edb90bf51b975999553d13961ed8fa))\n* pass 0 instead of nil for current buffer ([#227](https://github.com/folke/which-key.nvim/issues/227)) ([387fd67](https://github.com/folke/which-key.nvim/commit/387fd676d3f9b419d38890820f6e262dc0fadb46))\n* passing registers in INSERT mode, is not by pasting them 😅 [#62](https://github.com/folke/which-key.nvim/issues/62) ([342c8cd](https://github.com/folke/which-key.nvim/commit/342c8cdb3651967c96c356eb2d79561c0c9273ee))\n* place popup correctly respecting cmdheight [#28](https://github.com/folke/which-key.nvim/issues/28) ([490e4d5](https://github.com/folke/which-key.nvim/commit/490e4d55315b74c63a63ada89ecf0e660a94db9a))\n* possible nil value in health check ([b1627ca](https://github.com/folke/which-key.nvim/commit/b1627caa25e24c580bbc88377942353875f93a41))\n* possible recursion ([f7fef32](https://github.com/folke/which-key.nvim/commit/f7fef32701aba0a822ac0a82679aea454bec702f))\n* prevent double escaping of key codes ([1676611](https://github.com/folke/which-key.nvim/commit/167661151204ea7da2d365113a76ab223b3dc880))\n* properly escape sequence ([2473329](https://github.com/folke/which-key.nvim/commit/24733293bb7b28f3d98d4a88323eb13cbe5b46f2))\n* properly escape terminal chars to see if we already hooked a trigger ([1bee8a1](https://github.com/folke/which-key.nvim/commit/1bee8a151e72e5738d813964492248c9bbc4c5ba))\n* properly format unicode text in columns (fixes [#66](https://github.com/folke/which-key.nvim/issues/66)) ([e3066fa](https://github.com/folke/which-key.nvim/commit/e3066facb6ed91ac013e4ff8faf24997ed44459c))\n* properly handle &lt; chatracters (should be <lt&gt;) ([e618f84](https://github.com/folke/which-key.nvim/commit/e618f8403e615d4344f2964839ee0e2013b4253e))\n* properly handle &lt; when loading WK [#16](https://github.com/folke/which-key.nvim/issues/16) ([6cf68b4](https://github.com/folke/which-key.nvim/commit/6cf68b49d48f2e07b82aee18ad01c4115d9ce0e5))\n* properly handle &lt;lt&gt; when executing keys (fixes [#16](https://github.com/folke/which-key.nvim/issues/16) again) ([8500ebf](https://github.com/folke/which-key.nvim/commit/8500ebf69e30629fc0e00f4b52afefc0cfe38379))\n* properly handle buffer=0 as the current buffer. Fixes [#91](https://github.com/folke/which-key.nvim/issues/91) ([9ea98e5](https://github.com/folke/which-key.nvim/commit/9ea98e59ddeeafc9181815dd714bea513b298e33))\n* properly handle selected regsiters when executing keys [#36](https://github.com/folke/which-key.nvim/issues/36) ([5248a2d](https://github.com/folke/which-key.nvim/commit/5248a2db7e46803e8d8786f84b05280116cec707))\n* properly parse internal key codes and key notation ([535703c](https://github.com/folke/which-key.nvim/commit/535703cd4f08623e12458b5522be1f4ec2a878e7))\n* redraw after nvim_echo to fix issue with cmdheight=0 ([abcc2c6](https://github.com/folke/which-key.nvim/commit/abcc2c63f723b69c0b31ccacdfddbaf3a03e2c12))\n* registers plugin for visual mode ([86a58ea](https://github.com/folke/which-key.nvim/commit/86a58eac6a3bc69f5aa373b29df993d14fda3307))\n* remove unnecessary replacement of backslash ([#284](https://github.com/folke/which-key.nvim/issues/284)) ([7afe584](https://github.com/folke/which-key.nvim/commit/7afe58460305bc68515858c22d39368bc75984b3))\n* removed debug code ([2f823b8](https://github.com/folke/which-key.nvim/commit/2f823b87293657b5c34cf94a0ef72af02d0117e7))\n* removed feedkeys as typed, since some normal mappings stop working ([e6a63ec](https://github.com/folke/which-key.nvim/commit/e6a63ec73efffdc63ee9da84d8a1dd1cbdff4650))\n* removed triggers_nowait from README since this really only makes sense for plugins ([69fcfff](https://github.com/folke/which-key.nvim/commit/69fcfffe48f859b4192c111756221f967c8876b5))\n* Reset `+` and `*` to default register when clipboard is set ([#233](https://github.com/folke/which-key.nvim/issues/233)) ([8154e65](https://github.com/folke/which-key.nvim/commit/8154e6552ef3188efb6c68d968791ac90e8f2b76))\n* reset op_count when it's 0 ([e3ad7c9](https://github.com/folke/which-key.nvim/commit/e3ad7c92743b9168abbe974100909e7e761bdacd))\n* set noautocmd on the WhichKey window, so it works properly for other floats like Telescope ([36fdfe8](https://github.com/folke/which-key.nvim/commit/36fdfe833207c120997c669a2c51060813f2f8a7))\n* set scheduled instantly ([dc9c3be](https://github.com/folke/which-key.nvim/commit/dc9c3be7acae2a486c117f5a9f6ada62b2243336))\n* show correct level and sort on keys / group ([a372c63](https://github.com/folke/which-key.nvim/commit/a372c63d5551a3656b7fa4388bdaf456d0d2cbb5))\n* show error when setup was not run ([194f788](https://github.com/folke/which-key.nvim/commit/194f788cae6b41fe7edf362b6030237a1c221beb))\n* sort keys case insensitive [#25](https://github.com/folke/which-key.nvim/issues/25) ([e26be8c](https://github.com/folke/which-key.nvim/commit/e26be8c3cb876d634545ed7013c69f45f4e9375c))\n* special handling needed when &lt;leader&gt; = <bslash> [#40](https://github.com/folke/which-key.nvim/issues/40) ([c4a59d7](https://github.com/folke/which-key.nvim/commit/c4a59d76135563ea73beb87cf0d6d7a3302563be))\n* start of visual selection mark should be &lt;lt&gt; instead of < [#69](https://github.com/folke/which-key.nvim/issues/69) ([840311c](https://github.com/folke/which-key.nvim/commit/840311c272eda2c4fc0d92070e9ef2dd13f884e7))\n* typo ([4bacbfd](https://github.com/folke/which-key.nvim/commit/4bacbfdacb9eebee339d36243fe17b9185ccbb74))\n* use buffer instead of bufnr + added warning ([df49a59](https://github.com/folke/which-key.nvim/commit/df49a59efdfd6a90f412aa251914183fec8593af))\n* use Comment as fallback color for the Separator ([7ee35a7](https://github.com/folke/which-key.nvim/commit/7ee35a7614e34e562fd3f815ad35bd6d7e456093))\n* use config.key_labels for cmdline trail as well (Fixes [#108](https://github.com/folke/which-key.nvim/issues/108)) ([1872dd8](https://github.com/folke/which-key.nvim/commit/1872dd8ca9daa0f6478a7771087aedae8518cb97))\n* use mode instead of redraw when cmdheight=0. (Fixes [#327](https://github.com/folke/which-key.nvim/issues/327)) ([c966279](https://github.com/folke/which-key.nvim/commit/c96627900191355e6788629bbf5239d7295221f0))\n* use secret nop bindings to make sure timeoutlen is always respected ([eccd5f8](https://github.com/folke/which-key.nvim/commit/eccd5f8bf22e60620eee833946638b90552c9b69))\n* use strwidth instead of strdisplaywidth ([386591e](https://github.com/folke/which-key.nvim/commit/386591e24afe88c1c52c2291d450e7d7ad9cf02a))\n\n\n### Performance Improvements\n\n* as long as we didnt finish loading, queue registers ([1bac978](https://github.com/folke/which-key.nvim/commit/1bac978464fd00dddbeee9c5584120f553b1a660))\n* defer loading to VimEnter and only process hooks once when ready ([84ddcdc](https://github.com/folke/which-key.nvim/commit/84ddcdcd862c4bb6dcac84a876f66f9777ecef7c))\n* no need to create triggers for all levels. first level that is not a cmd is enough ([3cc0424](https://github.com/folke/which-key.nvim/commit/3cc042498db5792b8f3b081310926c779c7aac07))\n* no need to hook buffer-local if we have a global hook for a certain prefix ([bb5e0d9](https://github.com/folke/which-key.nvim/commit/bb5e0d9be9c73b7d343ff4bf0ffbb9b6b4696811))\n* only load modules when needed ([6f8ae23](https://github.com/folke/which-key.nvim/commit/6f8ae23540bc5f980862d2d5aa6d3c02bb1e2da0))\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "NEWS.md",
    "content": "# 💥 What's New in 3.0?\n\nMajor update for [which-key.nvim](https://github.com/folke/which-key.nvim)! This release includes a complete rewrite and several new features.\n**which-key** was my very first plugin, so it was time for a fresh start. 🎉\n\n- ✨ **Full Rewrite**: Improved performance and functionality.\n- 👀 **Visual & Operator Pending Mode Integration**: Now uses `ModeChanged`, eliminating the need for operator remappings.\n- 🔧 **Simplified Mappings**: Removed obscure secret mappings.\n- 🔒 **Safer Auto Triggers**: Auto triggers are now never created for single keys apart from `g` and `z`. All other letters are unsafe.\n- ⏱️ **Delay**: Set delay independently of `timeoutlen`.\n- 🛠️ **Layout**:\n  - Presets: `classic`, `modern`, and `helix`.\n  - Enable/disable which-key for specific modes.\n  - Configurable sorting with options like `local`, `order`, `group`, `alphanum`, `mod`, `lower`, `icase`, `desc`, and `manual`.\n  - Expand groups with fewer keymaps.\n  - Customizable string replacements for `key` and `desc`.\n- 🎨 **Icon Support**:\n  - Auto-detect icons for keymaps using `lazy.nvim`.\n  - Custom icon rules and specifications for mapping levels.\n- 🚫 **Never Get in the Way**: Avoids overlapping with the cursor.\n- 🗂️ **New Mapping Spec**: New and better mappings spec, more in line with `vim.keymap.set` and how you define keymaps with [lazy.nvim](https://github.com/folke/lazy.nvim)\n- 🐛 New Bugs: Lots of new and exciting bugs to discover! 🐞\n\n## Screenshots\n\n**Classic Mode**\n![image](https://github.com/folke/which-key.nvim/assets/292349/14195bd3-1015-4c44-81c6-4ef8f2410c1b)\n\n**Modern Mode**\n![image](https://github.com/folke/which-key.nvim/assets/292349/842e9311-ded9-458a-bed4-2b12f075c85f)\n\n**Helix Mode**\n![image](https://github.com/folke/which-key.nvim/assets/292349/ca553e0c-e92d-4968-9dce-de91601c5c5c)\n\nFor detailed configuration and usage instructions, refer to the updated README.\n"
  },
  {
    "path": "README.md",
    "content": "# 💥 Which Key\n\n**WhichKey** helps you remember your Neovim keymaps, by showing available keybindings\nin a popup as you type.\n\n![image](https://github.com/user-attachments/assets/89277334-dcdc-4b0f-9fd4-02f27012f589)\n![image](https://github.com/user-attachments/assets/f8d71a75-312e-4a42-add8-d153493b2633)\n![image](https://github.com/user-attachments/assets/e4400a1d-7e71-4439-b6ff-6cbc40647a6f)\n\n## ✨ Features\n\n- 🔍 **Key Binding Help**: show available keybindings in a popup as you type.\n- ⌨️ **Modes**: works in normal, insert, visual, operator pending, terminal and command mode.\n  Every mode can be enabled/disabled.\n- 🛠️ **Customizable Layouts**: choose from `classic`, `modern`, and `helix` presets or customize the window.\n- 🔄 **Flexible Sorting**: sort by `local`, `order`, `group`, `alphanum`, `mod`, `lower`, `icase`, `desc`, or `manual`.\n- 🎨 **Formatting**: customizable key labels and descriptions\n- 🖼️ **Icons**: integrates with [mini.icons](https://github.com/echasnovski/mini.icons) and [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n- ⏱️ **Delay**: delay is independent of `timeoutlen`\n- 🌐 **Plugins**: built-in plugins for marks, registers, presets, and spelling suggestions\n- 🚀 **Operators, Motions, Text Objects**: help for operators, motions and text objects\n- 🐙 **Hydra Mode**: keep the popup open until you hit `<esc>`\n\n## ⚡️ Requirements\n\n- **Neovim** >= 0.9.4\n- for proper icons support:\n  - [mini.icons](https://github.com/echasnovski/mini.icons) _(optional)_\n  - [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons) _(optional)_\n  - a [Nerd Font](https://www.nerdfonts.com/) **_(optional)_**\n\n## 📦 Installation\n\nInstall the plugin with your package manager:\n\n### [lazy.nvim](https://github.com/folke/lazy.nvim)\n\n```lua\n{\n  \"folke/which-key.nvim\",\n  event = \"VeryLazy\",\n  opts = {\n    -- your configuration comes here\n    -- or leave it empty to use the default settings\n    -- refer to the configuration section below\n  },\n  keys = {\n    {\n      \"<leader>?\",\n      function()\n        require(\"which-key\").show({ global = false })\n      end,\n      desc = \"Buffer Local Keymaps (which-key)\",\n    },\n  },\n}\n```\n\n## ⚙️ Configuration\n\n> [!important]\n> Make sure to run `:checkhealth which-key` if something isn't working properly\n\n**WhichKey** is highly configurable. Expand to see the list of all the default options below.\n\n<details><summary>Default Options</summary>\n\n<!-- config:start -->\n\n```lua\n---@class wk.Opts\nlocal defaults = {\n  ---@type false | \"classic\" | \"modern\" | \"helix\"\n  preset = \"classic\",\n  -- Delay before showing the popup. Can be a number or a function that returns a number.\n  ---@type number | fun(ctx: { keys: string, mode: string, plugin?: string }):number\n  delay = function(ctx)\n    return ctx.plugin and 0 or 200\n  end,\n  ---@param mapping wk.Mapping\n  filter = function(mapping)\n    -- example to exclude mappings without a description\n    -- return mapping.desc and mapping.desc ~= \"\"\n    return true\n  end,\n  --- You can add any mappings here, or use `require('which-key').add()` later\n  ---@type wk.Spec\n  spec = {},\n  -- show a warning when issues were detected with your mappings\n  notify = true,\n  -- Which-key automatically sets up triggers for your mappings.\n  -- But you can disable this and setup the triggers manually.\n  -- Check the docs for more info.\n  ---@type wk.Spec\n  triggers = {\n    { \"<auto>\", mode = \"nxso\" },\n  },\n  -- Start hidden and wait for a key to be pressed before showing the popup\n  -- Only used by enabled xo mapping modes.\n  ---@param ctx { mode: string, operator: string }\n  defer = function(ctx)\n    return ctx.mode == \"V\" or ctx.mode == \"<C-V>\"\n  end,\n  plugins = {\n    marks = true, -- shows a list of your marks on ' and `\n    registers = true, -- shows your registers on \" in NORMAL or <C-r> in INSERT mode\n    -- the presets plugin, adds help for a bunch of default keybindings in Neovim\n    -- No actual key bindings are created\n    spelling = {\n      enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions\n      suggestions = 20, -- how many suggestions should be shown in the list?\n    },\n    presets = {\n      operators = true, -- adds help for operators like d, y, ...\n      motions = true, -- adds help for motions\n      text_objects = true, -- help for text objects triggered after entering an operator\n      windows = true, -- default bindings on <c-w>\n      nav = true, -- misc bindings to work with windows\n      z = true, -- bindings for folds, spelling and others prefixed with z\n      g = true, -- bindings for prefixed with g\n    },\n  },\n  ---@type wk.Win.opts\n  win = {\n    -- don't allow the popup to overlap with the cursor\n    no_overlap = true,\n    -- width = 1,\n    -- height = { min = 4, max = 25 },\n    -- col = 0,\n    -- row = math.huge,\n    -- border = \"none\",\n    padding = { 1, 2 }, -- extra window padding [top/bottom, right/left]\n    title = true,\n    title_pos = \"center\",\n    zindex = 1000,\n    -- Additional vim.wo and vim.bo options\n    bo = {},\n    wo = {\n      -- winblend = 10, -- value between 0-100 0 for fully opaque and 100 for fully transparent\n    },\n  },\n  layout = {\n    width = { min = 20 }, -- min and max width of the columns\n    spacing = 3, -- spacing between columns\n  },\n  keys = {\n    scroll_down = \"<c-d>\", -- binding to scroll down inside the popup\n    scroll_up = \"<c-u>\", -- binding to scroll up inside the popup\n  },\n  ---@type (string|wk.Sorter)[]\n  --- Mappings are sorted using configured sorters and natural sort of the keys\n  --- Available sorters:\n  --- * local: buffer-local mappings first\n  --- * order: order of the items (Used by plugins like marks / registers)\n  --- * group: groups last\n  --- * alphanum: alpha-numerical first\n  --- * mod: special modifier keys last\n  --- * manual: the order the mappings were added\n  --- * case: lower-case first\n  sort = { \"local\", \"order\", \"group\", \"alphanum\", \"mod\" },\n  ---@type number|fun(node: wk.Node):boolean?\n  expand = 0, -- expand groups when <= n mappings\n  -- expand = function(node)\n  --   return not node.desc -- expand all nodes without a description\n  -- end,\n  -- Functions/Lua Patterns for formatting the labels\n  ---@type table<string, ({[1]:string, [2]:string}|fun(str:string):string)[]>\n  replace = {\n    key = {\n      function(key)\n        return require(\"which-key.view\").format(key)\n      end,\n      -- { \"<Space>\", \"SPC\" },\n    },\n    desc = {\n      { \"<Plug>%(?(.*)%)?\", \"%1\" },\n      { \"^%+\", \"\" },\n      { \"<[cC]md>\", \"\" },\n      { \"<[cC][rR]>\", \"\" },\n      { \"<[sS]ilent>\", \"\" },\n      { \"^lua%s+\", \"\" },\n      { \"^call%s+\", \"\" },\n      { \"^:%s*\", \"\" },\n    },\n  },\n  icons = {\n    breadcrumb = \"»\", -- symbol used in the command line area that shows your active key combo\n    separator = \"➜\", -- symbol used between a key and it's label\n    group = \"+\", -- symbol prepended to a group\n    ellipsis = \"…\",\n    -- set to false to disable all mapping icons,\n    -- both those explicitly added in a mapping\n    -- and those from rules\n    mappings = true,\n    --- See `lua/which-key/icons.lua` for more details\n    --- Set to `false` to disable keymap icons from rules\n    ---@type wk.IconRule[]|false\n    rules = {},\n    -- use the highlights from mini.icons\n    -- When `false`, it will use `WhichKeyIcon` instead\n    colors = true,\n    -- used by key format\n    keys = {\n      Up = \" \",\n      Down = \" \",\n      Left = \" \",\n      Right = \" \",\n      C = \"󰘴 \",\n      M = \"󰘵 \",\n      D = \"󰘳 \",\n      S = \"󰘶 \",\n      CR = \"󰌑 \",\n      Esc = \"󱊷 \",\n      ScrollWheelDown = \"󱕐 \",\n      ScrollWheelUp = \"󱕑 \",\n      NL = \"󰌑 \",\n      BS = \"󰁮\",\n      Space = \"󱁐 \",\n      Tab = \"󰌒 \",\n      F1 = \"󱊫\",\n      F2 = \"󱊬\",\n      F3 = \"󱊭\",\n      F4 = \"󱊮\",\n      F5 = \"󱊯\",\n      F6 = \"󱊰\",\n      F7 = \"󱊱\",\n      F8 = \"󱊲\",\n      F9 = \"󱊳\",\n      F10 = \"󱊴\",\n      F11 = \"󱊵\",\n      F12 = \"󱊶\",\n    },\n  },\n  show_help = true, -- show a help message in the command line for using WhichKey\n  show_keys = true, -- show the currently pressed key and its label as a message in the command line\n  -- disable WhichKey for certain buf types and file types.\n  disable = {\n    ft = {},\n    bt = {},\n  },\n  debug = false, -- enable wk.log in the current directory\n}\n```\n\n<!-- config:end -->\n\n</details>\n\n## ⌨️ Mappings\n\n**WhichKey** automatically gets the descriptions of your keymaps from the `desc`\nattribute of the keymap. So for most use-cases, you don't need to do anything else.\n\nHowever, the **mapping spec** is still useful to configure group descriptions and mappings that don't really exist as a regular keymap.\n\n> [!WARNING]\n> The **mappings spec** changed in `v3`, so make sure to only use the new `add` method if\n> you updated your existing mappings.\n\nMappings can be added as part of the config `opts.spec`, or can be added later\nusing `require(\"which-key\").add()`.\n`wk.add()` can be called multiple times from anywhere in your config files.\n\nA mapping has the following attributes:\n\n- **[1]**: (`string`) lhs **_(required)_**\n- **[2]**: (`string|fun()`) rhs **_(optional)_**: when present, it will create the mapping\n- **desc**: (`string|fun():string`) description **_(required for non-groups)_**\n- **group**: (`string|fun():string`) group name **_(optional)_**\n- **mode**: (`string|string[]`) mode **_(optional, defaults to `\"n\"`)_**\n- **cond**: (`boolean|fun():boolean`) condition to enable the mapping **_(optional)_**\n- **hidden**: (`boolean`) hide the mapping **_(optional)_**\n- **icon**: (`string|wk.Icon|fun():(wk.Icon|string)`) icon spec **_(optional)_**\n- **proxy**: (`string`) proxy to another mapping **_(optional)_**\n- **expand**: (`fun():wk.Spec`) nested mappings **_(optional)_**\n- any other option valid for `vim.keymap.set`. These are only used for creating mappings.\n\nWhen `desc`, `group`, or `icon` are functions, they are evaluated every time\nthe popup is shown.\n\nThe `expand` property allows to create dynamic mappings. Only functions as `rhs` are supported for dynamic mappings.\nTwo examples are included in `which-key.extras`:\n\n- `require(\"which-key.extras\").expand.buf`: creates numerical key to buffer mappings\n- `require(\"which-key.extras\").expand.win`: creates numerical key to window mappings\n\n```lua\nlocal wk = require(\"which-key\")\nwk.add({\n  { \"<leader>f\", group = \"file\" }, -- group\n  { \"<leader>ff\", \"<cmd>Telescope find_files<cr>\", desc = \"Find File\", mode = \"n\" },\n  { \"<leader>fb\", function() print(\"hello\") end, desc = \"Foobar\" },\n  { \"<leader>fn\", desc = \"New File\" },\n  { \"<leader>f1\", hidden = true }, -- hide this keymap\n  { \"<leader>w\", proxy = \"<c-w>\", group = \"windows\" }, -- proxy to window mappings\n  { \"<leader>b\", group = \"buffers\", expand = function()\n      return require(\"which-key.extras\").expand.buf()\n    end\n  },\n  {\n    -- Nested mappings are allowed and can be added in any order\n    -- Most attributes can be inherited or overridden on any level\n    -- There's no limit to the depth of nesting\n    mode = { \"n\", \"v\" }, -- NORMAL and VISUAL mode\n    { \"<leader>q\", \"<cmd>q<cr>\", desc = \"Quit\" }, -- no need to specify mode since it's inherited\n    { \"<leader>w\", \"<cmd>w<cr>\", desc = \"Write\" },\n  }\n})\n```\n\n## 🎯 Triggers\n\nThere's two ways that **which-key** can be triggered:\n\n- by a trigger keymap\n- by a `ModeChanged` event for visual and operator pending mode\n\nBoth can be configured using `opts.triggers` and `opts.defer`.\n\nBy default `opts.triggers` includes `{ \"<auto>\", mode = \"nixsotc\" }`, which\nwill setup keymap triggers for every mode automatically and will trigger during\n`ModeChanged`.\n\n> [!NOTE]\n> Auto triggers will never be created for existing keymaps.\n> That includes every valid single key Neovim builtin mapping.\n> If you want to trigger on a builtin keymap, you have to add it manually.\n>\n> ```lua\n>  triggers = {\n>    { \"<auto>\", mode = \"nixsotc\" },\n>    { \"a\", mode = { \"n\", \"v\" } },\n>  }\n> ```\n\n> [!TIP]\n> To manually setup triggers, you can set `opts.triggers` to:\n>\n> ```lua\n>  triggers = {\n>    { \"<leader>\", mode = { \"n\", \"v\" } },\n>  }\n> ```\n\nFor `ModeChanged` triggers, you can configure the `opts.defer` option.\nWhen it returns `true`, the popup will be shown only after an additional key is pressed.\nSo `yaf`, would show which-key after pressing `ya`, but not after `y`.\n\n> [!TIP]\n> Defer some operators:\n>\n> ```lua\n> ---@param ctx { mode: string, operator: string }\n> defer = function(ctx)\n>   if vim.list_contains({ \"d\", \"y\" }, ctx.operator) then\n>     return true\n>   end\n>   return vim.list_contains({ \"<C-V>\", \"V\" }, ctx.mode)\n> end,\n> ```\n\n## 🎨 Icons\n\n> [!note]\n> For full support, you need to install either [mini.icons](https://github.com/echasnovski/mini.icons) or [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)\n\nThere's multiple ways to set icons for your keymaps:\n\n- if you use lazy.nvim, then some icons will be autodetected for keymaps belonging to certain plugins.\n- custom rules to decide what icon to use\n- in your mapping spec, you can specify what icon to use at any level, so at the node for `<leader>g` for example, to apply to all git keymaps.\n\nThe `icon` attribute of a mapping can be a `string`, which will be used as the actual icon,\nor an `wk.Icon` object, which can have the following attributes:\n\n- `icon` (`string`): the icon to use **_(optional)_**\n- `hl` (`string`): the highlight group to use for the icon **_(optional)_**\n- `color` (`string`): the color to use for the icon **_(optional)_**\n  valid colors are: `azure`, `blue`, `cyan`, `green`, `grey`, `orange`, `purple`, `red`, `yellow`\n- `cat` (`string`): the category of the icon **_(optional)_**\n  valid categories are: `file`, `filetype`, `extension`\n- `name` (`string`): the name of the icon in the specified category **_(optional)_**\n\n> [!TIP]\n> If you'd rather not use icons, you can disable them\n> by setting `opts.icons.mappings` to `false`.\n\n## 🚀 Usage\n\nWhen the **WhichKey** popup is open, you can use the following key bindings (they are also displayed at the bottom of the screen):\n\n- hit one of the keys to open a group or execute a key binding\n- `<esc>` to cancel and close the popup\n- `<bs>` go up one level\n- `<c-d>` scroll down\n- `<c-u>` scroll up\n\n## 🐙 Hydra Mode\n\nHydra mode is a special mode that keeps the popup open until you hit `<esc>`.\n\n```lua\n-- Show hydra mode for changing windows\nrequire(\"which-key\").show({\n  keys = \"<c-w>\",\n  loop = true, -- this will keep the popup open until you hit <esc>\n})\n```\n\n## 🔥 Plugins\n\nFour built-in plugins are included with **WhichKey**.\n\n### Presets\n\nBuilt-in key binding help for `motions`, `text-objects`, `operators`, `windows`, `nav`, `z` and `g` and more.\n\n### Marks\n\nShows a list of your buffer local and global marks when you hit \\` or '\n\n![image](https://github.com/user-attachments/assets/43fb0874-7f79-4521-aee9-03e2b0841758)\n\n### Registers\n\nShows a list of your buffer local and global registers when you hit \" in _NORMAL_ mode, or `<c-r>` in _INSERT_ mode.\n\n![image](https://github.com/user-attachments/assets/d8077dcb-56fb-47b0-ad9e-1aba5db16950)\n\n### Spelling\n\nWhen enabled, this plugin hooks into `z=` and replaces the full-screen spelling suggestions window by a list of suggestions within **WhichKey**.\n\n![image](https://github.com/user-attachments/assets/102c7963-329a-40b9-b0a8-72c8656318b7)\n\n## 🎨 Colors\n\nThe table below shows all the highlight groups defined for **WhichKey** with their default link.\n\n<!-- colors:start -->\n\n| Highlight Group | Default Group | Description |\n| --- | --- | --- |\n| **WhichKey** | ***Function*** |  |\n| **WhichKeyBorder** | ***FloatBorder*** | Border of the which-key window |\n| **WhichKeyDesc** | ***Identifier*** | description |\n| **WhichKeyGroup** | ***Keyword*** | group name |\n| **WhichKeyIcon** | ***@markup.link*** | icons |\n| **WhichKeyIconAzure** | ***Function*** |  |\n| **WhichKeyIconBlue** | ***DiagnosticInfo*** |  |\n| **WhichKeyIconCyan** | ***DiagnosticHint*** |  |\n| **WhichKeyIconGreen** | ***DiagnosticOk*** |  |\n| **WhichKeyIconGrey** | ***Normal*** |  |\n| **WhichKeyIconOrange** | ***DiagnosticWarn*** |  |\n| **WhichKeyIconPurple** | ***Constant*** |  |\n| **WhichKeyIconRed** | ***DiagnosticError*** |  |\n| **WhichKeyIconYellow** | ***DiagnosticWarn*** |  |\n| **WhichKeyNormal** | ***NormalFloat*** | Normal in th which-key window |\n| **WhichKeySeparator** | ***Comment*** | the separator between the key and its description |\n| **WhichKeyTitle** | ***FloatTitle*** | Title of the which-key window |\n| **WhichKeyValue** | ***Comment*** | values by plugins (like marks, registers, etc) |\n\n<!-- colors:end -->\n"
  },
  {
    "path": "TODO.md",
    "content": "# Todo\n\n- [x] create keymaps in register()\n- [x] distinction between actual keymap and just a desc\n- [x] virtual mappings wihtout real children?\n- [x] registers / counts?\n- [x] presets / plugins\n- [x] config?\n- [x] auto blacklist single keys for default keymaps (for mappings like `aa`, a hook would be created for `a` and `a` would be ignored)\n- [x] custom sorting\n- [x] gr doesn't work because of grn and friends\n- [x] same for gc opmode and gc normal mode\n- [x] yank and shift-paste hangs\n- [x] macro recording / macro execution\n- [x] spell\n- [x] spell with count, like `1z=`\n- [x] which-key-ignore\n- [x] empty groups?\n- [x] timeoutlen and nowait\n- [x] ui presets\n- [x] ui opts & columns etc\n- [x] scroll window\n- [x] help text?\n- [x] plugin layout?\n- [x] ✅ 🔥🔥🚀\n- [x] minimize attach\n- [x] sometimes incorrectly attached `gcc` not working\n- [x] error handling for view\n- [x] spelling layout\n- [x] better mappings parser? Especially needs typings\n- [x] Mappings with mode `v`\n- [x] allow register from opts\n- [x] auto gen docs\n- [x] health\n- [x] `<leader>gh_`\n- [x] devicons support\n- [x] nowait, timeoutlen and delay\n- [x] new mappings DSL\n- [x] News\n- [x] normal mode mappings in terminal mode?\n- [x] dynamic size\n- [x] situation with visual mode\n- [x] fix timeoutlen\n- [x] document hydra mode\n- [x] floating help text?\n- [x] move old option check to checkhealth\n- [x] show scrolling hint when can't fit all mappings\n- [ ] more tests\n- [ ] hint characters in desc\n- [ ] intgerate with lazy.nvim. Get description there if set\n"
  },
  {
    "path": "doc/which-key.nvim.txt",
    "content": "*which-key.nvim.txt*                                       which-key.nvim docs\n\n==============================================================================\nTable of Contents                           *which-key.nvim-table-of-contents*\n\n1. Which Key                                        |which-key.nvim-which-key|\n  - Features                               |which-key.nvim-which-key-features|\n  - Requirements                       |which-key.nvim-which-key-requirements|\n  - Installation                       |which-key.nvim-which-key-installation|\n  - Configuration                     |which-key.nvim-which-key-configuration|\n  - Mappings                               |which-key.nvim-which-key-mappings|\n  - Triggers                               |which-key.nvim-which-key-triggers|\n  - Icons                                     |which-key.nvim-which-key-icons|\n  - Usage                                     |which-key.nvim-which-key-usage|\n  - Hydra Mode                           |which-key.nvim-which-key-hydra-mode|\n  - Plugins                                 |which-key.nvim-which-key-plugins|\n  - Colors                                   |which-key.nvim-which-key-colors|\n2. Links                                                |which-key.nvim-links|\n\n==============================================================================\n1. Which Key                                        *which-key.nvim-which-key*\n\n**WhichKey** helps you remember your Neovim keymaps, by showing available\nkeybindings in a popup as you type.\n\n\n\n\nFEATURES                                   *which-key.nvim-which-key-features*\n\n- **Key Binding Help**: show available keybindings in a popup as you type.\n- **Modes**: works in normal, insert, visual, operator pending, terminal and command mode.\n    Every mode can be enabled/disabled.\n- **Customizable Layouts**: choose from `classic`, `modern`, and `helix` presets or customize the window.\n- **Flexible Sorting**: sort by `local`, `order`, `group`, `alphanum`, `mod`, `lower`, `icase`, `desc`, or `manual`.\n- **Formatting**: customizable key labels and descriptions\n- **Icons**: integrates with mini.icons <https://github.com/echasnovski/mini.icons> and nvim-web-devicons <https://github.com/nvim-tree/nvim-web-devicons>\n- **Delay**: delay is independent of `timeoutlen`\n- **Plugins**: built-in plugins for marks, registers, presets, and spelling suggestions\n- **Operators, Motions, Text Objects**: help for operators, motions and text objects\n- **Hydra Mode**: keep the popup open until you hit `<esc>`\n\n\nREQUIREMENTS                           *which-key.nvim-which-key-requirements*\n\n- **Neovim** >= 0.9.4\n- for proper icons support:\n    - mini.icons <https://github.com/echasnovski/mini.icons> _(optional)_\n    - nvim-web-devicons <https://github.com/nvim-tree/nvim-web-devicons> _(optional)_\n    - a Nerd Font <https://www.nerdfonts.com/> **(optional)**\n\n\nINSTALLATION                           *which-key.nvim-which-key-installation*\n\nInstall the plugin with your package manager:\n\n\nLAZY.NVIM ~\n\n>lua\n    {\n      \"folke/which-key.nvim\",\n      event = \"VeryLazy\",\n      opts = {\n        -- your configuration comes here\n        -- or leave it empty to use the default settings\n        -- refer to the configuration section below\n      },\n      keys = {\n        {\n          \"<leader>?\",\n          function()\n            require(\"which-key\").show({ global = false })\n          end,\n          desc = \"Buffer Local Keymaps (which-key)\",\n        },\n      },\n    }\n<\n\n\nCONFIGURATION                         *which-key.nvim-which-key-configuration*\n\n\n  [!important] Make sure to run `:checkhealth which-key` if something isn’t\n  working properly\n**WhichKey** is highly configurable. Expand to see the list of all the default\noptions below.\n\nDefault Options ~\n\n>lua\n    ---@class wk.Opts\n    local defaults = {\n      ---@type false | \"classic\" | \"modern\" | \"helix\"\n      preset = \"classic\",\n      -- Delay before showing the popup. Can be a number or a function that returns a number.\n      ---@type number | fun(ctx: { keys: string, mode: string, plugin?: string }):number\n      delay = function(ctx)\n        return ctx.plugin and 0 or 200\n      end,\n      ---@param mapping wk.Mapping\n      filter = function(mapping)\n        -- example to exclude mappings without a description\n        -- return mapping.desc and mapping.desc ~= \"\"\n        return true\n      end,\n      --- You can add any mappings here, or use `require('which-key').add()` later\n      ---@type wk.Spec\n      spec = {},\n      -- show a warning when issues were detected with your mappings\n      notify = true,\n      -- Which-key automatically sets up triggers for your mappings.\n      -- But you can disable this and setup the triggers manually.\n      -- Check the docs for more info.\n      ---@type wk.Spec\n      triggers = {\n        { \"<auto>\", mode = \"nxso\" },\n      },\n      -- Start hidden and wait for a key to be pressed before showing the popup\n      -- Only used by enabled xo mapping modes.\n      ---@param ctx { mode: string, operator: string }\n      defer = function(ctx)\n        return ctx.mode == \"V\" or ctx.mode == \"<C-V>\"\n      end,\n      plugins = {\n        marks = true, -- shows a list of your marks on ' and `\n        registers = true, -- shows your registers on \" in NORMAL or <C-r> in INSERT mode\n        -- the presets plugin, adds help for a bunch of default keybindings in Neovim\n        -- No actual key bindings are created\n        spelling = {\n          enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions\n          suggestions = 20, -- how many suggestions should be shown in the list?\n        },\n        presets = {\n          operators = true, -- adds help for operators like d, y, ...\n          motions = true, -- adds help for motions\n          text_objects = true, -- help for text objects triggered after entering an operator\n          windows = true, -- default bindings on <c-w>\n          nav = true, -- misc bindings to work with windows\n          z = true, -- bindings for folds, spelling and others prefixed with z\n          g = true, -- bindings for prefixed with g\n        },\n      },\n      ---@type wk.Win.opts\n      win = {\n        -- don't allow the popup to overlap with the cursor\n        no_overlap = true,\n        -- width = 1,\n        -- height = { min = 4, max = 25 },\n        -- col = 0,\n        -- row = math.huge,\n        -- border = \"none\",\n        padding = { 1, 2 }, -- extra window padding [top/bottom, right/left]\n        title = true,\n        title_pos = \"center\",\n        zindex = 1000,\n        -- Additional vim.wo and vim.bo options\n        bo = {},\n        wo = {\n          -- winblend = 10, -- value between 0-100 0 for fully opaque and 100 for fully transparent\n        },\n      },\n      layout = {\n        width = { min = 20 }, -- min and max width of the columns\n        spacing = 3, -- spacing between columns\n      },\n      keys = {\n        scroll_down = \"<c-d>\", -- binding to scroll down inside the popup\n        scroll_up = \"<c-u>\", -- binding to scroll up inside the popup\n      },\n      ---@type (string|wk.Sorter)[]\n      --- Mappings are sorted using configured sorters and natural sort of the keys\n      --- Available sorters:\n      --- * local: buffer-local mappings first\n      --- * order: order of the items (Used by plugins like marks / registers)\n      --- * group: groups last\n      --- * alphanum: alpha-numerical first\n      --- * mod: special modifier keys last\n      --- * manual: the order the mappings were added\n      --- * case: lower-case first\n      sort = { \"local\", \"order\", \"group\", \"alphanum\", \"mod\" },\n      ---@type number|fun(node: wk.Node):boolean?\n      expand = 0, -- expand groups when <= n mappings\n      -- expand = function(node)\n      --   return not node.desc -- expand all nodes without a description\n      -- end,\n      -- Functions/Lua Patterns for formatting the labels\n      ---@type table<string, ({[1]:string, [2]:string}|fun(str:string):string)[]>\n      replace = {\n        key = {\n          function(key)\n            return require(\"which-key.view\").format(key)\n          end,\n          -- { \"<Space>\", \"SPC\" },\n        },\n        desc = {\n          { \"<Plug>%(?(.*)%)?\", \"%1\" },\n          { \"^%+\", \"\" },\n          { \"<[cC]md>\", \"\" },\n          { \"<[cC][rR]>\", \"\" },\n          { \"<[sS]ilent>\", \"\" },\n          { \"^lua%s+\", \"\" },\n          { \"^call%s+\", \"\" },\n          { \"^:%s*\", \"\" },\n        },\n      },\n      icons = {\n        breadcrumb = \"»\", -- symbol used in the command line area that shows your active key combo\n        separator = \"➜\", -- symbol used between a key and it's label\n        group = \"+\", -- symbol prepended to a group\n        ellipsis = \"…\",\n        -- set to false to disable all mapping icons,\n        -- both those explicitly added in a mapping\n        -- and those from rules\n        mappings = true,\n        --- See `lua/which-key/icons.lua` for more details\n        --- Set to `false` to disable keymap icons from rules\n        ---@type wk.IconRule[]|false\n        rules = {},\n        -- use the highlights from mini.icons\n        -- When `false`, it will use `WhichKeyIcon` instead\n        colors = true,\n        -- used by key format\n        keys = {\n          Up = \" \",\n          Down = \" \",\n          Left = \" \",\n          Right = \" \",\n          C = \"󰘴 \",\n          M = \"󰘵 \",\n          D = \"󰘳 \",\n          S = \"󰘶 \",\n          CR = \"󰌑 \",\n          Esc = \"󱊷 \",\n          ScrollWheelDown = \"󱕐 \",\n          ScrollWheelUp = \"󱕑 \",\n          NL = \"󰌑 \",\n          BS = \"󰁮\",\n          Space = \"󱁐 \",\n          Tab = \"󰌒 \",\n          F1 = \"󱊫\",\n          F2 = \"󱊬\",\n          F3 = \"󱊭\",\n          F4 = \"󱊮\",\n          F5 = \"󱊯\",\n          F6 = \"󱊰\",\n          F7 = \"󱊱\",\n          F8 = \"󱊲\",\n          F9 = \"󱊳\",\n          F10 = \"󱊴\",\n          F11 = \"󱊵\",\n          F12 = \"󱊶\",\n        },\n      },\n      show_help = true, -- show a help message in the command line for using WhichKey\n      show_keys = true, -- show the currently pressed key and its label as a message in the command line\n      -- disable WhichKey for certain buf types and file types.\n      disable = {\n        ft = {},\n        bt = {},\n      },\n      debug = false, -- enable wk.log in the current directory\n    }\n<\n\n\nMAPPINGS                                   *which-key.nvim-which-key-mappings*\n\n**WhichKey** automatically gets the descriptions of your keymaps from the\n`desc` attribute of the keymap. So for most use-cases, you don’t need to do\nanything else.\n\nHowever, the **mapping spec** is still useful to configure group descriptions\nand mappings that don’t really exist as a regular keymap.\n\n\n  [!WARNING] The **mappings spec** changed in `v3`, so make sure to only use the\n  new `add` method if you updated your existing mappings.\nMappings can be added as part of the config `opts.spec`, or can be added later\nusing `require(\"which-key\").add()`. `wk.add()` can be called multiple times\nfrom anywhere in your config files.\n\nA mapping has the following attributes:\n\n- **[1]**: (`string`) lhs **(required)**\n- **[2]**: (`string|fun()`) rhs **(optional)**: when present, it will create the mapping\n- **desc**: (`string|fun():string`) description **(required for non-groups)**\n- **group**: (`string|fun():string`) group name **(optional)**\n- **mode**: (`string|string[]`) mode **(optional, defaults to \"n\")**\n- **cond**: (`boolean|fun():boolean`) condition to enable the mapping **(optional)**\n- **hidden**: (`boolean`) hide the mapping **(optional)**\n- **icon**: (`string|wk.Icon|fun():(wk.Icon|string)`) icon spec **(optional)**\n- **proxy**: (`string`) proxy to another mapping **(optional)**\n- **expand**: (`fun():wk.Spec`) nested mappings **(optional)**\n- any other option valid for `vim.keymap.set`. These are only used for creating mappings.\n\nWhen `desc`, `group`, or `icon` are functions, they are evaluated every time\nthe popup is shown.\n\nThe `expand` property allows to create dynamic mappings. Only functions as\n`rhs` are supported for dynamic mappings. Two examples are included in\n`which-key.extras`:\n\n- `require(\"which-key.extras\").expand.buf`: creates numerical key to buffer mappings\n- `require(\"which-key.extras\").expand.win`: creates numerical key to window mappings\n\n>lua\n    local wk = require(\"which-key\")\n    wk.add({\n      { \"<leader>f\", group = \"file\" }, -- group\n      { \"<leader>ff\", \"<cmd>Telescope find_files<cr>\", desc = \"Find File\", mode = \"n\" },\n      { \"<leader>fb\", function() print(\"hello\") end, desc = \"Foobar\" },\n      { \"<leader>fn\", desc = \"New File\" },\n      { \"<leader>f1\", hidden = true }, -- hide this keymap\n      { \"<leader>w\", proxy = \"<c-w>\", group = \"windows\" }, -- proxy to window mappings\n      { \"<leader>b\", group = \"buffers\", expand = function()\n          return require(\"which-key.extras\").expand.buf()\n        end\n      },\n      {\n        -- Nested mappings are allowed and can be added in any order\n        -- Most attributes can be inherited or overridden on any level\n        -- There's no limit to the depth of nesting\n        mode = { \"n\", \"v\" }, -- NORMAL and VISUAL mode\n        { \"<leader>q\", \"<cmd>q<cr>\", desc = \"Quit\" }, -- no need to specify mode since it's inherited\n        { \"<leader>w\", \"<cmd>w<cr>\", desc = \"Write\" },\n      }\n    })\n<\n\n\nTRIGGERS                                   *which-key.nvim-which-key-triggers*\n\nThere’s two ways that **which-key** can be triggered:\n\n- by a trigger keymap\n- by a `ModeChanged` event for visual and operator pending mode\n\nBoth can be configured using `opts.triggers` and `opts.defer`.\n\nBy default `opts.triggers` includes `{ \"<auto>\", mode = \"nixsotc\" }`, which\nwill setup keymap triggers for every mode automatically and will trigger during\n`ModeChanged`.\n\n\n  [!NOTE] Auto triggers will never be created for existing keymaps. That includes\n  every valid single key Neovim builtin mapping. If you want to trigger on a\n  builtin keymap, you have to add it manually.\n  >lua\n       triggers = {\n         { \"<auto>\", mode = \"nixsotc\" },\n         { \"a\", mode = { \"n\", \"v\" } },\n       }\n  <\n\n  [!TIP] To manually setup triggers, you can set `opts.triggers` to:\n  >lua\n       triggers = {\n         { \"<leader>\", mode = { \"n\", \"v\" } },\n       }\n  <\nFor `ModeChanged` triggers, you can configure the `opts.defer` option. When it\nreturns `true`, the popup will be shown only after an additional key is\npressed. So `yaf`, would show which-key after pressing `ya`, but not after `y`.\n\n\n  [!TIP] Defer some operators:\n  >lua\n      ---@param ctx { mode: string, operator: string }\n      defer = function(ctx)\n        if vim.list_contains({ \"d\", \"y\" }, ctx.operator) then\n          return true\n        end\n        return vim.list_contains({ \"<C-V>\", \"V\" }, ctx.mode)\n      end,\n  <\n\nICONS                                         *which-key.nvim-which-key-icons*\n\n\n  [!note] For full support, you need to install either mini.icons\n  <https://github.com/echasnovski/mini.icons> or nvim-web-devicons\n  <https://github.com/nvim-tree/nvim-web-devicons>\nThere’s multiple ways to set icons for your keymaps:\n\n- if you use lazy.nvim, then some icons will be autodetected for keymaps belonging to certain plugins.\n- custom rules to decide what icon to use\n- in your mapping spec, you can specify what icon to use at any level, so at the node for `<leader>g` for example, to apply to all git keymaps.\n\nThe `icon` attribute of a mapping can be a `string`, which will be used as the\nactual icon, or an `wk.Icon` object, which can have the following attributes:\n\n- `icon` (`string`): the icon to use **(optional)**\n- `hl` (`string`): the highlight group to use for the icon **(optional)**\n- `color` (`string`): the color to use for the icon **(optional)**\n    valid colors are: `azure`, `blue`, `cyan`, `green`, `grey`, `orange`, `purple`, `red`, `yellow`\n- `cat` (`string`): the category of the icon **(optional)**\n    valid categories are: `file`, `filetype`, `extension`\n- `name` (`string`): the name of the icon in the specified category **(optional)**\n\n\n  [!TIP] If you’d rather not use icons, you can disable them by setting\n  `opts.icons.mappings` to `false`.\n\nUSAGE                                         *which-key.nvim-which-key-usage*\n\nWhen the **WhichKey** popup is open, you can use the following key bindings\n(they are also displayed at the bottom of the screen):\n\n- hit one of the keys to open a group or execute a key binding\n- `<esc>` to cancel and close the popup\n- `<bs>` go up one level\n- `<c-d>` scroll down\n- `<c-u>` scroll up\n\n\nHYDRA MODE                               *which-key.nvim-which-key-hydra-mode*\n\nHydra mode is a special mode that keeps the popup open until you hit `<esc>`.\n\n>lua\n    -- Show hydra mode for changing windows\n    require(\"which-key\").show({\n      keys = \"<c-w>\",\n      loop = true, -- this will keep the popup open until you hit <esc>\n    })\n<\n\n\nPLUGINS                                     *which-key.nvim-which-key-plugins*\n\nFour built-in plugins are included with **WhichKey**.\n\n\nPRESETS ~\n\nBuilt-in key binding help for `motions`, `text-objects`, `operators`,\n`windows`, `nav`, `z` and `g` and more.\n\n\nMARKS ~\n\nShows a list of your buffer local and global marks when you hit ` or ’\n\n\nREGISTERS ~\n\nShows a list of your buffer local and global registers when you hit ” in\n_NORMAL_ mode, or `<c-r>` in _INSERT_ mode.\n\n\nSPELLING ~\n\nWhen enabled, this plugin hooks into `z=` and replaces the full-screen spelling\nsuggestions window by a list of suggestions within **WhichKey**.\n\n\nCOLORS                                       *which-key.nvim-which-key-colors*\n\nThe table below shows all the highlight groups defined for **WhichKey** with\ntheir default link.\n\n  -----------------------------------------------------------------------\n  Highlight Group         Default Group           Description\n  ----------------------- ----------------------- -----------------------\n  WhichKey                Function                \n\n  WhichKeyBorder          FloatBorder             Border of the which-key\n                                                  window\n\n  WhichKeyDesc            Identifier              description\n\n  WhichKeyGroup           Keyword                 group name\n\n  WhichKeyIcon            @markup.link            icons\n\n  WhichKeyIconAzure       Function                \n\n  WhichKeyIconBlue        DiagnosticInfo          \n\n  WhichKeyIconCyan        DiagnosticHint          \n\n  WhichKeyIconGreen       DiagnosticOk            \n\n  WhichKeyIconGrey        Normal                  \n\n  WhichKeyIconOrange      DiagnosticWarn          \n\n  WhichKeyIconPurple      Constant                \n\n  WhichKeyIconRed         DiagnosticError         \n\n  WhichKeyIconYellow      DiagnosticWarn          \n\n  WhichKeyNormal          NormalFloat             Normal in th which-key\n                                                  window\n\n  WhichKeySeparator       Comment                 the separator between\n                                                  the key and its\n                                                  description\n\n  WhichKeyTitle           FloatTitle              Title of the which-key\n                                                  window\n\n  WhichKeyValue           Comment                 values by plugins (like\n                                                  marks, registers, etc)\n  -----------------------------------------------------------------------\n==============================================================================\n2. Links                                                *which-key.nvim-links*\n\n1. *image*: https://github.com/user-attachments/assets/89277334-dcdc-4b0f-9fd4-02f27012f589\n2. *image*: https://github.com/user-attachments/assets/f8d71a75-312e-4a42-add8-d153493b2633\n3. *image*: https://github.com/user-attachments/assets/e4400a1d-7e71-4439-b6ff-6cbc40647a6f\n4. *image*: https://github.com/user-attachments/assets/43fb0874-7f79-4521-aee9-03e2b0841758\n5. *image*: https://github.com/user-attachments/assets/d8077dcb-56fb-47b0-ad9e-1aba5db16950\n6. *image*: https://github.com/user-attachments/assets/102c7963-329a-40b9-b0a8-72c8656318b7\n\nGenerated by panvimdoc <https://github.com/kdheepak/panvimdoc>\n\nvim:tw=78:ts=8:noet:ft=help:norl:\n"
  },
  {
    "path": "lua/which-key/buf.lua",
    "content": "local Config = require(\"which-key.config\")\nlocal Tree = require(\"which-key.tree\")\nlocal Triggers = require(\"which-key.triggers\")\nlocal Util = require(\"which-key.util\")\n\n---@class wk.Mode\n---@field buf wk.Buffer\n---@field mode string\n---@field tree wk.Tree\n---@field triggers wk.Node[]\nlocal Mode = {}\nMode.__index = Mode\n\n---@param node wk.Node\nlocal function is_special(node)\n  return (node:is_plugin() or node:is_proxy()) and not node.keymap\nend\n\n--- Checks if it's safe to add a trigger for the given node\n---@param node wk.Node\n---@param no_single? boolean\nlocal function is_safe(node, no_single)\n  if node.keymap or is_special(node) or node:count() == 0 then\n    return false\n  end\n  if no_single and #node.path == 1 then\n    local key = node.path[1]\n    -- only z or g are safe\n    if key:match(\"^[a-z]$\") and not key:match(\"^[gz]$\") then\n      return false\n    end\n    -- only Z is safe\n    if key:match(\"^[A-Z]$\") and not key:match(\"^[Z]$\") then\n      return false\n    end\n  end\n  return true\nend\n\nfunction Mode:__tostring()\n  return string.format(\"Mode(%s:%d)\", self.mode, self.buf.buf)\nend\n\n---@param buf wk.Buffer\n---@param mode string\nfunction Mode.new(buf, mode)\n  local self = setmetatable({}, Mode)\n  self.buf = buf\n  self.mode = mode\n  self.tree = Tree.new()\n  self.triggers = {}\n  self:update()\n  return self\nend\n\nfunction Mode:attach()\n  self.triggers = {}\n\n  -- NOTE: order is important for nowait to work!\n  -- * first add plugin mappings\n  -- * then add triggers\n  self.tree:walk(function(node)\n    if is_special(node) and not node:has_nowait_ancestor() then\n      table.insert(self.triggers, node)\n      return false\n    end\n  end)\n\n  if Config.triggers.modes[self.mode] then\n    -- Auto triggers\n    self.tree:walk(function(node)\n      if node.keymap and node.keymap.nowait then\n        return false\n      end\n      if is_safe(node, true) then\n        table.insert(self.triggers, node)\n        return false\n      end\n    end)\n  end\n\n  -- Manual triggers\n  for _, t in ipairs(Config.triggers.mappings) do\n    if self:has(t) then\n      local node = self.tree:find(t.lhs)\n      if node and is_safe(node) then\n        table.insert(self.triggers, node)\n      end\n    end\n  end\n\n  Triggers.schedule(self)\nend\n\nfunction Mode:xo()\n  return self.mode:find(\"[xo]\") ~= nil\nend\n\nfunction Mode:clear()\n  Triggers.detach(self)\n  self.tree:clear()\nend\n\n---@param mode string\nfunction Mode:is(mode)\n  if mode == \"v\" then\n    return self.mode == \"x\" or self.mode == \"s\"\n  end\n  return self.mode == mode\nend\n\n---@param mapping wk.Keymap\nfunction Mode:has(mapping)\n  return self:is(mapping.mode) and (not mapping.buffer or mapping.buffer == self.buf.buf)\nend\n\nfunction Mode:update()\n  self.tree:clear()\n\n  local mappings = vim.api.nvim_get_keymap(self.mode)\n  vim.list_extend(mappings, vim.api.nvim_buf_get_keymap(self.buf.buf, self.mode))\n  ---@cast mappings wk.Keymap[]\n\n  for _, mapping in ipairs(mappings) do\n    if mapping.desc and mapping.desc:find(\"which-key-trigger\", 1, true) then\n      -- ignore which-key triggers\n    elseif Util.is_nop(mapping.rhs) then\n      self.tree:add(mapping, true)\n    elseif mapping.lhs:sub(1, 6) ~= \"<Plug>\" and mapping.lhs:sub(1, 5) ~= \"<SNR>\" then\n      self.tree:add(mapping)\n    end\n  end\n\n  for _, m in ipairs(Config.mappings) do\n    if self:has(m) then\n      self.tree:add(m, true)\n    end\n  end\n\n  self.tree:fix()\n  self:attach()\n  vim.schedule(function()\n    require(\"which-key.state\").update()\n  end)\nend\n\n---@class wk.Buffer\n---@field buf number\n---@field modes table<string, wk.Mode>\nlocal Buf = {}\nBuf.__index = Buf\n\n---@param buf? number\nfunction Buf.new(buf)\n  local self = setmetatable({}, Buf)\n  buf = buf or 0\n  self.buf = buf == 0 and vim.api.nvim_get_current_buf() or buf\n  self.modes = {}\n  return self\nend\n\n---@param opts? wk.Filter\nfunction Buf:clear(opts)\n  opts = opts or {}\n  assert(not opts.buf or opts.buf == self.buf, \"buffer mismatch\")\n  ---@type string[]\n  local modes = opts.mode and { opts.mode } or vim.tbl_keys(self.modes)\n  for _, m in ipairs(modes) do\n    local mode = self.modes[m]\n    if mode then\n      mode:clear()\n      self.modes[m] = nil\n    end\n  end\nend\n\nfunction Buf:valid()\n  return vim.api.nvim_buf_is_valid(self.buf)\nend\n\n---@param opts? wk.Filter\n---@return wk.Mode?\nfunction Buf:get(opts)\n  if not self:valid() then\n    return\n  end\n  opts = opts or {}\n  local mode = opts.mode or Util.mapmode()\n  local ret = self.modes[mode]\n  if not ret then\n    self.modes[mode] = Mode.new(self, mode)\n    Util.debug(\"new \" .. tostring(self.modes[mode]))\n    return self.modes[mode]\n  elseif opts.update then\n    Util.debug(\"update \" .. tostring(ret))\n    ret:update()\n  end\n  return ret\nend\n\nlocal M = {}\nM.Buf = Buf\nM.bufs = {} ---@type table<number,wk.Buffer>\n\n---@param opts? wk.Filter\nfunction M.get(opts)\n  M.cleanup()\n  opts = opts or {}\n  local buf = opts.buf or vim.api.nvim_get_current_buf()\n\n  if not vim.api.nvim_buf_is_valid(buf) then\n    return\n  end\n\n  local ft = vim.bo[buf].filetype\n  local bt = vim.bo[buf].buftype\n\n  if vim.tbl_contains(Config.disable.ft, ft) then\n    return\n  end\n  if vim.tbl_contains(Config.disable.bt, bt) then\n    return\n  end\n\n  M.bufs[buf] = M.bufs[buf] or Buf.new(buf)\n  return M.bufs[buf]:get(opts)\nend\n\nfunction M.cleanup()\n  for buf, _ in pairs(M.bufs) do\n    if not vim.api.nvim_buf_is_valid(buf) then\n      M.bufs[buf] = nil\n    end\n  end\nend\n\n---@param opts? wk.Filter\nfunction M.clear(opts)\n  M.cleanup()\n  opts = opts or {}\n  ---@type number[]\n  local bufs = opts.buf and { opts.buf } or vim.tbl_keys(M.bufs)\n  for _, b in ipairs(bufs) do\n    if M.bufs[b] then\n      M.bufs[b]:clear(opts)\n    end\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/colors.lua",
    "content": "local M = {}\n\nM.colors = {\n  [\"\"] = \"Function\", -- the key\n  Separator = \"Comment\", -- the separator between the key and its description\n  Group = \"Keyword\", -- group name\n  Desc = \"Identifier\", -- description\n  Normal = \"NormalFloat\", -- Normal in th which-key window\n  Title = \"FloatTitle\", -- Title of the which-key window\n  Border = \"FloatBorder\", -- Border of the which-key window\n  Value = \"Comment\", -- values by plugins (like marks, registers, etc)\n  Icon = \"@markup.link\", -- icons\n  IconAzure = \"Function\",\n  IconBlue = \"DiagnosticInfo\",\n  IconCyan = \"DiagnosticHint\",\n  IconGreen = \"DiagnosticOk\",\n  IconGrey = \"Normal\",\n  IconOrange = \"DiagnosticWarn\",\n  IconPurple = \"Constant\",\n  IconRed = \"DiagnosticError\",\n  IconYellow = \"DiagnosticWarn\",\n}\n\nfunction M.setup()\n  for k, v in pairs(M.colors) do\n    vim.api.nvim_set_hl(0, \"WhichKey\" .. k, { link = v, default = true })\n  end\n  M.fix_colors()\n  vim.api.nvim_create_autocmd(\"ColorScheme\", {\n    group = vim.api.nvim_create_augroup(\"wk-colors\", { clear = true }),\n    callback = M.fix_colors,\n  })\nend\n\nfunction M.fix_colors()\n  for k in pairs(M.colors) do\n    if k:find(\"^Icon\") then\n      local color = k:gsub(\"^Icon\", \"\")\n      local wk_hl_group = \"WhichKeyIcon\" .. color\n      local mini_hl_group = \"MiniIcons\" .. color\n      local wk_hl = vim.api.nvim_get_hl(0, {\n        name = wk_hl_group,\n        link = true,\n      })\n      local mini_hl = vim.api.nvim_get_hl(0, {\n        name = mini_hl_group,\n        link = true,\n      })\n      if wk_hl.default and not vim.tbl_isempty(mini_hl) then\n        vim.api.nvim_set_hl(0, wk_hl_group, { link = mini_hl_group })\n      end\n    end\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/config.lua",
    "content": "---@class wk.Config: wk.Opts\n---@field triggers {mappings: wk.Mapping[], modes: table<string,boolean>}\nlocal M = {}\n\nM.version = \"3.17.0\" -- x-release-please-version\n\n---@class wk.Opts\nlocal defaults = {\n  ---@type false | \"classic\" | \"modern\" | \"helix\"\n  preset = \"classic\",\n  -- Delay before showing the popup. Can be a number or a function that returns a number.\n  ---@type number | fun(ctx: { keys: string, mode: string, plugin?: string }):number\n  delay = function(ctx)\n    return ctx.plugin and 0 or 200\n  end,\n  ---@param mapping wk.Mapping\n  filter = function(mapping)\n    -- example to exclude mappings without a description\n    -- return mapping.desc and mapping.desc ~= \"\"\n    return true\n  end,\n  --- You can add any mappings here, or use `require('which-key').add()` later\n  ---@type wk.Spec\n  spec = {},\n  -- show a warning when issues were detected with your mappings\n  notify = true,\n  -- Which-key automatically sets up triggers for your mappings.\n  -- But you can disable this and setup the triggers manually.\n  -- Check the docs for more info.\n  ---@type wk.Spec\n  triggers = {\n    { \"<auto>\", mode = \"nxso\" },\n  },\n  -- Start hidden and wait for a key to be pressed before showing the popup\n  -- Only used by enabled xo mapping modes.\n  ---@param ctx { mode: string, operator: string }\n  defer = function(ctx)\n    return ctx.mode == \"V\" or ctx.mode == \"<C-V>\"\n  end,\n  plugins = {\n    marks = true, -- shows a list of your marks on ' and `\n    registers = true, -- shows your registers on \" in NORMAL or <C-r> in INSERT mode\n    -- the presets plugin, adds help for a bunch of default keybindings in Neovim\n    -- No actual key bindings are created\n    spelling = {\n      enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions\n      suggestions = 20, -- how many suggestions should be shown in the list?\n    },\n    presets = {\n      operators = true, -- adds help for operators like d, y, ...\n      motions = true, -- adds help for motions\n      text_objects = true, -- help for text objects triggered after entering an operator\n      windows = true, -- default bindings on <c-w>\n      nav = true, -- misc bindings to work with windows\n      z = true, -- bindings for folds, spelling and others prefixed with z\n      g = true, -- bindings for prefixed with g\n    },\n  },\n  ---@type wk.Win.opts\n  win = {\n    -- don't allow the popup to overlap with the cursor\n    no_overlap = true,\n    -- width = 1,\n    -- height = { min = 4, max = 25 },\n    -- col = 0,\n    -- row = math.huge,\n    -- border = \"none\",\n    padding = { 1, 2 }, -- extra window padding [top/bottom, right/left]\n    title = true,\n    title_pos = \"center\",\n    zindex = 1000,\n    -- Additional vim.wo and vim.bo options\n    bo = {},\n    wo = {\n      -- winblend = 10, -- value between 0-100 0 for fully opaque and 100 for fully transparent\n    },\n  },\n  layout = {\n    width = { min = 20 }, -- min and max width of the columns\n    spacing = 3, -- spacing between columns\n  },\n  keys = {\n    scroll_down = \"<c-d>\", -- binding to scroll down inside the popup\n    scroll_up = \"<c-u>\", -- binding to scroll up inside the popup\n  },\n  ---@type (string|wk.Sorter)[]\n  --- Mappings are sorted using configured sorters and natural sort of the keys\n  --- Available sorters:\n  --- * local: buffer-local mappings first\n  --- * order: order of the items (Used by plugins like marks / registers)\n  --- * group: groups last\n  --- * alphanum: alpha-numerical first\n  --- * mod: special modifier keys last\n  --- * manual: the order the mappings were added\n  --- * case: lower-case first\n  sort = { \"local\", \"order\", \"group\", \"alphanum\", \"mod\" },\n  ---@type number|fun(node: wk.Node):boolean?\n  expand = 0, -- expand groups when <= n mappings\n  -- expand = function(node)\n  --   return not node.desc -- expand all nodes without a description\n  -- end,\n  -- Functions/Lua Patterns for formatting the labels\n  ---@type table<string, ({[1]:string, [2]:string}|fun(str:string):string)[]>\n  replace = {\n    key = {\n      function(key)\n        return require(\"which-key.view\").format(key)\n      end,\n      -- { \"<Space>\", \"SPC\" },\n    },\n    desc = {\n      { \"<Plug>%(?(.*)%)?\", \"%1\" },\n      { \"^%+\", \"\" },\n      { \"<[cC]md>\", \"\" },\n      { \"<[cC][rR]>\", \"\" },\n      { \"<[sS]ilent>\", \"\" },\n      { \"^lua%s+\", \"\" },\n      { \"^call%s+\", \"\" },\n      { \"^:%s*\", \"\" },\n    },\n  },\n  icons = {\n    breadcrumb = \"»\", -- symbol used in the command line area that shows your active key combo\n    separator = \"➜\", -- symbol used between a key and it's label\n    group = \"+\", -- symbol prepended to a group\n    ellipsis = \"…\",\n    -- set to false to disable all mapping icons,\n    -- both those explicitly added in a mapping\n    -- and those from rules\n    mappings = true,\n    --- See `lua/which-key/icons.lua` for more details\n    --- Set to `false` to disable keymap icons from rules\n    ---@type wk.IconRule[]|false\n    rules = {},\n    -- use the highlights from mini.icons\n    -- When `false`, it will use `WhichKeyIcon` instead\n    colors = true,\n    -- used by key format\n    keys = {\n      Up = \" \",\n      Down = \" \",\n      Left = \" \",\n      Right = \" \",\n      C = \"󰘴 \",\n      M = \"󰘵 \",\n      D = \"󰘳 \",\n      S = \"󰘶 \",\n      CR = \"󰌑 \",\n      Esc = \"󱊷 \",\n      ScrollWheelDown = \"󱕐 \",\n      ScrollWheelUp = \"󱕑 \",\n      NL = \"󰌑 \",\n      BS = \"󰁮\",\n      Space = \"󱁐 \",\n      Tab = \"󰌒 \",\n      F1 = \"󱊫\",\n      F2 = \"󱊬\",\n      F3 = \"󱊭\",\n      F4 = \"󱊮\",\n      F5 = \"󱊯\",\n      F6 = \"󱊰\",\n      F7 = \"󱊱\",\n      F8 = \"󱊲\",\n      F9 = \"󱊳\",\n      F10 = \"󱊴\",\n      F11 = \"󱊵\",\n      F12 = \"󱊶\",\n    },\n  },\n  show_help = true, -- show a help message in the command line for using WhichKey\n  show_keys = true, -- show the currently pressed key and its label as a message in the command line\n  -- disable WhichKey for certain buf types and file types.\n  disable = {\n    ft = {},\n    bt = {},\n  },\n  debug = false, -- enable wk.log in the current directory\n}\n\nM.loaded = false\n\n---@type wk.Keymap[]\nM.mappings = {}\n\n---@type wk.Opts\nM.options = nil\n\n---@type {opt:string, msg:string}[]\nM.issues = {}\n\nfunction M.validate()\n  local deprecated = {\n    [\"operators\"] = \"see `opts.defer`\",\n    [\"key_labels\"] = \"see `opts.replace`\",\n    \"motions\",\n    [\"popup_mappings\"] = \"see `opts.keys`\",\n    [\"window\"] = \"see `opts.win`\",\n    [\"ignore_missing\"] = \"see `opts.filter`\",\n    \"hidden\",\n    [\"triggers_nowait\"] = \"see `opts.delay`\",\n    [\"triggers_blacklist\"] = \"see `opts.triggers`\",\n    [\"disable.trigger\"] = \"see `opts.triggers`\",\n    [\"modes\"] = \"see `opts.triggers`\",\n  }\n  for k, v in pairs(deprecated) do\n    local opt = type(k) == \"number\" and v or k\n    local msg = \"option is deprecated.\" .. (type(k) == \"number\" and \"\" or \" \" .. v)\n    local parts = vim.split(opt, \".\", { plain = true })\n    if vim.tbl_get(M.options, unpack(parts)) ~= nil then\n      table.insert(M.issues, { opt = opt, msg = msg })\n    end\n  end\n  if type(M.options.triggers) ~= \"table\" then\n    table.insert(M.issues, { opt = \"triggers\", msg = \"triggers must be a table\" })\n  end\nend\n\n---@param opts? wk.Opts\nfunction M.setup(opts)\n  if vim.fn.has(\"nvim-0.9.4\") == 0 then\n    return vim.notify(\"which-key.nvim requires Neovim >= 0.9.4\", vim.log.levels.ERROR)\n  end\n  M.options = vim.tbl_deep_extend(\"force\", {}, defaults, opts or {})\n\n  local function load()\n    if M.loaded then\n      return\n    end\n    local Util = require(\"which-key.util\")\n\n    if M.options.preset then\n      local Presets = require(\"which-key.presets\")\n      M.options = vim.tbl_deep_extend(\"force\", {}, defaults, Presets[M.options.preset] or {}, opts or {})\n    end\n\n    M.validate()\n    if #M.issues > 0 then\n      Util.warn({\n        \"There are issues with your config.\",\n        \"Use `:checkhealth which-key` to find out more.\",\n      }, { once = true })\n    end\n\n    for k, v in pairs(M.options.keys) do\n      M.options.keys[k] = Util.norm(v)\n    end\n\n    if M.options.debug then\n      Util.debug(\"\\n\\nDebug Started for v\" .. M.version)\n      if package.loaded.lazy then\n        local Git = require(\"lazy.manage.git\")\n        local plugin = require(\"lazy.core.config\").plugins[\"which-key.nvim\"]\n        Util.debug(vim.inspect(Git.info(plugin.dir)))\n      end\n    end\n\n    local wk = require(\"which-key\")\n\n    -- replace by the real add function\n    wk.add = M.add\n\n    if type(M.options.triggers) ~= \"table\" then\n      ---@diagnostic disable-next-line: inject-field\n      M.options.triggers = defaults.triggers\n    end\n\n    M.triggers = {\n      mappings = require(\"which-key.mappings\").parse(M.options.triggers),\n      modes = {},\n    }\n    ---@param m wk.Mapping\n    M.triggers.mappings = vim.tbl_filter(function(m)\n      if m.lhs == \"<auto>\" then\n        M.triggers.modes[m.mode] = true\n        return false\n      end\n      return true\n    end, M.triggers.mappings)\n\n    -- load presets first so that they can be overriden by the user\n    require(\"which-key.plugins\").setup()\n\n    -- process mappings queue\n    for _, todo in ipairs(wk._queue) do\n      M.add(todo.spec, todo.opts)\n    end\n    wk._queue = {}\n\n    -- finally, add the mapppings from the config\n    M.add(M.options.spec)\n\n    -- setup colors and start which-key\n    require(\"which-key.colors\").setup()\n    require(\"which-key.state\").setup()\n\n    M.loaded = true\n  end\n  local _load = vim.schedule_wrap(load)\n\n  if vim.v.vim_did_enter == 1 then\n    _load()\n  else\n    vim.api.nvim_create_autocmd(\"VimEnter\", { once = true, callback = _load })\n  end\n\n  vim.api.nvim_create_user_command(\"WhichKey\", function(cmd)\n    load()\n    local mode, keys = cmd.args:match(\"^([nixsotc]?)%s*(.*)$\")\n    if not mode then\n      return require(\"which-key.util\").error(\"Usage: WhichKey [mode] [keys]\")\n    end\n    if mode == \"\" then\n      mode = \"n\"\n    end\n    require(\"which-key\").show({ mode = mode, keys = keys })\n  end, {\n    nargs = \"*\",\n  })\nend\n\n---@param opts? wk.Parse\n---@param mappings wk.Spec\nfunction M.add(mappings, opts)\n  opts = opts or {}\n  opts.create = opts.create ~= false\n  local Mappings = require(\"which-key.mappings\")\n  for _, km in ipairs(Mappings.parse(mappings, opts)) do\n    table.insert(M.mappings, km)\n    km.idx = #M.mappings\n  end\n  if M.loaded then\n    require(\"which-key.buf\").clear()\n  end\nend\n\nreturn setmetatable(M, {\n  __index = function(_, k)\n    if rawget(M, \"options\") == nil then\n      M.setup()\n    end\n    local opts = rawget(M, \"options\")\n    return k == \"options\" and opts or opts[k]\n  end,\n})\n"
  },
  {
    "path": "lua/which-key/docs.lua",
    "content": "local Docs = require(\"lazy.docs\")\n\nlocal M = {}\n\nfunction M.update()\n  local config = Docs.extract(\"lua/which-key/config.lua\", \"\\n(--@class wk%.Opts.-\\n})\")\n  config = config:gsub(\"%s*debug = false.\\n\", \"\\n\")\n  Docs.save({\n    config = config,\n    colors = Docs.colors({\n      modname = \"which-key.colors\",\n      path = \"lua/which-key/colors.lua\",\n      name = \"WhichKey\",\n    }),\n  })\nend\n\nM.update()\nprint(\"Updated docs\")\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/extras.lua",
    "content": "local M = {}\n\n---@type table<string, fun():wk.Spec>\nM.expand = {}\n\n---@return number[]\nfunction M.bufs()\n  local current = vim.api.nvim_get_current_buf()\n  return vim.tbl_filter(function(buf)\n    return buf ~= current and vim.bo[buf].buflisted\n  end, vim.api.nvim_list_bufs())\nend\n\nfunction M.bufname(buf)\n  local name = vim.api.nvim_buf_get_name(buf)\n  return name == \"\" and \"[No Name]\" or vim.fn.fnamemodify(name, \":~:.\")\nend\n\n---@param spec wk.Spec[]\nfunction M.add_keys(spec)\n  table.sort(spec, function(a, b)\n    return a.desc < b.desc\n  end)\n  spec = vim.list_slice(spec, 1, 10)\n  for i, v in ipairs(spec) do\n    v[1] = tostring(i - 1)\n  end\n  return spec\nend\n\nfunction M.expand.buf()\n  local ret = {} ---@type wk.Spec[]\n\n  for _, buf in ipairs(M.bufs()) do\n    local name = M.bufname(buf)\n    ret[#ret + 1] = {\n      \"\",\n      function()\n        vim.api.nvim_set_current_buf(buf)\n      end,\n      desc = name,\n      icon = { cat = \"file\", name = name },\n    }\n  end\n  return M.add_keys(ret)\nend\n\nfunction M.expand.win()\n  ---@type wk.Spec[]\n  local ret = {}\n  local current = vim.api.nvim_get_current_win()\n  for _, win in ipairs(vim.api.nvim_list_wins()) do\n    local is_float = vim.api.nvim_win_get_config(win).relative ~= \"\"\n    if win ~= current and not is_float then\n      local buf = vim.api.nvim_win_get_buf(win)\n      local name = M.bufname(buf)\n      ret[#ret + 1] = {\n        \"\",\n        function()\n          vim.api.nvim_set_current_win(win)\n        end,\n        desc = name,\n        icon = { cat = \"file\", name = name },\n      }\n    end\n  end\n  return M.add_keys(ret)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/health.lua",
    "content": "local Buf = require(\"which-key.buf\")\nlocal Config = require(\"which-key.config\")\nlocal Icons = require(\"which-key.icons\")\nlocal Mappings = require(\"which-key.mappings\")\nlocal Migrate = require(\"which-key.migrate\")\nlocal Tree = require(\"which-key.tree\")\nlocal Util = require(\"which-key.util\")\n\nlocal M = {}\n\nlocal start = vim.health.start or vim.health.report_start\nlocal ok = vim.health.ok or vim.health.report_ok\nlocal warn = vim.health.warn or vim.health.report_warn\nlocal error = vim.health.error or vim.health.report_error\nlocal info = vim.health.info or vim.health.report_info\n\n-- TODO: Add more checks\n-- * duplicate desc\n-- * mapping.desc ~= keymap.desc\n-- * check for old-style mappings\n\nfunction M.check()\n  ok(\n    \"Most of these checks are for informational purposes only.\\n\"\n      .. \"WARNINGS should be treated as a warning, and don't necessarily indicate a problem with your config.\\n\"\n      .. \"Please |DON'T| report these warnings as an issue.\"\n  )\n\n  start(\"Checking your config\")\n\n  if #Config.issues > 0 then\n    local msg = {\n      \"There are issues with your config:\",\n    }\n    vim.list_extend(\n      msg,\n      vim.tbl_map(function(issue)\n        return \"- `opts.\" .. issue.opt .. \"`: \" .. issue.msg\n      end, Config.issues)\n    )\n    msg[#msg + 1] = \"Please refer to the docs for more info.\"\n    warn(table.concat(msg, \"\\n\"))\n  end\n\n  local have_icons = false\n  for _, provider in ipairs(Icons.providers) do\n    if provider.available == nil then\n      provider.available = pcall(require, provider.name)\n    end\n    if provider.available then\n      ok(\"|\" .. provider.name .. \"| is installed\")\n      have_icons = true\n    else\n      warn(\"|\" .. provider.name .. \"| is not installed\")\n    end\n  end\n  if not have_icons then\n    warn(\"Keymap icon support will be limited.\")\n  end\n\n  start(\"Checking for issues with your mappings\")\n  if #Mappings.notifs == 0 then\n    ok(\"No issues reported\")\n  end\n  for _, notif in ipairs(Mappings.notifs) do\n    local msg = notif.msg\n    if notif.spec then\n      msg = msg .. \": >\\n\" .. vim.inspect(notif.spec)\n      if msg:find(\"old version\") then\n        local fixed = Migrate.migrate(notif.spec)\n        msg = msg .. \"\\n\\n-- Suggested Spec:\\n\" .. fixed\n      end\n    end\n    (notif.level >= vim.log.levels.ERROR and error or warn)(msg)\n  end\n\n  start(\"checking for overlapping keymaps\")\n  local found = false\n\n  Buf.cleanup()\n\n  ---@type table<string, boolean>\n  local reported = {}\n\n  local mapmodes = vim.split(\"nixsotc\", \"\")\n\n  for _, buf in pairs(Buf.bufs) do\n    for _, mapmode in ipairs(mapmodes) do\n      local mode = buf:get({ mode = mapmode })\n      if mode then\n        mode.tree:walk(function(node)\n          local km = node.keymap\n          if not km or Util.is_nop(km.rhs) or node.keys:sub(1, 6) == \"<Plug>\" then\n            return\n          end\n          if node.keymap and node:count() > 0 then\n            local id = mode.mode .. \":\" .. node.keys\n            if reported[id] then\n              return\n            end\n            reported[id] = true\n            local overlaps = {}\n            local descs = {}\n            if node.desc and node.desc ~= \"\" then\n              descs[#descs + 1] = \"- <\" .. node.keys .. \">: \" .. node.desc\n            end\n            local queue = node:children()\n            while #queue > 0 do\n              local child = table.remove(queue)\n              if child.keymap then\n                table.insert(overlaps, \"<\" .. child.keys .. \">\")\n                if child.desc and child.desc ~= \"\" then\n                  descs[#descs + 1] = \"- <\" .. child.keys .. \">: \" .. child.desc\n                end\n              end\n              vim.list_extend(queue, child:children())\n            end\n            if #overlaps > 0 then\n              found = true\n              warn(\n                \"In mode `\"\n                  .. mode.mode\n                  .. \"`, <\"\n                  .. node.keys\n                  .. \"> overlaps with \"\n                  .. table.concat(overlaps, \", \")\n                  .. \":\\n\"\n                  .. table.concat(descs, \"\\n\")\n              )\n            end\n            return false\n          end\n        end)\n      end\n    end\n  end\n\n  if found then\n    ok(\n      \"Overlapping keymaps are only reported for informational purposes.\\n\"\n        .. \"This doesn't necessarily mean there is a problem with your config.\"\n    )\n  else\n    ok(\"No overlapping keymaps found\")\n  end\n\n  start(\"Checking for duplicate mappings\")\n\n  if vim.tbl_isempty(Tree.dups) then\n    ok(\"No duplicate mappings found\")\n  else\n    for _, mappings in pairs(Tree.dups) do\n      ---@type wk.Mapping[]\n      mappings = vim.tbl_keys(mappings)\n      local first = mappings[1]\n      warn(\n        \"Duplicates for <\"\n          .. first.lhs\n          .. \"> in mode `\"\n          .. first.mode\n          .. \"`:\\n\"\n          .. table.concat(\n            vim.tbl_map(function(m)\n              m = vim.deepcopy(m)\n              local desc = (m.desc and (m.desc .. \": \") or \"\")\n              m.desc = nil\n              m.idx = nil\n              m.mode = nil\n              m.lhs = nil\n              return \"* \" .. desc .. \"`\" .. vim.inspect(m):gsub(\"%s+\", \" \") .. \"`\"\n            end, mappings),\n            \"\\n\"\n          )\n      )\n    end\n    ok(\n      \"Duplicate mappings are only reported for informational purposes.\\n\"\n        .. \"This doesn't necessarily mean there is a problem with your config.\"\n    )\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/icons.lua",
    "content": "local Config = require(\"which-key.config\")\n\nlocal M = {}\n\n--- * `WhichKeyColorAzure`  - azure.\n--- * `WhichKeyColorBlue`   - blue.\n--- * `WhichKeyColorCyan`   - cyan.\n--- * `WhichKeyColorGreen`  - green.\n--- * `WhichKeyColorGrey`   - grey.\n--- * `WhichKeyColorOrange` - orange.\n--- * `WhichKeyColorPurple` - purple.\n--- * `WhichKeyColorRed`    - red.\n--- * `WhichKeyColorYellow` - yellow.\n\n---@type wk.IconRule[]\nM.rules = {\n  { plugin = \"fzf-lua\", cat = \"filetype\", name = \"fzf\" },\n  { plugin = \"neo-tree.nvim\", cat = \"filetype\", name = \"neo-tree\" },\n  { plugin = \"octo.nvim\", cat = \"filetype\", name = \"git\" },\n  { plugin = \"yanky.nvim\", icon = \"󰅇\", color = \"yellow\" },\n  { plugin = \"zen-mode.nvim\", icon = \"󱅻 \", color = \"cyan\" },\n  { plugin = \"telescope.nvim\", pattern = \"telescope\", icon = \"\", color = \"blue\" },\n  { plugin = \"trouble.nvim\", cat = \"filetype\", name = \"trouble\" },\n  { plugin = \"todo-comments.nvim\", cat = \"file\", name = \"TODO\" },\n  { plugin = \"grapple.nvim\", pattern = \"grapple\", icon = \"󰛢\", color = \"azure\" },\n  { plugin = \"nvim-spectre\", icon = \"󰛔 \", color = \"blue\" },\n  { plugin = \"grug-far.nvim\", pattern = \"grug\", icon = \"󰛔 \", color = \"blue\" },\n  { plugin = \"noice.nvim\", pattern = \"noice\", icon = \"󰈸\", color = \"orange\" },\n  { plugin = \"persistence.nvim\", icon = \" \", color = \"azure\" },\n  { plugin = \"neotest\", cat = \"filetype\", name = \"neotest-summary\" },\n  { plugin = \"lazy.nvim\", cat = \"filetype\", name = \"lazy\" },\n  { plugin = \"snacks.nvim\", icon = \"󱥰 \", color = \"purple\" },\n  { plugin = \"refactoring.nvim\", pattern = \"refactor\", icon = \" \", color = \"cyan\" },\n  { pattern = \"profiler\", icon = \"⚡\", color = \"orange\" },\n  { plugin = \"CopilotChat.nvim\", icon = \" \", color = \"orange\" },\n  { pattern = \"%f[%a]git\", cat = \"filetype\", name = \"git\" },\n  { pattern = \"terminal\", icon = \" \", color = \"red\" },\n  { pattern = \"find\", icon = \" \", color = \"green\" },\n  { pattern = \"search\", icon = \" \", color = \"green\" },\n  { pattern = \"test\", cat = \"filetype\", name = \"neotest-summary\" },\n  { pattern = \"lazy\", cat = \"filetype\", name = \"lazy\" },\n  { pattern = \"buffer\", icon = \"󰈔\", color = \"cyan\" },\n  { pattern = \"file\", icon = \"󰈔\", color = \"cyan\" },\n  { pattern = \"window\", icon = \" \", color = \"blue\" },\n  { pattern = \"diagnostic\", icon = \"󱖫 \", color = \"green\" },\n  { pattern = \"format\", icon = \" \", color = \"cyan\" },\n  { pattern = \"debug\", icon = \"󰃤 \", color = \"red\" },\n  { pattern = \"code\", icon = \" \", color = \"orange\" },\n  { pattern = \"notif\", icon = \"󰵅 \", color = \"blue\" },\n  { pattern = \"toggle\", icon = \" \", color = \"yellow\" },\n  { pattern = \"session\", icon = \" \", color = \"azure\" },\n  { pattern = \"exit\", icon = \"󰈆 \", color = \"red\" },\n  { pattern = \"quit\", icon = \"󰈆 \", color = \"red\" },\n  { pattern = \"tab\", icon = \"󰓩 \", color = \"purple\" },\n  { pattern = \"%f[%a]ai\", icon = \" \", color = \"green\" },\n  { pattern = \"ui\", icon = \"󰙵 \", color = \"cyan\" },\n}\n\n---@type wk.IconProvider[]\nM.providers = {\n  {\n    name = \"mini.icons\",\n    get = function(icon)\n      local Icons = require(\"mini.icons\")\n      local ico, ico_hl, ico_def = Icons.get(icon.cat, icon.name) --[[@as string, string, boolean]]\n      if not ico_def then\n        return ico, ico_hl\n      end\n    end,\n  },\n  {\n    name = \"nvim-web-devicons\",\n    get = function(icon)\n      local Icons = require(\"nvim-web-devicons\")\n      if icon.cat == \"filetype\" then\n        return Icons.get_icon_by_filetype(icon.name, { default = false })\n      elseif icon.cat == \"file\" then\n        return Icons.get_icon(icon.name, nil, { default = false }) --[[@as string, string]]\n      elseif icon.cat == \"extension\" then\n        return Icons.get_icon(nil, icon.name, { default = false }) --[[@as string, string]]\n      end\n    end,\n  },\n}\n\n---@return wk.IconProvider?\nfunction M.get_provider()\n  for _, provider in ipairs(M.providers) do\n    if provider.available == nil then\n      provider.available = pcall(require, provider.name)\n    end\n    if provider.available then\n      return provider\n    end\n  end\nend\n\nfunction M.have()\n  return M.get_provider() ~= nil\nend\n\n---@param icon wk.Icon|string\n---@return string?, string?\nfunction M.get_icon(icon)\n  icon = type(icon) == \"string\" and { cat = \"filetype\", name = icon } or icon --[[@as wk.Icon]]\n  ---@type string?, string?\n  local ret, hl\n  if icon.icon then\n    ret, hl = icon.icon, icon.hl\n  elseif icon.cat and icon.name then\n    local provider = M.get_provider()\n    if provider then\n      ret, hl = provider.get(icon)\n    end\n  end\n  if ret then\n    if icon.color then\n      hl = \"WhichKeyIcon\" .. icon.color:sub(1, 1):upper() .. icon.color:sub(2)\n    end\n    if not hl or Config.icons.colors == false or icon.color == false then\n      hl = \"WhichKeyIcon\"\n    end\n    return ret, hl\n  end\nend\n\n---@param rules wk.IconRule[]\n---@param opts? {keymap?: wk.Keymap, desc?: string, ft?:string|string[]}|wk.Icon\n---@param check_ft? boolean\n---@return string?, string?\nfunction M._get(rules, opts, check_ft)\n  opts = opts or {}\n  opts.ft = type(opts.ft) == \"string\" and { opts.ft } or opts.ft\n\n  ---@type string?\n  local plugin\n  local fts = opts.ft or {} --[[@as string[] ]]\n\n  if opts.keymap and package.loaded.lazy then\n    local LazyUtil = require(\"lazy.core.util\")\n    local Keys = require(\"lazy.core.handler\").handlers.keys --[[@as LazyKeysHandler]]\n    local keys = Keys.parse(opts.keymap.lhs, opts.keymap.mode)\n    plugin = Keys.managed[keys.id]\n    if plugin then\n      fts[#fts + 1] = LazyUtil.normname(plugin)\n    end\n  end\n\n  -- plugin icons\n  if plugin then\n    for _, icon in ipairs(rules) do\n      if icon.plugin == plugin then\n        local ico, hl = M.get_icon(icon)\n        if ico then\n          return ico, hl\n        end\n      end\n    end\n  end\n\n  -- filetype icons\n  if check_ft then\n    if opts.keymap and opts.keymap.buffer and opts.keymap.buffer ~= 0 then\n      pcall(function()\n        fts[#fts + 1] = vim.bo[opts.keymap.buffer].filetype\n      end)\n    end\n    for _, ft in ipairs(fts) do\n      local icon, hl = M.get_icon({ cat = \"filetype\", name = ft })\n      if icon then\n        return icon, hl\n      end\n    end\n  end\n\n  -- pattern icons\n  if opts.desc then\n    for _, icon in ipairs(rules) do\n      if icon.pattern and opts.desc:lower():find(icon.pattern) then\n        local ico, hl = M.get_icon(icon)\n        if ico then\n          return ico, hl\n        end\n      end\n    end\n  end\nend\n\n---@param opts {keymap?: wk.Keymap, desc?: string, ft?:string|string[]}|wk.Icon|string\nfunction M.get(opts)\n  if not Config.icons.mappings then\n    return\n  end\n  if type(opts) == \"string\" then\n    opts = { icon = opts }\n  end\n\n  if opts.icon or opts.cat then\n    return M.get_icon(opts)\n  end\n\n  if Config.icons.rules == false then\n    return\n  end\n  local icon, hl = M._get(Config.icons.rules, opts)\n  if icon then\n    return icon, hl\n  end\n\n  return M._get(M.rules, opts, true)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/init.lua",
    "content": "---@class wk\n---@field private _queue {spec: wk.Spec, opts?: wk.Parse}[]\nlocal M = {}\n\nM._queue = {}\nM.did_setup = false\n\n--- Open which-key\n---@param opts? wk.Filter|string\nfunction M.show(opts)\n  opts = opts or {}\n  opts = type(opts) == \"string\" and { keys = opts } or opts\n  if opts.delay == nil then\n    opts.delay = 0\n  end\n  opts.waited = vim.o.timeoutlen\n  ---@diagnostic disable-next-line: param-type-mismatch\n  if not require(\"which-key.state\").start(opts) then\n    require(\"which-key.util\").warn(\n      \"No mappings found for mode `\" .. (opts.mode or \"n\") .. \"` and keys `\" .. (opts.keys or \"\") .. \"`\"\n    )\n  end\nend\n\n---@param opts? wk.Opts\nfunction M.setup(opts)\n  M.did_setup = true\n  require(\"which-key.config\").setup(opts)\nend\n\n-- Use `require(\"which-key\").add()` instead.\n-- The spec is different though, so check the docs!\n---@deprecated\n---@param mappings wk.Spec\n---@param opts? wk.Mapping\nfunction M.register(mappings, opts)\n  if opts then\n    for k, v in pairs(opts) do\n      mappings[k] = v\n    end\n  end\n  M.add(mappings, { version = 1 })\nend\n\n--- Add mappings to which-key\n---@param mappings wk.Spec\n---@param opts? wk.Parse\nfunction M.add(mappings, opts)\n  table.insert(M._queue, { spec = mappings, opts = opts })\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/layout.lua",
    "content": "local Config = require(\"which-key.config\")\nlocal M = {}\n\nlocal dw = vim.fn.strdisplaywidth\n\n--- When `size` is a number, it is returned as is (fixed dize).\n--- Otherwise, it is a percentage of `parent` (relative size).\n--- If `size` is negative, it is subtracted from `parent`.\n--- If `size` is a table, it is a range of values.\n---@alias wk.Dim number|{min:number, max:number}\n\n---@param size number\n---@param parent number\n---@param ... wk.Dim\n---@return number\nfunction M.dim(size, parent, ...)\n  size = math.abs(size) < 1 and parent * size or size\n  size = size < 0 and parent + size or size\n  for _, dim in ipairs({ ... } --[[ @as wk.Dim[] ]]) do\n    if type(dim) == \"number\" then\n      size = M.dim(dim, parent)\n    else\n      local min = dim.min and M.dim(dim.min, parent) or 0\n      local max = dim.max and M.dim(dim.max, parent) or parent\n      size = math.max(min, math.min(max, size))\n    end\n  end\n  return math.floor(math.max(0, math.min(parent, size)) + 0.5)\nend\n\n---@class wk.Table: wk.Table.opts\nlocal Table = {}\nTable.__index = Table\n\n---@param opts wk.Table.opts\nfunction Table.new(opts)\n  local self = setmetatable({}, Table)\n  self.cols = opts.cols\n  self.rows = opts.rows\n  return self\nend\n\n---@param opts? {spacing?: number}\n---@return string[][], number[], number\nfunction Table:cells(opts)\n  opts = opts or {}\n  opts.spacing = opts.spacing or 1\n\n  local widths = {} ---@type number[] actual column widths\n\n  local cells = {} ---@type string[][]\n\n  local total = 0\n  for c, col in ipairs(self.cols) do\n    widths[c] = 0\n    local all_ws = true\n    for r, row in ipairs(self.rows) do\n      cells[r] = cells[r] or {}\n      local value = row[col.key] or col.default or \"\"\n      value = tostring(value)\n      value = value:gsub(\"%s*$\", \"\")\n      value = value:gsub(\"\\n\", Config.icons.keys.NL)\n      value = vim.fn.strtrans(value)\n      if value:find(\"%S\") then\n        all_ws = false\n      end\n      if col.padding then\n        value = (\" \"):rep(col.padding[1] or 0) .. value .. (\" \"):rep(col.padding[2] or 0)\n      end\n      if c ~= #self.cols then\n        value = value .. (\" \"):rep(opts.spacing)\n      end\n      cells[r][c] = value\n      widths[c] = math.max(widths[c], dw(value))\n    end\n    if all_ws then\n      widths[c] = 0\n      for _, cell in pairs(cells) do\n        cell[c] = \"\"\n      end\n    end\n    total = total + widths[c]\n  end\n\n  return cells, widths, total\nend\n\n---@param opts {width: number, spacing?: number}\nfunction Table:layout(opts)\n  local cells, widths = self:cells(opts)\n\n  local free = opts.width\n\n  for c, col in ipairs(self.cols) do\n    if not col.width then\n      free = free - widths[c]\n    end\n  end\n  free = math.max(free, 0)\n\n  for c, col in ipairs(self.cols) do\n    if col.width then\n      widths[c] = M.dim(widths[c], free, { max = col.width })\n      free = free - widths[c]\n    end\n  end\n\n  ---@type {value: string, hl?:string}[][]\n  local ret = {}\n\n  for _, row in ipairs(cells) do\n    ---@type {value: string, hl?:string}[]\n    local line = {}\n    for c, col in ipairs(self.cols) do\n      local value = row[c]\n      local width = dw(value)\n      if width > widths[c] then\n        local old = value\n        value = \"\"\n        for i = 0, vim.fn.strchars(old) do\n          value = value .. vim.fn.strcharpart(old, i, 1)\n          if dw(value) >= widths[c] - 1 - (opts.spacing or 1) then\n            break\n          end\n        end\n        value = value .. Config.icons.ellipsis .. string.rep(\" \", opts.spacing or 1)\n      else\n        local align = col.align or \"left\"\n        if align == \"left\" then\n          value = value .. (\" \"):rep(widths[c] - width)\n        elseif align == \"right\" then\n          value = (\" \"):rep(widths[c] - width) .. value\n        elseif align == \"center\" then\n          local pad = (widths[c] - width) / 2\n          value = (\" \"):rep(math.floor(pad)) .. value .. (\" \"):rep(math.ceil(pad))\n        end\n      end\n      line[#line + 1] = { value = value, hl = col.hl }\n    end\n    ret[#ret + 1] = line\n  end\n  return ret\nend\n\nM.new = Table.new\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/mappings.lua",
    "content": "local Config = require(\"which-key.config\")\nlocal Util = require(\"which-key.util\")\n\nlocal M = {}\n\nM.VERSION = 2\nM.notifs = {} ---@type {msg:string, level:number, spec?:wk.Spec}[]\n\n---@class wk.Field\n---@field transform? string|(fun(value: any, parent:table): (value:any, key:string?))\n---@field inherit? boolean\n---@field deprecated? boolean\n\n---@class wk.Parse\n---@field version? number\n---@field create? boolean\n---@field notify? boolean\n\nM.notify = true\n\n---@type table<string, wk.Field>\nM.fields = {\n  -- map args\n  rhs = {},\n  lhs = {},\n  buffer = { inherit = true },\n  callback = { transform = \"rhs\" },\n  desc = {},\n  expr = { inherit = true },\n  mode = { inherit = true },\n  noremap = {\n    transform = function(value)\n      return not value, \"remap\"\n    end,\n  },\n  nowait = { inherit = true },\n  remap = { inherit = true },\n  replace_keycodes = { inherit = true },\n  script = {},\n  silent = { inherit = true },\n  unique = { inherit = true },\n  -- wk args\n  plugin = { inherit = true },\n  group = {},\n  hidden = { inherit = true },\n  cond = { inherit = true },\n  preset = { inherit = true },\n  icon = { inherit = true },\n  real = { inherit = true },\n  proxy = {},\n  expand = {},\n  -- deprecated\n  name = { transform = \"group\", deprecated = true },\n  prefix = { inherit = true, deprecated = true },\n  cmd = { transform = \"rhs\", deprecated = true },\n}\n\n---@param msg string\n---@param spec? wk.Spec\nfunction M.error(msg, spec)\n  M.log(msg, vim.log.levels.ERROR, spec)\nend\n\n---@param msg string\n---@param spec? wk.Spec\nfunction M.warn(msg, spec)\n  M.log(msg, vim.log.levels.WARN, spec)\nend\n\n---@param msg string\n---@param level number\n---@param spec? wk.Spec\nfunction M.log(msg, level, spec)\n  if not M.notify then\n    return\n  end\n  M.notifs[#M.notifs + 1] = { msg = msg, level = level, spec = spec }\n  if Config.notify then\n    Util.warn({\n      \"There were issues reported with your **which-key** mappings.\",\n      \"Use `:checkhealth which-key` to find out more.\",\n    }, { once = true })\n  end\nend\n\n---@param spec wk.Spec\n---@param field string|number\n---@param types string|string[]\nfunction M.expect(spec, field, types)\n  types = type(types) == \"string\" and { types } or types\n  local ok = false\n  for _, t in ipairs(types) do\n    if type(spec[field]) == t then\n      ok = true\n      break\n    end\n  end\n  if not ok then\n    M.error(\"Expected `\" .. field .. \"` to be \" .. table.concat(types, \", \"), spec)\n  end\n  return ok\nend\n\n---@param spec wk.Spec\n---@param ret? wk.Mapping[]\n---@param opts? wk.Parse\nfunction M._parse(spec, ret, opts)\n  opts = opts or {}\n  opts.version = opts.version or M.VERSION\n  if spec.version then\n    opts.version = spec.version\n    spec.version = nil\n  end\n\n  if ret == nil and opts.version ~= M.VERSION then\n    M.warn(\n      \"You're using an old version of the which-key spec.\\n\"\n        .. \"Your mappings will work, but it's recommended to update them to the new version.\\n\"\n        .. \"Please check the docs and suggested spec below for more info.\\nMappings\",\n      vim.deepcopy(spec)\n    )\n  end\n\n  ret = ret or {}\n\n  spec = type(spec) == \"string\" and { desc = spec } or spec\n\n  ---@type wk.Mapping\n  local mapping = {}\n\n  ---@type wk.Spec[]\n  local children = {}\n\n  local keys = vim.tbl_keys(spec)\n\n  table.sort(keys, function(a, b)\n    local ta, tb = type(a), type(b)\n    if type(a) == type(b) then\n      return a < b\n    end\n    return ta < tb\n  end)\n\n  -- process fields\n  for _, k in ipairs(keys) do\n    local v = spec[k]\n    local field = M.fields[k] ---@type wk.Field?\n    if field then\n      if type(field.transform) == \"string\" then\n        k = field.transform --[[@as string]]\n      elseif type(field.transform) == \"function\" then\n        local vv, kk = field.transform(v, spec)\n        v, k = vv, (kk or k)\n      end\n      mapping[k] = v\n    elseif type(k) == \"string\" then\n      if opts.version == 1 then\n        if M.expect(spec, k, { \"string\", \"table\" }) then\n          if type(v) == \"string\" then\n            table.insert(children, { prefix = (spec.prefix or \"\") .. k, desc = v })\n          elseif type(v) == \"table\" then\n            v.prefix = (spec.prefix or \"\") .. k\n            table.insert(children, v)\n          end\n        end\n      else\n        M.error(\"Invalid field `\" .. k .. \"`\", spec)\n      end\n    elseif type(k) == \"number\" and type(v) == \"table\" then\n      if opts.version == 1 then\n        v.prefix = spec.prefix or \"\"\n      end\n      table.insert(children, v)\n      spec[k] = nil\n    end\n  end\n\n  local count = #spec\n\n  -- process mapping\n  if opts.version == M.VERSION then\n    if count == 1 then\n      if M.expect(spec, 1, \"string\") then\n        mapping.lhs = spec[1] --[[@as string]]\n      end\n    elseif count == 2 then\n      if M.expect(spec, 1, \"string\") and M.expect(spec, 2, { \"string\", \"function\" }) then\n        mapping.lhs = spec[1] --[[@as string]]\n        mapping.rhs = spec[2] --[[@as string]]\n      end\n    elseif count > 2 then\n      M.error(\"expected 1 or 2 elements, got \" .. count, spec)\n    end\n  elseif opts.version == 1 then\n    if mapping.expr and mapping.replace_keycodes == nil then\n      mapping.replace_keycodes = false\n    end\n    if count == 1 then\n      if M.expect(spec, 1, \"string\") then\n        if mapping.desc then\n          M.warn(\"overwriting desc\", spec)\n        end\n        mapping.desc = spec[1] --[[@as string]]\n      end\n    elseif count == 2 then\n      if M.expect(spec, 1, { \"string\", \"function\" }) and M.expect(spec, 2, \"string\") then\n        if mapping.desc then\n          M.warn(\"overwriting desc\", spec)\n        end\n        mapping.rhs = spec[1] --[[@as string]]\n        mapping.desc = spec[2] --[[@as string]]\n      end\n    elseif count > 2 then\n      M.error(\"expected 1 or 2 elements, got \" .. count, spec)\n    end\n  end\n\n  -- add mapping\n  M.add(mapping, ret, opts)\n\n  -- process children\n  for _, child in ipairs(children) do\n    for k, v in pairs(mapping) do\n      if M.fields[k] and M.fields[k].inherit and child[k] == nil then\n        child[k] = v\n      end\n    end\n    M._parse(child, ret, opts)\n  end\n\n  return ret\nend\n\n---@param mapping wk.Spec\n---@param opts? wk.Parse\n---@param ret wk.Mapping[]\nfunction M.add(mapping, ret, opts)\n  opts = opts or {}\n  if mapping.cond == false or ((type(mapping.cond) == \"function\") and not mapping.cond()) then\n    return\n  end\n  ---@cast mapping wk.Mapping|wk.Spec\n  mapping.cond = nil\n  if mapping.desc == \"which_key_ignore\" then\n    mapping.hidden = true\n    mapping.desc = nil\n  end\n  if type(mapping.group) == \"string\" or type(mapping.group) == \"function\" then\n    mapping.desc = mapping.group --[[@as string]]\n    mapping.group = true\n  end\n  if mapping.plugin then\n    mapping.group = true\n  end\n  if mapping.group and mapping.desc then\n    mapping.desc = mapping.desc\n    if type(mapping.desc) == \"string\" then\n      mapping.desc = mapping.desc:gsub(\"^%+\", \"\")\n    end\n  end\n  if mapping.buffer == 0 or mapping.buffer == true then\n    mapping.buffer = vim.api.nvim_get_current_buf()\n  end\n  if mapping.rhs then\n    mapping.silent = mapping.silent ~= false\n  end\n  mapping.lhs = mapping.lhs or mapping.prefix\n  if not mapping.lhs then\n    return\n  end\n  mapping.prefix = nil\n\n  local has_desc = mapping.desc ~= nil\n  Util.getters(mapping, { \"desc\", \"icon\" })\n\n  if has_desc or mapping.group or mapping.hidden or mapping.rhs or (opts.version == M.VERSION and mapping.lhs) then\n    local modes = mapping.mode or { \"n\" } --[[@as string|string[] ]]\n    modes = type(modes) == \"string\" and vim.split(modes, \"\") or modes --[[@as string[] ]]\n    for _, mode in ipairs(modes) do\n      if mode ~= \"v\" and mode ~= Util.mapmode(mode) then\n        M.warn(\"Invalid mode `\" .. mode .. \"`\", mapping)\n      end\n      local m = vim.deepcopy(mapping)\n      m.mode = mode\n      table.insert(ret, m)\n    end\n  end\nend\n\n---@param mapping wk.Mapping\nfunction M.create(mapping)\n  assert(mapping.lhs, \"Missing lhs\")\n  assert(mapping.mode, \"Missing mode\")\n  assert(mapping.rhs, \"Missing rhs\")\n  local valid =\n    { \"remap\", \"noremap\", \"buffer\", \"silent\", \"nowait\", \"expr\", \"unique\", \"script\", \"desc\", \"replace_keycodes\" }\n  local opts = {} ---@type vim.keymap.set.Opts\n  for _, k in ipairs(valid) do\n    if mapping[k] ~= nil then\n      opts[k] = mapping[k]\n    end\n  end\n  vim.keymap.set(mapping.mode, mapping.lhs, mapping.rhs, opts)\nend\n\n---@param spec wk.Spec\n---@param opts? wk.Parse\nfunction M.parse(spec, opts)\n  opts = opts or {}\n  M.notify = opts.notify ~= false\n  local ret = M._parse(spec, nil, opts)\n  M.notify = true\n  for _, m in ipairs(ret) do\n    if m.rhs and opts.create then\n      M.create(m)\n    end\n  end\n  return ret\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/migrate.lua",
    "content": "local Mappings = require(\"which-key.mappings\")\n\nlocal M = {}\n\n---@param spec wk.Spec\nfunction M.migrate(spec)\n  spec = vim.deepcopy(spec)\n  local mappings = Mappings.parse(spec, { version = 1, notify = false })\n  ---@type table<string, {m:wk.Mapping, mode:string[]}>\n  local mapping_modes = {}\n\n  for _, m in ipairs(mappings) do\n    m.preset = nil\n    m[1] = m.lhs:gsub(\"<lt>\", \"<\")\n    m[2] = m.rhs\n    m.lhs = nil\n    m.rhs = nil\n    local mode = m.mode\n    m.mode = nil\n    if m.silent then\n      m.silent = nil\n    end\n    if m.group then\n      m.group = m.desc\n      m.desc = nil\n    end\n    local id = vim.inspect(m)\n    mapping_modes[id] = mapping_modes[id] or { m = m, mode = {} }\n    table.insert(mapping_modes[id].mode, mode)\n  end\n\n  mappings = vim.tbl_map(function(v)\n    local m = v.m\n    if not vim.deep_equal(v.mode, { \"n\" }) then\n      m.mode = v.mode\n    end\n    return m\n  end, vim.tbl_values(mapping_modes))\n\n  table.sort(mappings, function(a, b)\n    return a[1] < b[1]\n  end)\n\n  -- Group by modes\n  ---@type table<string, wk.Mapping[]>\n  local modes = {}\n  for _, m in pairs(mappings) do\n    local mode = m.mode or {}\n    table.sort(mode)\n    local id = table.concat(mode)\n    modes[id] = modes[id] or {}\n    table.insert(modes[id], m)\n  end\n  local lines = {}\n  for mode, maps in pairs(modes) do\n    if #maps > 2 and mode ~= \"\" then\n      lines[#lines + 1] = \"  {\"\n      lines[#lines + 1] = \"    mode = \" .. vim.inspect(maps[1].mode) .. \",\"\n      for _, m in ipairs(maps) do\n        m.mode = nil\n        lines[#lines + 1] = \"    \" .. vim.inspect(m):gsub(\"%s+\", \" \") .. \",\"\n      end\n      lines[#lines + 1] = \"  },\"\n    else\n      for _, m in ipairs(maps) do\n        if m.mode and #m.mode == 1 then\n          m.mode = m.mode[1]\n        end\n        lines[#lines + 1] = \"  \" .. vim.inspect(m):gsub(\"%s+\", \" \") .. \",\"\n      end\n    end\n  end\n\n  return \"{\\n\" .. table.concat(lines, \"\\n\") .. \"\\n}\"\nend\nreturn M\n"
  },
  {
    "path": "lua/which-key/node.lua",
    "content": "local Util = require(\"which-key.util\")\n\n---@class wk.Node\n---@field _children table<string, wk.Node>\nlocal M = {}\n\n---@param parent? wk.Node\n---@param key? string\n---@return wk.Node\nfunction M.new(parent, key)\n  local self = setmetatable({}, M)\n  self.parent = parent\n  self.key = key or \"\"\n  self.path = {}\n  self.global = true\n  self._children = {}\n  self.keys = (parent and parent.keys or \"\") .. self.key\n  for _, p in ipairs(parent and parent.path or {}) do\n    table.insert(self.path, p)\n  end\n  if key then\n    table.insert(self.path, key)\n  end\n  return self\nend\n\nfunction M:has_nowait_ancestor()\n  local node = self\n  while node do\n    if node.keymap and node.keymap.nowait then\n      return true\n    end\n    node = node.parent\n  end\n  return false\nend\n\nfunction M:is_local()\n  if self.path[1] == Util.norm(\"<localleader>\") then\n    return true\n  end\n  if self.buffer and self.buffer > 0 then\n    return true\n  end\n  for _, child in pairs(self._children) do\n    if child:is_local() then\n      return true\n    end\n  end\n  return false\nend\n\nfunction M:__index(k)\n  if k == \"mapping\" or k == \"keymap\" then\n    return\n  end\n  local v = rawget(M, k)\n  if v ~= nil then\n    return v\n  end\n  for _, m in ipairs({ \"mapping\", \"keymap\" }) do\n    local mm = rawget(self, m)\n    if k == m then\n      return mm\n    end\n    if mm and mm[k] ~= nil then\n      return mm[k]\n    end\n  end\nend\n\nfunction M:__tostring()\n  local info = { \"Node(\" .. self.keys .. \")\" }\n  if self:is_plugin() then\n    info[#info + 1] = \"Plugin(\" .. self.plugin .. \")\"\n  end\n  if self:is_proxy() then\n    info[#info + 1] = \"Proxy(\" .. self.mapping.proxy .. \")\"\n  end\n  return table.concat(info, \" \")\nend\n\n---@param depth? number\nfunction M:inspect(depth)\n  local indent = (\"  \"):rep(depth or 0)\n  local ret = { indent .. tostring(self) }\n  for _, child in ipairs(self:children()) do\n    table.insert(ret, child:inspect((depth or 0) + 1))\n  end\n  return table.concat(ret, \"\\n\")\nend\n\nfunction M:count()\n  return not self:can_expand() and vim.tbl_count(self._children) or #self:children()\nend\n\nfunction M:is_group()\n  return self:can_expand() or self:count() > 0\nend\n\nfunction M:is_proxy()\n  return self.mapping and self.mapping.proxy\nend\n\nfunction M:is_plugin()\n  return self.plugin ~= nil\nend\n\nfunction M:can_expand()\n  return self.plugin or (self.mapping and (self.mapping.proxy or self.mapping.expand))\nend\n\n---@return wk.Node[]\nfunction M:children()\n  return vim.tbl_values(self:expand())\nend\n\n---@return table<string, wk.Node>\nfunction M:expand()\n  if not self:can_expand() then\n    return self._children\n  end\n\n  ---@type table<string, wk.Node>\n  local ret = {}\n\n  -- plugin mappings\n  if self.plugin then\n    local plugin = require(\"which-key.plugins\").plugins[self.plugin or \"\"]\n    assert(plugin, \"plugin not found\")\n    Util.debug((\"Plugin(%q).expand\"):format(self.plugin))\n\n    for i, item in ipairs(plugin.expand()) do\n      item.order = i\n      local child = M.new(self, item.key) --[[@as wk.Node.plugin.item]]\n      setmetatable(child, { __index = setmetatable(item, M) })\n      ret[item.key] = child\n    end\n  end\n\n  -- proxy mappings\n  local proxy = self.mapping.proxy\n  if proxy then\n    local keys = Util.keys(proxy)\n    local root = self:root()\n    local node = root:find(keys, { expand = true })\n    if node then\n      for k, v in pairs(node:expand()) do\n        ret[k] = v\n      end\n    end\n  end\n\n  -- expand mappings\n  local expand = self.mapping and self.mapping.expand\n  if expand then\n    local Tree = require(\"which-key.tree\")\n    local tmp = Tree.new()\n    local mappings = require(\"which-key.mappings\").parse(expand())\n    for _, mapping in ipairs(mappings) do\n      tmp:add(mapping, true)\n    end\n    for _, child in ipairs(tmp.root:children()) do\n      local action = child.mapping and child.mapping.rhs\n      if type(action) == \"function\" then\n        child.action = action\n      elseif type(action) == \"string\" then\n        Util.error(\"expand mappings only support functions as rhs:\\n\" .. vim.inspect(child.mapping))\n      end\n      ret[child.key] = child\n    end\n  end\n\n  -- custom mappings\n  for k, v in pairs(self._children) do\n    ret[k] = v\n  end\n\n  return ret\nend\n\nfunction M:root()\n  local node = self\n  while node.parent do\n    node = node.parent\n  end\n  return node\nend\n\n---@param path string[]|string\n---@param opts? { create?: boolean, expand?: boolean }\n---@return wk.Node?\nfunction M:find(path, opts)\n  path = (type(path) == \"string\" and { path } or path) --[[@as string[] ]]\n  opts = opts or {}\n  local node = self\n  for _, key in ipairs(path) do\n    local child ---@type wk.Node?\n    if opts.expand then\n      child = node:expand()[key]\n    else\n      child = node._children[key]\n    end\n    if not child then\n      if not opts.create then\n        return\n      end\n      child = M.new(node, key)\n      node._children[key] = child\n    end\n    node = child\n  end\n  return node\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/plugins/init.lua",
    "content": "local Config = require(\"which-key.config\")\nlocal Util = require(\"which-key.util\")\n\nlocal M = {}\n\n---@type table<string, wk.Plugin>\nM.plugins = {}\n\nfunction M.setup()\n  for name, opts in pairs(Config.plugins) do\n    -- only setup plugin if we didnt load it before\n    if not M.plugins[name] then\n      if type(opts) == \"boolean\" then\n        opts = { enabled = opts }\n      end\n      opts.enabled = opts.enabled ~= false\n      if opts.enabled then\n        M.plugins[name] = require(\"which-key.plugins.\" .. name)\n        M._setup(M.plugins[name], opts)\n      end\n    end\n  end\nend\n\n---@param plugin wk.Plugin\nfunction M._setup(plugin, opts)\n  if plugin.mappings then\n    Config.add(plugin.mappings)\n  end\n\n  if plugin.setup then\n    plugin.setup(opts)\n  end\nend\n\n---@param name string\nfunction M.cols(name)\n  local plugin = M.plugins[name]\n  assert(plugin, \"plugin not found\")\n  local ret = {} ---@type wk.Col[]\n  vim.list_extend(ret, plugin.cols or {})\n  ret[#ret + 1] = { key = \"value\", hl = \"WhichKeyValue\", width = 0.5 }\n  return ret\nend\n\n---@class wk.Node.plugin.item: wk.Node,wk.Plugin.item\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/plugins/marks.lua",
    "content": "---@diagnostic disable: missing-fields, inject-field\n---@type wk.Plugin\nlocal M = {}\n\nM.name = \"marks\"\n\nM.mappings = {\n  icon = { icon = \"󰸕 \", color = \"orange\" },\n  plugin = \"marks\",\n  { \"`\", desc = \"marks\" },\n  { \"'\", desc = \"marks\" },\n  { \"g`\", desc = \"marks\" },\n  { \"g'\", desc = \"marks\" },\n}\n\nlocal labels = {\n  [\"^\"] = \"Last position of cursor in insert mode\",\n  [\".\"] = \"Last change in current buffer\",\n  ['\"'] = \"Last exited current buffer\",\n  [\"0\"] = \"In last file edited\",\n  [\"'\"] = \"Back to line in current buffer where jumped from\",\n  [\"`\"] = \"Back to position in current buffer where jumped from\",\n  [\"[\"] = \"To beginning of previously changed or yanked text\",\n  [\"]\"] = \"To end of previously changed or yanked text\",\n  [\"<lt>\"] = \"To beginning of last visual selection\",\n  [\">\"] = \"To end of last visual selection\",\n}\n\nM.cols = {\n  { key = \"lnum\", hl = \"Number\", align = \"right\" },\n}\n\nfunction M.expand()\n  local buf = vim.api.nvim_get_current_buf()\n  local items = {} ---@type wk.Plugin.item[]\n\n  local marks = {} ---@type vim.fn.getmarklist.ret.item[]\n  vim.list_extend(marks, vim.fn.getmarklist(buf))\n  vim.list_extend(marks, vim.fn.getmarklist())\n\n  for _, mark in pairs(marks) do\n    local key = mark.mark:sub(2, 2)\n    local lnum = mark.pos[2]\n\n    local line ---@type string?\n    if mark.pos[1] and mark.pos[1] ~= 0 then\n      line = vim.api.nvim_buf_get_lines(mark.pos[1], lnum - 1, lnum, false)[1]\n    end\n\n    local file = mark.file and vim.fn.fnamemodify(mark.file, \":p:~:.\")\n\n    table.insert(items, {\n      key = key,\n      desc = labels[key] or file and (\"file: \" .. file) or \"\",\n      value = vim.trim(line or file or \"\"),\n      highlights = { { 1, 5, \"Number\" } },\n      lnum = lnum,\n    })\n  end\n\n  return items\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/plugins/presets.lua",
    "content": "local M = {}\n\nM.name = \"presets\"\n\nM.operators = {\n  preset = true,\n  mode = { \"n\", \"x\" },\n  { \"!\", desc = \"Run program\" },\n  { \"<\", desc = \"Indent left\" },\n  { \">\", desc = \"Indent right\" },\n  { \"V\", desc = \"Visual Line\" },\n  { \"c\", desc = \"Change\" },\n  { \"d\", desc = \"Delete\" },\n  { \"gU\", desc = \"Uppercase\" },\n  { \"gu\", desc = \"Lowercase\" },\n  { \"g~\", desc = \"Toggle case\" },\n  { \"gw\", desc = \"Format\" },\n  { \"r\", desc = \"Replace\" },\n  { \"v\", desc = \"Visual\" },\n  { \"y\", desc = \"Yank\" },\n  { \"zf\", desc = \"Create fold\" },\n  { \"~\", desc = \"Toggle case\" },\n}\n\nM.motions = {\n  mode = { \"o\", \"x\", \"n\" },\n  preset = true,\n  { \"$\", desc = \"End of line\" },\n  { \"%\", desc = \"Matching (){}[]\" },\n  { \"0\", desc = \"Start of line\" },\n  { \"F\", desc = \"Move to prev char\" },\n  { \"G\", desc = \"Last line\" },\n  { \"T\", desc = \"Move before prev char\" },\n  { \"^\", desc = \"Start of line (non ws)\" },\n  { \"b\", desc = \"Prev word\" },\n  { \"e\", desc = \"Next end of word\" },\n  { \"f\", desc = \"Move to next char\" },\n  { \"ge\", desc = \"Prev end of word\" },\n  { \"gg\", desc = \"First line\" },\n  { \"h\", desc = \"Left\" },\n  { \"j\", desc = \"Down\" },\n  { \"k\", desc = \"Up\" },\n  { \"l\", desc = \"Right\" },\n  { \"t\", desc = \"Move before next char\" },\n  { \"w\", desc = \"Next word\" },\n  { \"{\", desc = \"Prev empty line\" },\n  { \"}\", desc = \"Next empty line\" },\n  { \";\", desc = \"Next ftFT\" },\n  { \",\", desc = \"Prev ftFT\" },\n  { \"/\", desc = \"Search forward\" },\n  { \"?\", desc = \"Search backward\" },\n  { \"B\", desc = \"Prev WORD\" },\n  { \"E\", desc = \"Next end of WORD\" },\n  { \"W\", desc = \"Next WORD\" },\n}\n\nM.text_objects = {\n  mode = { \"o\", \"x\" },\n  preset = true,\n  { \"a\", group = \"around\" },\n  { 'a\"', desc = '\" string' },\n  { \"a'\", desc = \"' string\" },\n  { \"a(\", desc = \"[(]) block\" },\n  { \"a)\", desc = \"[(]) block\" },\n  { \"a<\", desc = \"<> block\" },\n  { \"a>\", desc = \"<> block\" },\n  { \"aB\", desc = \"[{]} block\" },\n  { \"aW\", desc = \"WORD with ws\" },\n  { \"a[\", desc = \"[] block\" },\n  { \"a]\", desc = \"[] block\" },\n  { \"a`\", desc = \"` string\" },\n  { \"ab\", desc = \"[(]) block\" },\n  { \"ap\", desc = \"paragraph\" },\n  { \"as\", desc = \"sentence\" },\n  { \"at\", desc = \"tag block\" },\n  { \"aw\", desc = \"word with ws\" },\n  { \"a{\", desc = \"[{]} block\" },\n  { \"a}\", desc = \"[{]} block\" },\n  { \"i\", group = \"inside\" },\n  { 'i\"', desc = 'inner \" string' },\n  { \"i'\", desc = \"inner ' string\" },\n  { \"i(\", desc = \"inner [(])\" },\n  { \"i)\", desc = \"inner [(])\" },\n  { \"i<\", desc = \"inner <>\" },\n  { \"i>\", desc = \"inner <>\" },\n  { \"iB\", desc = \"inner [{]}\" },\n  { \"iW\", desc = \"inner WORD\" },\n  { \"i[\", desc = \"inner []\" },\n  { \"i]\", desc = \"inner []\" },\n  { \"i`\", desc = \"inner ` string\" },\n  { \"ib\", desc = \"inner [(])\" },\n  { \"ip\", desc = \"inner paragraph\" },\n  { \"is\", desc = \"inner sentence\" },\n  { \"it\", desc = \"inner tag block\" },\n  { \"iw\", desc = \"inner word\" },\n  { \"i{\", desc = \"inner [{]}\" },\n  { \"i}\", desc = \"inner [{]}\" },\n}\n\nM.windows = {\n  preset = true,\n  mode = { \"n\", \"x\" },\n  { \"<c-w>\", group = \"window\" },\n  { \"<c-w>+\", desc = \"Increase height\" },\n  { \"<c-w>-\", desc = \"Decrease height\" },\n  { \"<c-w><\", desc = \"Decrease width\" },\n  { \"<c-w>=\", desc = \"Equally high and wide\" },\n  { \"<c-w>>\", desc = \"Increase width\" },\n  { \"<c-w>T\", desc = \"Break out into a new tab\" },\n  { \"<c-w>_\", desc = \"Max out the height\" },\n  { \"<c-w>h\", desc = \"Go to the left window\" },\n  { \"<c-w>j\", desc = \"Go to the down window\" },\n  { \"<c-w>k\", desc = \"Go to the up window\" },\n  { \"<c-w>l\", desc = \"Go to the right window\" },\n  { \"<c-w>o\", desc = \"Close all other windows\" },\n  { \"<c-w>q\", desc = \"Quit a window\" },\n  { \"<c-w>s\", desc = \"Split window\" },\n  { \"<c-w>v\", desc = \"Split window vertically\" },\n  { \"<c-w>w\", desc = \"Switch windows\" },\n  { \"<c-w>x\", desc = \"Swap current with next\" },\n  { \"<c-w>|\", desc = \"Max out the width\" },\n  { \"<c-w>H\", desc = \"Move window to far left\" },\n  { \"<c-w>J\", desc = \"Move window to far bottom\" },\n  { \"<c-w>K\", desc = \"Move window to far top\" },\n  { \"<c-w>L\", desc = \"Move window to far right\" },\n}\n\nM.z = {\n  preset = true,\n  { \"z<CR>\", desc = \"Top this line\" },\n  { \"z=\", desc = \"Spelling suggestions\" },\n  { \"zA\", desc = \"Toggle all folds under cursor\" },\n  { \"zC\", desc = \"Close all folds under cursor\" },\n  { \"zD\", desc = \"Delete all folds under cursor\" },\n  { \"zE\", desc = \"Delete all folds in file\" },\n  { \"zH\", desc = \"Half screen to the left\" },\n  { \"zL\", desc = \"Half screen to the right\" },\n  { \"zM\", desc = \"Close all folds\" },\n  { \"zO\", desc = \"Open all folds under cursor\" },\n  { \"zR\", desc = \"Open all folds\" },\n  { \"za\", desc = \"Toggle fold under cursor\" },\n  { \"zb\", desc = \"Bottom this line\" },\n  { \"zc\", desc = \"Close fold under cursor\" },\n  { \"zd\", desc = \"Delete fold under cursor\" },\n  { \"ze\", desc = \"Right this line\" },\n  { \"zg\", desc = \"Add word to spell list\" },\n  { \"zi\", desc = \"Toggle folding\" },\n  { \"zm\", desc = \"Fold more\" },\n  { \"zo\", desc = \"Open fold under cursor\" },\n  { \"zr\", desc = \"Fold less\" },\n  { \"zs\", desc = \"Left this line\" },\n  { \"zt\", desc = \"Top this line\" },\n  { \"zv\", desc = \"Show cursor line\" },\n  { \"zw\", desc = \"Mark word as bad/misspelling\" },\n  { \"zx\", desc = \"Update folds\" },\n  { \"zz\", desc = \"Center this line\" },\n}\n\nM.nav = {\n  preset = true,\n  { \"H\", desc = \"Home line of window (top)\" },\n  { \"L\", desc = \"Last line of window\" },\n  { \"M\", desc = \"Middle line of window\" },\n  { \"[%\", desc = \"Previous unmatched group\" },\n  { \"[(\", desc = \"Previous (\" },\n  { \"[<\", desc = \"Previous <\" },\n  { \"[M\", desc = \"Previous method end\" },\n  { \"[m\", desc = \"Previous method start\" },\n  { \"[s\", desc = \"Previous misspelled word\" },\n  { \"[{\", desc = \"Previous {\" },\n  { \"]%\", desc = \"Next unmatched group\" },\n  { \"](\", desc = \"Next (\" },\n  { \"]<\", desc = \"Next <\" },\n  { \"]M\", desc = \"Next method end\" },\n  { \"]m\", desc = \"Next method start\" },\n  { \"]s\", desc = \"Next misspelled word\" },\n  { \"]{\", desc = \"Next {\" },\n}\n\nM.g = {\n  preset = true,\n  { \"g%\", desc = \"Cycle backwards through results\" },\n  { \"g,\", desc = \"Go to [count] newer position in change list\" },\n  { \"g;\", desc = \"Go to [count] older position in change list\" },\n  { \"gN\", desc = \"Search backwards and select\" },\n  { \"gT\", desc = \"Go to previous tab page\" },\n  { \"gf\", desc = \"Go to file under cursor\" },\n  { \"gi\", desc = \"Go to last insert\" },\n  { \"gn\", desc = \"Search forwards and select\" },\n  { \"gt\", desc = \"Go to next tab page\" },\n  { \"gv\", desc = \"Last visual selection\" },\n  { \"gx\", desc = \"Open file with system app\" },\n}\n\nfunction M.setup(opts)\n  local wk = require(\"which-key\")\n\n  -- Operators\n  if opts.operators then\n    wk.add(M.operators)\n  end\n\n  -- Motions\n  if opts.motions then\n    wk.add(M.motions)\n  end\n\n  -- Text objects\n  if opts.text_objects then\n    wk.add(M.text_objects)\n  end\n\n  -- Misc\n  for _, preset in pairs({ \"windows\", \"nav\", \"z\", \"g\" }) do\n    if opts[preset] ~= false then\n      wk.add(M[preset])\n    end\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/plugins/registers.lua",
    "content": "local Util = require(\"which-key.util\")\n\n---@diagnostic disable: missing-fields, inject-field\n---@type wk.Plugin\nlocal M = {}\n\nM.name = \"registers\"\n\nM.mappings = {\n  icon = { icon = \"󰅍 \", color = \"blue\" },\n  plugin = \"registers\",\n  { '\"', mode = { \"n\", \"x\" }, desc = \"registers\" },\n  { \"<c-r>\", mode = { \"i\", \"c\" }, desc = \"registers\" },\n}\n\nM.registers = '*+\"-:.%/#=_abcdefghijklmnopqrstuvwxyz0123456789'\n\nlocal labels = {\n  ['\"'] = \"last deleted, changed, or yanked content\",\n  [\"0\"] = \"last yank\",\n  [\"-\"] = \"deleted or changed content smaller than one line\",\n  [\".\"] = \"last inserted text\",\n  [\"%\"] = \"name of the current file\",\n  [\":\"] = \"most recent executed command\",\n  [\"#\"] = \"alternate buffer\",\n  [\"=\"] = \"result of an expression\",\n  [\"+\"] = \"synchronized with the system clipboard\",\n  [\"*\"] = \"synchronized with the selection clipboard\",\n  [\"_\"] = \"black hole\",\n  [\"/\"] = \"last search pattern\",\n}\n\nM.replace = {\n  [\"<Space>\"] = \" \",\n  [\"<lt>\"] = \"<\",\n  [\"<NL>\"] = \"\\n\",\n  [\"\\r\"] = \"\",\n}\n\nfunction M.expand()\n  local items = {} ---@type wk.Plugin.item[]\n\n  local is_osc52 = vim.g.clipboard and vim.g.clipboard.name == \"OSC 52\"\n  local has_clipboard = vim.g.loaded_clipboard_provider == 2\n\n  for i = 1, #M.registers, 1 do\n    local key = M.registers:sub(i, i)\n    local value = \"\"\n    if is_osc52 and key:match(\"[%+%*]\") then\n      value = \"OSC 52 detected, register not checked to maintain compatibility\"\n    elseif has_clipboard or not key:match(\"[%+%*]\") then\n      local ok, reg_value = pcall(vim.fn.getreg, key, 1)\n      value = (ok and reg_value or \"\") --[[@as string]]\n    end\n    if value ~= \"\" then\n      value = vim.fn.keytrans(value) --[[@as string]]\n      for k, v in pairs(M.replace) do\n        value = value:gsub(k, v) --[[@as string]]\n      end\n      table.insert(items, { key = key, desc = labels[key] or \"\", value = value })\n    end\n  end\n  return items\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/plugins/spelling.lua",
    "content": "---@diagnostic disable: missing-fields, inject-field\n---@type wk.Plugin\nlocal M = {}\n\nM.name = \"spelling\"\n\nM.mappings = {\n  {\n    \"z=\",\n    icon = { icon = \" \", color = \"red\" },\n    plugin = \"spelling\",\n    desc = \"Spelling Suggestions\",\n  },\n}\n\n---@type table<string, any>\nM.opts = {}\n\nfunction M.setup(opts)\n  M.opts = opts\nend\n\nfunction M.expand()\n  -- if started with a count, let the default keybinding work\n  local count = vim.v.count\n  if count and count > 0 then\n    return {}\n  end\n\n  local cursor_word = vim.fn.expand(\"<cword>\")\n  -- get a misspelled word from under the cursor, if not found, then use the cursor_word instead\n  local bad = vim.fn.spellbadword(cursor_word)\n  local word = bad[1] == \"\" and cursor_word or bad[1]\n\n  ---@type string[]\n  local suggestions = vim.fn.spellsuggest(word, M.opts.suggestions or 20, bad[2] == \"caps\" and 1 or 0)\n\n  local items = {} ---@type wk.Plugin.item[]\n  local keys = \"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\n  for i, label in ipairs(suggestions) do\n    local key = keys:sub(i, i)\n\n    table.insert(items, {\n      key = key,\n      desc = label,\n      action = function()\n        vim.cmd(\"norm! \" .. i .. \"z=\")\n      end,\n    })\n  end\n  return items\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/presets.lua",
    "content": "---@type table<string, wk.Opts>\nreturn {\n  helix = {\n    win = {\n      width = { min = 30, max = 60 },\n      height = { min = 4, max = 0.75 },\n      padding = { 0, 1 },\n      col = -1,\n      row = -1,\n      border = \"rounded\",\n      title = true,\n      title_pos = \"left\",\n    },\n    layout = {\n      width = { min = 30 },\n    },\n  },\n  modern = {\n    win = {\n      width = 0.9,\n      height = { min = 4, max = 25 },\n      col = 0.5,\n      row = -1,\n      border = \"rounded\",\n      title = true,\n      title_pos = \"center\",\n    },\n  },\n  classic = {\n    win = {\n      width = math.huge,\n      height = { min = 4, max = 25 },\n      col = 0,\n      row = -1,\n      border = \"none\",\n    },\n  },\n}\n"
  },
  {
    "path": "lua/which-key/state.lua",
    "content": "local Buf = require(\"which-key.buf\")\nlocal Config = require(\"which-key.config\")\nlocal Triggers = require(\"which-key.triggers\")\nlocal Util = require(\"which-key.util\")\n\nlocal uv = vim.uv or vim.loop\n\nlocal M = {}\n\n---@class wk.State\n---@field mode wk.Mode\n---@field node wk.Node\n---@field filter wk.Filter\n---@field started number\n---@field show boolean\n\n---@type wk.State?\nM.state = nil\nM.recursion = 0\nM.recursion_timer = uv.new_timer()\nM.redraw_timer = uv.new_timer()\n\n---@return boolean safe, string? reason\nfunction M.safe(mode_change)\n  local old, _new = unpack(vim.split(mode_change, \":\", { plain = true }))\n  if old == \"c\" then\n    return false, \"command-mode\"\n  elseif Util.in_macro() then\n    return false, \"macro\"\n  elseif mode_change:lower() == \"v:v\" then\n    return false, \"visual-block\"\n  end\n  local pending = vim.fn.getcharstr(1)\n  if pending ~= \"\" then\n    return false, \"pending \" .. (\"%q\"):format(vim.fn.strtrans(pending))\n  end\n  return true\nend\n\nfunction M.setup()\n  local group = vim.api.nvim_create_augroup(\"wk\", { clear = true })\n\n  if Config.debug then\n    vim.on_key(function(_raw, key)\n      if key and #key > 0 then\n        key = vim.fn.keytrans(key)\n        if not key:find(\"ScrollWheel\") and not key:find(\"Mouse\") then\n          Util.debug(\"on_key\", key)\n        end\n      end\n    end)\n  end\n\n  vim.api.nvim_create_autocmd({ \"RecordingEnter\", \"RecordingLeave\" }, {\n    group = group,\n    callback = function(ev)\n      Util.debug(ev.event)\n      if ev.event == \"RecordingEnter\" then\n        Buf.clear({ buf = ev.buf })\n        M.stop()\n      end\n    end,\n  })\n\n  local hide = uv.new_timer()\n  vim.api.nvim_create_autocmd({ \"FocusLost\", \"FocusGained\" }, {\n    group = group,\n    callback = function(ev)\n      if ev.event == \"FocusGained\" then\n        hide:stop()\n      elseif M.state then\n        hide:start(5000, 0, function()\n          vim.api.nvim_input(\"<esc>\")\n        end)\n      end\n    end,\n  })\n\n  local function defer()\n    local mode = vim.api.nvim_get_mode().mode\n    local mode_keys = Util.keys(mode)\n    local ctx = {\n      operator = mode:find(\"o\") and vim.v.operator or nil,\n      mode = mode_keys[1],\n    }\n    return Config.defer(ctx)\n  end\n\n  local cooldown = Util.cooldown()\n  -- this prevents restarting which-key in the same tick\n  vim.api.nvim_create_autocmd(\"ModeChanged\", {\n    group = group,\n    callback = function(ev)\n      Util.trace(\"ModeChanged(\" .. ev.match .. \")\")\n      local mode = Buf.get()\n\n      if cooldown() then\n        Util.debug(\"cooldown\")\n        Util.trace()\n        return\n      end\n\n      local safe, reason = M.safe(ev.match)\n      Util.debug(safe and \"Safe(true)\" or (\"Unsafe(\" .. reason .. \")\"))\n      if not safe then\n        if mode then\n          Triggers.suspend(mode)\n        end\n        -- dont start when recording or when chars are pending\n        cooldown(true) -- cooldown till next tick\n        M.stop()\n        -- make sure the buffer mode exists\n      elseif mode and Util.xo() then\n        if Config.triggers.modes[mode.mode] and not M.state then\n          M.start({ defer = defer() })\n        end\n      elseif not ev.match:find(\"c\") then\n        M.stop()\n      end\n      Util.trace()\n    end,\n  })\n\n  vim.api.nvim_create_autocmd({ \"LspAttach\", \"LspDetach\" }, {\n    group = group,\n    callback = function(ev)\n      Util.trace(ev.event .. \"(\" .. ev.buf .. \")\")\n      Buf.clear({ buf = ev.buf })\n      Util.trace()\n    end,\n  })\n\n  vim.api.nvim_create_autocmd({ \"BufReadPost\", \"BufNew\" }, {\n    group = group,\n    callback = function(ev)\n      Util.trace(ev.event .. \"(\" .. ev.buf .. \")\")\n      Buf.clear({ buf = ev.buf })\n      Util.trace()\n    end,\n  })\n\n  local current_buf = vim.api.nvim_get_current_buf()\n  vim.api.nvim_create_autocmd({ \"BufEnter\" }, {\n    group = group,\n    callback = function(ev)\n      current_buf = ev.buf ---@type number\n      Util.trace(ev.event .. \"(\" .. ev.buf .. \")\")\n      Buf.get()\n      Util.trace()\n    end,\n  })\n\n  -- HACK: ModeChanged does not always trigger, so we need to manually\n  -- check for mode changes. This seems to be due to the usage of `:norm` in autocmds.\n  -- See https://github.com/folke/which-key.nvim/issues/787\n  local timer = uv.new_timer()\n  timer:start(0, 50, function()\n    local mode = Util.mapmode()\n    -- check if the mode exists for the current buffer\n    if Buf.bufs[current_buf] and Buf.bufs[current_buf].modes[mode] then\n      return\n    end\n    vim.schedule(Buf.get)\n  end)\nend\n\nfunction M.stop()\n  if M.state == nil then\n    return\n  end\n  Util.debug(\"state:stop\")\n  M.state = nil\n  vim.schedule(function()\n    if not M.state then\n      require(\"which-key.view\").hide()\n    end\n  end)\nend\n\n---@param state wk.State\n---@param key? string\n---@return wk.Node? node\nfunction M.check(state, key)\n  local View = require(\"which-key.view\")\n  local node = key == nil and state.node or (key and state.node:find(key, { expand = true }))\n\n  local delta = uv.hrtime() / 1e6 - state.started\n  local timedout = vim.o.timeout and delta > vim.o.timeoutlen\n\n  if node then\n    -- NOTE: a node can be both a keymap and a group\n    -- when it's both, we honor timeoutlen and nowait to decide what to do\n    local has_children = node:count() > 0\n    local is_nowait = node.keymap and (node.keymap.nowait == 1 or not timedout)\n    local is_action = node.action ~= nil\n    if has_children and not is_nowait and not is_action then\n      Util.debug(\"continue\", node.keys, tostring(state.mode), node.plugin)\n      return node\n    end\n  elseif key == \"<Esc>\" then\n    if state.mode:xo() then\n      Util.exit() -- cancel and exit if in xo mode\n    end\n    return\n  elseif key == \"<BS>\" then\n    return state.node.parent or state.mode.tree.root\n  elseif View.valid() and key == Config.keys.scroll_down then\n    View.scroll(false)\n    return state.node\n  elseif View.valid() and key == Config.keys.scroll_up then\n    View.scroll(true)\n    return state.node\n  end\n  M.execute(state, key, node)\nend\n\n---@param state wk.State\n---@param key? string\n---@param node? wk.Node\n---@return false|wk.Node?\nfunction M.execute(state, key, node)\n  Triggers.suspend(state.mode)\n\n  if node and node.action then\n    return node.action()\n  end\n\n  local keystr = node and node.keys or (state.node.keys .. (key or \"\"))\n  if not state.mode:xo() then\n    if vim.v.count > 0 and state.mode.mode ~= \"i\" and state.mode.mode ~= \"c\" then\n      keystr = vim.v.count .. keystr\n    end\n    if vim.v.register ~= Util.reg() and state.mode.mode ~= \"i\" and state.mode.mode ~= \"c\" then\n      keystr = '\"' .. vim.v.register .. keystr\n    end\n  end\n  Util.debug(\"feedkeys\", tostring(state.mode), keystr)\n  local feed = vim.api.nvim_replace_termcodes(keystr, true, true, true)\n  vim.api.nvim_feedkeys(feed, \"mit\", false)\nend\n\nfunction M.getchar()\n  return pcall(vim.fn.getcharstr)\nend\n\n---@param state wk.State\n---@return wk.Node? node, boolean? exit\nfunction M.step(state)\n  M.redraw_timer:start(\n    50,\n    0,\n    vim.schedule_wrap(function()\n      if vim.api.nvim__redraw then\n        vim.api.nvim__redraw({ cursor = true, valid = true, flush = true })\n      else\n        vim.cmd.redraw()\n      end\n    end)\n  )\n  vim.schedule(function() end)\n  Util.debug(\"getchar\")\n  local ok, char = M.getchar()\n  if not ok then\n    Util.debug(\"nok\", char)\n    return nil, true\n  end\n  local key = vim.fn.keytrans(char)\n  Util.debug(\"got\", key)\n\n  local node = M.check(state, key)\n  if node == state.node then\n    return M.step(state) -- same node, so try again (scrolling)\n  end\n  return node, key == \"<Esc>\"\nend\n\n---@param opts? wk.Filter\nfunction M.start(opts)\n  Util.trace(\"State(start)\", function()\n    local mode = opts and opts.mode or Util.mapmode()\n    local buf = opts and opts.buf or 0\n    local keys = opts and opts.keys or \"\"\n    return { \"Mode(\" .. mode .. \":\" .. buf .. \") Node(\" .. keys .. \")\", opts }\n  end)\n\n  opts = opts or {}\n  opts.update = true\n  local mode = Buf.get(opts)\n  opts.update = nil\n  if not mode then\n    Util.debug(\"no mode\")\n    Util.trace()\n    return false\n  end\n  local node = mode.tree:find(opts.keys or {}, { expand = true })\n  if not node then\n    Util.debug(\"no node\")\n    Util.trace()\n    return false\n  end\n\n  local mapmode = mode.mode\n  M.recursion = M.recursion + 1\n  M.recursion_timer:start(500, 0, function()\n    M.recursion = 0\n  end)\n\n  if M.recursion > 50 then\n    Util.error({\n      \"Recursion detected.\",\n      \"Are you manually loading which-key in a keymap?\",\n      \"Use `opts.triggers` instead.\",\n      \"Please check the docs.\",\n    })\n    Util.debug(\"recursion detected. Aborting\")\n    Util.trace()\n    return false\n  end\n\n  local View = require(\"which-key.view\")\n\n  M.state = {\n    mode = mode,\n    node = node,\n    filter = opts,\n    started = uv.hrtime() / 1e6 - (opts.waited or 0),\n    show = opts.defer ~= true,\n  }\n\n  if not M.check(M.state) then\n    Util.debug(\"executed\")\n    Util.trace()\n    return true\n  end\n\n  local exit = false\n\n  while M.state do\n    mode = Buf.get(opts)\n    if not mode or mode.mode ~= mapmode then\n      break\n    end\n    if M.state.show then\n      View.update(opts)\n    end\n    local child, _exit = M.step(M.state)\n    if child and M.state then\n      M.state.node = child\n      M.state.show = true\n    else\n      exit = _exit or false\n      break\n    end\n  end\n  M.redraw_timer:stop()\n\n  if opts.loop and not exit then\n    -- NOTE: flush pending keys to prevent a trigger loop\n    vim.api.nvim_feedkeys(\"\", \"x\", false)\n    vim.schedule(function()\n      M.start(opts)\n    end)\n  else\n    M.state = nil\n    View.hide()\n  end\n  Util.trace()\n  return true\nend\n\nfunction M.update()\n  if not M.state then\n    return\n  end\n  local mode = Buf.get()\n  if not mode or mode.mode ~= M.state.mode.mode then\n    return\n  end\n  local node = mode.tree:find(M.state.node.path)\n  if not node then\n    return\n  end\n  M.state.node = node\n  require(\"which-key.view\").update({ schedule = false })\nend\n\n---@param opts {delay?:number, mode:string, keys:string, plugin?:string, waited?: number}\nfunction M.delay(opts)\n  local delay = opts.delay or type(Config.delay) == \"function\" and Config.delay(opts) or Config.delay --[[@as number]]\n  if opts.waited then\n    delay = delay - opts.waited\n  end\n  return math.max(0, delay)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/text.lua",
    "content": "local Util = require(\"which-key.util\")\n\n---@class wk.Segment\n---@field str string Text\n---@field hl? string Extmark hl group\n---@field line? number line number in a multiline segment\n---@field width? number\n\n---@class wk.Text.opts\n---@field multiline? boolean\n---@field indent? boolean\n\n---@class wk.Text\n---@field _lines wk.Segment[][]\n---@field _col number\n---@field _indents string[]\n---@field _opts wk.Text.opts\nlocal M = {}\nM.__index = M\n\nM.ns = vim.api.nvim_create_namespace(\"wk.text\")\n\n---@param opts? wk.Text.opts\nfunction M.new(opts)\n  local self = setmetatable({}, M)\n  self._lines = {}\n  self._col = 0\n  self._opts = opts or {}\n  self._indents = {}\n  for i = 0, 100, 1 do\n    self._indents[i] = (\" \"):rep(i)\n  end\n  return self\nend\n\nfunction M:height()\n  return #self._lines\nend\n\n---@return number\nfunction M:width()\n  local width = 0\n  for _, line in ipairs(self._lines) do\n    local w = 0\n    for _, segment in ipairs(line) do\n      w = w + vim.fn.strdisplaywidth(segment.str)\n    end\n    width = math.max(width, w)\n  end\n  return width\nend\n\n---@param text string|wk.Segment[]\n---@param opts? string|{hl?:string, line?:number}\nfunction M:append(text, opts)\n  opts = opts or {}\n  if #self._lines == 0 then\n    self:nl()\n  end\n\n  if type(text) == \"table\" then\n    for _, s in ipairs(text) do\n      s.width = s.width or #s.str\n      self._col = self._col + s.width\n      table.insert(self._lines[#self._lines], s)\n    end\n    return self\n  end\n\n  opts = type(opts) == \"string\" and { hl = opts } or opts\n\n  for l, line in ipairs(vim.split(text, \"\\n\", { plain = true })) do\n    local width = #line\n    self._col = self._col + width\n    table.insert(self._lines[#self._lines], {\n      str = line,\n      width = width,\n      hl = opts.hl,\n      line = opts.line or l,\n    })\n  end\n  return self\nend\n\nfunction M:nl()\n  table.insert(self._lines, {})\n  self._col = 0\n  return self\nend\n\n---@param opts? {sep?:string}\nfunction M:statusline(opts)\n  local sep = opts and opts.sep or \" \"\n  local lines = {} ---@type string[]\n  for _, line in ipairs(self._lines) do\n    local parts = {}\n    for _, segment in ipairs(line) do\n      local str = segment.str:gsub(\"%%\", \"%%%%\")\n      if segment.hl then\n        str = (\"%%#%s#%s%%*\"):format(segment.hl, str)\n      end\n      parts[#parts + 1] = str\n    end\n    table.insert(lines, table.concat(parts, \"\"))\n  end\n  return table.concat(lines, sep)\nend\n\nfunction M:render(buf)\n  local lines = {}\n\n  for _, line in ipairs(self._lines) do\n    local parts = {} ---@type string[]\n    for _, segment in ipairs(line) do\n      parts[#parts + 1] = segment.str\n    end\n    table.insert(lines, table.concat(parts, \"\"))\n  end\n\n  vim.bo[buf].modifiable = true\n  vim.api.nvim_buf_clear_namespace(buf, M.ns, 0, -1)\n  vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)\n\n  for l, line in ipairs(self._lines) do\n    local col = 0\n    local row = l - 1\n\n    for _, segment in ipairs(line) do\n      local width = segment.width\n      if segment.hl then\n        Util.set_extmark(buf, M.ns, row, col, {\n          hl_group = segment.hl,\n          end_col = col + width,\n        })\n      end\n      col = col + width\n    end\n  end\n  vim.bo[buf].modifiable = false\nend\n\nfunction M:trim()\n  while #self._lines > 0 and #self._lines[#self._lines] == 0 do\n    table.remove(self._lines)\n  end\nend\n\nfunction M:row()\n  return #self._lines == 0 and 1 or #self._lines\nend\n\n---@param opts? {display:boolean}\nfunction M:col(opts)\n  if opts and opts.display then\n    local ret = 0\n    for _, segment in ipairs(self._lines[#self._lines] or {}) do\n      ret = ret + vim.fn.strdisplaywidth(segment.str)\n    end\n    return ret\n  end\n  return self._col\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/tree.lua",
    "content": "local Config = require(\"which-key.config\")\nlocal Node = require(\"which-key.node\")\nlocal Util = require(\"which-key.util\")\n\n---@class wk.Tree\n---@field root wk.Node\nlocal M = {}\nM.__index = M\n\n---@type table<string, table<wk.Mapping|wk.Keymap, true>>\nM.dups = {}\n\nfunction M.new()\n  local self = setmetatable({}, M)\n  self:clear()\n  return self\nend\n\nfunction M:clear()\n  self.root = Node.new()\nend\n\n---@param keymap wk.Mapping|wk.Keymap\n---@param virtual? boolean\nfunction M:add(keymap, virtual)\n  if not Config.filter(keymap) then\n    return\n  end\n  local keys = Util.keys(keymap.lhs, { norm = true })\n  local node = assert(self.root:find(keys, { create = true }))\n  node.plugin = node.plugin or keymap.plugin\n  if virtual then\n    ---@cast node wk.Node\n    if node.mapping and not keymap.preset and not node.mapping.preset then\n      local id = keymap.mode .. \":\" .. node.keys\n      M.dups[id] = M.dups[id] or {}\n      M.dups[id][keymap] = true\n      M.dups[id][node.mapping] = true\n    end\n    if not (keymap.preset and node.keymap and node.keymap.desc) then\n      node.mapping = keymap --[[@as wk.Mapping]]\n    end\n  else\n    node.keymap = keymap\n  end\nend\n\n---@param node wk.Node\nfunction M:del(node)\n  if node == self.root then\n    return self:clear()\n  end\n  local parent = node.parent\n  assert(parent, \"node has no parent\")\n  parent._children[node.key] = nil\n  if not self:keep(parent) then\n    self:del(parent)\n  end\nend\n\n---@param node wk.Node\nfunction M:keep(node)\n  if node.hidden or (node.keymap and node.keymap.desc == \"which_key_ignore\") then\n    return false\n  end\n  if node.mapping and node.mapping.real and not node.keymap then\n    return false\n  end\n  return node.keymap or (node.mapping and not node.group) or node:is_group()\nend\n\nfunction M:fix()\n  self:walk(function(node)\n    if not self:keep(node) then\n      self:del(node)\n      return false\n    end\n  end)\nend\n\n---@param keys string|string[]\n---@param opts? { create?: boolean, expand?: boolean }\n---@return wk.Node?\nfunction M:find(keys, opts)\n  keys = type(keys) == \"string\" and Util.keys(keys) or keys\n  return self.root:find(keys, opts)\nend\n\n---@param fn fun(node: wk.Node):boolean?\n---@param opts? {expand?: boolean}\nfunction M:walk(fn, opts)\n  opts = opts or {}\n  ---@type wk.Node[]\n  local queue = { self.root }\n  while #queue > 0 do\n    local node = table.remove(queue, 1) ---@type wk.Node\n    if node == self.root or fn(node) ~= false then\n      local children = opts.expand and node:children() or node._children\n      for _, child in pairs(children) do\n        queue[#queue + 1] = child\n      end\n    end\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/triggers.lua",
    "content": "local Util = require(\"which-key.util\")\n\n---@class wk.Trigger\n---@field buf number\n---@field mode string\n---@field keys string\n---@field plugin? string\n\nlocal M = {}\nM._triggers = {} ---@type table<string, wk.Trigger>\nM.suspended = {} ---@type table<wk.Mode, boolean>\n\nM.timer = (vim.uv or vim.loop).new_timer()\n\n--- Checks if a mapping already exists that is not a which-key trigger.\n---@param trigger wk.Trigger\nfunction M.is_mapped(trigger)\n  ---@type wk.Keymap?\n  local km\n  pcall(vim.api.nvim_buf_call, trigger.buf, function()\n    km = vim.fn.maparg(trigger.keys, trigger.mode, false, true) --[[@as wk.Keymap]]\n  end)\n  -- not mapped\n  if not km or vim.tbl_isempty(km) then\n    return false\n  end\n  -- ignore <Nop> mappings\n  if Util.is_nop(km.rhs) then\n    return false\n  end\n  -- ignore which-key triggers\n  if km.desc and km.desc:find(\"which-key-trigger\", 1, true) then\n    return false\n  end\n  return true\nend\n\n---@param trigger wk.Trigger\nfunction M.add(trigger)\n  if M.is_mapped(trigger) then\n    return\n  end\n  vim.keymap.set(trigger.mode, trigger.keys, function()\n    require(\"which-key.state\").start({\n      keys = trigger.keys,\n    })\n  end, {\n    buffer = trigger.buf,\n    nowait = true,\n    desc = \"which-key-trigger\" .. (trigger.plugin and \" \" .. trigger.plugin or \"\"),\n  })\n  M._triggers[M.id(trigger)] = trigger\nend\n\nfunction M.is_active()\n  return vim.tbl_isempty(M._triggers)\nend\n\n---@param trigger wk.Trigger\nfunction M.del(trigger)\n  M._triggers[M.id(trigger)] = nil\n  if not vim.api.nvim_buf_is_valid(trigger.buf) then\n    return\n  end\n  if M.is_mapped(trigger) then\n    return\n  end\n  pcall(vim.keymap.del, trigger.mode, trigger.keys, { buffer = trigger.buf })\nend\n\n---@param trigger wk.Trigger\nfunction M.id(trigger)\n  return trigger.buf .. \":\" .. trigger.mode .. \":\" .. trigger.keys\nend\n\n---@param trigger wk.Trigger\nfunction M.has(trigger)\n  return M._triggers[M.id(trigger)] ~= nil\nend\n\n---@param mode wk.Mode\n---@param triggers? wk.Trigger[]\nfunction M.update(mode, triggers)\n  M.cleanup()\n  if not mode.buf:valid() then\n    for _, trigger in pairs(M._triggers) do\n      if trigger.buf == mode.buf.buf then\n        M.del(trigger)\n      end\n    end\n    return\n  end\n  local adds = {} ---@type string[]\n  local dels = {} ---@type string[]\n  local keep = {} ---@type table<string, boolean>\n  for _, node in ipairs(triggers or mode.triggers) do\n    ---@type wk.Trigger\n    local trigger = {\n      buf = mode.buf.buf,\n      mode = mode.mode,\n      keys = node.keys,\n      plugin = node.plugin,\n    }\n    local id = M.id(trigger)\n    keep[id] = true\n    if not M.has(trigger) then\n      adds[#adds + 1] = trigger.keys\n      M.add(trigger)\n    end\n  end\n  for id, trigger in pairs(M._triggers) do\n    if trigger.buf == mode.buf.buf and trigger.mode == mode.mode and not keep[id] then\n      M.del(trigger)\n      dels[#dels + 1] = trigger.keys\n    end\n  end\n  if #adds > 0 then\n    Util.debug(\"Trigger(add) \" .. tostring(mode) .. \" \" .. table.concat(adds, \" \"))\n  end\n  if #dels > 0 then\n    Util.debug(\"Trigger(del) \" .. tostring(mode) .. \" \" .. table.concat(dels, \" \"))\n  end\nend\n\n---@param mode wk.Mode\nfunction M.attach(mode)\n  if M.suspended[mode] then\n    return\n  end\n  M.update(mode)\nend\n\n---@param mode wk.Mode\nfunction M.detach(mode)\n  M.update(mode, {})\nend\n\n---@param mode? wk.Mode\nfunction M.schedule(mode)\n  if mode then\n    M.suspended[mode] = true\n  end\n  M.timer:start(\n    0,\n    0,\n    vim.schedule_wrap(function()\n      if Util.in_macro() then\n        return vim.defer_fn(M.schedule, 100)\n      end\n      for m, _ in pairs(M.suspended) do\n        M.suspended[m] = nil\n        M.attach(m)\n      end\n    end)\n  )\nend\n\nfunction M.cleanup()\n  for _, trigger in pairs(M._triggers) do\n    if not vim.api.nvim_buf_is_valid(trigger.buf) then\n      M.del(trigger)\n    end\n  end\nend\n\n---@param mode wk.Mode\nfunction M.suspend(mode)\n  Util.debug(\"suspend\", tostring(mode))\n  M.detach(mode)\n  M.suspended[mode] = true\n  M.schedule()\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/types.lua",
    "content": "---@meta\n\n--# selene: allow(unused_variable)\n\n---@class wk.Filter\n---@field mode? string\n---@field buf? number\n---@field keys? string\n---@field global? boolean\n---@field local? boolean\n---@field update? boolean\n---@field delay? number\n---@field loop? boolean\n---@field defer? boolean don't show the popup immediately. Wait for the first key to be pressed\n---@field waited? number\n---@field check? boolean\n---@field expand? boolean\n\n---@class wk.Icon\n---@field icon? string\n---@field hl? string\n---@field cat? \"file\" | \"filetype\" | \"extension\"\n---@field name? string\n---@field color? false | \"azure\" | \"blue\" | \"cyan\" | \"green\" | \"grey\" | \"orange\" | \"purple\" | \"red\" | \"yellow\"\n\n---@class wk.IconProvider\n---@field name string\n---@field available? boolean\n---@field get fun(icon: wk.Icon):(icon: string?, hl: string?)\n\n---@class wk.IconRule: wk.Icon\n---@field pattern? string\n---@field plugin? string\n\n---@class wk.Keymap: vim.api.keyset.keymap\n---@field lhs string\n---@field mode string\n---@field rhs? string|fun()\n---@field lhsraw? string\n---@field buffer? number\n\n--- Represents a node in the which-key tree\n---@class wk.Node: wk.Mapping\n---@field key string single key of the node\n---@field path string[] path to the node (all keys leading to this node)\n---@field keys string full key sequence\n---@field parent? wk.Node parent node\n---@field keymap? wk.Keymap Real keymap\n---@field mapping? wk.Mapping Mapping info supplied by user\n---@field action? fun() action to execute when node is selected (used by plugins)\n\n---@class wk.Mapping: wk.Keymap\n---@field idx? number\n---@field plugin? string\n---@field group? boolean\n---@field remap? boolean\n---@field hidden? boolean\n---@field real? boolean this is a mapping for a real keymap. Hide it if the real keymap does not exist\n---@field preset? boolean\n---@field icon? wk.Icon|string\n---@field proxy? string\n---@field expand? fun():wk.Spec\n\n---@class wk.Spec: {[number]: wk.Spec} , wk.Mapping\n---@field [1]? string\n---@field [2]? string|fun()\n---@field lhs? string\n---@field group? string|fun():string\n---@field desc? string|fun():string\n---@field icon? wk.Icon|string|fun():(wk.Icon|string)\n---@field buffer? number|boolean\n---@field mode? string|string[]\n---@field cond? boolean|fun():boolean?\n\n---@class wk.Win.opts: vim.api.keyset.win_config\n---@field width? wk.Dim\n---@field height? wk.Dim\n---@field wo? vim.wo\n---@field bo? vim.bo\n---@field padding? {[1]: number, [2]:number}\n---@field no_overlap? boolean\n\n---@class wk.Col\n---@field key string\n---@field hl? string\n---@field width? number\n---@field padding? number[]\n---@field default? string\n---@field align? \"left\"|\"right\"|\"center\"\n\n---@class wk.Table.opts\n---@field cols wk.Col[]\n---@field rows table<string, string>[]\n\n---@class wk.Plugin.item\n---@field key string\n---@field value string\n---@field desc string\n---@field order? number\n---@field action? fun()\n\n---@class wk.Plugin\n---@field name string\n---@field cols? wk.Col[]\n---@field mappings? wk.Spec\n---@field expand fun():wk.Plugin.item[]\n---@field setup fun(opts: table<string, any>)\n\n---@class wk.Item: wk.Node\n---@field node wk.Node\n---@field key string\n---@field raw_key string\n---@field desc string\n---@field group? boolean\n---@field order? number\n---@field icon? string\n---@field icon_hl? string\n"
  },
  {
    "path": "lua/which-key/util.lua",
    "content": "local M = {}\n\nM.cache = {\n  keys = {}, ---@type table<string, string[]>\n  norm = {}, ---@type table<string, string>\n  termcodes = {}, ---@type table<string, string>\n}\n\nfunction M.t(str)\n  M.cache.termcodes[str] = M.cache.termcodes[str] or vim.api.nvim_replace_termcodes(str, true, true, true)\n  return M.cache.termcodes[str]\nend\n\nM.CR = M.t(\"<cr>\")\nM.ESC = M.t(\"<esc>\")\nM.BS = M.t(\"<bs>\")\nM.EXIT = M.t(\"<C-\\\\><C-n>\")\nM.LUA_CALLBACK = \"\\x80\\253g\"\nM.CMD = \"\\x80\\253h\"\n\nfunction M.exit()\n  vim.api.nvim_feedkeys(M.EXIT, \"n\", false)\n  vim.api.nvim_feedkeys(M.ESC, \"n\", false)\nend\n\nfunction M.in_macro()\n  return vim.fn.reg_recording() ~= \"\" or vim.fn.reg_executing() ~= \"\"\nend\n\n---@param rhs string|fun()\nfunction M.is_nop(rhs)\n  return type(rhs) == \"string\" and (rhs == \"\" or rhs:lower() == \"<nop>\")\nend\n\n--- Normalizes (and fixes) the lhs of a keymap\n---@param lhs string\nfunction M.norm(lhs)\n  if M.cache.norm[lhs] then\n    return M.cache.norm[lhs]\n  end\n  M.cache.norm[lhs] = vim.fn.keytrans(M.t(lhs))\n  return M.cache.norm[lhs]\nend\n\n-- Default register\nfunction M.reg()\n  -- this will be set to 2 if there is a non-empty clipboard\n  -- tool available\n  if vim.g.loaded_clipboard_provider ~= 2 then\n    return '\"'\n  end\n  local cb = vim.o.clipboard\n  return cb:find(\"unnamedplus\") and \"+\" or cb:find(\"unnamed\") and \"*\" or '\"'\nend\n\n--- Returns the keys of a keymap, taking multibyte and special keys into account\n---@param lhs string\n---@param opts? {norm?: boolean}\nfunction M.keys(lhs, opts)\n  lhs = opts and opts.norm == false and lhs or M.norm(lhs)\n  if M.cache.keys[lhs] then\n    return M.cache.keys[lhs]\n  end\n  local ret = {} ---@type string[]\n  local bytes = vim.fn.str2list(lhs) ---@type number[]\n  local special = nil ---@type string?\n  for _, byte in ipairs(bytes) do\n    local char = vim.fn.nr2char(byte) ---@type string\n    if char == \"<\" then\n      special = \"<\"\n    elseif special then\n      special = special .. char\n      if char == \">\" then\n        ret[#ret + 1] = special == \"<lt>\" and \"<\" or special\n        special = nil\n      end\n    else\n      ret[#ret + 1] = char\n    end\n  end\n\n  M.cache.keys[lhs] = ret\n  return ret\nend\n\n---@param mode? string\nfunction M.mapmode(mode)\n  mode = mode or vim.api.nvim_get_mode().mode\n  mode = mode:gsub(M.t(\"<C-V>\"), \"v\"):gsub(M.t(\"<C-S>\"), \"s\"):lower()\n  if mode:sub(1, 2) == \"no\" then\n    return \"o\"\n  end\n  if mode:sub(1, 1) == \"v\" then\n    return \"x\" -- mapmode is actually \"x\" for visual only mappings\n  end\n  return mode:sub(1, 1):match(\"[ncitsxo]\") or \"n\"\nend\n\nfunction M.xo()\n  return M.mapmode():find(\"[xo]\") ~= nil\nend\n\n---@alias NotifyOpts {level?: number, title?: string, once?: boolean, id?:string}\n\n---@param msg string|string[]\n---@param opts? NotifyOpts\nfunction M.notify(msg, opts)\n  opts = opts or {}\n  msg = type(msg) == \"table\" and table.concat(msg, \"\\n\") or msg\n  ---@cast msg string\n  msg = vim.trim(msg)\n  return vim[opts.once and \"notify_once\" or \"notify\"](msg, opts.level, {\n    title = opts.title or \"which-key.nvim\",\n    on_open = function(win)\n      M.wo(win, { conceallevel = 3, spell = false, concealcursor = \"n\" })\n      vim.treesitter.start(vim.api.nvim_win_get_buf(win), \"markdown\")\n    end,\n  })\nend\n\n---@param msg string|string[]\n---@param opts? NotifyOpts\nfunction M.warn(msg, opts)\n  M.notify(msg, vim.tbl_extend(\"keep\", { level = vim.log.levels.WARN }, opts or {}))\nend\n\n---@param msg string|string[]\n---@param opts? NotifyOpts\nfunction M.info(msg, opts)\n  M.notify(msg, vim.tbl_extend(\"keep\", { level = vim.log.levels.INFO }, opts or {}))\nend\n\n---@param msg string|string[]\n---@param opts? NotifyOpts\nfunction M.error(msg, opts)\n  M.notify(msg, vim.tbl_extend(\"keep\", { level = vim.log.levels.ERROR }, opts or {}))\nend\n\n---@generic F: fun()\n---@param ms number\n---@param fn F\n---@return F\nfunction M.debounce(ms, fn)\n  local timer = (vim.uv or vim.loop).new_timer()\n  return function(...)\n    local args = { ... }\n    timer:start(\n      ms,\n      0,\n      vim.schedule_wrap(function()\n        fn(args)\n      end)\n    )\n  end\nend\n\n---@param opts? {msg?: string}\nfunction M.try(fn, opts)\n  local ok, err = pcall(fn)\n  if not ok then\n    local msg = opts and opts.msg or \"Something went wrong:\"\n    msg = msg .. \"\\n\" .. err\n    M.error(msg)\n  end\nend\n\n---@param buf number\n---@param row number\n---@param ns number\n---@param col number\n---@param opts vim.api.keyset.set_extmark\n---@param debug_info? any\nfunction M.set_extmark(buf, ns, row, col, opts, debug_info)\n  local ok, err = pcall(vim.api.nvim_buf_set_extmark, buf, ns, row, col, opts)\n  if not ok then\n    M.error(\n      \"Failed to set extmark for preview:\\n\"\n        .. vim.inspect({ info = debug_info, row = row, col = col, opts = opts, error = err })\n    )\n  end\nend\n\n---@param n number buffer or window number\n---@param type \"win\" | \"buf\"\n---@param opts vim.wo | vim.bo\nlocal function set_opts(n, type, opts)\n  ---@diagnostic disable-next-line: no-unknown\n  for k, v in pairs(opts or {}) do\n    ---@diagnostic disable-next-line: no-unknown\n    pcall(vim.api.nvim_set_option_value, k, v, type == \"win\" and {\n      scope = \"local\",\n      win = n,\n    } or { buf = n })\n  end\nend\n\n---@param win number\n---@param opts vim.wo\nfunction M.wo(win, opts)\n  set_opts(win, \"win\", opts)\nend\n\n---@param buf number\n---@param opts vim.bo\nfunction M.bo(buf, opts)\n  set_opts(buf, \"buf\", opts)\nend\n\nlocal trace_level = 0\n---@param msg? string\n---@param ...? any\nfunction M.trace(msg, ...)\n  if not msg then\n    trace_level = trace_level - 1\n    return\n  end\n  trace_level = math.max(trace_level, 0)\n  M.debug(msg, ...)\n  trace_level = trace_level + 1\nend\n\n---@param msg? string\n---@param ...? any\nfunction M.debug(msg, ...)\n  if not require(\"which-key.config\").debug then\n    return\n  end\n  local data = { ... }\n  if #data == 0 then\n    data = nil\n  elseif #data == 1 then\n    data = data[1]\n  end\n  if type(data) == \"function\" then\n    data = data()\n  end\n  if type(data) == \"table\" then\n    data = table.concat(\n      vim.tbl_map(function(value)\n        return type(value) == \"string\" and value or vim.inspect(value):gsub(\"%s+\", \" \")\n      end, data),\n      \" \"\n    )\n  end\n  if data and type(data) ~= \"string\" then\n    data = vim.inspect(data):gsub(\"%s+\", \" \")\n  end\n  msg = data and (\"%s: %s\"):format(msg, data) or msg\n  msg = string.rep(\"  \", trace_level) .. msg\n  M.log(msg .. \"\\n\")\nend\n\nfunction M.log(msg)\n  local file = \"./wk.log\"\n  local fd = io.open(file, \"a+\")\n  if not fd then\n    error((\"Could not open file %s for writing\"):format(file))\n  end\n  fd:write(msg)\n  fd:close()\nend\n\n--- Returns a function that returns true if the cooldown is active.\n--- The cooldown will be active for the given duration or 0 if no duration is given.\n--- Runs in the main loop.\n--- cooldown(true) will wait till the next tick.\n---@return fun(cooldown?: number|boolean): boolean\nfunction M.cooldown()\n  local waiting = false\n  ---@param cooldown? number|boolean\n  return function(cooldown)\n    if waiting then\n      return true\n    elseif cooldown then\n      waiting = true\n      vim.defer_fn(function()\n        waiting = false\n      end, type(cooldown) == \"number\" and cooldown or 0)\n    end\n    return false\n  end\nend\n\n---@generic T: table\n---@param t T\n---@param fields string[]\n---@return T\nfunction M.getters(t, fields)\n  local getters = {} ---@type table<string, fun():any>\n  for _, prop in ipairs(fields) do\n    if type(t[prop]) == \"function\" then\n      getters[prop] = t[prop]\n      rawset(t, prop, nil)\n    end\n  end\n\n  if not vim.tbl_isempty(getters) then\n    setmetatable(t, {\n      __index = function(_, key)\n        if getters[key] then\n          return getters[key](t)\n        end\n      end,\n    })\n  end\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/view.lua",
    "content": "local Buf = require(\"which-key.buf\")\nlocal Config = require(\"which-key.config\")\nlocal Icons = require(\"which-key.icons\")\nlocal Layout = require(\"which-key.layout\")\nlocal Plugins = require(\"which-key.plugins\")\nlocal State = require(\"which-key.state\")\nlocal Text = require(\"which-key.text\")\nlocal Tree = require(\"which-key.tree\")\nlocal Util = require(\"which-key.util\")\nlocal Win = require(\"which-key.win\")\n\nlocal M = {}\nM.view = nil ---@type wk.Win?\nM.footer = nil ---@type wk.Win?\nM.timer = (vim.uv or vim.loop).new_timer()\n\n---@alias wk.Sorter fun(node:wk.Item): (string|number)\n\n---@type table<string, wk.Sorter>\nM.fields = {\n  order = function(item)\n    return item.order and item.order or 1000\n  end,\n  [\"local\"] = function(item)\n    return item.keymap and item.keymap.buffer ~= 0 and 0 or 1000\n  end,\n  manual = function(item)\n    return item.mapping and item.mapping.idx or 10000\n  end,\n  desc = function(item)\n    return item.desc or \"~\"\n  end,\n  group = function(item)\n    return item.group and 1 or 0\n  end,\n  alphanum = function(item)\n    return item.key:find(\"^%w+$\") and 0 or 1\n  end,\n  mod = function(item)\n    return item.key:find(\"^<.*>$\") and 0 or 1\n  end,\n  case = function(item)\n    return item.key:lower() == item.key and 0 or 1\n  end,\n  natural = function(item)\n    local ret = item.key:gsub(\"%d+\", function(d)\n      return (\"%09d\"):format(tonumber(d))\n    end)\n    return ret:lower()\n  end,\n}\n\n---@param lhs string\nfunction M.format(lhs)\n  local keys = Util.keys(lhs)\n  local ret = vim.tbl_map(function(key)\n    local inner = key:match(\"^<(.*)>$\")\n    if not inner then\n      return key\n    end\n    if inner == \"NL\" then\n      inner = \"C-J\"\n    end\n    local parts = vim.split(inner, \"-\", { plain = true })\n    for i, part in ipairs(parts) do\n      if i == 1 or i ~= #parts or not part:match(\"^%w$\") then\n        parts[i] = Config.icons.keys[part] or parts[i]\n      end\n    end\n    return table.concat(parts, \"\")\n  end, keys)\n  return table.concat(ret, \"\")\nend\n\n---@param nodes wk.Item[]\n---@param fields? (string|wk.Sorter)[]\nfunction M.sort(nodes, fields)\n  fields = vim.deepcopy(fields or Config.sort)\n  vim.list_extend(fields, { \"natural\", \"case\" })\n  table.sort(nodes, function(a, b)\n    for _, f in ipairs(fields) do\n      local field = type(f) == \"function\" and f or M.fields[f]\n      if field then\n        local aa = field(a)\n        local bb = field(b)\n        if aa ~= bb then\n          return aa < bb\n        end\n      end\n    end\n    return a.raw_key < b.raw_key\n  end)\nend\n\nfunction M.valid()\n  return M.view and M.view:valid()\nend\n\n---@param opts? {delay?: number, schedule?: boolean, waited?: number}\nfunction M.update(opts)\n  local state = State.state\n\n  if not state then\n    M.hide()\n    return\n  end\n\n  opts = opts or {}\n  if M.valid() then\n    M.show()\n  elseif opts.schedule ~= false then\n    local delay = opts.delay\n      or State.delay({\n        mode = state.mode.mode,\n        keys = state.node.keys,\n        plugin = state.node.plugin,\n        waited = opts.waited,\n      })\n    M.timer:start(\n      delay,\n      0,\n      vim.schedule_wrap(function()\n        Util.try(M.show)\n      end)\n    )\n  end\nend\n\nfunction M.hide()\n  if M.view then\n    M.view:hide()\n    M.view = nil\n  end\n  if M.footer then\n    M.footer:hide()\n    M.footer = nil\n  end\nend\n\n---@param field string\n---@param value string\n---@return string\nfunction M.replace(field, value)\n  for _, repl in pairs(Config.replace[field]) do\n    value = type(repl) == \"function\" and (repl(value) or value) or value:gsub(repl[1], repl[2])\n  end\n  return value\nend\n\n---@param node wk.Node\nfunction M.icon(node)\n  -- plugin items should not get icons\n  if node.parent and node.parent.plugin then\n    return\n  end\n  if node.mapping and node.mapping.icon then\n    return Icons.get(node.mapping.icon)\n  end\n  local icon, icon_hl = Icons.get({ keymap = node.keymap, desc = node.desc })\n  if icon then\n    return icon, icon_hl\n  end\n  if node.parent then\n    return M.icon(node.parent)\n  end\nend\n\n---@param node wk.Node\n---@param opts? {default?: \"count\"|\"path\", parent?: wk.Node, group?: boolean}\nfunction M.item(node, opts)\n  opts = opts or {}\n  opts.default = opts.default or \"count\"\n  local child_count = (node:can_expand() or opts.group == false) and 0 or node:count()\n  local desc = node.desc\n  if not desc and node.keymap and node.keymap.rhs ~= \"\" and type(node.keymap.rhs) == \"string\" then\n    desc = node.keymap.rhs --[[@as string]]\n  end\n  if not desc and opts.default == \"count\" and child_count > 0 then\n    desc = child_count .. \" keymap\" .. (child_count > 1 and \"s\" or \"\")\n  end\n  if not desc and opts.default == \"path\" then\n    desc = node.keys\n  end\n  desc = M.replace(\"desc\", desc or \"\")\n  local icon, icon_hl = M.icon(node)\n\n  local raw_key = node.key\n  if opts.parent and opts.parent ~= node and node.keys:find(opts.parent.keys, 1, true) == 1 then\n    raw_key = node.keys:sub(opts.parent.keys:len() + 1)\n  end\n\n  local group = node:is_group()\n  ---@type wk.Item\n  return setmetatable({\n    node = node,\n    icon = icon or \"\",\n    icon_hl = icon_hl,\n    key = M.replace(\"key\", raw_key),\n    raw_key = raw_key,\n    desc = group and Config.icons.group .. desc or desc,\n    group = group,\n  }, { __index = node })\nend\n\n---@param node wk.Node\n---@param opts? {title?: boolean}\nfunction M.trail(node, opts)\n  opts = opts or {}\n\n  ---@param group? string\n  local function hl(group)\n    return opts.title and \"WhichKeyTitle\" or (group and (\"WhichKey\" .. group) or \"WhichKeyGroup\")\n  end\n\n  local trail = {} ---@type string[][]\n  local did_op = false\n  while node do\n    local desc = node.desc and (Config.icons.group .. M.replace(\"desc\", node.desc))\n      or node.key and M.replace(\"key\", node.key)\n      or \"\"\n    node = node.parent\n    if desc ~= \"\" then\n      if node and #trail > 0 then\n        table.insert(trail, 1, { \" \" .. Config.icons.breadcrumb .. \" \", hl(\"Separator\") })\n      end\n      table.insert(trail, 1, { desc, hl() })\n    end\n    local m = State.state.mode.mode\n    if not did_op and not node and (m == \"x\" or m == \"o\") then\n      did_op = true\n      local mode = Buf.get({ buf = State.state.mode.buf.buf, mode = \"n\" })\n      if mode then\n        node = mode.tree:find(m == \"x\" and \"v\" or vim.v.operator)\n      end\n    end\n  end\n  if #trail > 0 then\n    table.insert(trail, 1, { \" \", hl() })\n    table.insert(trail, { \" \", hl() })\n    return trail\n  end\nend\n\n---@param root wk.Node\n---@param node wk.Node\n---@param expand fun(node:wk.Node): boolean\n---@param filter fun(node:wk.Node): boolean\n---@param ret? wk.Item[]\nfunction M.expand(root, node, expand, filter, ret)\n  ret = ret or {}\n  if not filter(node) then\n    return ret\n  end\n  if not node:is_plugin() and expand(node) then\n    if node.keymap then\n      ret[#ret + 1] = M.item(node, { group = false, parent = root })\n    end\n    for _, child in ipairs(node:children()) do\n      M.expand(root, child, expand, filter, ret)\n    end\n  else\n    ret[#ret + 1] = M.item(node, { parent = root })\n  end\n  return ret\nend\n\nfunction M.show()\n  local state = State.state\n  if not (state and state.show and state.node:is_group()) then\n    M.hide()\n    return\n  end\n  local text = Text.new()\n\n  ---@type wk.Node[]\n  local children = state.node:children()\n\n  if state.filter.global == false and state.filter.expand == nil then\n    state.filter.expand = true\n  end\n\n  ---@param node wk.Node\n  local function filter(node)\n    local l = state.filter[\"local\"] ~= false\n    local g = state.filter.global ~= false\n    if not g and not l then\n      return false\n    end\n    if g and l then\n      return true\n    end\n    local is_local = node:is_local()\n    return l and is_local or g and not is_local\n  end\n\n  ---@param node wk.Node\n  local function expand(node)\n    if node:is_plugin() then\n      return false\n    end\n    if state.filter.expand then\n      return true\n    end\n    if node:can_expand() then\n      return false\n    end\n    if type(Config.expand) == \"function\" then\n      return Config.expand(node)\n    end\n    local child_count = node:count()\n    return child_count > 0 and child_count <= Config.expand\n  end\n\n  ---@type wk.Item[]\n  local items = {}\n  for _, node in ipairs(children) do\n    vim.list_extend(items, M.expand(state.node, node, expand, filter))\n  end\n\n  M.sort(items)\n\n  ---@type wk.Col[]\n  local cols = {\n    { key = \"key\", hl = \"WhichKey\", align = \"right\" },\n    { key = \"sep\", hl = \"WhichKeySeparator\", default = Config.icons.separator },\n    { key = \"icon\", padding = { 0, 0 } },\n  }\n  if state.node.plugin then\n    vim.list_extend(cols, Plugins.cols(state.node.plugin))\n  end\n  cols[#cols + 1] = { key = \"desc\", width = math.huge }\n\n  local t = Layout.new({ cols = cols, rows = items })\n\n  local opts = Win.defaults(Config.win)\n  local container = {\n    width = Layout.dim(vim.o.columns, vim.o.columns, opts.width),\n    height = Layout.dim(vim.o.lines, vim.o.lines, opts.height),\n  }\n  local _, _, max_row_width = t:cells()\n  local box_width = Layout.dim(max_row_width, container.width, Config.layout.width)\n  local box_count = math.max(math.floor(container.width / (box_width + Config.layout.spacing)), 1)\n  box_width = math.floor(container.width / box_count)\n  local box_height = math.max(math.ceil(#items / box_count), 2)\n\n  local rows = t:layout({ width = box_width - Config.layout.spacing })\n\n  for _ = 1, Config.win.padding[1] + 1 do\n    text:nl()\n  end\n\n  for l = 1, box_height do\n    text:append(string.rep(\" \", Config.win.padding[2]))\n    for b = 1, box_count do\n      local i = (b - 1) * box_height + l\n      local item = items[i]\n      local row = rows[i]\n      if b ~= 1 or box_count > 1 then\n        text:append(string.rep(\" \", Config.layout.spacing))\n      end\n      if item then\n        for c, col in ipairs(row) do\n          local hl = col.hl\n          if cols[c].key == \"desc\" then\n            hl = item.group and \"WhichKeyGroup\" or \"WhichKeyDesc\"\n          end\n          if cols[c].key == \"icon\" then\n            hl = item.icon_hl\n          end\n          text:append(col.value, hl)\n        end\n      end\n    end\n    text:append(string.rep(\" \", Config.win.padding[2]))\n    text:nl()\n  end\n  text:trim()\n\n  for _ = 1, Config.win.padding[1] do\n    text:nl()\n  end\n\n  local show_keys = Config.show_keys\n\n  local has_border = opts.border and opts.border ~= \"none\"\n  if has_border then\n    if opts.title == true then\n      opts.title = M.trail(state.node, { title = true })\n      show_keys = false\n    end\n    if opts.footer == true then\n      opts.footer = M.trail(state.node, { title = true })\n      show_keys = false\n    end\n    if not opts.title then\n      opts.title = \"\"\n      opts.title_pos = nil\n    end\n    if not opts.footer then\n      opts.footer = \"\"\n      opts.footer_pos = nil\n    end\n  else\n    opts.footer = nil\n    opts.footer_pos = nil\n    opts.title = nil\n    opts.title_pos = nil\n  end\n\n  local bw = has_border and 2 or 0\n\n  opts.width = Layout.dim(text:width() + bw, vim.o.columns, opts.width)\n  opts.height = Layout.dim(text:height() + bw, vim.o.lines, opts.height)\n\n  if Config.show_help then\n    opts.height = opts.height + 1\n  end\n\n  -- top-left\n  opts.col = Layout.dim(opts.col, vim.o.columns - opts.width)\n  opts.row = Layout.dim(opts.row, vim.o.lines - opts.height - vim.o.cmdheight)\n\n  opts.width = opts.width - bw\n  opts.height = opts.height - bw\n  M.check_overlap(opts)\n\n  M.view = M.view or Win.new(opts)\n  M.view:show(opts)\n\n  if Config.show_help or show_keys then\n    text:nl()\n    local footer = Text.new()\n    if show_keys then\n      footer:append(\" \")\n      for _, segment in ipairs(M.trail(state.node) or {}) do\n        footer:append(segment[1], segment[2])\n      end\n    end\n    if Config.show_help then\n      ---@type {key: string, desc: string}[]\n      local keys = {\n        { key = \"<esc>\", desc = \"close\" },\n      }\n      if state.node.parent then\n        keys[#keys + 1] = { key = \"<bs>\", desc = \"back\" }\n      end\n      if opts.height < text:height() then\n        keys[#keys + 1] = { key = Config.keys.scroll_down .. \"/\" .. Config.keys.scroll_up, desc = \"scroll\" }\n      end\n      local help = Text.new()\n      for k, key in ipairs(keys) do\n        help:append(M.replace(\"key\", Util.norm(key.key)), \"WhichKey\"):append(\" \" .. key.desc, \"WhichKeySeparator\")\n        if k < #keys then\n          help:append(\"  \")\n        end\n      end\n      local col = footer:col({ display = true })\n      local ws = string.rep(\" \", math.floor((opts.width - help:width()) / 2) - col)\n      footer:append(ws)\n      footer:append(help._lines[1])\n    end\n    footer:trim()\n    M.footer = M.footer or Win.new()\n    M.footer:show({\n      relative = \"win\",\n      win = M.view.win,\n      col = 0,\n      row = opts.height - 1,\n      width = opts.width,\n      height = 1,\n      zindex = M.view.opts.zindex + 1,\n      border = \"none\",\n    })\n    footer:render(M.footer.buf)\n  end\n\n  text:render(M.view.buf)\n  vim.api.nvim_win_call(M.view.win, function()\n    vim.fn.winrestview({ topline = 1 })\n  end)\n  vim.cmd.redraw()\nend\n\n---@param opts wk.Win.opts\nfunction M.check_overlap(opts)\n  if Config.win.no_overlap == false then\n    return\n  end\n  local row, col = vim.fn.screenrow(), vim.fn.screencol()\n  local overlaps = (row >= opts.row and row <= opts.row + opts.height)\n    and (col >= opts.col and col <= opts.col + opts.width)\n  -- dd(overlaps and \"overlaps\" or \"no overlap\", {\n  --   editor = { lines = vim.o.lines, columns = vim.o.columns },\n  --   cursor = { col = col, row = row },\n  --   win = { row = opts.row, col = opts.col, height = opts.height, width = opts.width },\n  --   overlaps = overlaps,\n  -- })\n  if overlaps then\n    opts.row = row + 1\n    opts.height = math.max(vim.o.lines - opts.row, 4)\n  end\nend\n\n---@param up boolean\nfunction M.scroll(up)\n  return M.view and M.view:scroll(up)\nend\n\nreturn M\n"
  },
  {
    "path": "lua/which-key/win.lua",
    "content": "local Util = require(\"which-key.util\")\n\n---@class wk.Win\n---@field win? number\n---@field buf? number\n---@field opts wk.Win.opts\nlocal M = {}\nM.__index = M\n\n---@class wk.Win.opts\nlocal override = {\n  relative = \"editor\",\n  style = \"minimal\",\n  focusable = false,\n  noautocmd = true,\n  wo = {\n    scrolloff = 0,\n    foldenable = false,\n    winhighlight = \"Normal:WhichKeyNormal,FloatBorder:WhichKeyBorder,FloatTitle:WhichKeyTitle\",\n    winbar = \"\",\n    statusline = \"\",\n    wrap = false,\n  },\n  bo = {\n    buftype = \"nofile\",\n    bufhidden = \"wipe\",\n    filetype = \"wk\",\n  },\n}\n\n---@type wk.Win.opts\nlocal defaults = { col = 0, row = math.huge, zindex = 1000 }\n\n---@param opts? wk.Win.opts\nfunction M.defaults(opts)\n  return vim.tbl_deep_extend(\"force\", {}, defaults, opts or {}, override)\nend\n\n---@param opts? wk.Win.opts\nfunction M.new(opts)\n  local self = setmetatable({}, M)\n  self.opts = M.defaults(opts)\n  return self\nend\n\nfunction M:valid()\n  return self.buf and vim.api.nvim_buf_is_valid(self.buf) and self.win and vim.api.nvim_win_is_valid(self.win) or false\nend\n\nfunction M:hide()\n  if not (self.buf or self.win) then\n    return\n  end\n\n  ---@type number?, number?\n  local buf, win = self.buf, self.win\n  self.buf, self.win = nil, nil\n\n  local function try_close()\n    pcall(vim.api.nvim_win_close, win, true)\n    pcall(vim.api.nvim_buf_delete, buf, { force = true })\n    win = win and vim.api.nvim_win_is_valid(win) and win or nil\n    buf = buf and vim.api.nvim_buf_is_valid(buf) and buf or nil\n    if win or buf then\n      vim.schedule(try_close)\n    end\n  end\n\n  try_close()\nend\n\n---@param opts? wk.Win.opts\nfunction M:show(opts)\n  if opts then\n    self.opts = vim.tbl_deep_extend(\"force\", self.opts, opts)\n  end\n  local win_opts = vim.deepcopy(self.opts)\n  win_opts.wo = nil\n  win_opts.bo = nil\n  win_opts.padding = nil\n  win_opts.no_overlap = nil\n\n  if vim.fn.has(\"nvim-0.10\") == 0 then\n    win_opts.footer = nil\n  end\n\n  if self:valid() then\n    win_opts.noautocmd = nil\n    return vim.api.nvim_win_set_config(self.win, win_opts)\n  end\n\n  local ei = vim.go.eventignore\n  vim.go.eventignore = \"all\"\n\n  self.buf = vim.api.nvim_create_buf(false, true)\n  Util.bo(self.buf, self.opts.bo or {})\n  self.win = vim.api.nvim_open_win(self.buf, false, win_opts)\n  Util.wo(self.win, self.opts.wo or {})\n\n  vim.go.eventignore = ei\nend\n\n---@param up boolean\nfunction M:scroll(up)\n  if not self:valid() then\n    return\n  end\n  local height = vim.api.nvim_win_get_height(self.win)\n  local delta = math.ceil((up and -1 or 1) * height / 2)\n  local view = vim.api.nvim_win_call(self.win, vim.fn.winsaveview)\n  local top = view.topline ---@type number\n  top = top + delta\n  top = math.max(top, 1)\n  top = math.min(top, vim.api.nvim_buf_line_count(self.buf) - height + 1)\n  vim.api.nvim_win_call(self.win, function()\n    vim.fn.winrestview({ topline = top, lnum = top })\n  end)\nend\n\nreturn M\n"
  },
  {
    "path": "plugin/which-key.lua",
    "content": "local timer = (vim.uv or vim.loop).new_timer()\ntimer:start(\n  500,\n  0,\n  vim.schedule_wrap(function()\n    local wk = require(\"which-key\")\n    if not wk.did_setup then\n      wk.setup()\n    end\n  end)\n)\n"
  },
  {
    "path": "scripts/docs",
    "content": "#!/bin/env bash\n\nnvim -u tests/minit.lua -l lua/which-key/docs.lua\n"
  },
  {
    "path": "scripts/test",
    "content": "#!/usr/bin/env bash\n\nnvim -l tests/minit.lua --minitest \"$@\"\n"
  },
  {
    "path": "selene.toml",
    "content": "std=\"vim\"\n\n[lints]\nmixed_table=\"allow\"\n"
  },
  {
    "path": "stylua.toml",
    "content": "indent_type = \"Spaces\"\nindent_width = 2\ncolumn_width = 120\n[sort_requires]\nenabled = true\n\n"
  },
  {
    "path": "tests/buf_spec.lua",
    "content": "local Buf = require(\"which-key.buf\")\n\nbefore_each(function()\n  require(\"helpers\").reset()\nend)\n\ndescribe(\"triggers\", function()\n  it(\"does not create hooks for default mappings\", function()\n    vim.keymap.set(\"n\", \"aa\", \"<nop>\")\n    Buf.get({ mode = \"n\" })\n    local m = vim.fn.maparg(\"a\", \"n\", false, true)\n    assert.same(vim.empty_dict(), m)\n  end)\nend)\n"
  },
  {
    "path": "tests/helpers.lua",
    "content": "local M = {}\n\n---@param lines? string[]\nfunction M.reset(lines)\n  vim.o.showmode = false\n  vim.api.nvim_feedkeys(vim.keycode(\"<Ignore><C-\\\\><C-n><esc>\"), \"nx\", false)\n  vim.cmd(\"enew\")\n  vim.cmd(\"normal! <c-w>o\")\n  vim.api.nvim_buf_set_lines(0, 0, -1, false, lines or {})\nend\n\nreturn M\n"
  },
  {
    "path": "tests/layout_spec.lua",
    "content": "local layout = require(\"which-key.layout\")\n\ndescribe(\"dim\", function()\n  local tests = {\n    { 100, { 200 }, 100 },\n    { 0.2, { 100 }, 20 },\n    { -0.2, { 100 }, 80 },\n    { -20, { 100 }, 80 },\n    { 1, { 100 }, 1 },\n    { 100, { 200, { min = 50 } }, 100 },\n    { 100, { 200, { max = 150 } }, 100 },\n    { 100, { 200, { max = 150, min = 50 } }, 100 },\n    { 100, { 200, { max = 150, min = 150 } }, 150 },\n    { 0.2, { 100, { max = 150, min = 20 } }, 20 },\n    { 0.2, { 100, { max = 50, min = 20 } }, 20 },\n    { math.huge, { 200 }, 200 },\n    { -0.5, { 200 }, 100 },\n    { 0.5, { 200 }, 100 },\n    { 0.5, { 200, { min = 150 } }, 150 },\n    { -0.5, { 200, { max = 50 } }, 50 },\n    { 300, { 200, { max = 250 } }, 200 },\n    { 300, { 200, { min = 250 } }, 200 },\n    { -100, { 100, { max = 90, min = 20 } }, 20 },\n    { -200, { 100, { max = -50, min = -50 } }, 0 },\n    { 0.2, { 100, { min = 0.5 } }, 50 },\n    { -200, { 100 }, 0 },\n    { -1, { 100 }, 99 },\n    { -0.1, { 100 }, 90 },\n    { 0.1, { 100 }, 10 },\n    { 14, { 212, 0.9 }, 191 },\n  }\n\n  for _, test in ipairs(tests) do\n    it(\"size=\" .. test[1] .. \", parent=\" .. test[2][1] .. \", result = \" .. test[3], function()\n      assert.are.equal(test[3], layout.dim(test[1], unpack(test[2])))\n    end)\n  end\nend)\n"
  },
  {
    "path": "tests/mappings_spec.lua",
    "content": "local Mappings = require(\"which-key.mappings\")\n\nbefore_each(function()\n  Mappings.notifs = {}\nend)\n\ndescribe(\"specs v1\", function()\n  local tests = {\n    {\n      spec = {\n        [\"<leader>\"] = {\n          name = \"leader\",\n          [\"a\"] = { \"a\" },\n          [\"b\"] = { \"b\" },\n          [\"c\"] = { \"c\" },\n        },\n      },\n      mappings = {\n        { lhs = \"<leader>\", group = true, desc = \"leader\", mode = \"n\" },\n        { lhs = \"<leader>a\", desc = \"a\", mode = \"n\" },\n        { lhs = \"<leader>b\", desc = \"b\", mode = \"n\" },\n        { lhs = \"<leader>c\", desc = \"c\", mode = \"n\" },\n      },\n    },\n    {\n      spec = {\n        mode = \"v\",\n        [\"<leader>\"] = {\n          name = \"leader\",\n          [\"a\"] = { \"a\" },\n          [\"b\"] = { \"b\" },\n          [\"c\"] = { \"c\" },\n        },\n      },\n      mappings = {\n        { lhs = \"<leader>\", group = true, desc = \"leader\", mode = \"v\" },\n        { lhs = \"<leader>a\", desc = \"a\", mode = \"v\" },\n        { lhs = \"<leader>b\", desc = \"b\", mode = \"v\" },\n        { lhs = \"<leader>c\", desc = \"c\", mode = \"v\" },\n      },\n    },\n    {\n      spec = { desc = \"foo\", noremap = true },\n      mappings = {},\n    },\n    {\n      spec = { a = { desc = \"which_key_ignore\" } },\n      mappings = {\n        { lhs = \"a\", hidden = true, mode = \"n\" },\n      },\n    },\n    {\n      spec = { a = { \"foo\", cond = false } },\n      mappings = {},\n    },\n    {\n      spec = { a = { \"foo\", cond = true } },\n      mappings = {\n        { desc = \"foo\", lhs = \"a\", mode = \"n\" },\n      },\n    },\n    {\n      spec = {\n        a = { \"a\", cmd = \"aa\" },\n        b = { \"b\", callback = \"bb\" },\n        c = { \"cc\", \"c\" },\n        d = { \"dd\", desc = \"d\" },\n      },\n      mappings = {\n        { lhs = \"a\", desc = \"a\", rhs = \"aa\", mode = \"n\", silent = true },\n        { lhs = \"b\", desc = \"b\", rhs = \"bb\", mode = \"n\", silent = true },\n        { lhs = \"c\", desc = \"c\", rhs = \"cc\", mode = \"n\", silent = true },\n        { lhs = \"d\", desc = \"dd\", mode = \"n\" },\n      },\n    },\n    {\n      spec = {\n        a = { \"a1\" },\n        b = { \"b1\", \"b2\" },\n        c = { \"c1\", desc = \"c2\" },\n      },\n      mappings = {\n        { lhs = \"a\", desc = \"a1\", mode = \"n\" },\n        { lhs = \"b\", desc = \"b2\", rhs = \"b1\", mode = \"n\", silent = true },\n        { lhs = \"c\", desc = \"c1\", mode = \"n\" },\n      },\n    },\n  }\n\n  -- Function to run the tests\n  for t, test in ipairs(tests) do\n    it(tostring(t), function()\n      local result = Mappings.parse(test.spec, { version = 1 })\n      assert.same(test.mappings, result)\n      local errors = vim.tbl_filter(function(n)\n        return n.level >= vim.log.levels.ERROR\n      end, Mappings.notifs)\n      assert.same({}, errors)\n    end)\n  end\nend)\n"
  },
  {
    "path": "tests/minit.lua",
    "content": "#!/usr/bin/env -S nvim -l\n\nvim.env.LAZY_STDPATH = \".tests\"\nvim.env.LAZY_PATH = vim.fs.normalize(\"~/projects/lazy.nvim\")\n\nif vim.fn.isdirectory(vim.env.LAZY_PATH) == 1 then\n  loadfile(vim.env.LAZY_PATH .. \"/bootstrap.lua\")()\nelse\n  load(vim.fn.system(\"curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua\"), \"bootstrap.lua\")()\nend\n\n-- Setup lazy.nvim\nrequire(\"lazy.minit\").setup({\n  spec = {\n    {\n      dir = vim.uv.cwd(),\n      opts = {\n        notify = false,\n      },\n    },\n  },\n})\n"
  },
  {
    "path": "tests/util_spec.lua",
    "content": "---@module 'luassert'\n\nlocal Util = require(\"which-key.util\")\n\ndescribe(\"parse keys\", function()\n  local tests = {\n    [\" <c-a><esc>Ä<lt>🔥foo\"] = {\n      \"<Space>\",\n      \"<C-A>\",\n      \"<Esc>\",\n      \"Ä\",\n      \"<\",\n      \"🔥\",\n      \"f\",\n      \"o\",\n      \"o\",\n    },\n    [\"\\1<esc>Ä<lt>🔥foo\"] = {\n      \"<C-A>\",\n      \"<Esc>\",\n      \"Ä\",\n      \"<\",\n      \"🔥\",\n      \"f\",\n      \"o\",\n      \"o\",\n    },\n    [\"<esc>\"] = { \"<Esc>\" },\n    [\"foo<baz>\"] = { \"f\", \"o\", \"o\", \"<\", \"b\", \"a\", \"z\", \">\" },\n    [\"foo<bar>\"] = { \"f\", \"o\", \"o\", \"|\" },\n    [\"foo<a-2>\"] = { \"f\", \"o\", \"o\", \"<M-2>\" },\n    [\"foo<A-2>\"] = { \"f\", \"o\", \"o\", \"<M-2>\" },\n    [\"foo<m-2>\"] = { \"f\", \"o\", \"o\", \"<M-2>\" },\n    [\"foo<M-2>\"] = { \"f\", \"o\", \"o\", \"<M-2>\" },\n    [\"foo<\"] = { \"f\", \"o\", \"o\", \"<\" },\n    [\"foo<bar\"] = { \"f\", \"o\", \"o\", \"<\", \"b\", \"a\", \"r\" },\n    [\"foo>\"] = { \"f\", \"o\", \"o\", \">\" },\n    -- test with japanese chars\n    [\"fooあ\"] = { \"f\", \"o\", \"o\", \"あ\" },\n    [\"fooあ<lt>\"] = { \"f\", \"o\", \"o\", \"あ\", \"<\" },\n    [\"fooあ<lt>bar\"] = { \"f\", \"o\", \"o\", \"あ\", \"<\", \"b\", \"a\", \"r\" },\n    [\"fooあ<lt>bar<lt>\"] = { \"f\", \"o\", \"o\", \"あ\", \"<\", \"b\", \"a\", \"r\", \"<\" },\n    [\"fooあ<lt>bar<lt>baz\"] = { \"f\", \"o\", \"o\", \"あ\", \"<\", \"b\", \"a\", \"r\", \"<\", \"b\", \"a\", \"z\" },\n    [\"fooあ<lt>bar<lt>baz<lt>\"] = { \"f\", \"o\", \"o\", \"あ\", \"<\", \"b\", \"a\", \"r\", \"<\", \"b\", \"a\", \"z\", \"<\" },\n    [\"fooあ<lt>bar<lt>baz<lt>qux\"] = {\n      \"f\",\n      \"o\",\n      \"o\",\n      \"あ\",\n      \"<\",\n      \"b\",\n      \"a\",\n      \"r\",\n      \"<\",\n      \"b\",\n      \"a\",\n      \"z\",\n      \"<\",\n      \"q\",\n      \"u\",\n      \"x\",\n    },\n    [\"fooあ<lt>bar<lt>baz<lt>qux<lt>\"] = {\n      \"f\",\n      \"o\",\n      \"o\",\n      \"あ\",\n      \"<\",\n      \"b\",\n      \"a\",\n      \"r\",\n      \"<\",\n      \"b\",\n      \"a\",\n      \"z\",\n      \"<\",\n      \"q\",\n      \"u\",\n      \"x\",\n      \"<\",\n    },\n  }\n\n  for input, output in pairs(tests) do\n    it((\"should parse %q\"):format(input), function()\n      local keys = Util.keys(input)\n      assert.same(output, keys)\n    end)\n  end\nend)\n\ndescribe(\"modes\", function()\n  before_each(function()\n    require(\"helpers\").reset()\n  end)\n\n  local tests = {\n    [\"gg\"] = \"n\",\n    [\"vl\"] = \"x\",\n    [\"<c-v>j\"] = \"x\",\n    [\"gh\"] = \"s\",\n    [\"aa\"] = \"i\",\n    [\"ciw\"] = \"o\",\n    [\"c\"] = \"n\",\n    [\"<cmd>terminal exit<cr>\"] = \"n\",\n  }\n\n  local inputs = vim.tbl_keys(tests)\n  table.sort(inputs)\n  for _, input in ipairs(inputs) do\n    local output = tests[input]\n    it((\"should return %q for %q\"):format(output, input), function()\n      local mode = \"n\"\n      assert.same(mode, Util.mapmode())\n      vim.api.nvim_create_autocmd(\"ModeChanged\", {\n        once = true,\n        callback = function()\n          mode = Util.mapmode()\n        end,\n      })\n      vim.api.nvim_feedkeys(vim.keycode(input), \"nitx\", false)\n      assert.same(output, mode)\n    end)\n  end\nend)\n"
  },
  {
    "path": "vim.yml",
    "content": "base: lua51\nlua_versions:\n  - luajit\n\nglobals:\n  Snacks:\n    any: true\n  vim:\n    any: true\n  jit:\n    any: true\n  assert:\n    any: true\n  describe:\n    any: true\n  it:\n    any: true\n  before_each:\n    any: true\n"
  }
]