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,1182 @@
1
+ --- *mini.cmdline* Command line tweaks
2
+ ---
3
+ --- MIT License Copyright (c) 2025 Evgeni Chasnovski
4
+
5
+ --- Features:
6
+ ---
7
+ --- - Autocomplete with customizable delay. Enhances |cmdline-completion| and
8
+ --- manual |'wildchar'| pressing experience.
9
+ --- Requires Neovim>=0.11, though Neovim>=0.12 is recommended.
10
+ ---
11
+ --- - Autocorrect words as-you-type. Only words that must come from a fixed set of
12
+ --- candidates (like commands and options) are autocorrected by default.
13
+ ---
14
+ --- - Autopeek command range as-you-type. Shows a floating window with range lines
15
+ --- along with customizable context lines.
16
+ ---
17
+ --- What it doesn't do:
18
+ ---
19
+ --- - Customization of command line UI. Use |ui2| (on Neovim>=0.12).
20
+ ---
21
+ --- - Customization of autocompletion candidates. They are computed
22
+ --- via |cmdline-completion|.
23
+ ---
24
+ --- # Setup ~
25
+ ---
26
+ --- This module needs a setup with `require('mini.cmdline').setup({})` (replace `{}`
27
+ --- with your `config` table). It will create global Lua table `MiniCmdline` which
28
+ --- you can use for scripting or manually (with `:lua MiniCmdline.*`).
29
+ ---
30
+ --- See |MiniCmdline.config| for `config` structure and default values.
31
+ ---
32
+ --- You can override runtime config settings locally to buffer inside
33
+ --- `vim.b.minicmdline_config` which should have same structure as
34
+ --- `MiniCmdline.config`. See |mini.nvim-buffer-local-config| for more details.
35
+ ---
36
+ --- # Suggested option values ~
37
+ ---
38
+ --- Some options are set automatically (if not set before |MiniCmdline.setup()|):
39
+ --- - |'wildmode'| is set to "noselect,full" for less intrusive autocompletion.
40
+ --- Requires Neovim>=0.11 and enabled `config.autocomplete`.
41
+ --- - |'wildoptions'| is set to "pum,fuzzy" to enable fuzzy matching.
42
+ ---
43
+ --- # Comparisons ~
44
+ ---
45
+ --- - [folke/noice.nvim](https://github.com/folke/noice.nvim):
46
+ --- - Mostly focuses on visual aspects of the Command line.
47
+ --- This modules is aimed to improve its workflow without changing UI.
48
+ ---
49
+ --- - [nacro90/numb.nvim](https://github.com/nacro90/numb.nvim):
50
+ --- - Designed to preview only a single line range defined by numbers.
51
+ --- This module handles any form of |:range| and |:range-offset| for both
52
+ --- one and two line ranges.
53
+ --- - Shows target line directly in the normal window.
54
+ --- This module uses a dedicated floating window.
55
+ ---
56
+ --- - Built-in |cmdline-autocompletion| (on Neovim>=0.12):
57
+ --- - This module on Neovim>=0.12 uses that as its base for autocompletion.
58
+ --- Ont top of that it also provides customizable delay and predicate.
59
+ ---
60
+ --- - Built-in |ui2| (on Neovim>=0.12):
61
+ --- - Mostly focuses on visual aspects of the Command line.
62
+ --- This modules is aimed to improve its workflow without changing UI.
63
+ ---
64
+ --- # Highlight groups ~
65
+ --- *MiniCmdline-hl-groups*
66
+ ---
67
+ --- - `MiniCmdlinePeekBorder` - border of autopeek window.
68
+ --- - `MiniCmdlinePeekLineNr` - line numbers in autopeek window.
69
+ --- - `MiniCmdlinePeekNormal` - basic foreground/background of autopeek window.
70
+ --- - `MiniCmdlinePeekSep` - statuscolumn separator in autopeek window.
71
+ --- - `MiniCmdlinePeekSign` - signs in autopeek window.
72
+ --- - `MiniCmdlinePeekTitle` - title of autopeek window.
73
+ ---
74
+ --- # Disabling ~
75
+ ---
76
+ --- To disable acting in mappings, set `vim.g.minicmdline_disable` (globally) or
77
+ --- `vim.b.minicmdline_disable` (for a buffer) to `true`. Considering high number
78
+ --- of different scenarios and customization intentions, writing exact rules
79
+ --- for disabling module's functionality is left to user.
80
+ --- See |mini.nvim-disabling-recipes| for common recipes.
81
+ ---@tag MiniCmdline
82
+
83
+ ---@diagnostic disable:undefined-field
84
+ ---@diagnostic disable:discard-returns
85
+ ---@diagnostic disable:unused-local
86
+
87
+ -- Module definition ==========================================================
88
+ local MiniCmdline = {}
89
+ local H = {}
90
+
91
+ --- Module setup
92
+ ---
93
+ ---@param config table|nil Module config table. See |MiniCmdline.config|.
94
+ ---
95
+ ---@usage >lua
96
+ --- require('mini.cmdline').setup() -- use default config
97
+ --- -- OR
98
+ --- require('mini.cmdline').setup({}) -- replace {} with your config table
99
+ --- <
100
+ MiniCmdline.setup = function(config)
101
+ -- TODO: Remove after Neovim=0.9 support is dropped
102
+ if vim.fn.has('nvim-0.10') == 0 then
103
+ vim.notify(
104
+ '(mini.cmdline) Neovim<0.10 is soft deprecated (module works but is not supported).'
105
+ .. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
106
+ .. ' Please update your Neovim version.'
107
+ )
108
+ end
109
+
110
+ -- Export module
111
+ _G.MiniCmdline = MiniCmdline
112
+
113
+ -- Setup config
114
+ config = H.setup_config(config)
115
+
116
+ -- Apply config
117
+ H.apply_config(config)
118
+
119
+ -- Define behavior
120
+ H.create_autocommands()
121
+
122
+ -- Create default highlighting
123
+ H.create_default_hl()
124
+ end
125
+
126
+ --- Defaults ~
127
+ ---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
128
+ ---@text # General ~
129
+ ---
130
+ --- - Each feature is configured via separate table.
131
+ --- - Use `enable = false` to disable a feature.
132
+ ---
133
+ ---# Autocomplete ~
134
+ ---
135
+ --- `config.autocomplete` is used to configure autocompletion: automatic show
136
+ --- of |'wildmenu'|.
137
+ ---
138
+ --- `autocomplete.delay` defines a (debounce style) delay after which |'wildchar'|
139
+ --- is triggered to show wildmenu.
140
+ --- Default: 0. Note: Neovim>=0.12 is recommended for positive values if you
141
+ --- want to reduce flicker (thanks to |wildtrigger()|).
142
+ ---
143
+ --- `autocomplete.predicate` defines a condition of whether to trigger completion
144
+ --- at the current command line state. Takes a table with input data and should
145
+ --- return `true` to show completion and `false` otherwise. Will be called before
146
+ --- the possible delay at current command line state.
147
+ --- Default: |MiniCmdline.default_autocomplete_predicate()|.
148
+ ---
149
+ --- Input data fields:
150
+ --- - <line> `(string)` - current command line text. See |getcmdline()|.
151
+ --- - <pos> `(number)` - current command line column. See |getcmdpos()|.
152
+ --- - <line_prev> `(string)` - command line text before the latest change.
153
+ --- - <pos_prev> `(number)` - command line column before the latest cursor move.
154
+ ---
155
+ --- Example of blocking completion based on completion type (as some may be slow): >lua
156
+ ---
157
+ --- local block_compltype = { shellcmd = true }
158
+ --- require('mini.cmdline').setup({
159
+ --- autocomplete = {
160
+ --- predicate = function()
161
+ --- return not block_compltype[vim.fn.getcmdcompltype()]
162
+ --- end,
163
+ --- },
164
+ --- })
165
+ --- <
166
+ --- Similar approach can be used to enable completion only for normal Ex commands.
167
+ --- Use `return vim.fn.getcmdtype() == ':'` as a predicate output.
168
+ ---
169
+ ---# Autocorrect ~
170
+ ---
171
+ --- `config.autocorrect` is used to configure autocorrection: automatic adjustment
172
+ --- of bad words as you type them. This works only when appending single character
173
+ --- at the end of the command line. Editing already typed words does not trigger
174
+ --- autocorrect (allows correcting the autocorrection).
175
+ ---
176
+ --- When to autocorrect is computed automatically based on |getcmdcomplpat()| after
177
+ --- every key press: if it doesn't add the character to completion pattern, then
178
+ --- the pattern before the key press is attempted to be corrected.
179
+ --- There is also an autocorrection attempt for the last word just before
180
+ --- executing the command.
181
+ ---
182
+ --- Notes:
183
+ --- - This is intended mostly for fixing typos and not as a shortcut for fuzzy
184
+ --- matching. Performing the latter automatically is too intrusive. Explicitly
185
+ --- use fuzzy completion for that (set up by default).
186
+ ---
187
+ --- - Default autocorrection is done only for words that must come from a fixed
188
+ --- set of candidates (like commands and options) by choosing the one with
189
+ --- the lowest string distance.
190
+ --- See |MiniCmdline.default_autocorrect_func()| for details.
191
+ ---
192
+ --- - Word that matches some Command-line |abbreviation| is not autocorrected.
193
+ ---
194
+ --- - If current command expects only a single argument (like |:colorscheme|), then
195
+ --- autocorrection will happen only just before executing the command.
196
+ ---
197
+ --- `autocorrect.func` is a function that can be used to customize autocorrection.
198
+ --- Takes a table with input data and should return a string with the correct word
199
+ --- or `nil` for no autocorrection. Default: |MiniCmdline.default_autocorrect_func()|.
200
+ ---
201
+ --- Input data fields:
202
+ --- - <word> `(string)` - word to be autocorrected. Never empty string.
203
+ --- - <type> `(string)` - word type. Output of |getcmdcompltype()|.
204
+ ---
205
+ ---# Autopeek ~
206
+ ---
207
+ --- `config.autopeek` is used to configure automatic peeking: show command's target
208
+ --- range in a floating window. The window will appear above command line and show
209
+ --- current buffer with the focus on left and right (if present and differs from
210
+ --- left) range lines.
211
+ ---
212
+ --- `autopeek.n_context` defines how many lines to show above and below the target.
213
+ --- The range itself is visualized by default with the statuscolumn signs.
214
+ --- Default: 1.
215
+ ---
216
+ --- `autopeek.predicate` defines a condition of whether to show peek window at
217
+ --- the current command line state. Takes a table with input data and should
218
+ --- return `true` to peek and `false` otherwise.
219
+ --- Will be called only if it is possible to parse range from the current command
220
+ --- line text and it is for buffer lines (no command or |:command-addr| is `lines`)
221
+ --- Default: |MiniCmdline.default_autopeek_predicate()|.
222
+ ---
223
+ --- Input data fields:
224
+ --- - <left> `(number)` - left range edge. Not necessarily smallest.
225
+ --- - <right> `(number)` - right range edge. Same as `left` for a single line range.
226
+ --- - <cmd> `(string)` - full command name. Can be empty string if no valid
227
+ --- command is (yet) entered.
228
+ ---
229
+ --- `autopeek.window` defines behavior of a peek window.
230
+ --- `autopeek.window.config` is a table defining floating window characteristics
231
+ --- or a callable returning such table.
232
+ --- It should have the same structure as in |nvim_open_win()|.
233
+ ---
234
+ --- `autopeek.window.statuscolumn` is a special function that can be used to
235
+ --- customize |'statuscolumn'| value for the peek window. Takes a table with input
236
+ --- data and should return a string to display for line |v:lnum|.
237
+ --- Default: |MiniCmdline.default_autopeek_statuscolumn()|.
238
+ --- Input data fields are the same as for `autopeek.predicate`.
239
+ ---
240
+ --- Example of showing `<` and `>` signs on range lines: >lua
241
+ ---
242
+ --- function(data)
243
+ --- local n, l, r = vim.v.lnum, data.left, data.right
244
+ --- local s = n == l and (n == r and '* ' or '< ') or n == r and '> ' or ''
245
+ --- -- Needs explicit highlighting via `:h 'statusline'` syntax
246
+ --- return '%#MiniCmdlinePeekSign#' .. s
247
+ --- end
248
+ --- <
249
+ --- Notes:
250
+ --- - Peek window directly shows current buffer, which means that all its
251
+ --- extmarks, virtual text, virtual lines, etc. are also shown.
252
+ --- - Non-zero context might work unreliably if there are virtual lines.
253
+ --- - Peeking intentionally hides Visual selection if Command-line mode is entered
254
+ --- directly from it. Peeking `'<,'>` range already visualizes the selection.
255
+ --- To disable autopeek for this case, add the following code BEFORE
256
+ --- executing `require('mini.cmdline').setup()`: >lua
257
+ ---
258
+ --- local disable = vim.schedule_wrap(function()
259
+ --- local is_from_visual = vim.startswith(vim.fn.getcmdline(), "'<,'>")
260
+ --- MiniCmdline.config.autopeek.enable = not is_from_visual
261
+ --- end)
262
+ --- local reenable = function() MiniCmdline.config.autopeek.enable = true end
263
+ ---
264
+ --- vim.api.nvim_create_autocmd('CmdlineEnter', { callback = disable })
265
+ --- vim.api.nvim_create_autocmd('CmdlineLeave', { callback = reenable })
266
+ --- <
267
+ MiniCmdline.config = {
268
+ -- Autocompletion: show `:h 'wildmenu'` as you type
269
+ autocomplete = {
270
+ enable = true,
271
+
272
+ -- Delay (in ms) after which to trigger completion
273
+ -- Neovim>=0.12 is recommended for positive values
274
+ delay = 0,
275
+
276
+ -- Custom rule of when to trigger completion
277
+ predicate = nil,
278
+
279
+ -- Whether to map arrow keys for more consistent wildmenu behavior
280
+ map_arrows = true,
281
+ },
282
+
283
+ -- Autocorrection: adjust non-existing words (commands, options, etc.)
284
+ autocorrect = {
285
+ enable = true,
286
+
287
+ -- Custom autocorrection rule
288
+ func = nil,
289
+ },
290
+
291
+ -- Autopeek: show command's target range in a floating window
292
+ autopeek = {
293
+ enable = true,
294
+
295
+ -- Number of lines to show above and below range lines
296
+ n_context = 1,
297
+
298
+ -- Custom rule of when to show peek window
299
+ predicate = nil,
300
+
301
+ -- Window options
302
+ window = {
303
+ -- Floating window config
304
+ config = {},
305
+
306
+ -- Function to render statuscolumn
307
+ statuscolumn = nil,
308
+ },
309
+ },
310
+ }
311
+ --minidoc_afterlines_end
312
+
313
+ --- Default autocompletion predicate
314
+ ---
315
+ ---@param data table Input autocompletion data. As described in |MiniCmdline.config|.
316
+ ---@param opts table|nil Options. Reserved for future use.
317
+ ---
318
+ ---@return boolean If command line does not (yet) contain a letter - `false`,
319
+ --- otherwise - `true`. This makes autopeek easier to use for a numerical range.
320
+ MiniCmdline.default_autocomplete_predicate = function(data, opts) return data.line:find('%a') ~= nil end
321
+
322
+ --- Default autocorrection function
323
+ ---
324
+ --- - Return input word if `opts.strict_type=true` and input `type` is not proper.
325
+ --- - Get candidates via `opts.get_candidates()`.
326
+ --- Default: mostly via |getcompletion()| with empty pattern and input `type`.
327
+ --- Exceptions are `help` and `option` types: both list all available candidates
328
+ --- in their own ways.
329
+ --- - Choose the candidate with the lowest Damerau–Levenshtein distance
330
+ --- (smallest number of deletion/insertion/substitution/transposition needed
331
+ --- to transform one word into another; slightly prefers transposition).
332
+ --- Notes:
333
+ --- - Type `'command'` also chooses from all valid candidate abbreviations.
334
+ --- - Comparison is done both respecting and ignoring case.
335
+ ---
336
+ ---@param data table Input autocorrection data. As described in |MiniCmdline.config|.
337
+ ---@param opts table|nil Options. Possible fields:
338
+ --- - <strict_type> `(boolean)` - whether to restrict output only for types which
339
+ --- must have words from a fixed set of candidates (like command or option
340
+ --- names). Note: does not include `help` type since |:help| already has
341
+ --- "sophisticated algorithm" to handle typos. Default: `true`.
342
+ --- - <get_candidates> `(function)` - source of candidates. Will be called
343
+ --- with `data` as argument and should return array of string candidates to
344
+ --- choose from.
345
+ --- Default: for most types - |getcompletion()| with empty pattern and
346
+ --- input `type`; for `help` and `option` type - all available help tags and
347
+ --- option names (long and short) respectively.
348
+ ---
349
+ ---@return string Autocorrected word.
350
+ MiniCmdline.default_autocorrect_func = function(data, opts)
351
+ H.check_type('data', data, 'table')
352
+ H.check_type('data.word', data.word, 'string')
353
+ H.check_type('data.type', data.type, 'string')
354
+
355
+ opts = opts or {}
356
+ local strict_type = opts.strict_type == nil or opts.strict_type
357
+ if strict_type and not H.autocorrect_strict_types[data.type] then return data.word end
358
+
359
+ -- Get all valid words
360
+ local all = vim.is_callable(opts.get_candidates) and opts.get_candidates(data) or H.get_autocorrect_candidates(data)
361
+ if vim.tbl_contains(all, data.word) or data.word == '' then return data.word end
362
+
363
+ -- Make results stable in case several candidates have the same distance
364
+ table.sort(all)
365
+
366
+ -- Handle commands separately: need dedicated abbreviation length
367
+ -- computation and to allow `!`
368
+ if data.type == 'command' then return H.get_nearest_command(data.word, all) end
369
+
370
+ -- Fall back to computing nearest string without allowing abbreviations
371
+ local abbr_lens = vim.tbl_map(string.len, all)
372
+ return H.get_nearest_abbr(data.word, all, abbr_lens)
373
+ end
374
+
375
+ --- Default autopeek predicate
376
+ ---
377
+ ---@param data table Input autopeek data. As described in |MiniCmdline.config|.
378
+ ---@param opts table|nil Options. Reserved for future use.
379
+ ---
380
+ ---@return boolean If command defines |:command-preview| - `false`, otherwise - `true`.
381
+ --- This makes autopeek easier to use for commands like |:substitute|,
382
+ --- especially if |'inccommand'| is set to `split`.
383
+ MiniCmdline.default_autopeek_predicate = function(data, opts)
384
+ local cmd_preview_map = H.cache.cmd_preview_map or H.get_cmd_preview_map()
385
+ return cmd_preview_map[data.cmd] ~= true
386
+ end
387
+
388
+ --- Default autopeek statuscolumn
389
+ ---
390
+ --- - Show signs next to lines depending on their relation to peeked range.
391
+ --- Highlighted with `MiniCmdlinePeekSign` group.
392
+ --- - Show line numbers for left and right parts of the range.
393
+ --- Highlighted with `MiniCmdlinePeekLineNr` group.
394
+ --- - Separate statuscolumn and buffer text with dedicated separator character.
395
+ --- Highlighted with `MiniCmdlinePeekSep` group.
396
+ ---
397
+ --- Notes:
398
+ --- - Intended to only be used as a part of |'statuscolumn'| function, as it
399
+ --- uses |v:lnum| and |v:virtnum| to compute the output.
400
+ ---
401
+ --- Example of adjusting a `mid` sign: >lua
402
+ ---
403
+ --- local peek_stc_opts = { signs = { mid = '+' } }
404
+ --- local peek_stc = function(data)
405
+ --- return MiniCmdline.default_autopeek_statuscolumn(data, peek_stc_opts)
406
+ --- end
407
+ --- require('mini.cmdline').setup({
408
+ --- autopeek = { window = { statuscolumn = peek_stc } },
409
+ --- })
410
+ --- <
411
+ ---@param data table Input peek data. As described in |MiniCmdline.config|.
412
+ ---@param opts table|nil Options. Possible fields:
413
+ --- - <signs> `(table)` - signs to show. Possible fields:
414
+ --- - <same> `(string)` - on range if `left=right`. Default: `'🭬'`.
415
+ --- - <left> `(string)` - on `left` line. Default: `'┌'`.
416
+ --- - <mid> `(string)` - inside range. Default: `'┊'`.
417
+ --- - <right> `(string)` - on `right` line. Default: `'└'`.
418
+ --- - <out> `(string)` - outside of range. Default: `''` (no sign).
419
+ --- - <virt> `(string)` - virtual line. Default: `'•'`.
420
+ --- - <wrap> `(string)` - wrapped line. Default: `'↳'`.
421
+ --- - <sep> `(string)` - string to put at the end to separate statuscolumn and
422
+ --- buffer text. Default: `'│'`
423
+ ---
424
+ --- Note: Any sign and separator should have every `%` escaped as `%%` (due to its
425
+ --- special meaning in |'statuscolumn'|).
426
+ MiniCmdline.default_autopeek_statuscolumn = function(data, opts)
427
+ opts = opts or {}
428
+ local signs = opts.signs or {}
429
+ local sep_format = opts.sep == nil and '│' or opts.sep:gsub('%%', '%%%%')
430
+
431
+ if vim.v.virtnum ~= 0 then
432
+ local sign = (vim.v.virtnum < 0 and (signs.virt or '•') or (signs.wrap or '↳'))
433
+ -- Format as `sign %= sep-hl sep`
434
+ return sign .. '%=%#MiniCmdlinePeekSep#' .. sep_format:gsub('%%%%', '%%')
435
+ end
436
+
437
+ local n, l, r = vim.v.lnum, data.left, data.right
438
+ -- Format as `sign-hl sign linenr-hl %= linenr sep-hl sep`
439
+ local fmt = '%%#MiniCmdlinePeekSign#%s%%#MiniCmdlinePeekLineNr#%%=%s%%#MiniCmdlinePeekSep#' .. sep_format
440
+ if n == l and n == r then return string.format(fmt, signs.same or '🭬', n) end
441
+ if n == l then return string.format(fmt, signs.left or '┌', n) end
442
+ if n == r then return string.format(fmt, signs.right or '└', n) end
443
+ if (l < n and n < r) or (r < n and n < l) then return string.format(fmt, signs.mid or '┊', '') end
444
+ return string.format(fmt, signs.out or '', '')
445
+ end
446
+
447
+ -- Helper data ================================================================
448
+ -- Module default config
449
+ H.default_config = vim.deepcopy(MiniCmdline.config)
450
+
451
+ -- Timers
452
+ H.timers = {
453
+ autocomplete = vim.loop.new_timer(),
454
+ }
455
+
456
+ -- Autocomplete requires `noselect` flag of 'wildmode'. Present in Neovim>=0.11
457
+ H.can_autocomplete = vim.fn.has('nvim-0.11') == 1
458
+
459
+ -- Autocorrect types for which words *must* be from some fixed set
460
+ -- Basically a subset of `:h :command-complete` which might lead to an error if
461
+ -- word is not from a fixed set. Can be adjusted for more nuances.
462
+ -- Reasons for not including a type:
463
+ -- - The main reason is because type's usage can be done in context when
464
+ -- creating a new object. Like `:edit new-file` for `file` type.
465
+ -- - No `help` because there already is an autocorrection with a "sophisticated
466
+ -- algorithm to decide which match is better than another one".
467
+ -- - No `buffer` because completion candidates only include names for listed
468
+ -- buffers. So ids of listed buffers and name+ids of unlisted buffers are
469
+ -- missing. Also, partial buffer name is enough for `:buffer`, which would
470
+ -- be too cumbersome to account for.
471
+ --stylua: ignore
472
+ H.autocorrect_strict_types = {
473
+ arglist = true, -- file names in argument list
474
+ -- augroup = true, -- autocmd groups
475
+ -- breakpoint = true, -- |:breakadd| suboptions
476
+ -- buffer = true, -- buffer names
477
+ color = true, -- color schemes
478
+ command = true, -- Ex command (and arguments)
479
+ compiler = true, -- compilers
480
+ diff_buffer = true, -- diff buffer names
481
+ -- dir = true, -- directory names
482
+ -- dir_in_path = true, -- directory names in |'cdpath'|
483
+ -- environment = true, -- environment variable names
484
+ event = true, -- autocommand events
485
+ -- expression = true, -- Vim expression
486
+ -- file = true, -- file and directory names
487
+ -- file_in_path = true, -- file and directory names in |'path'|
488
+ filetype = true, -- filetype names |'filetype'|
489
+ -- ['function'] = true, -- function name
490
+ -- help = true, -- help subjects
491
+ -- highlight = true, -- highlight groups
492
+ history = true, -- |:history| suboptions
493
+ keymap = true, -- keyboard mappings
494
+ locale = true, -- locale names (as output of locale -a)
495
+ -- lua = true, -- Lua expression |:lua|
496
+ mapclear = true, -- buffer argument
497
+ -- mapping = true, -- mapping name
498
+ -- menu = true, -- menus
499
+ messages = true, -- |:messages| suboptions
500
+ option = true, -- options
501
+ packadd = true, -- optional package |pack-add| names
502
+ -- runtime = true, -- file and directory names in |'runtimepath'|
503
+ -- scriptnames = true, -- sourced script names
504
+ -- shellcmd = true, -- Shell command
505
+ -- shellcmdline = true, -- First is a shell command and subsequent ones are filenames
506
+ sign = true, -- |:sign| suboptions
507
+ syntax = true, -- syntax file names |'syntax'|
508
+ syntime = true, -- |:syntime| suboptions
509
+ -- tag = true, -- tags
510
+ -- tag_listfiles = true, -- tags, file names are shown when CTRL-D is hit
511
+ -- user = true, -- user names
512
+ -- var = true, -- user variables
513
+ }
514
+
515
+ -- Various cache to use during command line edit
516
+ H.cache = {}
517
+
518
+ -- Helper functionality =======================================================
519
+ -- Settings -------------------------------------------------------------------
520
+ H.setup_config = function(config)
521
+ H.check_type('config', config, 'table', true)
522
+ config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})
523
+
524
+ H.check_type('autocomplete', config.autocomplete, 'table')
525
+ H.check_type('autocomplete.enable', config.autocomplete.enable, 'boolean')
526
+ H.check_type('autocomplete.delay', config.autocomplete.delay, 'number')
527
+ H.check_type('autocomplete.predicate', config.autocomplete.predicate, 'function', true)
528
+ H.check_type('autocomplete.map_arrows', config.autocomplete.map_arrows, 'boolean')
529
+
530
+ H.check_type('autocorrect', config.autocorrect, 'table')
531
+ H.check_type('autocorrect.enable', config.autocorrect.enable, 'boolean')
532
+ H.check_type('autocorrect.func', config.autocorrect.func, 'function', true)
533
+
534
+ H.check_type('autopeek', config.autopeek, 'table')
535
+ H.check_type('autopeek.enable', config.autopeek.enable, 'boolean')
536
+ H.check_type('autopeek.n_context', config.autopeek.n_context, 'number')
537
+ H.check_type('autopeek.predicate', config.autopeek.predicate, 'callable', true)
538
+ H.check_type('autopeek.window', config.autopeek.window, 'table')
539
+ local autopeek_win_config = config.autopeek.window.config
540
+ if not (type(autopeek_win_config) == 'table' or vim.is_callable(autopeek_win_config)) then
541
+ H.error('`autopeek.window.config` should be table or callable, not ' .. type(autopeek_win_config))
542
+ end
543
+ H.check_type('autopeek.window.statuscolumn', config.autopeek.window.statuscolumn, 'callable', true)
544
+
545
+ return config
546
+ end
547
+
548
+ H.apply_config = function(config)
549
+ MiniCmdline.config = config
550
+
551
+ -- Try setting suggested option values
552
+ -- NOTE: This makes it more like 'mini.completion' (with 'noselect')
553
+ local was_set = vim.api.nvim_get_option_info2('wildmode', { scope = 'global' }).was_set
554
+ if not was_set and config.autocomplete.enable and H.can_autocomplete then vim.o.wildmode = 'noselect,full' end
555
+
556
+ was_set = vim.api.nvim_get_option_info2('wildoptions', { scope = 'global' }).was_set
557
+ if not was_set then vim.o.wildoptions = 'pum,fuzzy' end
558
+
559
+ -- Set useful mappings
560
+ if config.autocomplete.map_arrows then
561
+ local map_arrow = function(dir, wildmenu_prefix, desc)
562
+ local rhs = function() return (vim.fn.wildmenumode() == 1 and wildmenu_prefix or '') .. dir end
563
+ vim.keymap.set('c', dir, rhs, { expr = true, desc = desc })
564
+ end
565
+ map_arrow('<Left>', '<Space><BS>', 'Move cursor left')
566
+ map_arrow('<Right>', '<Space><BS>', 'Move cursor right')
567
+ -- NOTE: All tests seem to pass without these mappings. But it is mentioned
568
+ -- in `:h cmdline-autocompletion`, so probably worth adding
569
+ map_arrow('<Up>', '<C-e>', 'Go to earlier history')
570
+ map_arrow('<Down>', '<C-e>', 'Go to newer history')
571
+ end
572
+ end
573
+
574
+ H.create_autocommands = function()
575
+ local gr = vim.api.nvim_create_augroup('MiniCmdline', {})
576
+
577
+ local au = function(event, pattern, callback, desc)
578
+ vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })
579
+ end
580
+
581
+ -- Act on command line events. Notes:
582
+ -- - Schedule for 'CmdlineEnter' to not act on mappings like `:...`
583
+ -- (like `:<C-u>...` popular for Visual mode).
584
+ -- - Prefer 'CursorMovedC' to track command line change as it is triggered
585
+ -- both after only position change and after text change. Schedule its
586
+ -- callback to work around autcompletion issues with mocking wildchar.
587
+ -- - Do not schedule 'CmdlineLeave' to be able to set command text before
588
+ -- executing it.
589
+ au('CmdlineEnter', '*', vim.schedule_wrap(H.on_cmdline_enter), 'Act on command line enter')
590
+ local update_event = vim.fn.has('nvim-0.11') == 1 and 'CursorMovedC' or 'CmdlineChanged'
591
+ au(update_event, '*', vim.schedule_wrap(H.on_cmdline_update), 'Act on command line update')
592
+ au('CmdlineLeave', '*', H.on_cmdline_leave, 'Act on command line leave')
593
+
594
+ au('VimResized', '*', function() H.autopeek(true) end, 'Adjust peek window')
595
+ au('CmdwinEnter', '*', function() H.peek_hide() end, 'Hide peek window')
596
+
597
+ au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')
598
+ end
599
+
600
+ H.create_default_hl = function()
601
+ local hi = function(name, opts)
602
+ opts.default = true
603
+ vim.api.nvim_set_hl(0, name, opts)
604
+ end
605
+
606
+ hi('MiniCmdlinePeekBorder', { link = 'FloatBorder' })
607
+ hi('MiniCmdlinePeekLineNr', { link = 'DiagnosticSignWarn' })
608
+ hi('MiniCmdlinePeekNormal', { link = 'NormalFloat' })
609
+ hi('MiniCmdlinePeekSep', { link = 'SignColumn' })
610
+ hi('MiniCmdlinePeekSign', { link = 'DiagnosticSignHint' })
611
+ hi('MiniCmdlinePeekTitle', { link = 'FloatTitle' })
612
+ end
613
+
614
+ H.is_disabled = function() return vim.g.minicmdline_disable == true or vim.b.minicmdline_disable == true end
615
+
616
+ H.get_config = function() return vim.tbl_deep_extend('force', MiniCmdline.config, vim.b.minicmdline_config or {}) end
617
+
618
+ -- Autocommands ---------------------------------------------------------------
619
+ H.on_cmdline_enter = function()
620
+ -- Check for Command-line mode to not act on `:...` mappings
621
+ if H.is_disabled() or vim.fn.mode() ~= 'c' then return end
622
+
623
+ -- Act only on "not nested" command line (for simplicity). It can nest after
624
+ -- `c_CTRL-R_=`, since there are CmdlineEnter-CmdlineChanged-CmdlineLeave for
625
+ -- it without explicit leave-enter for the initial normal Ex command mode.
626
+ -- There doesn't seem to be a way to have `n_nested > 1`, but use counter of
627
+ -- nested levels instead of a boolean `is_nested` just in case.
628
+ if H.cache.state ~= nil then
629
+ H.cache.n_nested = (H.cache.n_nested or 0) + 1
630
+ return
631
+ end
632
+
633
+ H.cache = {
634
+ buf_id = vim.api.nvim_get_current_buf(),
635
+ cmd_preview_map = H.get_cmd_preview_map(),
636
+ cmd_type = vim.fn.getcmdtype(),
637
+ config = H.get_config(),
638
+ peek = {},
639
+ state = H.get_cmd_state(),
640
+ state_prev = H.get_cmd_state(true),
641
+ }
642
+ H.cache.autocomplete_predicate = H.cache.config.autocomplete.predicate or MiniCmdline.default_autocomplete_predicate
643
+ H.cache.buf_is_cmdwin = vim.fn.getbufinfo(H.cache.buf_id)[1].command == 1
644
+
645
+ H.cache.autopeek_predicate = H.cache.config.autopeek.predicate or MiniCmdline.default_autopeek_predicate
646
+ MiniCmdline._peek_statuscolumn = H.make_peek_statuscolumn()
647
+ if H.cache.config.autopeek.enable then H.autopeek() end
648
+ end
649
+
650
+ H.on_cmdline_update = function()
651
+ if H.cache.state == nil or H.cache.n_nested ~= nil then return end
652
+
653
+ -- Track state only if there was an actual change (line or position)
654
+ local state = H.get_cmd_state()
655
+ local is_same_line = state.line == H.cache.state.line
656
+ if is_same_line and state.pos == H.cache.state.pos then return end
657
+
658
+ -- Update state accounting for some edge cases
659
+ if H.cache.state_prev.compltype == 'option' then H.adjust_option_cmd_state(state) end
660
+ H.cache.state_prev, H.cache.state = H.cache.state, state
661
+
662
+ -- Act only on text change
663
+ if is_same_line then return end
664
+ local config = H.cache.config
665
+ if config.autocomplete.enable and H.can_autocomplete then H.autocomplete() end
666
+ if config.autocorrect.enable then H.autocorrect(false) end
667
+ if config.autopeek.enable then H.autopeek() end
668
+ end
669
+
670
+ H.on_cmdline_leave = function()
671
+ if H.cache.state == nil then return end
672
+ if H.cache.n_nested ~= nil then
673
+ H.cache.n_nested = H.cache.n_nested > 1 and (H.cache.n_nested - 1) or nil
674
+ return
675
+ end
676
+
677
+ if H.cache.config.autocorrect.enable and not vim.v.event.abort then H.autocorrect(true) end
678
+ H.peek_hide()
679
+ H.cache = {}
680
+ MiniCmdline._peek_statuscolumn = nil
681
+ end
682
+
683
+ H.get_cmd_state = function(is_init)
684
+ local compltype = vim.fn.getcmdcompltype()
685
+ if is_init then return { complpat = '', compltype = compltype, line = '', pos = 1, cmd = {} } end
686
+ return { complpat = H.getcmdcomplpat(), compltype = compltype, line = vim.fn.getcmdline(), pos = vim.fn.getcmdpos() }
687
+ end
688
+
689
+ H.adjust_option_cmd_state = function(state)
690
+ -- Cases like `set nowrap invmagic` are completed specially. After `no`/`inv`
691
+ -- there is a specialized completion only for boolean options. In practice it
692
+ -- results into `compltype=''` and `complpat=<text after no/inv>`.
693
+ -- This interferes with how autocorrection is detected, as it relies on whole
694
+ -- `nowrap` / `invmagic` to be a single complpat *with compltype=option*.
695
+ --
696
+ -- The solution is to detect cases "it was compltype=option but now it isn't"
697
+ -- and try to expand complpat to match the whole word on cursor's left.
698
+ if state.compltype == 'option' then return end
699
+ state.complpat = state.line:sub(1, state.pos - 1):match(' (%w+)$') or ''
700
+ state.compltype = state.complpat ~= '' and 'option' or state.compltype
701
+ end
702
+
703
+ -- Autocomplete ---------------------------------------------------------------
704
+ H.autocomplete = function()
705
+ H.timers.autocomplete:stop()
706
+
707
+ -- Do not complete if predicate says so
708
+ local state, state_prev = H.cache.state, H.cache.state_prev
709
+ local data = { line = state.line, pos = state.pos, line_prev = state_prev.line, pos_prev = state_prev.pos }
710
+ if not H.cache.autocomplete_predicate(data) then return H.hide_wild() end
711
+
712
+ -- Do nothing in some problematic cases (when wildmenu does not work)
713
+ -- TODO: Remove after compatibility with Neovim=0.11 is dropped
714
+ if H.block_autocomplete() then return end
715
+
716
+ local delay = H.cache.config.autocomplete.delay
717
+ if delay == 0 then return H.trigger_complete() end
718
+ H.timers.autocomplete:start(delay, 0, H.trigger_complete_scheduled)
719
+ end
720
+
721
+ H.block_autocomplete = function() return false end
722
+ if vim.fn.has('nvim-0.12') == 0 then
723
+ H.block_autocomplete = function()
724
+ -- Block for non-interactive command type
725
+ if H.cache.cmd_type ~= ':' then return true end
726
+
727
+ -- Block for cases when there is no completion candidates. This affects
728
+ -- performance (completion candidates are computed twice), but it is
729
+ -- the most robust way of dealing with problematic situations:
730
+ -- - Some commands don't have completion defined: `:s`, `:g`, etc.
731
+ -- - Some cases result in verbatim `^I` inserted. Like after bang (`:q!`).
732
+ --
733
+ -- The `vim.fn.getcmdcompltype() == ''` condition is too wide as it denies
734
+ -- legitimate cases of when there are available completion candidates.
735
+ -- Like in user commands created with `vim.api.nvim_create_user_command()`.
736
+ local line_before_pos = H.cache.state.line:sub(1, H.cache.state.pos - 1)
737
+ -- `getcompletion` may result in error, like after `:ltag `
738
+ local ok, candidates = pcall(vim.fn.getcompletion, line_before_pos, 'cmdline')
739
+ return not (ok and #candidates > 0)
740
+ end
741
+ end
742
+
743
+ H.trigger_complete = function()
744
+ if vim.fn.mode() ~= 'c' then return end
745
+ H.trigger_wild()
746
+ end
747
+
748
+ H.trigger_complete_scheduled = vim.schedule_wrap(H.trigger_complete)
749
+
750
+ H.trigger_wild = function() vim.fn.wildtrigger() end
751
+ if vim.fn.has('nvim-0.12') == 0 then
752
+ H.trigger_wild = function()
753
+ -- Not triggering when wildmenu is shown helps avoiding trigger after
754
+ -- manually pressing wildchar (as text is also changes).
755
+ if vim.fn.wildmenumode() == 1 then return end
756
+ -- Type `<C-z>` which is "Trigger 'wildmode', but always available."
757
+ vim.api.nvim_feedkeys('\26', 'nt', false)
758
+ end
759
+ end
760
+
761
+ H.hide_wild = function()
762
+ -- Ensure that there is no outdated pmenu after `wildtrigger()`
763
+ vim.cmd('redraw')
764
+
765
+ -- This works, but it triggers wildmenu, which is not usable when the point
766
+ -- is to hide pmenu if `autocomplete.predicate()` returned `false` ()
767
+ -- local keys = (vim.fn.wildmenumode() == 0 and '\26' or '') .. '\5'
768
+ -- vim.api.nvim_feedkeys(keys, 'nt', false)
769
+ end
770
+ if vim.fn.has('nvim-0.12') == 0 then H.hide_wild = function() end end
771
+
772
+ -- Autocorrect ----------------------------------------------------------------
773
+ H.autocorrect = function(is_final)
774
+ -- Act only for normal Ex commands after a word is just finished typing
775
+ if not (H.cache.cmd_type == ':' and H.cache.state.line:find('%S') ~= nil) then return end
776
+
777
+ local state, state_prev = H.cache.state, H.cache.state_prev
778
+ local line, line_prev = state.line, state_prev.line
779
+ local pos, pos_prev = state.pos, state_prev.pos
780
+
781
+ -- Act only when a char is appended. It makes tweaking autocorrected text
782
+ -- easier by going back and editing it. This is also easier to implement.
783
+ local is_at_end, was_at_end = (pos - 1) == line:len(), (pos_prev - 1) == line_prev:len()
784
+ local new = line:sub(pos_prev)
785
+ local is_char_append = is_at_end and was_at_end and line == (line_prev .. new) and vim.fn.strchars(new) <= 1
786
+ local is_word_finished = not vim.startswith(state.complpat, state_prev.complpat)
787
+
788
+ if not (is_char_append and (is_word_finished or is_final)) then return end
789
+
790
+ -- Compute autocorrection
791
+ local state_to_use = is_final and state or state_prev
792
+ local word = state_to_use.complpat
793
+ if word == '' or vim.fn.maparg(word, 'c', true) ~= '' then return end
794
+
795
+ local func = H.cache.config.autocorrect.func or MiniCmdline.default_autocorrect_func
796
+ local new_word = func({ word = word, type = state_to_use.compltype }) or word
797
+
798
+ if word == new_word then return end
799
+ if type(new_word) ~= 'string' then return H.notify('Can not autocorrect for ' .. vim.inspect(word), 'WARN') end
800
+
801
+ -- Set corrected word
802
+ local init_pos = state_to_use.pos
803
+ local new_line = line:sub(1, init_pos - word:len() - 1) .. new_word .. line:sub(init_pos)
804
+ -- - Use `noautocmd` to not conflict with `autocomplete` on `CmdlineChanged`
805
+ local cmd = string.format('call setcmdline(%s, %s)', vim.inspect(new_line), new_line:len() + 1)
806
+ vim.cmd('noautocmd ' .. cmd)
807
+ end
808
+
809
+ H.get_autocorrect_candidates = function(data)
810
+ if data.type == 'help' then
811
+ local help_buf = vim.api.nvim_create_buf(false, true)
812
+ vim.bo[help_buf].buftype = 'help'
813
+ -- - NOTE: no dedicated buffer name because it is immediately wiped out
814
+ local tags = vim.api.nvim_buf_call(help_buf, function() return vim.fn.taglist('.*') end)
815
+ vim.api.nvim_buf_delete(help_buf, { force = true })
816
+ return vim.tbl_map(function(x) return x.name end, tags)
817
+ end
818
+
819
+ if data.type == 'option' then
820
+ local all = {}
821
+ for name, info in pairs(vim.api.nvim_get_all_options_info()) do
822
+ table.insert(all, name)
823
+
824
+ local is_bool = info.type == 'boolean'
825
+ table.insert(all, is_bool and ('no' .. name) or nil)
826
+ table.insert(all, is_bool and ('inv' .. name) or nil)
827
+
828
+ local has_shortname = info.shortname ~= ''
829
+ table.insert(all, has_shortname and info.shortname or nil)
830
+ table.insert(all, (has_shortname and is_bool) and ('no' .. info.shortname) or nil)
831
+ table.insert(all, (has_shortname and is_bool) and ('inv' .. info.shortname) or nil)
832
+ end
833
+ return all
834
+ end
835
+
836
+ local ok, all = pcall(vim.fn.getcompletion, '', data.type)
837
+ return ok and all or { data.word }
838
+ end
839
+
840
+ H.get_nearest_command = function(ref, all)
841
+ -- Do not alter `:=` command, as it is a special Lua shorthand command
842
+ if ref:sub(1, 1) == '=' then return ref end
843
+
844
+ -- Allow trailing special punctuation (specific to commands)
845
+ local word, suffix = ref:match('^(.+)([!|]?)$')
846
+
847
+ -- Account for the fact that commands can be abbreviated (`:h |20.2|`):
848
+ local cmd_abbr_lens, usr_cmds, usr_max_len = {}, {}, 0
849
+ for _, cmd in ipairs(all) do
850
+ -- User command abbreviation needs to uniquely identify command name
851
+ if cmd:find('^[A-Z]') ~= nil then
852
+ usr_cmds[cmd] = true
853
+ usr_max_len = math.max(usr_max_len, cmd:len())
854
+ else
855
+ -- ANY abbreviation of ANY built-in command is a valid command (may be
856
+ -- different; `wincmd`->`w`==`write`). Its an internal optimization.
857
+ -- EXCEPT: `:def` abbreviation of `:defer` is not allowed.
858
+ cmd_abbr_lens[cmd] = cmd == 'defer' and 4 or 1
859
+ end
860
+ end
861
+
862
+ -- Slice user commands with increasing abbreviation length to find which
863
+ -- ones can be uniquely identified by it
864
+ for cur_abbr_len = 1, usr_max_len do
865
+ local cur_abbrs = {}
866
+ for cmd, _ in pairs(usr_cmds) do
867
+ local abbr = cmd:sub(1, cur_abbr_len)
868
+ cur_abbrs[abbr] = cur_abbrs[abbr] or {}
869
+ table.insert(cur_abbrs[abbr], cmd)
870
+ end
871
+
872
+ for _, cmd_arr in pairs(cur_abbrs) do
873
+ if #cmd_arr == 1 then
874
+ local cmd = cmd_arr[1]
875
+ cmd_abbr_lens[cmd] = math.min(cur_abbr_len, cmd:len())
876
+ usr_cmds[cmd] = nil
877
+ end
878
+ end
879
+ end
880
+
881
+ local abbr_lens = vim.tbl_map(function(x) return cmd_abbr_lens[x] end, all)
882
+ return H.get_nearest_abbr(word, all, abbr_lens) .. suffix
883
+ end
884
+
885
+ H.get_nearest_abbr = function(word, candidates, abbr_lens)
886
+ local tolower = vim.fn.tolower
887
+ local word_split = vim.split(word, '')
888
+ local word_split_l = vim.split(tolower(word), '')
889
+
890
+ -- Prefer closest string respecting case first, then try ignorecase
891
+ local res, res_dist = nil, math.huge
892
+ for i, cand in ipairs(candidates) do
893
+ local min_abbr_len = abbr_lens[i]
894
+ local d, abbr_len = H.string_abbr_dist(word_split, vim.split(cand, ''), min_abbr_len)
895
+ if d < res_dist then
896
+ res, res_dist = cand:sub(1, abbr_len), d
897
+ end
898
+ end
899
+ for i, cand in ipairs(candidates) do
900
+ local min_abbr_len = abbr_lens[i]
901
+ local cand_word_l = tolower(cand)
902
+ local d_l, abbr_len_l = H.string_abbr_dist(word_split_l, vim.split(cand_word_l, ''), min_abbr_len)
903
+ if d_l < res_dist then
904
+ res, res_dist = cand:sub(1, abbr_len_l), d_l
905
+ end
906
+ end
907
+
908
+ return res
909
+ end
910
+
911
+ H.string_abbr_dist = function(ref, cand, min_abbr_len)
912
+ -- Source: https://en.wikipedia.org/wiki/Damerau-Levenshtein_distance
913
+ -- d[i][j] - distance between `ref[1:i]` and `cand[1:j]` abbreviations
914
+ local d = {}
915
+ for i = 0, #ref do
916
+ d[i] = { [0] = i }
917
+ end
918
+ for j = 0, #cand do
919
+ d[0][j] = j
920
+ end
921
+ for i = 1, #ref do
922
+ for j = 1, #cand do
923
+ local cost = ref[i] == cand[j] and 0 or 1
924
+ -- Account for deletion, insertion, substitution
925
+ d[i][j] = math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost)
926
+ -- Account for transposition. Slightly favor them over others, as it is
927
+ -- a common source for autocorrection
928
+ if i > 1 and j > 1 and ref[i] == cand[j - 1] and ref[i - 1] == cand[j] then
929
+ d[i][j] = math.min(d[i][j], d[i - 2][j - 2] + 0.99 * cost)
930
+ end
931
+ end
932
+ end
933
+
934
+ -- Find the candidate abbreviation with the smallest distance
935
+ local abbr_d = d[#ref]
936
+ local dist, abbr_len = math.huge, nil
937
+ for j = min_abbr_len, #cand do
938
+ if abbr_d[j] < dist then
939
+ dist, abbr_len = abbr_d[j], j
940
+ end
941
+ end
942
+
943
+ return dist, abbr_len
944
+ end
945
+
946
+ -- Autopeek -------------------------------------------------------------------
947
+ H.autopeek = function(force)
948
+ -- Decide if peek needs to be shown or hidden
949
+ if not (H.cache.cmd_type == ':' and not H.cache.buf_is_cmdwin) then return end
950
+
951
+ local line = H.cache.state.line
952
+ if line:find('%S') == nil then H.peek_hide() end
953
+
954
+ local parsed = H.parse_cmd(line)
955
+ local range, cmd = parsed.range, parsed.cmd
956
+ if range[1] == nil and range[2] == nil then return H.peek_hide() end
957
+
958
+ -- Normalize range lines
959
+ local n_lines = vim.api.nvim_buf_line_count(0)
960
+ local left = H.clamp(range[1] or range[2], 1, n_lines)
961
+ local right = H.clamp(range[2] or range[1], 1, n_lines)
962
+ local from = right < left and right or left
963
+ local to = right < left and left or right
964
+ local data = { left = left, right = right, cmd = parsed.cmd }
965
+
966
+ -- Do not peek if predicate says so
967
+ if not H.cache.autopeek_predicate(data) then return H.peek_hide() end
968
+
969
+ -- Force peek update if command line height has changed when typing
970
+ local cmdheight = math.ceil((vim.fn.strdisplaywidth(line) + 1) / vim.o.columns)
971
+ cmdheight = math.max(cmdheight, vim.o.cmdheight)
972
+ force = force or cmdheight ~= H.cache.peek.cmdheight
973
+
974
+ -- Skip peek update if command line state is the same (for performance)
975
+ local cur_data = H.cache.peek.data or {}
976
+ local is_data_same = left == cur_data.left and right == cur_data.right and cmd == cur_data.cmd
977
+ if not force and is_data_same then return end
978
+
979
+ H.cache.peek.cmdheight = cmdheight
980
+ H.cache.peek.data = data
981
+ H.cache.peek.win_id = H.peek_show(from, to)
982
+ end
983
+
984
+ H.peek_show = function(from, to)
985
+ -- Compute height to show union of left and right contexts plus possible fold
986
+ local n_context = math.max(H.cache.config.autopeek.n_context, 0)
987
+ local n_lines = vim.api.nvim_buf_line_count(0)
988
+ local cont_from = H.peek_new_context(from, n_context, n_lines)
989
+ local cont_to = H.peek_new_context(to, n_context, n_lines)
990
+ local height = H.peek_get_height(cont_from, cont_to)
991
+
992
+ -- Ensure opened window of enough height.
993
+ -- NOTE: This uses current buffer directly, which means that all its extmarks
994
+ -- are shown. This is both good (for extra text highlighting) and bad
995
+ -- (virtual lines and text) thing. Ideally, extmark "owners" should take care
996
+ -- of where they should be shown. Usually setting something like "only show
997
+ -- inside this particular window" makes sense. Like in 'mini.diff' and
998
+ -- 'mini.indentscope'. This is currently not (robustly) possible. Sources:
999
+ -- - https://github.com/neovim/neovim/issues/19654
1000
+ -- - https://github.com/neovim/neovim/pull/27361
1001
+ -- - https://github.com/neovim/neovim/pull/28432
1002
+ -- - https://github.com/neovim/neovim/pull/28728
1003
+ local config = H.peek_get_config(height)
1004
+ local win_id = H.cache.peek.win_id
1005
+ win_id = H.is_valid_win(win_id) and win_id or vim.api.nvim_open_win(0, false, config)
1006
+ vim.api.nvim_win_set_config(win_id, config)
1007
+
1008
+ -- Ensure context fits the window (it may be not enough height to fit whole)
1009
+ if config.height < height then H.peek_adjust_context(cont_from, cont_to, height, config.height) end
1010
+
1011
+ -- Finalize window view
1012
+ vim.api.nvim_win_call(win_id, function()
1013
+ -- Define window-local options
1014
+ vim.cmd("setlocal foldenable foldlevel=0 foldmethod=manual foldminlines=1 foldtext=''")
1015
+ vim.cmd('setlocal foldcolumn=0 nocursorline nonumber scrolloff=0 signcolumn=no nowrap')
1016
+ vim.wo.list = vim.go.list
1017
+ vim.wo.listchars = vim.go.listchars
1018
+ vim.wo.statuscolumn = '%{%v:lua.MiniCmdline._peek_statuscolumn()%}'
1019
+ vim.wo.winhighlight = 'NormalFloat:MiniCmdlinePeekNormal'
1020
+ .. ',FloatBorder:MiniCmdlinePeekBorder'
1021
+ .. ',FloatTitle:MiniCmdlinePeekTitle'
1022
+
1023
+ -- Display range lines with context, fold the excess, ensure at least one
1024
+ -- range end is shown (might be not the case if there are virtual lines).
1025
+ vim.api.nvim_win_set_cursor(0, { cont_from.before, 0 })
1026
+ vim.cmd('normal! zEzt')
1027
+ vim.api.nvim_win_set_cursor(0, { cont_from.at, 0 })
1028
+ local from_after, to_before = cont_from.after, cont_to.before
1029
+ if to_before - from_after > 1 then vim.cmd(string.format('%s,%sfold', from_after + 1, to_before - 1)) end
1030
+ end)
1031
+
1032
+ -- NOTE: Need explicit redraw because otherwise window is not shown
1033
+ vim.cmd('redraw')
1034
+ return win_id
1035
+ end
1036
+
1037
+ H.peek_new_context = function(at, n_context, n_lines)
1038
+ return { before = H.clamp(at - n_context, 1, n_lines), at = at, after = H.clamp(at + n_context, 1, n_lines) }
1039
+ end
1040
+
1041
+ H.peek_get_height = function(cont_from, cont_to)
1042
+ -- L(a or b) = L(a) + L(b) - L(a and b). Also adjust for fold.
1043
+ local n_from = cont_from.after - cont_from.before + 1
1044
+ local n_to = cont_to.after - cont_to.before + 1
1045
+ local n_both = math.max(cont_from.after - cont_to.before + 1, 0)
1046
+ local n_fold = (cont_to.before - cont_from.after > 1) and 1 or 0
1047
+ return (n_from + n_to - n_both) + n_fold
1048
+ end
1049
+
1050
+ H.peek_get_config = function(height)
1051
+ local cmdheight = H.cache.peek.cmdheight
1052
+
1053
+ local default_config = { relative = 'editor', style = 'minimal', zindex = 199 }
1054
+ default_config.anchor = 'SE'
1055
+ default_config.row = math.max(vim.o.lines - cmdheight, 1)
1056
+ default_config.col = 1
1057
+ default_config.width = vim.o.columns
1058
+ default_config.height = height
1059
+
1060
+ default_config.border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'single' or nil
1061
+ default_config.title = ' Peek '
1062
+ default_config.focusable = false
1063
+
1064
+ local win_config = H.cache.config.autopeek.window.config
1065
+ if vim.is_callable(win_config) then win_config = win_config() end
1066
+ local config = vim.tbl_deep_extend('force', default_config, win_config or {})
1067
+
1068
+ -- Tweak config values to ensure they are proper, accounting for border
1069
+ local offset = config.border == 'none' and 0 or 2
1070
+ config.height = math.max(math.min(config.height, vim.o.lines - cmdheight - offset), 1)
1071
+ config.width = math.min(config.width, vim.o.columns - offset)
1072
+
1073
+ if type(config.title) == 'string' then config.title = H.fit_to_width(config.title, config.width) end
1074
+
1075
+ return config
1076
+ end
1077
+
1078
+ H.peek_adjust_context = function(cont_from, cont_to, height, target_height)
1079
+ local extra = height - target_height
1080
+
1081
+ -- First truncate outer context (keeping top and bottom equal)
1082
+ -- NOTE: Reduce in a cycle and not via a formula since outer context can be
1083
+ -- shorter if its range line is close to file border
1084
+ while extra > 0 do
1085
+ local n_from_out, n_to_out = cont_from.at - cont_from.before, cont_to.after - cont_to.at
1086
+ if n_from_out <= 0 and n_to_out <= 0 then break end
1087
+
1088
+ local is_reduce_from = n_from_out > n_to_out
1089
+ cont_from.before = cont_from.before + (is_reduce_from and 1 or 0)
1090
+ cont_to.after = cont_to.after - (is_reduce_from and 0 or 1)
1091
+ extra = extra - 1
1092
+ end
1093
+ if extra <= 0 then return end
1094
+
1095
+ -- Hide excess inner context under the fold
1096
+ -- NOTE: Reduce height by 3 to make space for `from`, `to`, and fold
1097
+ local inner_context_lines = math.max(target_height - 3, 0)
1098
+ local half_height = math.floor(0.5 * inner_context_lines)
1099
+ cont_from.after = cont_from.at + half_height
1100
+ cont_to.before = cont_to.at - (inner_context_lines - half_height)
1101
+ end
1102
+
1103
+ H.peek_hide = function()
1104
+ local info = H.cache.peek or {}
1105
+ H.win_close_safely(info.win_id)
1106
+ H.cache.peek = {}
1107
+ end
1108
+
1109
+ H.make_peek_statuscolumn = function()
1110
+ local statuscolumn = H.cache.config.autopeek.window.statuscolumn or MiniCmdline.default_autopeek_statuscolumn
1111
+ return function() return statuscolumn(H.cache.peek.data) or '' end
1112
+ end
1113
+
1114
+ -- Utilities ------------------------------------------------------------------
1115
+ H.error = function(msg) error('(mini.cmdline) ' .. msg, 0) end
1116
+
1117
+ H.check_type = function(name, val, ref, allow_nil)
1118
+ if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
1119
+ H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
1120
+ end
1121
+
1122
+ H.notify = function(msg, level_name, silent)
1123
+ if not silent then vim.notify('(mini.cmdline) ' .. msg, vim.log.levels[level_name]) end
1124
+ end
1125
+
1126
+ H.clamp = function(x, from, to) return math.min(math.max(x, from), to) end
1127
+
1128
+ H.is_valid_win = function(win_id) return type(win_id) == 'number' and vim.api.nvim_win_is_valid(win_id) end
1129
+
1130
+ H.win_close_safely = function(win_id)
1131
+ if H.is_valid_win(win_id) then vim.api.nvim_win_close(win_id, true) end
1132
+ end
1133
+
1134
+ H.fit_to_width = function(text, width)
1135
+ local t_width = vim.fn.strchars(text)
1136
+ return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))
1137
+ end
1138
+
1139
+ H.get_cmd_preview_map = function()
1140
+ local res = { substitute = true, smagic = true, snomagic = true }
1141
+ -- NOTE: Check `name` type as on Neovim<0.11 output can be `{ [true] = 6 }`
1142
+ for name, data in pairs(vim.api.nvim_get_commands({})) do
1143
+ if type(name) == 'string' and data.preview then res[name] = true end
1144
+ end
1145
+ for name, data in pairs(vim.api.nvim_buf_get_commands(0, {})) do
1146
+ if type(name) == 'string' and data.preview then res[name] = true end
1147
+ end
1148
+ return res
1149
+ end
1150
+
1151
+ H.parse_cmd = function(line)
1152
+ local ok, parsed = pcall(vim.api.nvim_parse_cmd, line, {})
1153
+ local needs_reparse = not ok
1154
+
1155
+ -- Try extra parsing to have a result for some edge cases
1156
+ -- - Line with only range
1157
+ if not ok then
1158
+ ok, parsed = pcall(vim.api.nvim_parse_cmd, line .. 'sort', {})
1159
+ end
1160
+ -- - Unfinished `/xxx` range
1161
+ if not ok and line:find('/') ~= nil then
1162
+ ok, parsed = pcall(vim.api.nvim_parse_cmd, line .. '/sort', {})
1163
+ end
1164
+ -- - Unrecognized command
1165
+ if not ok and line:find('%a') ~= nil and line:find('^%A') ~= nil then
1166
+ ok, parsed = pcall(vim.api.nvim_parse_cmd, line:match('^%A+') .. 'sort', {})
1167
+ end
1168
+
1169
+ -- Treat `range` only as a "line range"
1170
+ local range = (ok and parsed.addr == 'line') and parsed.range or {}
1171
+ local cmd = needs_reparse and '' or parsed.cmd
1172
+ return { range = range, cmd = cmd }
1173
+ end
1174
+
1175
+ H.getcmdcomplpat = function() return vim.fn.getcmdcomplpat() end
1176
+ if vim.fn.has('nvim-0.11') == 0 then
1177
+ -- Match alphanumeric characters to cursor's left, if present
1178
+ -- This is not 100% how it works, but good enough
1179
+ H.getcmdcomplpat = function() return vim.fn.getcmdline():sub(1, vim.fn.getcmdpos() - 1):match('%w+$') or '' end
1180
+ end
1181
+
1182
+ return MiniCmdline