retrovim 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/.conda/retrovim.yaml +259 -0
  2. package/.conda/terax.icns +0 -0
  3. package/.conda/terax.ico +0 -0
  4. package/.conda/terax.png +0 -0
  5. package/.github/workflows/release.yml +95 -0
  6. package/.gitmodules +3 -0
  7. package/.npm/kanata_touchcursor.js +28 -0
  8. package/.npm/nvim.js +26 -0
  9. package/.npm/yazi.js +26 -0
  10. package/.npm/zsh.js +17 -0
  11. package/.pip/kanata_touchcursor/__init__.py +28 -0
  12. package/.pip/nvim/__init__.py +31 -0
  13. package/.pip/yazi/__init__.py +31 -0
  14. package/.pip/zsh/__init__.py +22 -0
  15. package/CHANGELOG.md +26 -0
  16. package/LICENSE +674 -0
  17. package/README.md +336 -0
  18. package/kanata/touchcursor.kbd +164 -0
  19. package/nvim/init.lua +813 -0
  20. package/nvim/plugins/mini.nvim/.github/DISCUSSION_TEMPLATE/q-a.yml +72 -0
  21. package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/bug-report.yml +136 -0
  22. package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/config.yml +5 -0
  23. package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/feature-request.yml +75 -0
  24. package/nvim/plugins/mini.nvim/.github/PULL_REQUEST_TEMPLATE.md +2 -0
  25. package/nvim/plugins/mini.nvim/.github/workflows/quality-control.yml +150 -0
  26. package/nvim/plugins/mini.nvim/.pre-commit-config.yaml +20 -0
  27. package/nvim/plugins/mini.nvim/.stylua.toml +7 -0
  28. package/nvim/plugins/mini.nvim/.styluaignore +1 -0
  29. package/nvim/plugins/mini.nvim/CHANGELOG.md +1894 -0
  30. package/nvim/plugins/mini.nvim/CODE_OF_CONDUCT.md +132 -0
  31. package/nvim/plugins/mini.nvim/CONTRIBUTING.md +331 -0
  32. package/nvim/plugins/mini.nvim/LICENSE +21 -0
  33. package/nvim/plugins/mini.nvim/MAINTAINING.md +330 -0
  34. package/nvim/plugins/mini.nvim/Makefile +51 -0
  35. package/nvim/plugins/mini.nvim/README.md +261 -0
  36. package/nvim/plugins/mini.nvim/TESTING.md +1011 -0
  37. package/nvim/plugins/mini.nvim/benchmarks/starter/README.md +35 -0
  38. package/nvim/plugins/mini.nvim/benchmarks/starter/benchmark.sh +56 -0
  39. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-alpha.lua +21 -0
  40. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-original.lua +17 -0
  41. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-starter.lua +18 -0
  42. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_empty.lua +4 -0
  43. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_starter-default.lua +7 -0
  44. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-alpha.lua +10 -0
  45. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-original.lua +7 -0
  46. package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-starter.lua +20 -0
  47. package/nvim/plugins/mini.nvim/benchmarks/starter/install.sh +10 -0
  48. package/nvim/plugins/mini.nvim/benchmarks/starter/make_summary.py +68 -0
  49. package/nvim/plugins/mini.nvim/benchmarks/starter/startup-summary.md +10 -0
  50. package/nvim/plugins/mini.nvim/colors/miniautumn.lua +55 -0
  51. package/nvim/plugins/mini.nvim/colors/minicyan.lua +95 -0
  52. package/nvim/plugins/mini.nvim/colors/minischeme.lua +95 -0
  53. package/nvim/plugins/mini.nvim/colors/minispring.lua +53 -0
  54. package/nvim/plugins/mini.nvim/colors/minisummer.lua +49 -0
  55. package/nvim/plugins/mini.nvim/colors/miniwinter.lua +51 -0
  56. package/nvim/plugins/mini.nvim/colors/randomhue.lua +16 -0
  57. package/nvim/plugins/mini.nvim/doc/mini-ai.txt +889 -0
  58. package/nvim/plugins/mini.nvim/doc/mini-align.txt +923 -0
  59. package/nvim/plugins/mini.nvim/doc/mini-animate.txt +937 -0
  60. package/nvim/plugins/mini.nvim/doc/mini-base16.txt +285 -0
  61. package/nvim/plugins/mini.nvim/doc/mini-basics.txt +359 -0
  62. package/nvim/plugins/mini.nvim/doc/mini-bracketed.txt +622 -0
  63. package/nvim/plugins/mini.nvim/doc/mini-bufremove.txt +123 -0
  64. package/nvim/plugins/mini.nvim/doc/mini-clue.txt +760 -0
  65. package/nvim/plugins/mini.nvim/doc/mini-cmdline.txt +392 -0
  66. package/nvim/plugins/mini.nvim/doc/mini-colors.txt +880 -0
  67. package/nvim/plugins/mini.nvim/doc/mini-comment.txt +230 -0
  68. package/nvim/plugins/mini.nvim/doc/mini-completion.txt +477 -0
  69. package/nvim/plugins/mini.nvim/doc/mini-cursorword.txt +105 -0
  70. package/nvim/plugins/mini.nvim/doc/mini-deps.txt +590 -0
  71. package/nvim/plugins/mini.nvim/doc/mini-diff.txt +661 -0
  72. package/nvim/plugins/mini.nvim/doc/mini-doc.txt +434 -0
  73. package/nvim/plugins/mini.nvim/doc/mini-extra.txt +856 -0
  74. package/nvim/plugins/mini.nvim/doc/mini-files.txt +1018 -0
  75. package/nvim/plugins/mini.nvim/doc/mini-fuzzy.txt +160 -0
  76. package/nvim/plugins/mini.nvim/doc/mini-git.txt +425 -0
  77. package/nvim/plugins/mini.nvim/doc/mini-hipatterns.txt +489 -0
  78. package/nvim/plugins/mini.nvim/doc/mini-hues.txt +420 -0
  79. package/nvim/plugins/mini.nvim/doc/mini-icons.txt +508 -0
  80. package/nvim/plugins/mini.nvim/doc/mini-indentscope.txt +485 -0
  81. package/nvim/plugins/mini.nvim/doc/mini-input.txt +932 -0
  82. package/nvim/plugins/mini.nvim/doc/mini-jump.txt +202 -0
  83. package/nvim/plugins/mini.nvim/doc/mini-jump2d.txt +525 -0
  84. package/nvim/plugins/mini.nvim/doc/mini-keymap.txt +449 -0
  85. package/nvim/plugins/mini.nvim/doc/mini-map.txt +717 -0
  86. package/nvim/plugins/mini.nvim/doc/mini-misc.txt +431 -0
  87. package/nvim/plugins/mini.nvim/doc/mini-move.txt +181 -0
  88. package/nvim/plugins/mini.nvim/doc/mini-notify.txt +434 -0
  89. package/nvim/plugins/mini.nvim/doc/mini-nvim.txt +431 -0
  90. package/nvim/plugins/mini.nvim/doc/mini-operators.txt +472 -0
  91. package/nvim/plugins/mini.nvim/doc/mini-pairs.txt +346 -0
  92. package/nvim/plugins/mini.nvim/doc/mini-pick.txt +1535 -0
  93. package/nvim/plugins/mini.nvim/doc/mini-sessions.txt +239 -0
  94. package/nvim/plugins/mini.nvim/doc/mini-snippets.txt +1291 -0
  95. package/nvim/plugins/mini.nvim/doc/mini-splitjoin.txt +536 -0
  96. package/nvim/plugins/mini.nvim/doc/mini-starter.txt +618 -0
  97. package/nvim/plugins/mini.nvim/doc/mini-statusline.txt +361 -0
  98. package/nvim/plugins/mini.nvim/doc/mini-surround.txt +863 -0
  99. package/nvim/plugins/mini.nvim/doc/mini-tabline.txt +151 -0
  100. package/nvim/plugins/mini.nvim/doc/mini-test.txt +966 -0
  101. package/nvim/plugins/mini.nvim/doc/mini-trailspace.txt +91 -0
  102. package/nvim/plugins/mini.nvim/doc/mini-visits.txt +937 -0
  103. package/nvim/plugins/mini.nvim/logo.png +0 -0
  104. package/nvim/plugins/mini.nvim/lua/mini/ai.lua +2244 -0
  105. package/nvim/plugins/mini.nvim/lua/mini/align.lua +2076 -0
  106. package/nvim/plugins/mini.nvim/lua/mini/animate.lua +2127 -0
  107. package/nvim/plugins/mini.nvim/lua/mini/base16.lua +1752 -0
  108. package/nvim/plugins/mini.nvim/lua/mini/basics.lua +772 -0
  109. package/nvim/plugins/mini.nvim/lua/mini/bracketed.lua +2013 -0
  110. package/nvim/plugins/mini.nvim/lua/mini/bufremove.lua +283 -0
  111. package/nvim/plugins/mini.nvim/lua/mini/clue.lua +2096 -0
  112. package/nvim/plugins/mini.nvim/lua/mini/cmdline.lua +1182 -0
  113. package/nvim/plugins/mini.nvim/lua/mini/colors.lua +2483 -0
  114. package/nvim/plugins/mini.nvim/lua/mini/comment.lua +586 -0
  115. package/nvim/plugins/mini.nvim/lua/mini/completion.lua +2094 -0
  116. package/nvim/plugins/mini.nvim/lua/mini/cursorword.lua +311 -0
  117. package/nvim/plugins/mini.nvim/lua/mini/deps.lua +1660 -0
  118. package/nvim/plugins/mini.nvim/lua/mini/diff.lua +1938 -0
  119. package/nvim/plugins/mini.nvim/lua/mini/doc.lua +1371 -0
  120. package/nvim/plugins/mini.nvim/lua/mini/extra.lua +2290 -0
  121. package/nvim/plugins/mini.nvim/lua/mini/files.lua +3145 -0
  122. package/nvim/plugins/mini.nvim/lua/mini/fuzzy.lua +356 -0
  123. package/nvim/plugins/mini.nvim/lua/mini/git.lua +1737 -0
  124. package/nvim/plugins/mini.nvim/lua/mini/hipatterns.lua +1042 -0
  125. package/nvim/plugins/mini.nvim/lua/mini/hues.lua +2088 -0
  126. package/nvim/plugins/mini.nvim/lua/mini/icons.lua +2254 -0
  127. package/nvim/plugins/mini.nvim/lua/mini/indentscope.lua +1158 -0
  128. package/nvim/plugins/mini.nvim/lua/mini/init.lua +427 -0
  129. package/nvim/plugins/mini.nvim/lua/mini/input.lua +2183 -0
  130. package/nvim/plugins/mini.nvim/lua/mini/jump.lua +609 -0
  131. package/nvim/plugins/mini.nvim/lua/mini/jump2d.lua +1244 -0
  132. package/nvim/plugins/mini.nvim/lua/mini/keymap.lua +880 -0
  133. package/nvim/plugins/mini.nvim/lua/mini/map.lua +1709 -0
  134. package/nvim/plugins/mini.nvim/lua/mini/misc.lua +969 -0
  135. package/nvim/plugins/mini.nvim/lua/mini/move.lua +509 -0
  136. package/nvim/plugins/mini.nvim/lua/mini/notify.lua +938 -0
  137. package/nvim/plugins/mini.nvim/lua/mini/operators.lua +1349 -0
  138. package/nvim/plugins/mini.nvim/lua/mini/pairs.lua +657 -0
  139. package/nvim/plugins/mini.nvim/lua/mini/pick.lua +3876 -0
  140. package/nvim/plugins/mini.nvim/lua/mini/sessions.lua +689 -0
  141. package/nvim/plugins/mini.nvim/lua/mini/snippets.lua +2828 -0
  142. package/nvim/plugins/mini.nvim/lua/mini/splitjoin.lua +1132 -0
  143. package/nvim/plugins/mini.nvim/lua/mini/starter.lua +1599 -0
  144. package/nvim/plugins/mini.nvim/lua/mini/statusline.lua +686 -0
  145. package/nvim/plugins/mini.nvim/lua/mini/surround.lua +2388 -0
  146. package/nvim/plugins/mini.nvim/lua/mini/tabline.lua +564 -0
  147. package/nvim/plugins/mini.nvim/lua/mini/test.lua +2516 -0
  148. package/nvim/plugins/mini.nvim/lua/mini/trailspace.lua +215 -0
  149. package/nvim/plugins/mini.nvim/lua/mini/visits.lua +1577 -0
  150. package/nvim/plugins/mini.nvim/readmes/mini-ai.md +190 -0
  151. package/nvim/plugins/mini.nvim/readmes/mini-align.md +203 -0
  152. package/nvim/plugins/mini.nvim/readmes/mini-animate.md +214 -0
  153. package/nvim/plugins/mini.nvim/readmes/mini-base16.md +198 -0
  154. package/nvim/plugins/mini.nvim/readmes/mini-basics.md +184 -0
  155. package/nvim/plugins/mini.nvim/readmes/mini-bracketed.md +193 -0
  156. package/nvim/plugins/mini.nvim/readmes/mini-bufremove.md +139 -0
  157. package/nvim/plugins/mini.nvim/readmes/mini-clue.md +260 -0
  158. package/nvim/plugins/mini.nvim/readmes/mini-cmdline.md +183 -0
  159. package/nvim/plugins/mini.nvim/readmes/mini-colors.md +169 -0
  160. package/nvim/plugins/mini.nvim/readmes/mini-comment.md +183 -0
  161. package/nvim/plugins/mini.nvim/readmes/mini-completion.md +217 -0
  162. package/nvim/plugins/mini.nvim/readmes/mini-cursorword.md +137 -0
  163. package/nvim/plugins/mini.nvim/readmes/mini-deps.md +271 -0
  164. package/nvim/plugins/mini.nvim/readmes/mini-diff.md +289 -0
  165. package/nvim/plugins/mini.nvim/readmes/mini-doc.md +198 -0
  166. package/nvim/plugins/mini.nvim/readmes/mini-extra.md +158 -0
  167. package/nvim/plugins/mini.nvim/readmes/mini-files.md +247 -0
  168. package/nvim/plugins/mini.nvim/readmes/mini-fuzzy.md +134 -0
  169. package/nvim/plugins/mini.nvim/readmes/mini-git.md +168 -0
  170. package/nvim/plugins/mini.nvim/readmes/mini-hipatterns.md +176 -0
  171. package/nvim/plugins/mini.nvim/readmes/mini-hues.md +285 -0
  172. package/nvim/plugins/mini.nvim/readmes/mini-icons.md +183 -0
  173. package/nvim/plugins/mini.nvim/readmes/mini-indentscope.md +191 -0
  174. package/nvim/plugins/mini.nvim/readmes/mini-input.md +163 -0
  175. package/nvim/plugins/mini.nvim/readmes/mini-jump.md +161 -0
  176. package/nvim/plugins/mini.nvim/readmes/mini-jump2d.md +197 -0
  177. package/nvim/plugins/mini.nvim/readmes/mini-keymap.md +205 -0
  178. package/nvim/plugins/mini.nvim/readmes/mini-map.md +191 -0
  179. package/nvim/plugins/mini.nvim/readmes/mini-misc.md +145 -0
  180. package/nvim/plugins/mini.nvim/readmes/mini-move.md +163 -0
  181. package/nvim/plugins/mini.nvim/readmes/mini-notify.md +175 -0
  182. package/nvim/plugins/mini.nvim/readmes/mini-operators.md +193 -0
  183. package/nvim/plugins/mini.nvim/readmes/mini-pairs.md +158 -0
  184. package/nvim/plugins/mini.nvim/readmes/mini-pick.md +340 -0
  185. package/nvim/plugins/mini.nvim/readmes/mini-sessions.md +164 -0
  186. package/nvim/plugins/mini.nvim/readmes/mini-snippets.md +373 -0
  187. package/nvim/plugins/mini.nvim/readmes/mini-splitjoin.md +194 -0
  188. package/nvim/plugins/mini.nvim/readmes/mini-starter.md +176 -0
  189. package/nvim/plugins/mini.nvim/readmes/mini-statusline.md +155 -0
  190. package/nvim/plugins/mini.nvim/readmes/mini-surround.md +190 -0
  191. package/nvim/plugins/mini.nvim/readmes/mini-tabline.md +156 -0
  192. package/nvim/plugins/mini.nvim/readmes/mini-test.md +175 -0
  193. package/nvim/plugins/mini.nvim/readmes/mini-trailspace.md +137 -0
  194. package/nvim/plugins/mini.nvim/readmes/mini-visits.md +243 -0
  195. package/nvim/plugins/mini.nvim/scripts/dual_log.sh +13 -0
  196. package/nvim/plugins/mini.nvim/scripts/dual_push.sh +15 -0
  197. package/nvim/plugins/mini.nvim/scripts/dual_release.sh +102 -0
  198. package/nvim/plugins/mini.nvim/scripts/dual_sync.sh +115 -0
  199. package/nvim/plugins/mini.nvim/scripts/init-deps-example.lua +59 -0
  200. package/nvim/plugins/mini.nvim/scripts/lint-filename-length.sh +16 -0
  201. package/nvim/plugins/mini.nvim/scripts/lintcommit-ci.sh +18 -0
  202. package/nvim/plugins/mini.nvim/scripts/lintcommit.lua +393 -0
  203. package/nvim/plugins/mini.nvim/scripts/minidoc.lua +57 -0
  204. package/nvim/plugins/mini.nvim/scripts/minimal_init.lua +28 -0
  205. package/nvim/plugins/mini.nvim/scripts/minitest.lua +4 -0
  206. package/package.json +16 -0
  207. package/pyproject.toml +43 -0
  208. package/yazi/init.lua +12 -0
  209. package/yazi/keymap.toml +114 -0
  210. package/yazi/lesskey +5 -0
  211. package/yazi/plugins/bookmarks.yazi/main.lua +86 -0
  212. package/yazi/plugins/cd-git-root.yazi/main.lua +31 -0
  213. package/yazi/plugins/smart-enter.yazi/main.lua +11 -0
  214. package/yazi/theme.toml +26 -0
  215. package/yazi/yazi.toml +15 -0
  216. package/zsh/.zshrc +145 -0
  217. package/zsh/starship.toml +20 -0
  218. package/zsh/zsh-patina.toml +2 -0
@@ -0,0 +1,880 @@
1
+ --- *mini.keymap* Special key mappings
2
+ ---
3
+ --- MIT License Copyright (c) 2025 Evgeni Chasnovski
4
+
5
+ --- Features:
6
+ ---
7
+ --- - Map keys to perform configurable multi-step actions: if condition for step
8
+ --- one is true - execute step one action, else check step two, and so on until
9
+ --- falling back to executing original keys. This is usually referred to as
10
+ --- "smart" keys (like "smart tab"). See |MiniKeymap.map_multistep()|.
11
+ ---
12
+ --- There are many built-in steps targeted for Insert mode mappings of special
13
+ --- keys like <Tab>, <S-Tab>, <CR>, and <BS>:
14
+ --- - Navigate and accept |popupmenu-completion|. Useful for |mini.completion|.
15
+ --- - Navigate and expand |mini.snippets|.
16
+ --- - Execute <CR> and <BS> respecting |mini.pairs|.
17
+ --- - Jump before/after current tree-sitter node.
18
+ --- - Jump before opening and after closing characters (brackets and quotes).
19
+ --- - Increase/decrease indent when cursor is inside of it.
20
+ --- - Delete all whitespace to the left ("hungry backspace").
21
+ --- - Navigate |vim.snippet|.
22
+ --- - Navigate and accept in [hrsh7th/nvim-cmp](https://github.com/hrsh7th/nvim-cmp) completion.
23
+ --- - Navigate and accept in [Saghen/blink.cmp](https://github.com/Saghen/blink.cmp) completion.
24
+ --- - Navigate and expand [L3MON4D3/LuaSnip](https://github.com/L3MON4D3/LuaSnip) snippets.
25
+ --- - Execute <CR> and <BS> respecting [windwp/nvim-autopairs](https://github.com/windwp/nvim-autopairs).
26
+ ---
27
+ --- - Map keys as "combo": each key acts immediately plus execute extra action if
28
+ --- all are typed within configurable delay between each other.
29
+ --- See |MiniKeymap.map_combo()|. Some of the common use cases include:
30
+ --- - Map insertable keys (like "jk", "kj") in Insert and Command-line mode
31
+ --- to exit into Normal mode.
32
+ --- - Fight against bad habits of pressing the same navigation key by showing
33
+ --- a notification if there are too many of them pressed in a row.
34
+ ---
35
+ --- Sources with more details:
36
+ --- - |MiniKeymap-examples|
37
+ ---
38
+ --- # Setup ~
39
+ ---
40
+ --- This module doesn't need setup, but it can be done to improve usability.
41
+ --- Setup with `require('mini.keymap').setup({})` (replace `{}` with your `config`
42
+ --- table). It will create global Lua table `MiniKeymap` which you can use for
43
+ --- scripting or manually (with `:lua MiniKeymap.*`).
44
+ ---
45
+ --- See |MiniKeymap.config| for `config` structure and default values.
46
+ ---
47
+ --- This module doesn't have runtime options, so using `vim.b.minikeymap_config`
48
+ --- will have no effect here.
49
+ ---
50
+ --- # Comparisons ~
51
+ ---
52
+ --- - [max397574/better-escape.nvim](https://github.com/max397574/better-escape.nvim):
53
+ --- - Mostly similar to |MiniKeymap.map_combo()| with a different approach
54
+ --- to creating mappings.
55
+ --- - Mostly targeted for Insert mode mappings as pressed keys get removed
56
+ --- automatically after typed. This module allows more general cases while
57
+ --- requiring explicit removal of keys (usually via explicit `<BS><BS>`).
58
+ ---
59
+ --- - [abecodes/tabout.nvim](https://github.com/abecodes/tabout.nvim):
60
+ --- - Similar general idea as in `'jump_{after,before}_tsnode'` steps
61
+ --- of |MiniKeymap.map_multistep()|.
62
+ --- - Works only with enabled tree-sitter parser. This module provides
63
+ --- fallback via `'jump_after_close'` and `'jump_before_open'` that work
64
+ --- without tree-sitter parser.
65
+ --- - `tabout.nvim` has finer control of how the tree-sitter node movement
66
+ --- is done, while this module has "jump outside of current node" behavior.
67
+ ---
68
+ --- # Disabling ~
69
+ ---
70
+ --- To disable acting in mappings, set `vim.g.minikeymap_disable` (globally) or
71
+ --- `vim.b.minikeymap_disable` (for a buffer) to `true`. Considering high number
72
+ --- of different scenarios and customization intentions, writing exact rules
73
+ --- for disabling module's functionality is left to user.
74
+ --- See |mini.nvim-disabling-recipes| for common recipes.
75
+ ---@tag MiniKeymap
76
+
77
+ --- # Multi-step ~
78
+ ---
79
+ --- See |MiniKeymap.map_multistep()| for a general description of how multi-step
80
+ --- mappings work and what built-in steps are available.
81
+ ---
82
+ --- Setup that works well with |mini.completion| and |mini.pairs|: >lua
83
+ ---
84
+ --- local map_multistep = require('mini.keymap').map_multistep
85
+ --- map_multistep('i', '<Tab>', { 'pmenu_next' })
86
+ --- map_multistep('i', '<S-Tab>', { 'pmenu_prev' })
87
+ --- map_multistep('i', '<CR>', { 'pmenu_accept', 'minipairs_cr' })
88
+ --- map_multistep('i', '<BS>', { 'minipairs_bs' })
89
+ --- <
90
+ --- Use <Tab> / <S-Tab> to also navigate and expand |mini.snippets|: >lua
91
+ ---
92
+ --- local map_multistep = require('mini.keymap').map_multistep
93
+ ---
94
+ --- local tab_steps = { 'minisnippets_next','minisnippets_expand','pmenu_next' }
95
+ --- map_multistep('i', '<Tab>', tab_steps)
96
+ ---
97
+ --- local shifttab_steps = { 'minisnippets_prev', 'pmenu_prev' }
98
+ --- map_multistep('i', '<S-Tab>', shifttab_steps)
99
+ --- <
100
+ --- An extra smart <Tab> and <S-Tab>: >lua
101
+ ---
102
+ --- local map_multistep = require('mini.keymap').map_multistep
103
+ ---
104
+ --- -- NOTE: this will never insert tab, press <C-v><Tab> for that
105
+ --- local tab_steps = {
106
+ --- 'minisnippets_next', 'minisnippets_expand', 'pmenu_next',
107
+ --- 'jump_after_tsnode', 'jump_after_close',
108
+ --- }
109
+ --- map_multistep('i', '<Tab>', tab_steps)
110
+ ---
111
+ --- local shifttab_steps = {
112
+ --- 'minisnippets_prev', 'pmenu_prev',
113
+ --- 'jump_before_tsnode', 'jump_before_open',
114
+ --- }
115
+ --- map_multistep('i', '<S-Tab>', shifttab_steps)
116
+ --- <
117
+ --- Navigation in active |vim.snippet| session also requires mapping in |Select-mode|: >lua
118
+ ---
119
+ --- local map_multistep = require('mini.keymap').map_multistep
120
+ --- map_multistep({ 'i', 's' }, '<Tab>', { 'vimsnippet_next', 'pmenu_next' })
121
+ --- map_multistep({ 'i', 's' }, '<S-Tab>', { 'vimsnippet_prev', 'pmenu_prev' })
122
+ --- <
123
+ --- # Combos ~
124
+ ---
125
+ --- See |MiniKeymap.map_combo()| for a general description of what is a combo and
126
+ --- more caveats about its usage.
127
+ ---
128
+ --- All combos require their left hand side keys to be typed relatively quickly.
129
+ --- To adjust the delay between keys, add `{ delay = 500 }` (use custom value) as
130
+ --- fourth argument.
131
+ ---
132
+ --- ## "Better escape" to Normal mode ~
133
+ ---
134
+ --- Leave into |Normal-mode| without having to reach for <Esc> key: >lua
135
+ ---
136
+ --- -- Support most common modes. This can also contain 't', but would
137
+ --- -- only mean to press `<Esc>` inside terminal.
138
+ --- local mode = { 'i', 'c', 'x', 's' }
139
+ --- require('mini.keymap').map_combo(mode, 'jk', '<BS><BS><Esc>')
140
+ ---
141
+ --- -- To not have to worry about the order of keys, also map "kj"
142
+ --- require('mini.keymap').map_combo(mode, 'kj', '<BS><BS><Esc>')
143
+ ---
144
+ --- -- Escape into Normal mode from Terminal mode
145
+ --- require('mini.keymap').map_combo('t', 'jk', '<BS><BS><C-\\><C-n>')
146
+ --- require('mini.keymap').map_combo('t', 'kj', '<BS><BS><C-\\><C-n>')
147
+ --- <
148
+ --- ## Show bad navigation habits ~
149
+ ---
150
+ --- Show notification if there is too much movement by repeating same key: >lua
151
+ ---
152
+ --- local notify_many_keys = function(key)
153
+ --- local lhs = string.rep(key, 5)
154
+ --- local action = function() vim.notify('Too many ' .. key) end
155
+ --- require('mini.keymap').map_combo({ 'n', 'x' }, lhs, action)
156
+ --- end
157
+ --- notify_many_keys('h')
158
+ --- notify_many_keys('j')
159
+ --- notify_many_keys('k')
160
+ --- notify_many_keys('l')
161
+ --- <
162
+ --- ## Fix previous spelling mistake ~
163
+ ---
164
+ --- Fix previous spelling mistake (see |[s| and |z=|) without manually leaving
165
+ --- Insert mode: >lua
166
+ ---
167
+ --- local action = '<BS><BS><Esc>[s1z=gi<Right>'
168
+ --- require('mini.keymap').map_combo('i', 'kk', action)
169
+ --- <
170
+ --- ## Hide search highlighting ~
171
+ ---
172
+ --- Use double <Esc><Esc> to execute |:nohlsearch|. Although this can also be done
173
+ --- with `nmap <Esc> <Cmd>nohl<CR>`, the combo approach also exists and can be used
174
+ --- to free <Esc> mapping in Normal mode for something else. >lua
175
+ ---
176
+ --- local action = function() vim.cmd('nohlsearch') end
177
+ --- require('mini.keymap').map_combo({ 'n','i','x','c' }, '<Esc><Esc>', action)
178
+ --- <
179
+ --- ## Buffer navigation ~
180
+ ---
181
+ --- Replace some movements with easier to type alternatives: >lua
182
+ ---
183
+ --- local map_combo = require('mini.keymap').map_combo
184
+ --- map_combo({ 'n', 'x' }, 'll', 'g$')
185
+ --- map_combo({ 'n', 'x' }, 'hh', 'g^')
186
+ --- map_combo({ 'n', 'x' }, 'jj', '}')
187
+ --- map_combo({ 'n', 'x' }, 'kk', '{')
188
+ --- <
189
+ ---@tag MiniKeymap-examples
190
+
191
+ ---@diagnostic disable:undefined-field
192
+ ---@diagnostic disable:discard-returns
193
+ ---@diagnostic disable:unused-local
194
+
195
+ -- Module definition ==========================================================
196
+ local MiniKeymap = {}
197
+ local H = {}
198
+
199
+ --- Module setup
200
+ ---
201
+ ---@param config table|nil Module config table. See |MiniKeymap.config|.
202
+ ---
203
+ ---@usage >lua
204
+ --- require('mini.keymap').setup({}) -- replace {} with your config table
205
+ --- -- needs `keymap` field present
206
+ --- <
207
+ MiniKeymap.setup = function(config)
208
+ -- TODO: Remove after Neovim=0.9 support is dropped
209
+ if vim.fn.has('nvim-0.10') == 0 then
210
+ vim.notify(
211
+ '(mini.keymap) Neovim<0.10 is soft deprecated (module works but is not supported).'
212
+ .. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
213
+ .. ' Please update your Neovim version.'
214
+ )
215
+ end
216
+
217
+ -- Export module
218
+ _G.MiniKeymap = MiniKeymap
219
+
220
+ -- Setup config
221
+ config = H.setup_config(config)
222
+
223
+ -- Apply config
224
+ H.apply_config(config)
225
+ end
226
+
227
+ --- Defaults ~
228
+ ---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
229
+ MiniKeymap.config = {}
230
+ --minidoc_afterlines_end
231
+
232
+ --- Map multi-step action
233
+ ---
234
+ --- Mapping of a multi-step action is an expression mapping (|:map-expression|).
235
+ --- Executing a multi-step action is essentially:
236
+ --- - Check condition for step one. If `true` - execute step one action and stop.
237
+ --- - Check condition for step two, and so on.
238
+ --- - If there is no more steps, fall back to returning mapped key.
239
+ ---
240
+ --- For better user experience there are many built-in steps mostly designed
241
+ --- to create Insert mode "smart" mappings of <Tab>, <S-Tab>, <CR>, and <BS>.
242
+ --- Available built-in steps ("For key" is a suggestion, any can be used):
243
+ --- >
244
+ --- ┌─────────────────────┬────────────────┬──────────────────────────┬─────────┐
245
+ --- │ Step name │ Condition │ Action │ For key │
246
+ --- ├─────────────────────┴────────────────┴──────────────────────────┴─────────┤
247
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |ins-completion-menu| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
248
+ --- │ pmenu_next │ Pmenu visible │ Select next (as <C-n>) │ <Tab> │
249
+ --- │ pmenu_prev │ Pmenu visible │ Select prev (as <C-p>) │ <S-Tab> │
250
+ --- │ pmenu_accept │ Item selected │ Accept (as <C-y>) │ <CR> │
251
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.snippets| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
252
+ --- │ minisnippets_next │ Session active │ Jump to next tabstop │ <Tab> │
253
+ --- │ minisnippets_prev │ Session active │ Jump to prev tabstop │ <S-Tab> │
254
+ --- │ minisnippets_expand │ Can expand │ Expand snippet at cursor │ <Tab> │
255
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |mini.pairs| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
256
+ --- │ minipairs_cr │ Module set up │ <CR> respecting pairs │ <CR> │
257
+ --- │ minipairs_bs │ Module set up │ <BS> respecting pairs │ <BS> │
258
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Jump around in Insert mode ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
259
+ --- │ jump_after_tsnode │ TS parser │ Jump after node end │ <Tab> │
260
+ --- │ jump_before_tsnode │ TS parser │ Jump before node start │ <S-Tab> │
261
+ --- │ jump_after_close │ Insert mode │ Jump after )]}"'` │ <Tab> │
262
+ --- │ jump_before_open │ Insert mode │ Jump before ([{"'` │ <S-Tab> │
263
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ Work with whitespace ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
264
+ --- │ increase_indent │ Is on indent │ Increase indent │ <Tab> │
265
+ --- │ decrease_indent │ Is on indent │ Decrease indent │ <S-Tab> │
266
+ --- │ hungry_bs │ Space to left │ Delete all space to left │ <BS> │
267
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ |vim.snippet| ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
268
+ --- │ vimsnippet_next │ Session active │ Jump to next tabstop │ <Tab> │
269
+ --- │ vimsnippet_prev │ Session active │ Jump to prev tabstop │ <S-Tab> │
270
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'hrsh7th/nvim-cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
271
+ --- │ cmp_next │ Menu visible │ Select next item │ <Tab> │
272
+ --- │ cmp_prev │ Menu visible │ Select prev item │ <S-Tab> │
273
+ --- │ cmp_accept │ Item selected │ Accept selected item │ <CR> │
274
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'Saghen/blink.cmp' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
275
+ --- │ blink_next │ Menu visible │ Select next item │ <Tab> │
276
+ --- │ blink_prev │ Menu visible │ Select prev item │ <S-Tab> │
277
+ --- │ blink_accept │ Item selected │ Accept selected item │ <CR> │
278
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'L3MON4D3/LuaSnip' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
279
+ --- │ luasnip_next │ Session active │ Jump to next tabstop │ <Tab> │
280
+ --- │ luasnip_prev │ Session active │ Jump to prev tabstop │ <S-Tab> │
281
+ --- │ luasnip_expand │ Can expand │ Expand snippet at cursor │ <Tab> │
282
+ --- ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ 'windwp/nvim-autopairs' ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┤
283
+ --- │ nvimautopairs_cr │ Module present │ <CR> respecting pairs │ <CR> │
284
+ --- │ nvimautopairs_bs │ Module present │ <BS> respecting pairs │ <BS> │
285
+ --- └─────────────────────┴────────────────┴──────────────────────────┴─────────┘
286
+ --- <
287
+ --- Notes:
288
+ --- - Executing action has limitations of |:map-expression| (like not allowed text
289
+ --- or buffer changes, etc.). To execute complex lua code, use |vim.schedule()|
290
+ --- inside action, return the code as string in |:map-cmd| format, or return
291
+ --- a function to be later executed. See usage examples.
292
+ ---
293
+ --- - Some mapped keys (like <Tab>, <CR>) might require disabling smart presets
294
+ --- in plugins (like `nvim-cmp`, `blink-cmp`, `nvim-autopairs`).
295
+ ---
296
+ ---@param mode string|table Same as for |vim.keymap.set()|.
297
+ ---@param lhs string Same as for |vim.keymap.set()|.
298
+ ---@param steps table Array of steps. Each step can be a string with the name
299
+ --- of built-in step or a table with two callable methods (will be called
300
+ --- without arguments):
301
+ --- - <condition> - return `true` if the action should be executed.
302
+ --- - <action> - action to be executed if <condition> returns `true`.
303
+ --- For more flexibility, it can also return a value which can be:
304
+ --- - String - will be returned as expression output. Can be something like
305
+ --- `"<Tab>"` (treat as <Tab> key) or `"<Cmd>lua vim.notify('Hello')<CR>"`.
306
+ --- Should not escape keycodes (i.e. return "<Tab>" and not "\t").
307
+ --- To undo already done escape, use |keytrans()|.
308
+ --- - Function - will be executed as if `"<Cmd>lua f()<CR>"`, but does not
309
+ --- need to create a global function for that.
310
+ --- - `false` - do not stop going through steps.
311
+ ---@param opts table|nil Same as for |vim.keymap.set()|.
312
+ ---
313
+ ---@usage See |MiniKeymap-examples| for practical examples.
314
+ ---
315
+ --- Some illustrative examples: >lua
316
+ ---
317
+ --- _G.log = {}
318
+ --- local steps = {}
319
+ --- steps[1] = {
320
+ --- condition = function() table.insert(_G.log, 'C1'); return _G.cond1 end,
321
+ --- -- Compute and return keys. Will be emulated as pressed.
322
+ --- action = function() table.insert(_G.log, 'A1'); return 'hello' end,
323
+ --- }
324
+ ---
325
+ --- steps[2] = {
326
+ --- condition = function() table.insert(_G.log, 'C2'); return _G.cond2 end,
327
+ --- -- Perform action immediately, return `false` to keep asking other steps
328
+ --- action = function() table.insert(_G.log, 'A2'); return false end,
329
+ --- }
330
+ ---
331
+ --- steps[3] = {
332
+ --- condition = function() table.insert(_G.log, 'C3'); return _G.cond3 end,
333
+ --- -- Perform action later (to overcom expression mapping limitations)
334
+ --- action = function()
335
+ --- table.insert(_G.log, 'A3_1')
336
+ --- return function() table.insert(_G.log, 'A3_2') end
337
+ --- end,
338
+ --- }
339
+ ---
340
+ --- -- Make Insert mode <Tab> mapping
341
+ --- require('mini.keymap').map_multistep('i', '<Tab>', steps)
342
+ ---
343
+ --- -- Pressing <Tab> inserts fallback `\t`; logs C1+C2+C3
344
+ --- _G.cond1, _G.cond2, _G.cond3 = false, false, false
345
+ ---
346
+ --- -- Pressing <Tab> inserts `hello`; logs C1+A1
347
+ --- _G.cond1, _G.cond2, _G.cond3 = true, false, false
348
+ ---
349
+ --- -- Pressing <Tab> inserts nothing; logs C1+C2+A2+C3+A3_1+A3_2
350
+ --- _G.cond1, _G.cond2, _G.cond3 = false, true, true
351
+ --- <
352
+ MiniKeymap.map_multistep = function(mode, lhs, steps, opts)
353
+ H.check_type('lhs', lhs, 'string')
354
+ local lhs_raw, n_steps = vim.api.nvim_replace_termcodes(lhs, true, true, true), #steps
355
+ local lhs_keycode = vim.fn.keytrans(lhs_raw)
356
+ steps = H.normalize_steps(steps)
357
+
358
+ local rhs = function()
359
+ if H.is_disabled() then return lhs_keycode end
360
+ for i = 1, n_steps do
361
+ if steps[i].condition() then
362
+ local out = steps[i].action()
363
+ -- Allow custom string as output of expression mapping
364
+ if type(out) == 'string' then return out end
365
+ -- Allow callable output to be properly wrapped in `<Cmd>...<CR>`
366
+ if vim.is_callable(out) then return H.wrap_in_cmd_lua(out) end
367
+ -- Allow `false` output to indicate "keep processing next steps"
368
+ if out ~= false then return '' end
369
+ end
370
+ end
371
+ return lhs_keycode
372
+ end
373
+
374
+ local desc = 'Multi ' .. lhs_keycode
375
+ opts = vim.tbl_extend('force', { desc = desc }, opts or {}, { expr = true, replace_keycodes = true })
376
+ vim.keymap.set(mode, lhs, rhs, opts)
377
+ end
378
+
379
+ --- Generate step for multi-step mappings
380
+ ---
381
+ --- This is a table with function elements. Call to actually get a step.
382
+ MiniKeymap.gen_step = {}
383
+
384
+ --- Search pattern step
385
+ ---
386
+ --- Use |search()| to jump to pattern match. Possibly adjust final position to
387
+ --- be just to the right of the match (useful in Insert mode).
388
+ ---
389
+ ---@param pattern string Same as for |search()|.
390
+ ---@param flags string|nil Same as for |search()|.
391
+ ---@param opts table|nil Options. Possible fields:
392
+ --- - <side> `(string)` - one of `"before"` (default) or `"after"`.
393
+ --- - <stopline> `(number|function)` - forwarded to |search()| (as number or
394
+ --- as function's output after calling it before every search).
395
+ --- - <timeout> `(number)` - forwarded to |search()|.
396
+ --- - <skip> `(string|function)` - forwarded to |search()|.
397
+ ---
398
+ ---@return table Step which searches pattern.
399
+ ---
400
+ ---@usage Built-in |MiniKeymap.map_multistep()| steps "jump_after_close" and
401
+ --- "jump_before_open" use this, but only in Insert mode.
402
+ ---
403
+ --- Steps that jump before/after all consecutive brackets in several modes: >lua
404
+ ---
405
+ --- local keymap = require('mini.keymap')
406
+ --- local tab_step_insert = keymap.gen_step.search_pattern(
407
+ --- -- Need to use 'c' flag and 'after' side for robust "chaining"
408
+ --- [=[[)\]}]\+]=], 'ceW', { side = 'after' }
409
+ --- )
410
+ --- keymap.map_multistep('i', '<Tab>', { tab_step_insert })
411
+ --- local tab_step = keymap.gen_step.search_pattern([=[[)\]}]\+]=], 'eW')
412
+ --- keymap.map_multistep({ 'n', 'x' }, '<Tab>', { tab_step })
413
+ ---
414
+ --- local stab_step = keymap.gen_step.search_pattern([=[[(\[{]\+]=], 'bW')
415
+ --- keymap.map_multistep({ 'i', 'n', 'x' }, '<S-Tab>', { stab_step })
416
+ --- <
417
+ MiniKeymap.gen_step.search_pattern = function(pattern, flags, opts)
418
+ if type(pattern) ~= 'string' then H.error('`pattern` should be string, not ' .. vim.inspect(type(pattern))) end
419
+ flags = flags or ''
420
+ if type(flags) ~= 'string' then H.error('`flags` should be string, not ' .. vim.inspect(type(flags))) end
421
+
422
+ opts = vim.tbl_extend('force', { side = 'before', stopline = nil, timeout = nil, skip = nil }, opts or {})
423
+ local side = opts.side
424
+ if not (side == 'before' or side == 'after') then H.error('`opts.side` should be one of "before" or "after"') end
425
+
426
+ local stopline = opts.stopline or function() return nil end
427
+ if type(stopline) == 'number' then
428
+ local line = stopline
429
+ stopline = function() return line end
430
+ end
431
+ if not vim.is_callable(stopline) then H.error('`opts.stopline` should be number or callable') end
432
+
433
+ -- NOTEs:
434
+ -- - Using `normal!` doesn't go past the end of line and triggers
435
+ -- mode-change-related events.
436
+ -- - Adjusting pattern with `\zs` prefix doesn't work for consecutive matches
437
+ -- (like `)))`), as it will match every other one (first, third, etc.).
438
+ -- - Using `\@<=` quantifier doesn't work for the last match in consecutive
439
+ -- matches at end of line. Like `)))` at end of line won't put cursor at
440
+ -- end of line. The `[)\]}]\@<=\_.` also doesn't seem to work.
441
+ local adjust_cursor = function()
442
+ local pos = vim.api.nvim_win_get_cursor(0)
443
+ vim.api.nvim_win_set_cursor(0, { pos[1], pos[2] + 1 })
444
+ end
445
+ if side == 'before' then adjust_cursor = function() end end
446
+
447
+ local act = function()
448
+ H.hide_completion()
449
+ local had_match = vim.fn.search(pattern, flags, stopline(), opts.timeout, opts.skip)
450
+ if had_match ~= 0 then adjust_cursor() end
451
+ end
452
+
453
+ return { condition = function() return true end, action = function() return act end }
454
+ end
455
+
456
+ --- Map combo post action
457
+ ---
458
+ --- Create a combo: sequence of keys where each acts immediately plus execute
459
+ --- an extra action if all are typed within configurable delay between each other.
460
+ ---
461
+ --- Example for Insert mode "better escape" `jk` combo with `<BS><BS><Esc>` action:
462
+ --- - Press `j`. It is visible immediately without any side effects.
463
+ --- - Quickly (no more than default 200 ms after) press `k`. This triggers the
464
+ --- action which is equivalent to typing <BS><BS> (delete already present `jk`)
465
+ --- and <Esc> to exit into Normal mode.
466
+ ---
467
+ --- Notes:
468
+ --- - IMPORTANT! Combo is not a regular mapping but a separate key tracking
469
+ --- with |vim.on_key()|. This is important as combos will not be visible and
470
+ --- can not be managed as regular mappings. Instead each combo is associated
471
+ --- with a dedicated |namespace| (named for human readability). However, it is not
472
+ --- really expected to manage them on the fly after they are created.
473
+ ---
474
+ --- - String action is executed with |nvim_input()|, i.e. emulated keys will
475
+ --- respect custom mappings.
476
+ ---
477
+ --- - Different combos are tracked and act independent of each other. For example,
478
+ --- if there are combos for `jjk` and `jk` keys, fast typing `jjk` will execute both.
479
+ ---
480
+ --- - Neovim>=0.11 is recommended due to |vim.on_key()| improvement to allow
481
+ --- watching for keys as they are typed and not as if coming from mappings.
482
+ --- For example, this matters when creating a `jk` combo for Visual mode while
483
+ --- also having `xnoremap j gj` style of remaps. On Neovim<0.11 the fix is to
484
+ --- use `gjgk` as combo's left hand side.
485
+ ---
486
+ --- - Each combo adds very small but non-zero overhead on each keystroke.
487
+ --- Usually about 1-3 microseconds (i.e. 0.001-0.003 ms), which should be
488
+ --- fast enough for most setups. For a "normal, real world" coding session
489
+ --- with a total of ~20000 keystrokes it results in extra ~40ms of overhead
490
+ --- for a single created combo. Create many combos with caution.
491
+ ---
492
+ ---@param mode string|table String or array of string mode id (like "n", "i", etc.).
493
+ --- Array of several modes is more performant than several single mode combos.
494
+ ---@param lhs string|table String with tracked key sequence or an array of
495
+ --- tracked keys (one element - one key).
496
+ ---@param action string|function Action to perform after key sequence is detected.
497
+ --- If string, treated as keys and emulated with |nvim_input()|.
498
+ --- If function, executed in |vim.schedule()|. Can return string keys which will
499
+ --- be emulated.
500
+ ---@param opts table|nil Options. Possible fields:
501
+ --- - <delay> `(number)` - delay in milliseconds within which keys should be
502
+ --- pressed to detect a key sequence. Default: 200.
503
+ ---
504
+ ---@usage See |MiniKeymap-examples| for practical examples.
505
+ ---
506
+ --- Some illustrative examples: >lua
507
+ ---
508
+ --- local map_combo = require('mini.keymap').map_combo
509
+ ---
510
+ --- -- In Insert mode pressing `x` followed by `x` within 1 second logs 'A'
511
+ --- -- and emulates extra pressing of `yy`
512
+ --- _G.log = {}
513
+ --- local action = function() table.insert(_G.log, 'A'); return 'yy' end
514
+ --- map_combo('i', 'xx', action, { delay = 1000 })
515
+ --- <
516
+ MiniKeymap.map_combo = function(mode, lhs, action, opts)
517
+ if type(mode) == 'string' then mode = { mode } end
518
+ if not H.is_array_of(mode, H.is_string) then H.error('`mode` should be string or array of strings') end
519
+ local mode_tbl = H.combo_make_mode_tbl(mode)
520
+
521
+ local seq = H.combo_lhs_to_seq(lhs)
522
+ seq = vim.tbl_map(function(x) return vim.api.nvim_replace_termcodes(x, true, true, true) end, seq)
523
+
524
+ if not (type(action) == 'string' or vim.is_callable(action)) then
525
+ H.error('`action` should be either string of keys or callable')
526
+ end
527
+
528
+ -- Cache local values for better speed
529
+ opts = opts or {}
530
+ local delay = opts.delay or 200
531
+ if not (type(delay) == 'number' and delay > 0) then H.error('`opts.delay` should be a positive number') end
532
+
533
+ local hrtime, get_key = vim.loop.hrtime, H.combo_get_key
534
+ local i, last_time, n_seq = 0, hrtime(), #seq
535
+ local delay_ns = 1000000 * delay
536
+ -- NOTE: It is possible to track mode in 'ModeChanged' event and use it for
537
+ -- all combos (instead of `get_mode()` for each). Although it scales well
538
+ -- (O(1) instead of O(n) by number of combos), it can fail when something is
539
+ -- executed with 'eventignore' blocking 'ModeChanged' event (can happen with
540
+ -- plugins). Median `get_mode()` execution time is 0.15 microseconds and it
541
+ -- gets executed on every keystroke. If it proves to be too much, can be
542
+ -- reverted to 'ModeChanged' approach.
543
+ local get_mode = vim.fn.mode
544
+
545
+ -- Explicitly ignore keys from action. Otherwise they will be processed
546
+ -- because `nvim_input` mocks "as if typed" approach.
547
+ local input_keys = vim.schedule_wrap(function(keys)
548
+ H.combo_ignore = true
549
+ vim.api.nvim_input(keys)
550
+ -- NOTE: Can't unignore right away because `nvim_input` is executed later
551
+ H.combo_unignore_later()
552
+ end)
553
+
554
+ if type(action) == 'string' then
555
+ local keys = action
556
+ action = function() input_keys(keys) end
557
+ end
558
+ local act = vim.schedule_wrap(function()
559
+ if H.is_disabled() then return end
560
+ -- Allow action to return keys to manually mimic
561
+ local keys = action()
562
+ if type(keys) == 'string' and keys ~= '' then input_keys(keys) end
563
+ end)
564
+ local reset = function(key)
565
+ -- Make latest key start new combo, like for 'jjk' or j-wait-jj for 'jj'
566
+ i = seq[1] == key and 1 or 0
567
+ last_time = i == 0 and last_time or hrtime()
568
+ end
569
+
570
+ local watcher = function(key, typed)
571
+ -- Use only keys "as if typed" and in proper mode
572
+ key = get_key(key, typed)
573
+ if key == '' or (i == 0 and not mode_tbl[get_mode()]) or H.combo_ignore then return end
574
+
575
+ -- Advance tracking and reset if not in sequence
576
+ i = i + 1
577
+ if seq[i] ~= key then return reset(key) end
578
+
579
+ -- Reset if time between key presses is too big
580
+ local cur_time = hrtime()
581
+ if (cur_time - last_time) > delay_ns and i > 1 then return reset(key) end
582
+ last_time = cur_time
583
+
584
+ -- Wait for more info if sequence is not exhausted, act otherwise
585
+ if i < n_seq then return end
586
+ i = 0
587
+ act()
588
+ end
589
+
590
+ local combo_keys = table.concat(vim.tbl_map(vim.fn.keytrans, seq), '')
591
+ local ns_name = string.format('MiniKeymap-combo-%s-%s-%s', #H.ns_id_combo, table.concat(mode, ''), combo_keys)
592
+ local ns_id = vim.api.nvim_create_namespace(ns_name)
593
+ table.insert(H.ns_id_combo, ns_id)
594
+
595
+ return vim.on_key(watcher, ns_id)
596
+ end
597
+
598
+ -- Helper data ================================================================
599
+ -- Module default config
600
+ H.default_config = vim.deepcopy(MiniKeymap.config)
601
+
602
+ -- Namespaces for `on_key`
603
+ H.ns_id_combo = {}
604
+
605
+ -- Current mode used in "combo" mappings, for better speed
606
+ H.cur_mode = 'n'
607
+
608
+ -- Whether to ignore current keys as part of the combo. Needs to be global for
609
+ -- combo's RHS keys not interfering with tracking of other combos.
610
+ H.combo_ignore = false
611
+
612
+ -- Helper functionality =======================================================
613
+ -- Settings -------------------------------------------------------------------
614
+ H.setup_config = function(config)
615
+ H.check_type('config', config, 'table', true)
616
+ config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})
617
+ return config
618
+ end
619
+
620
+ H.apply_config = function(config) MiniKeymap.config = config end
621
+
622
+ H.is_disabled = function() return vim.g.minikeymap_disable == true or vim.b.minikeymap_disable == true end
623
+
624
+ -- Combo ----------------------------------------------------------------------
625
+ H.combo_lhs_to_seq = function(lhs)
626
+ if H.is_array_of(lhs, H.is_string) then return vim.deepcopy(lhs) end
627
+ if type(lhs) ~= 'string' then H.error('`lhs` should be string or array of strings') end
628
+
629
+ local res, i = {}, 1
630
+ while i <= lhs:len() do
631
+ local k, new_i = string.match(lhs, '^(%b<>)()', i)
632
+ if k == nil or k:find('^.+<') ~= nil then
633
+ k, new_i = vim.fn.strcharpart(lhs, i - 1, 1), i + 1
634
+ end
635
+ table.insert(res, k)
636
+ i = new_i
637
+ end
638
+ return res
639
+ end
640
+
641
+ H.combo_make_mode_tbl = function(mode)
642
+ local res = {}
643
+ for _, m in ipairs(mode) do
644
+ if m == 'x' then
645
+ res.v, res.V, res['\22'] = true, true, true
646
+ elseif m == 'v' then
647
+ res.s, res.v, res.V, res['\22'] = true, true, true, true
648
+ else
649
+ res[m] = true
650
+ end
651
+ end
652
+ return res
653
+ end
654
+
655
+ H.combo_unignore_later = vim.schedule_wrap(function() H.combo_ignore = false end)
656
+
657
+ H.combo_get_key = function(_, typed) return typed end
658
+ if vim.fn.has('nvim-0.11') == 0 then H.combo_get_key = function(key) return key end end
659
+
660
+ -- Multi-step -----------------------------------------------------------------
661
+ H.normalize_steps = function(steps)
662
+ if not H.islist(steps) then H.error('`steps` should be array') end
663
+ local res = {}
664
+ for i, step in ipairs(steps) do
665
+ local s = type(step) == 'string' and H.steps_builtin[step] or step
666
+ local is_step = type(s) == 'table' and vim.is_callable(s.condition) and vim.is_callable(s.action)
667
+ if not is_step then H.error('`steps` should contain valid steps, not ' .. vim.inspect(step)) end
668
+ table.insert(res, s)
669
+ end
670
+
671
+ return res
672
+ end
673
+
674
+ H.wrap_in_cmd_lua = function(f)
675
+ local needs_global_cleanup = _G.MiniKeymap == nil
676
+ _G.MiniKeymap = _G.MiniKeymap or {}
677
+ _G.MiniKeymap._f = f
678
+ local extra_cleanup = needs_global_cleanup and '; MiniKeymap = nil' or ''
679
+ return '<Cmd>lua MiniKeymap._f(); MiniKeymap._f = nil' .. extra_cleanup .. '<CR>'
680
+ end
681
+
682
+ H.make_cmd_lua_action = function(cmd_string)
683
+ return function() return '<Cmd>lua ' .. cmd_string .. '<CR>' end
684
+ end
685
+
686
+ H.has_module = function(name) return (pcall(require, name)) end
687
+
688
+ --stylua: ignore start
689
+ H.steps_builtin = {}
690
+
691
+ H.is_visible_pmenu = function() return vim.fn.pumvisible() == 1 end
692
+ H.is_selected_pmenu = function() return vim.fn.complete_info({ 'selected' }).selected ~= -1 end
693
+
694
+ H.steps_builtin.pmenu_next = { condition = H.is_visible_pmenu, action = function() return '<C-n>' end }
695
+ H.steps_builtin.pmenu_prev = { condition = H.is_visible_pmenu, action = function() return '<C-p>' end }
696
+ H.steps_builtin.pmenu_accept = { condition = H.is_selected_pmenu, action = function() return '<C-y>' end }
697
+
698
+ H.is_minisnippets_session = function() return _G.MiniSnippets ~= nil and _G.MiniSnippets.session.get() ~= nil end
699
+ H.is_minisnippets_matched = function() return _G.MiniSnippets ~= nil and #_G.MiniSnippets.expand({ insert = false }) > 0 end
700
+ H.make_minisnippets_action = function(dir) return H.make_cmd_lua_action('MiniSnippets.session.jump("' .. dir .. '")') end
701
+
702
+ H.steps_builtin.minisnippets_next = { condition = H.is_minisnippets_session, action = H.make_minisnippets_action('next') }
703
+ H.steps_builtin.minisnippets_prev = { condition = H.is_minisnippets_session, action = H.make_minisnippets_action('prev') }
704
+ H.steps_builtin.minisnippets_expand = { condition = H.is_minisnippets_matched, action = H.make_cmd_lua_action('MiniSnippets.expand()') }
705
+
706
+ H.has_minipairs = function() return _G.MiniPairs ~= nil end
707
+
708
+ H.steps_builtin.minipairs_cr = { condition = H.has_minipairs, action = function() return vim.fn.keytrans(_G.MiniPairs.cr()) end }
709
+ H.steps_builtin.minipairs_bs = { condition = H.has_minipairs, action = function() return vim.fn.keytrans(_G.MiniPairs.bs()) end }
710
+
711
+ H.can_jump_tsnode = function()
712
+ -- TODO: Remove `opts.error` after compatibility with Neovim=0.11 is dropped
713
+ local has_parser, parser = pcall(vim.treesitter.get_parser, 0, nil, { error = false })
714
+ return has_parser and parser ~= nil
715
+ end
716
+
717
+ H.make_jump_tsnode = function(side)
718
+ local act = function()
719
+ local node, pos, new_pos = H.get_tsnode(), vim.api.nvim_win_get_cursor(0), nil
720
+ while node ~= nil do
721
+ -- Output of `get_node_range` is 0-indexed with "from" data inclusive and
722
+ -- "to" data exclusive. This is exactly what is needed here:
723
+ -- - For "before" direction exact left end is needed. This will be used
724
+ -- in Insert mode and cursor will be between target and its left cell.
725
+ -- - For "after" direction the one cell to right (after normalization) is
726
+ -- needed because cursor in Insert mode will be just after the node.
727
+ local from_row, from_col, to_row, to_col = vim.treesitter.get_node_range(node)
728
+ local row = side == 'before' and from_row or to_row
729
+ local col = side == 'before' and from_col or to_col
730
+ new_pos = H.normalize_pos(row, col)
731
+ -- Iterate up the tree until different position is found. This is useful
732
+ -- for "before" direction and non-Insert mode.
733
+ if not (new_pos[1] == pos[1] and new_pos[2] == pos[2]) then
734
+ H.hide_completion()
735
+ pcall(vim.api.nvim_win_set_cursor, 0, new_pos)
736
+ new_pos = vim.api.nvim_win_get_cursor(0)
737
+ end
738
+ if not (new_pos[1] == pos[1] and new_pos[2] == pos[2]) then break end
739
+ node = node:parent()
740
+ end
741
+ end
742
+
743
+ -- Return callable which is wrapped to be executed after expression mapping
744
+ return function() return act end
745
+ end
746
+
747
+ H.steps_builtin.jump_after_tsnode = { condition = H.can_jump_tsnode, action = H.make_jump_tsnode('after') }
748
+ H.steps_builtin.jump_before_tsnode = { condition = H.can_jump_tsnode, action = H.make_jump_tsnode('before') }
749
+
750
+ H.steps_builtin.jump_after_close = {
751
+ condition = function() return vim.fn.mode() == 'i' end,
752
+ -- NOTE: In Insert mode 'c' flag (accept at cursor) with 'after' adjust are
753
+ -- needed for working "chaining". In other modes it is no flag and no adjust,
754
+ -- which is why these steps only work in Insert mode.
755
+ action = MiniKeymap.gen_step.search_pattern([=[[)\]}"'`]]=], 'cW', { side = 'after' }).action,
756
+ }
757
+ H.steps_builtin.jump_before_open = {
758
+ condition = function() return vim.fn.mode() == 'i' end,
759
+ action = MiniKeymap.gen_step.search_pattern([=[[(\[{"'`]]=], 'bW', { side = 'before' }).action,
760
+ }
761
+
762
+ H.is_in_indent = function()
763
+ local line, col = vim.api.nvim_get_current_line(), vim.fn.col('.')
764
+ local offset = vim.fn.mode() == 'i' and 1 or 0
765
+ return line:sub(1, col - offset):find('^%s*$') ~= nil
766
+ end
767
+
768
+ H.increase_indent_keys = { i = '<C-t>', v = '>', V = '>', ['\22'] = '>' }
769
+ H.decrease_indent_keys = { i = '<C-d>', v = '<', V = '<', ['\22'] = '<' }
770
+
771
+ H.steps_builtin.increase_indent = { condition = H.is_in_indent, action = function() return H.increase_indent_keys[vim.fn.mode()] or '>>' end }
772
+ H.steps_builtin.decrease_indent = { condition = H.is_in_indent, action = function() return H.decrease_indent_keys[vim.fn.mode()] or '<<' end }
773
+
774
+ H.hungry_bs_condition = function()
775
+ local line, col = vim.api.nvim_get_current_line(), vim.fn.col('.')
776
+ local offset = vim.fn.mode() == 'i' and 1 or 0
777
+ return line:sub(1, col - offset):find('%s+$') ~= nil
778
+ end
779
+
780
+ H.hungry_bs_action = function()
781
+ return function()
782
+ local line, lnum, col = vim.api.nvim_get_current_line(), vim.fn.line('.'), vim.fn.col('.')
783
+ local offset = vim.fn.mode() == 'i' and 1 or 0
784
+ local from_col = line:sub(1, col - offset):match('()%s+$')
785
+ vim.api.nvim_buf_set_text(0, lnum - 1, from_col - 1, lnum - 1, col - offset, {})
786
+ vim.api.nvim_win_set_cursor(0, { lnum, from_col - 1 })
787
+ end
788
+ end
789
+
790
+ H.steps_builtin.hungry_bs = { condition = H.hungry_bs_condition, action = H.hungry_bs_action }
791
+
792
+ H.make_vimsnippet_condition = function(dir) return function() return vim.snippet.active({ direction = dir }) end end
793
+ H.make_vimsnippet_action = function(dir) return H.make_cmd_lua_action('vim.snippet.jump(' .. dir .. ')') end
794
+
795
+ H.steps_builtin.vimsnippet_next = { condition = H.make_vimsnippet_condition(1), action = H.make_vimsnippet_action(1) }
796
+ H.steps_builtin.vimsnippet_prev = { condition = H.make_vimsnippet_condition(-1), action = H.make_vimsnippet_action(-1) }
797
+
798
+ H.is_visible_cmp = function() return H.has_module('cmp') and require('cmp').visible() end
799
+ H.is_selected_cmp = function() return H.has_module('cmp') and require('cmp').get_selected_entry() ~= nil end
800
+ H.make_cmp_action = function(action) return H.make_cmd_lua_action('require("cmp").' .. action .. '()') end
801
+
802
+ H.steps_builtin.cmp_next = { condition = H.is_visible_cmp, action = H.make_cmp_action('select_next_item') }
803
+ H.steps_builtin.cmp_prev = { condition = H.is_visible_cmp, action = H.make_cmp_action('select_prev_item') }
804
+ H.steps_builtin.cmp_accept = { condition = H.is_selected_cmp, action = H.make_cmp_action('confirm') }
805
+
806
+ H.is_visible_blink = function() return H.has_module('blink.cmp') and require('blink.cmp').is_menu_visible() end
807
+ H.is_selected_blink = function() return H.is_visible_blink() and require('blink.cmp').get_selected_item() ~= nil end
808
+ H.make_blink_action = function(action) return H.make_cmd_lua_action('require("blink.cmp").' .. action .. '()') end
809
+
810
+ H.steps_builtin.blink_next = { condition = H.is_visible_blink, action = H.make_blink_action('select_next') }
811
+ H.steps_builtin.blink_prev = { condition = H.is_visible_blink, action = H.make_blink_action('select_prev') }
812
+ H.steps_builtin.blink_accept = { condition = H.is_selected_blink, action = H.make_blink_action('accept') }
813
+
814
+ H.make_luasnip_condition = function(dir) return function() return H.has_module('luasnip') and require('luasnip').jumpable(dir) end end
815
+ H.is_luasnip_expandable = function() return H.has_module('luasnip') and require('luasnip').expandable() end
816
+ H.make_luasnip_action = function(dir) return H.make_cmd_lua_action('require("luasnip").jump(' .. dir .. ')') end
817
+
818
+ H.steps_builtin.luasnip_next = { condition = H.make_luasnip_condition(1), action = H.make_luasnip_action(1) }
819
+ H.steps_builtin.luasnip_prev = { condition = H.make_luasnip_condition(-1), action = H.make_luasnip_action(-1) }
820
+ H.steps_builtin.luasnip_expand = { condition = H.is_luasnip_expandable, action = H.make_cmd_lua_action('require("luasnip").expand()') }
821
+
822
+ H.has_nvimautopairs = function() return H.has_module('nvim-autopairs') end
823
+ H.make_nvimautopairs_action = function(method) return function() return vim.fn.keytrans(require('nvim-autopairs')[method]()) end end
824
+
825
+ H.steps_builtin.nvimautopairs_cr = { condition = H.has_nvimautopairs, action = H.make_nvimautopairs_action('autopairs_cr') }
826
+ H.steps_builtin.nvimautopairs_bs = { condition = H.has_nvimautopairs, action = H.make_nvimautopairs_action('autopairs_bs') }
827
+ --stylua: ignore end
828
+
829
+ -- Validators -----------------------------------------------------------------
830
+ H.is_string = function(x) return type(x) == 'string' end
831
+
832
+ H.is_array_of = function(x, predicate)
833
+ if not H.islist(x) then return false end
834
+ for i = 1, #x do
835
+ if not predicate(x[i]) then return false end
836
+ end
837
+ return true
838
+ end
839
+
840
+ -- Utilities ------------------------------------------------------------------
841
+ H.error = function(msg) error('(mini.keymap) ' .. msg, 0) end
842
+
843
+ H.check_type = function(name, val, ref, allow_nil)
844
+ if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
845
+ H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
846
+ end
847
+
848
+ H.notify = function(msg, level_name, silent)
849
+ if not silent then vim.notify('(mini.keymap) ' .. msg, vim.log.levels[level_name]) end
850
+ end
851
+
852
+ H.normalize_pos = function(row, col)
853
+ -- Input is {0,0} indexed, output is {1,0} indexed
854
+ if row < 0 or (row == 0 and col < 0) then return { 1, 0 } end
855
+ local last_row = vim.api.nvim_buf_line_count(0) - 1
856
+ local n_col_last_row = H.get_row_cols(last_row)
857
+ -- Assume this is used in Insert node, so placing just after EOL can be done
858
+ if row > last_row or (row == last_row and col > n_col_last_row) then return { last_row + 1, n_col_last_row } end
859
+
860
+ if col < 0 then return { row, H.get_row_cols(row - 1) } end
861
+ if col > H.get_row_cols(row) then return { row + 2, 0 } end
862
+ return { row + 1, col }
863
+ end
864
+
865
+ H.get_row_cols = function(row) return vim.fn.getline(row + 1):len() end
866
+
867
+ H.get_tsnode = function() return vim.treesitter.get_node() end
868
+
869
+ H.hide_completion = function()
870
+ -- NOTE: `complete()` instead of emulating <C-y> works immediately (without
871
+ -- the need to `vim.schedule()`). See 'mini.snippets' for more details.
872
+ -- NOTE: Checking 'pumvisible() == 1' should not lead to edge cases from
873
+ -- 'mini.snippets' (as there is no extmarks involved).
874
+ if vim.fn.mode() == 'i' and vim.fn.pumvisible() == 1 then vim.cmd('silent noautocmd call complete(col("."), [])') end
875
+ end
876
+
877
+ -- TODO: Remove after compatibility with Neovim=0.9 is dropped
878
+ H.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist
879
+
880
+ return MiniKeymap