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,969 @@
1
+ --- *mini.misc* Miscellaneous functions
2
+ ---
3
+ --- MIT License Copyright (c) 2021 Evgeni Chasnovski
4
+
5
+ --- Features the following functions:
6
+ --- - |MiniMisc.bench_time()| to benchmark function execution time.
7
+ --- Useful in combination with `stat_summary()`.
8
+ ---
9
+ --- - |MiniMisc.log_add()|, |MiniMisc.log_show()| and other helper functions to work
10
+ --- with a special in-memory log array. Useful when debugging Lua code.
11
+ ---
12
+ --- - |MiniMisc.put()| and |MiniMisc.put_text()| to pretty print its arguments
13
+ --- into command line and current buffer respectively.
14
+ ---
15
+ --- - |MiniMisc.resize_window()| to resize current window to its editable width.
16
+ ---
17
+ --- - |MiniMisc.safely()| to execute a function on a condition and warn on error.
18
+ --- Useful to organize |init.lua| in fail-safe sections with simple lazy loading.
19
+ ---
20
+ --- - |MiniMisc.setup_auto_root()| to set up automated change of current directory.
21
+ ---
22
+ --- - |MiniMisc.setup_termbg_sync()| to set up terminal background synchronization
23
+ --- (removes possible "frame" around current Neovim instance).
24
+ ---
25
+ --- - |MiniMisc.setup_restore_cursor()| to set up automated restoration of
26
+ --- cursor position on file reopen.
27
+ ---
28
+ --- - |MiniMisc.stat_summary()| to compute summary statistics of numerical array.
29
+ --- Useful in combination with `bench_time()`.
30
+ ---
31
+ --- - |MiniMisc.tbl_head()| and |MiniMisc.tbl_tail()| to return "first" and "last"
32
+ --- elements of table.
33
+ ---
34
+ --- - |MiniMisc.zoom()| to zoom in and out of a buffer, making it full screen
35
+ --- in a floating window.
36
+ ---
37
+ --- - And more.
38
+ ---
39
+ --- # Setup ~
40
+ ---
41
+ --- This module doesn't need setup, but it can be done to improve usability.
42
+ --- Setup with `require('mini.misc').setup({})` (replace `{}` with your
43
+ --- `config` table). It will create global Lua table `MiniMisc` which you can
44
+ --- use for scripting or manually (with `:lua MiniMisc.*`).
45
+ ---
46
+ --- See |MiniMisc.config| for `config` structure and default values.
47
+ ---
48
+ --- This module doesn't have runtime options, so using `vim.b.minimisc_config`
49
+ --- will have no effect here.
50
+ ---@tag MiniMisc
51
+
52
+ -- Module definition ==========================================================
53
+ local MiniMisc = {}
54
+ local H = {}
55
+
56
+ --- Module setup
57
+ ---
58
+ ---@param config table|nil Module config table. See |MiniMisc.config|.
59
+ ---
60
+ ---@usage >lua
61
+ --- require('mini.misc').setup() -- use default config
62
+ --- -- OR
63
+ --- require('mini.misc').setup({}) -- replace {} with your config table
64
+ --- <
65
+ MiniMisc.setup = function(config)
66
+ -- TODO: Remove after Neovim=0.9 support is dropped
67
+ if vim.fn.has('nvim-0.10') == 0 then
68
+ vim.notify(
69
+ '(mini.misc) Neovim<0.10 is soft deprecated (module works but is not supported).'
70
+ .. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
71
+ .. ' Please update your Neovim version.'
72
+ )
73
+ end
74
+
75
+ -- Export module
76
+ _G.MiniMisc = MiniMisc
77
+
78
+ -- Setup config
79
+ config = H.setup_config(config)
80
+
81
+ -- Apply config
82
+ H.apply_config(config)
83
+ end
84
+
85
+ --- Defaults ~
86
+ ---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
87
+ MiniMisc.config = {
88
+ -- Array of fields to make global (to be used as independent variables)
89
+ make_global = { 'put', 'put_text' },
90
+ }
91
+ --minidoc_afterlines_end
92
+
93
+ -- Module functionality =======================================================
94
+ --- Execute `f` several times and time how long it took
95
+ ---
96
+ ---@param f function Function which execution to benchmark.
97
+ ---@param n number|nil Number of times to execute `f(...)`. Default: 1.
98
+ ---@param ... any Arguments when calling `f`.
99
+ ---
100
+ ---@return ... Table with durations (in seconds; up to nanoseconds) and
101
+ --- output of (last) function execution.
102
+ MiniMisc.bench_time = function(f, n, ...)
103
+ n = n or 1
104
+ local durations, output = {}, nil
105
+ for _ = 1, n do
106
+ local start_time = vim.loop.hrtime()
107
+ output = f(...)
108
+ local end_time = vim.loop.hrtime()
109
+ table.insert(durations, 0.000000001 * (end_time - start_time))
110
+ end
111
+
112
+ return durations, output
113
+ end
114
+
115
+ --- Compute width of gutter (info column on the left of the window)
116
+ ---
117
+ ---@param win_id number|nil Window identifier (see |win_getid()|) for which gutter
118
+ --- width is computed. Default: 0 for current.
119
+ MiniMisc.get_gutter_width = function(win_id)
120
+ win_id = (win_id == nil or win_id == 0) and vim.api.nvim_get_current_win() or win_id
121
+ return vim.fn.getwininfo(win_id)[1].textoff
122
+ end
123
+
124
+ --- Add an entry to the in-memory log array
125
+ ---
126
+ --- Useful when trying to debug a Lua code (like Neovim config or plugin).
127
+ --- Use this instead of ad-hoc `print()` statements.
128
+ ---
129
+ --- Each entry is a table with the following fields:
130
+ --- - <desc> `(any)` - entry description. Usually a string describing a place
131
+ --- in the code.
132
+ --- - <state> `(any)` - data about current state. Usually a table.
133
+ --- - <timestamp> `(number)` - a timestamp of when the entry was added. A number of
134
+ --- milliseconds since the in-memory log was initiated (after |MiniMisc.setup()|
135
+ --- or |MiniMisc.log_clear()|). Useful during profiling.
136
+ ---
137
+ ---@param desc any Entry description.
138
+ ---@param state any Data about current state.
139
+ ---@param opts table|nil Options. Possible fields:
140
+ --- - <deepcopy> - (boolean) Whether to create a copy of tables in {state}.
141
+ --- Usually helpful to record the exact state during code execution and avoid
142
+ --- side effects of tables being changed in-place. Default `true`.
143
+ ---
144
+ ---@usage >lua
145
+ --- local t = { a = 1 }
146
+ --- MiniMisc.log_add('before', { t = t }) -- Will show `t = { a = 1 }` state
147
+ --- t.a = t.a + 1
148
+ --- MiniMisc.log_add('after', { t = t }) -- Will show `t = { a = 2 }` state
149
+ ---
150
+ --- -- Use `:lua MiniMisc.log_show()` or `:=MiniMisc.log_get()` to see the log
151
+ --- <
152
+ ---@seealso - |MiniMisc.log_get()| to get log array
153
+ --- - |MiniMisc.log_show()| to show log array in the dedicated buffer
154
+ --- - |MiniMisc.log_clear()| to clear the log array
155
+ MiniMisc.log_add = function(desc, state, opts)
156
+ opts = vim.tbl_extend('force', { deepcopy = true }, opts or {})
157
+ local entry = {
158
+ desc = desc,
159
+ state = opts.deepcopy and H.copy_tables(state) or state,
160
+ timestamp = 0.000001 * (vim.loop.hrtime() - H.log_cache.start_htime),
161
+ }
162
+ table.insert(H.log_cache.log, entry)
163
+ end
164
+
165
+ --- Get log array
166
+ ---
167
+ ---@return table[] Log array. Returned as is, without |vim.deepcopy()|.
168
+ ---
169
+ ---@seealso - |MiniMisc.log_add()| to add to the log array
170
+ MiniMisc.log_get = function() return H.log_cache.log end
171
+
172
+ --- Show log array in a scratch buffer
173
+ ---
174
+ ---@seealso - |MiniMisc.log_add()| to add to the log array
175
+ MiniMisc.log_show = function()
176
+ local buf_id = H.log_cache.buf_id
177
+ if buf_id == nil or not vim.api.nvim_buf_is_valid(buf_id) then
178
+ buf_id = vim.api.nvim_create_buf(true, true)
179
+ vim.api.nvim_buf_set_name(buf_id, 'minimisc://' .. buf_id .. '/log')
180
+ H.log_cache.buf_id = buf_id
181
+ end
182
+ local lines = vim.split(vim.inspect(H.log_cache.log), '\n')
183
+ vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
184
+
185
+ local buf_wins = vim.fn.win_findbuf(buf_id)
186
+ if buf_wins[1] == nil then return vim.api.nvim_win_set_buf(0, buf_id) end
187
+ vim.api.nvim_set_current_win(buf_wins[1])
188
+ end
189
+
190
+ --- Clear log array
191
+ ---
192
+ --- This also sets a new starting point for entry timestamps.
193
+ ---
194
+ ---@seealso - |MiniMisc.log_add()| to add to the log array
195
+ MiniMisc.log_clear = function()
196
+ H.log_cache.log = {}
197
+ H.log_cache.start_htime = vim.loop.hrtime()
198
+ H.notify('Cleared log')
199
+ end
200
+
201
+ H.log_cache = { log = {}, start_htime = vim.loop.hrtime(), buf_id = nil }
202
+
203
+ --- Print Lua objects in command line
204
+ ---
205
+ ---@param ... any Any number of objects to be printed each on separate line.
206
+ MiniMisc.put = function(...)
207
+ local objects = {}
208
+ -- Not using `{...}` because it removes `nil` input
209
+ for i = 1, select('#', ...) do
210
+ local v = select(i, ...)
211
+ table.insert(objects, vim.inspect(v))
212
+ end
213
+
214
+ print(table.concat(objects, '\n'))
215
+
216
+ return ...
217
+ end
218
+
219
+ --- Print Lua objects in current buffer
220
+ ---
221
+ ---@param ... any Any number of objects to be printed each on separate line.
222
+ MiniMisc.put_text = function(...)
223
+ local objects = {}
224
+ -- Not using `{...}` because it removes `nil` input
225
+ for i = 1, select('#', ...) do
226
+ local v = select(i, ...)
227
+ table.insert(objects, vim.inspect(v))
228
+ end
229
+
230
+ local lines = vim.split(table.concat(objects, '\n'), '\n')
231
+ local lnum = vim.api.nvim_win_get_cursor(0)[1]
232
+ vim.fn.append(lnum, lines)
233
+
234
+ return ...
235
+ end
236
+
237
+ --- Resize window to have exact number of editable columns
238
+ ---
239
+ ---@param win_id number|nil Window identifier (see |win_getid()|) to be resized.
240
+ --- Default: 0 for current.
241
+ ---@param text_width number|nil Number of editable columns resized window will
242
+ --- display. Default: first element of |'colorcolumn'| or otherwise |'textwidth'|
243
+ --- (using screen width as its default but not more than 79).
244
+ MiniMisc.resize_window = function(win_id, text_width)
245
+ win_id = win_id or 0
246
+ text_width = text_width or H.default_text_width(win_id)
247
+
248
+ vim.api.nvim_win_set_width(win_id, text_width + MiniMisc.get_gutter_width(win_id))
249
+ end
250
+
251
+ H.default_text_width = function(win_id)
252
+ local buf = vim.api.nvim_win_get_buf(win_id)
253
+ local textwidth = vim.bo[buf].textwidth
254
+ textwidth = (textwidth == 0) and math.min(vim.o.columns, 79) or textwidth
255
+
256
+ local colorcolumn = vim.wo[win_id].colorcolumn
257
+ if colorcolumn ~= '' then
258
+ local cc = vim.split(colorcolumn, ',')[1]
259
+ local is_cc_relative = vim.tbl_contains({ '-', '+' }, cc:sub(1, 1))
260
+
261
+ if is_cc_relative then
262
+ return textwidth + tonumber(cc)
263
+ else
264
+ return tonumber(cc)
265
+ end
266
+ else
267
+ return textwidth
268
+ end
269
+ end
270
+
271
+ --- Execute a function on a condition and warn on error
272
+ ---
273
+ --- Input function is executed exactly once. Its possible error is captured and is
274
+ --- shown as a |vim.notify()| warning.
275
+ ---
276
+ --- Useful to organize |init.lua| in fail-safe sections with simple lazy loading.
277
+ ---
278
+ ---@param when string When to execute a function. One of:
279
+ --- - `'now'` - immediately.
280
+ --- - `'later'` - queue to be executed soon without blocking the execution of next
281
+ --- code in file. Queued functions are executed in order they are added.
282
+ --- - `'delay:<number>'` - after a specified delay with |vim.defer_fn()|.
283
+ --- - `'event:<events>'` - on whichever specified event is triggered first.
284
+ --- - `'event:<events>~<patterns>` - same as above, but events must match
285
+ --- specified |autocmd-pattern|.
286
+ --- - `'filetype:<filetypes>'` - same as `'event:FileType~<filetypes>'`, but follow
287
+ --- successful function execution with |filetype-detect| for all normal buffers
288
+ --- (if new |ftdetect| scripts were added) and sourcing |ftplugin| (for buffers
289
+ --- matching `<filetypes>`). Intended to be used for loading "language plugins".
290
+ ---@param f function Function to execute (without arguments).
291
+ ---
292
+ ---@usage >lua
293
+ --- MiniMisc.safely('later', function()
294
+ --- vim.notify('This will be executed after the next "now" call')
295
+ --- end)
296
+ --- MiniMisc.safely('now', function() error('This will be a warning') end)
297
+ ---
298
+ --- MiniMisc.safely('event:InsertEnter', function()
299
+ --- require('mini.completion').setup()
300
+ --- end)
301
+ --- MiniMisc.safely('event:CmdlineEnter~/', function()
302
+ --- vim.notify('Start searching for the first time')
303
+ --- end)
304
+ ---
305
+ --- MiniMisc.safely('filetype:tex,plaintex', function()
306
+ --- -- Load plugin to improve writing LaTeX
307
+ --- end)
308
+ --- <
309
+ MiniMisc.safely = function(when, f)
310
+ H.check_type('when', when, 'string', false)
311
+ H.check_type('f', f, 'callable', false)
312
+
313
+ if when == 'now' then
314
+ H.execute_now(f)
315
+ return
316
+ end
317
+
318
+ -- Compute traceback before delaying execution to provide more info
319
+ local trace = debug.traceback('', 2)
320
+
321
+ if when == 'later' then
322
+ if #H.safely_cache.later == 0 then vim.schedule(H.execute_later) end
323
+ table.insert(H.safely_cache.later, { f = f, trace = trace })
324
+ return
325
+ end
326
+
327
+ local delay = tonumber(when:match('^delay:(%d+)$'))
328
+ if delay ~= nil then
329
+ vim.defer_fn(function() H.execute_now(f, trace) end, delay)
330
+ return
331
+ end
332
+
333
+ local events = when:match('^event:(.+)$')
334
+ if events then
335
+ local ev, patt = events:match('^(.+)~(.+)$')
336
+ local event = vim.split(ev or events, ',', { trimempty = true })
337
+ local pattern = vim.split(patt or '', ',', { trimempty = true })
338
+ H.make_defer_autocmd(event, pattern, f, trace)
339
+ return
340
+ end
341
+
342
+ local filetypes = when:match('^filetype:(.+)$')
343
+ if filetypes then
344
+ local ft_arr = vim.split(filetypes, ',')
345
+ -- NOTE: Needs `vim.schedule_wrap()` for a correct redetect. This also
346
+ -- prompts using `H.execute_now` and not rely on `H.make_defer_autocmd`.
347
+ local f_and_redetect = vim.schedule_wrap(function()
348
+ -- Look out for new 'ftdetect' scripts by comparing before and after
349
+ local ftdetect_scripts_before = vim.api.nvim_get_runtime_file('ftdetect/*.{vim,lua}', true)
350
+
351
+ local ok = H.execute_now(f, trace)
352
+
353
+ -- Skip redetect if there was error or detection is disabled
354
+ if not (ok and vim.g.did_load_filetypes == 1) then return end
355
+
356
+ local ftdetect_scripts_after = vim.api.nvim_get_runtime_file('ftdetect/*.{vim,lua}', true)
357
+ local needs_redetect = not vim.deep_equal(ftdetect_scripts_before, ftdetect_scripts_after)
358
+ for _, buf_id in ipairs(vim.api.nvim_list_bufs()) do
359
+ H.redetect_filetypes(buf_id, ft_arr, needs_redetect)
360
+ end
361
+ end)
362
+ return H.make_defer_autocmd('FileType', ft_arr, f_and_redetect)
363
+ end
364
+
365
+ H.error('Could not parse `when` in `safely`')
366
+ end
367
+
368
+ H.execute_now = function(f, init_trace)
369
+ local ok, err = xpcall(f, function(e) return debug.traceback(e .. '\n', 2) end)
370
+ if ok then return true end
371
+ init_trace = init_trace == nil and '' or ('\n\nTraceback of `MiniMisc.safely()` call:\n' .. init_trace)
372
+ H.notify('Error during safe execution: ' .. err .. init_trace, 'WARN')
373
+ return false
374
+ end
375
+
376
+ H.safely_cache = { later = {} }
377
+
378
+ H.execute_later = function()
379
+ local timer = assert(vim.loop.new_timer())
380
+ local f
381
+ f = vim.schedule_wrap(function()
382
+ local cb = H.safely_cache.later[1]
383
+ if cb == nil then
384
+ if not timer:is_closing() then timer:close() end
385
+ return
386
+ end
387
+
388
+ table.remove(H.safely_cache.later, 1)
389
+ H.execute_now(cb.f, cb.trace)
390
+ timer:start(1, 0, f)
391
+ end)
392
+ -- Space out "later" executions to be sure that they don't block anything
393
+ timer:start(1, 0, f)
394
+ end
395
+
396
+ H.make_defer_autocmd = function(event, pattern, f, trace)
397
+ if type(pattern) == 'table' and #pattern == 0 then pattern = nil end
398
+
399
+ local au_id
400
+ local function cb()
401
+ -- Execute exactly once, not once per event or pattern match
402
+ -- Delete before executing `f` to account for nested events
403
+ vim.api.nvim_del_autocmd(au_id)
404
+ H.execute_now(f, trace)
405
+ end
406
+
407
+ local group = vim.api.nvim_create_augroup('MiniMiscSafely', { clear = false })
408
+ local opts = { group = group, pattern = pattern, callback = cb, nested = true }
409
+ au_id = vim.api.nvim_create_autocmd(event, opts)
410
+ end
411
+
412
+ H.redetect_filetypes = function(buf_id, ft_arr, needs_redetect)
413
+ if not vim.api.nvim_buf_is_loaded(buf_id) then return end
414
+
415
+ vim.api.nvim_buf_call(buf_id, function()
416
+ -- Try detecting new filetypes
417
+ if needs_redetect and vim.bo.buftype == '' then vim.cmd('filetype detect') end
418
+
419
+ -- Force execution of 'ftplugin' scripts for matched filetypes
420
+ if vim.tbl_contains(ft_arr, vim.bo.filetype) then vim.bo.filetype = vim.bo.filetype end
421
+ end)
422
+ end
423
+
424
+ --- Set up automated change of current directory
425
+ ---
426
+ --- What it does:
427
+ --- - Creates autocommand which on every |BufEnter| event with |MiniMisc.find_root()|
428
+ --- finds root directory for current buffer file and sets |current-directory|
429
+ --- to it (using |chdir()|).
430
+ --- - Resets |'autochdir'| to `false`.
431
+ ---
432
+ ---@param names table|function|nil Forwarded to |MiniMisc.find_root()|.
433
+ ---@param fallback function|nil Forwarded to |MiniMisc.find_root()|.
434
+ ---
435
+ ---@usage >lua
436
+ --- require('mini.misc').setup()
437
+ --- MiniMisc.setup_auto_root()
438
+ --- <
439
+ MiniMisc.setup_auto_root = function(names, fallback)
440
+ names = names or { '.git', 'Makefile' }
441
+ if not (H.is_array_of(names, H.is_string) or vim.is_callable(names)) then
442
+ H.error('Argument `names` of `setup_auto_root()` should be array of string file names or a callable.')
443
+ end
444
+
445
+ fallback = fallback or function() return nil end
446
+ if not vim.is_callable(fallback) then H.error('Argument `fallback` of `setup_auto_root()` should be callable.') end
447
+
448
+ -- Disable conflicting option
449
+ vim.o.autochdir = false
450
+
451
+ -- Create autocommand
452
+ local set_root = vim.schedule_wrap(function(data)
453
+ if data.buf ~= vim.api.nvim_get_current_buf() then return end
454
+ local root = MiniMisc.find_root(data.buf, names, fallback)
455
+ if root == nil then return end
456
+ vim.fn.chdir(root)
457
+ end)
458
+ local augroup = vim.api.nvim_create_augroup('MiniMiscAutoRoot', {})
459
+ local opts = { group = augroup, nested = true, callback = set_root, desc = 'Find root and change current directory' }
460
+ vim.api.nvim_create_autocmd('BufEnter', opts)
461
+ end
462
+
463
+ --- Find root directory
464
+ ---
465
+ --- Based on a buffer name (full path to file opened in a buffer) find a root
466
+ --- directory. If buffer is not associated with file, returns `nil`.
467
+ ---
468
+ --- Root directory is a directory containing at least one of pre-defined files.
469
+ --- It is searched using |vim.fs.find()| with `upward = true` starting from
470
+ --- directory of current buffer file until first occurrence of root file(s).
471
+ ---
472
+ --- Notes:
473
+ --- - Uses directory path caching to speed up computations. This means that no
474
+ --- changes in root directory will be detected after directory path was already
475
+ --- used in this function. Reload Neovim to account for that.
476
+ ---
477
+ ---@param buf_id number|nil Buffer identifier (see |bufnr()|) to use.
478
+ --- Default: 0 for current.
479
+ ---@param names table|function|nil Array of file names or a callable used to
480
+ --- identify a root directory. Forwarded to |vim.fs.find()|.
481
+ --- Default: `{ '.git', 'Makefile' }`.
482
+ ---@param fallback function|nil Callable fallback to use if no root is found
483
+ --- with |vim.fs.find()|. Will be called with a buffer path and should return
484
+ --- a valid directory path.
485
+ MiniMisc.find_root = function(buf_id, names, fallback)
486
+ buf_id = buf_id or 0
487
+ names = names or { '.git', 'Makefile' }
488
+ fallback = fallback or function() return nil end
489
+
490
+ if not H.is_valid_buf(buf_id) then H.error('Argument `buf_id` of `find_root()` should be valid buffer id.') end
491
+ if not (H.is_array_of(names, H.is_string) or vim.is_callable(names)) then
492
+ H.error('Argument `names` of `find_root()` should be array of string file names or a callable.')
493
+ end
494
+ if not vim.is_callable(fallback) then H.error('Argument `fallback` of `find_root()` should be callable.') end
495
+
496
+ -- Compute directory to start search from. NOTEs on why not using file path:
497
+ -- - This has better performance because `vim.fs.find()` is called less.
498
+ -- - *Needs* to be a directory for callable `names` to work.
499
+ -- - Later search is done including initial `path` if directory, so this
500
+ -- should work for detecting buffer directory as root.
501
+ local path = vim.api.nvim_buf_get_name(buf_id)
502
+ if path == '' then return end
503
+ local dir_path = vim.fs.dirname(path)
504
+
505
+ -- Try using cache
506
+ local res = H.root_cache[dir_path]
507
+ if res ~= nil then return res end
508
+
509
+ -- Find root
510
+ local root_file = vim.fs.find(names, { path = dir_path, upward = true })[1]
511
+ if root_file ~= nil then
512
+ res = vim.fs.dirname(root_file)
513
+ else
514
+ res = fallback(path)
515
+ end
516
+
517
+ -- Use absolute path to an existing directory
518
+ if type(res) ~= 'string' then return end
519
+ res = vim.fs.normalize(vim.fn.fnamemodify(res, ':p'))
520
+ if vim.fn.isdirectory(res) == 0 then return end
521
+
522
+ -- Cache result per directory path
523
+ H.root_cache[dir_path] = res
524
+
525
+ return res
526
+ end
527
+
528
+ H.root_cache = {}
529
+
530
+ --- Set up terminal background synchronization
531
+ ---
532
+ --- What it does:
533
+ --- - Checks if terminal emulator supports OSC 11 control sequence through
534
+ --- appropriate `stdout`. Stops if not.
535
+ --- - Creates autocommands for |ColorScheme| and |VimResume| events, which
536
+ --- change terminal background to have same color as |guibg| of |hl-Normal|.
537
+ --- - Creates autocommands for |VimLeavePre| and |VimSuspend| events which set
538
+ --- terminal background back to its original color.
539
+ --- - Synchronizes background immediately to allow not depend on loading order.
540
+ ---
541
+ --- Primary use case is to remove possible "frame" around current Neovim instance
542
+ --- which appears if Neovim's |hl-Normal| background color differs from what is
543
+ --- used by terminal emulator itself.
544
+ ---
545
+ --- Works only on Neovim>=0.10.
546
+ ---
547
+ ---@param opts table|nil Options. Possible fields:
548
+ --- - <explicit_reset> `(boolean)` - whether to reset terminal background by
549
+ --- explicitly setting it to the color it had when this function was called.
550
+ --- Set to `true` if terminal emulator doesn't support OSC 111 control sequence.
551
+ --- Default: `false`.
552
+ MiniMisc.setup_termbg_sync = function(opts)
553
+ -- Handling `'\027]11;?\007'` response was added in Neovim 0.10
554
+ if vim.fn.has('nvim-0.10') == 0 then return H.notify('`setup_termbg_sync()` requires Neovim>=0.10', 'WARN') end
555
+
556
+ -- Proceed only if there is a valid stdout to use
557
+ local has_stdout_tty = false
558
+ for _, ui in ipairs(vim.api.nvim_list_uis()) do
559
+ has_stdout_tty = has_stdout_tty or ui.stdout_tty
560
+ end
561
+ if not has_stdout_tty then return end
562
+
563
+ opts = vim.tbl_extend('force', { explicit_reset = false }, opts or {})
564
+
565
+ -- Choose a method for how terminal emulator background is reset
566
+ local reset = function() io.stdout:write('\027]111\027\\') end
567
+ if opts.explicit_reset then reset = function() io.stdout:write('\027]11;' .. H.termbg_init .. '\007') end end
568
+
569
+ local augroup = vim.api.nvim_create_augroup('MiniMiscTermbgSync', { clear = true })
570
+ local track_au_id, bad_responses, had_proper_response = nil, {}, false
571
+ local f = function(args)
572
+ -- Process proper response only once
573
+ if had_proper_response then return end
574
+
575
+ -- Neovim=0.10 uses string sequence as response, while Neovim>=0.11 sets it
576
+ -- in `sequence` table field
577
+ local seq = type(args.data) == 'table' and args.data.sequence or args.data
578
+ local ok, termbg = pcall(H.parse_osc11, seq)
579
+ if not (ok and type(termbg) == 'string') then return table.insert(bad_responses, seq) end
580
+ had_proper_response = true
581
+ pcall(vim.api.nvim_del_autocmd, track_au_id)
582
+
583
+ -- Set up reset to the color returned from the very first call
584
+ H.termbg_init = H.termbg_init or termbg
585
+ vim.api.nvim_create_autocmd({ 'VimLeavePre', 'VimSuspend' }, { group = augroup, callback = reset })
586
+
587
+ -- Set up sync
588
+ local sync = function()
589
+ local normal = vim.api.nvim_get_hl_by_name('Normal', true)
590
+ if normal.background == nil then return reset() end
591
+ -- NOTE: use `io.stdout` instead of `io.write` to ensure correct target
592
+ -- Otherwise after `io.output(file); file:close()` there is an error
593
+ io.stdout:write(string.format('\027]11;#%06x\007', normal.background))
594
+ end
595
+ vim.api.nvim_create_autocmd({ 'VimResume', 'ColorScheme' }, { group = augroup, callback = sync })
596
+
597
+ -- Sync immediately
598
+ sync()
599
+ end
600
+
601
+ -- Ask about current background color and process the proper response.
602
+ -- NOTE: do not use `once = true` as Neovim itself triggers `TermResponse`
603
+ -- events during startup, so this should wait until the proper one.
604
+ track_au_id = vim.api.nvim_create_autocmd('TermResponse', { group = augroup, callback = f, nested = true })
605
+ io.stdout:write('\027]11;?\007')
606
+ vim.defer_fn(function()
607
+ if had_proper_response then return end
608
+ pcall(vim.api.nvim_del_augroup_by_id, augroup)
609
+ local bad_suffix = #bad_responses == 0 and '' or (', only these: ' .. vim.inspect(bad_responses))
610
+ local msg = '`setup_termbg_sync()` did not get proper response from terminal emulator' .. bad_suffix
611
+ H.notify(msg, 'WARN')
612
+ end, 1000)
613
+ end
614
+
615
+ -- Source: 'runtime/lua/vim/_defaults.lua' in Neovim source
616
+ H.parse_osc11 = function(x)
617
+ local r, g, b = x:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
618
+ if not (r and g and b) then
619
+ local a
620
+ r, g, b, a = x:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
621
+ if not (a and a:len() <= 4) then return end
622
+ end
623
+ if not (r and g and b) then return end
624
+ if not (r:len() <= 4 and g:len() <= 4 and b:len() <= 4) then return end
625
+ local parse_osc_hex = function(c) return c:len() == 1 and (c .. c) or c:sub(1, 2) end
626
+ return '#' .. parse_osc_hex(r) .. parse_osc_hex(g) .. parse_osc_hex(b)
627
+ end
628
+
629
+ --- Restore cursor position on file open
630
+ ---
631
+ --- When reopening a file this will make sure the cursor is placed back to the
632
+ --- position where you left before. This implements |restore-cursor| in a nicer way.
633
+ --- File should have a recognized file type (see |'filetype'|) and be opened in
634
+ --- a normal buffer (see |'buftype'|).
635
+ ---
636
+ --- Note: it relies on file mark data stored in |'shadafile'| (see |shada-f|).
637
+ --- Be sure to enable it.
638
+ ---
639
+ ---@param opts table|nil Options. Possible fields:
640
+ --- - <center> - (boolean) Center the window after we restored the cursor.
641
+ --- Default: `true`.
642
+ --- - <ignore_filetype> - Array with file types to be ignored (see |'filetype'|).
643
+ --- Default: `{ "gitcommit", "gitrebase" }`.
644
+ ---
645
+ ---@usage >lua
646
+ --- require('mini.misc').setup_restore_cursor()
647
+ --- <
648
+ MiniMisc.setup_restore_cursor = function(opts)
649
+ opts = opts or {}
650
+
651
+ opts.ignore_filetype = opts.ignore_filetype or { 'gitcommit', 'gitrebase' }
652
+ if not H.is_array_of(opts.ignore_filetype, H.is_string) then
653
+ H.error('In `setup_restore_cursor()` `opts.ignore_filetype` should be an array of strings.')
654
+ end
655
+
656
+ if opts.center == nil then opts.center = true end
657
+ if type(opts.center) ~= 'boolean' then H.error('In `setup_restore_cursor()` `opts.center` should be a boolean.') end
658
+
659
+ -- Create autocommand which runs once on `FileType` for every new buffer
660
+ local augroup = vim.api.nvim_create_augroup('MiniMiscRestoreCursor', {})
661
+ vim.api.nvim_create_autocmd('BufReadPre', {
662
+ group = augroup,
663
+ callback = function(data)
664
+ vim.api.nvim_create_autocmd('FileType', {
665
+ buffer = data.buf,
666
+ once = true,
667
+ callback = function() H.restore_cursor(opts) end,
668
+ })
669
+ end,
670
+ })
671
+ end
672
+
673
+ H.restore_cursor = function(opts)
674
+ -- Stop if not a normal buffer
675
+ if vim.bo.buftype ~= '' then return end
676
+
677
+ -- Stop if filetype is ignored
678
+ if vim.tbl_contains(opts.ignore_filetype, vim.bo.filetype) then return end
679
+
680
+ -- Stop if line is already specified (like during start with `nvim file +num`)
681
+ local cursor_line = vim.api.nvim_win_get_cursor(0)[1]
682
+ if cursor_line > 1 then return end
683
+
684
+ -- Stop if can't restore proper line for some reason
685
+ local mark_line = vim.api.nvim_buf_get_mark(0, [["]])[1]
686
+ local n_lines = vim.api.nvim_buf_line_count(0)
687
+ if not (1 <= mark_line and mark_line <= n_lines) then return end
688
+
689
+ -- Restore cursor and open just enough folds
690
+ vim.cmd([[normal! g`"zv]])
691
+
692
+ -- Center window
693
+ if opts.center then vim.cmd('normal! zz') end
694
+ end
695
+
696
+ --- Compute summary statistics of numerical array
697
+ ---
698
+ --- This might be useful to compute summary of time benchmarking with
699
+ --- |MiniMisc.bench_time()|.
700
+ ---
701
+ ---@param t table Array (table suitable for `ipairs`) of numbers.
702
+ ---
703
+ ---@return table Table with summary values under following keys (may be
704
+ --- extended in the future): <maximum>, <mean>, <median>, <minimum>, <n>
705
+ --- (number of elements), <sd> (sample standard deviation).
706
+ MiniMisc.stat_summary = function(t)
707
+ if not H.is_array_of(t, H.is_number) then
708
+ H.error('Input of `MiniMisc.stat_summary()` should be an array of numbers.')
709
+ end
710
+
711
+ -- Welford algorithm of computing variance
712
+ -- Source: https://www.johndcook.com/blog/skewness_kurtosis/
713
+ local n = #t
714
+ local delta, m1, m2 = 0, 0, 0
715
+ local minimum, maximum = math.huge, -math.huge
716
+ for i, x in ipairs(t) do
717
+ delta = x - m1
718
+ m1 = m1 + delta / i
719
+ m2 = m2 + delta * (x - m1)
720
+
721
+ -- Extremums
722
+ minimum = x < minimum and x or minimum
723
+ maximum = x > maximum and x or maximum
724
+ end
725
+
726
+ return {
727
+ maximum = maximum,
728
+ mean = m1,
729
+ median = H.compute_median(t),
730
+ minimum = minimum,
731
+ n = n,
732
+ sd = math.sqrt(n > 1 and m2 / (n - 1) or 0),
733
+ }
734
+ end
735
+
736
+ H.compute_median = function(t)
737
+ local n = #t
738
+ if n == 0 then return 0 end
739
+
740
+ local t_sorted = vim.deepcopy(t)
741
+ table.sort(t_sorted)
742
+ return 0.5 * (t_sorted[math.ceil(0.5 * n)] + t_sorted[math.ceil(0.5 * (n + 1))])
743
+ end
744
+
745
+ --- Return "first" elements of table as decided by `pairs`
746
+ ---
747
+ --- Note: order of elements might vary.
748
+ ---
749
+ ---@param t table Input table.
750
+ ---@param n number|nil Maximum number of first elements. Default: 5.
751
+ ---
752
+ ---@return table Table with at most `n` first elements of `t` (with same keys).
753
+ MiniMisc.tbl_head = function(t, n)
754
+ n = n or 5
755
+ local res, n_res = {}, 0
756
+ for k, val in pairs(t) do
757
+ if n_res >= n then return res end
758
+ res[k] = val
759
+ n_res = n_res + 1
760
+ end
761
+ return res
762
+ end
763
+
764
+ --- Return "last" elements of table as decided by `pairs`
765
+ ---
766
+ --- This function makes two passes through elements of `t`:
767
+ --- - First to count number of elements.
768
+ --- - Second to construct result.
769
+ ---
770
+ --- Note: order of elements might vary.
771
+ ---
772
+ ---@param t table Input table.
773
+ ---@param n number|nil Maximum number of last elements. Default: 5.
774
+ ---
775
+ ---@return table Table with at most `n` last elements of `t` (with same keys).
776
+ MiniMisc.tbl_tail = function(t, n)
777
+ n = n or 5
778
+
779
+ -- Count number of elements on first pass
780
+ local n_all = 0
781
+ for _, _ in pairs(t) do
782
+ n_all = n_all + 1
783
+ end
784
+
785
+ -- Construct result on second pass
786
+ local res = {}
787
+ local i, start_i = 0, n_all - n + 1
788
+ for k, val in pairs(t) do
789
+ i = i + 1
790
+ if i >= start_i then res[k] = val end
791
+ end
792
+ return res
793
+ end
794
+
795
+ --- Add possibility of nested comment leader
796
+ ---
797
+ --- This works by parsing |'commentstring'| buffer option, extracting
798
+ --- non-whitespace comment leader (symbols on the left of commented line), and
799
+ --- locally modifying |'comments'| option (by prepending `n:<leader>`). Does
800
+ --- nothing if |'commentstring'| is empty or has comment symbols both in front
801
+ --- and back (like `/*%s*/`).
802
+ ---
803
+ --- Nested comment leader added with this function is useful for formatting
804
+ --- nested comments. For example, have in Lua "first-level" comments with `--`
805
+ --- and "second-level" comments with `----`. With nested comment leader second
806
+ --- type can be formatted with `gq` in the same way as first one.
807
+ ---
808
+ --- Recommended usage is with |autocmd|: >lua
809
+ ---
810
+ --- local use_nested_comments = function() MiniMisc.use_nested_comments() end
811
+ --- vim.api.nvim_create_autocmd('BufEnter', { callback = use_nested_comments })
812
+ --- <
813
+ --- Note: for most filetypes |'commentstring'| option is added only when buffer
814
+ --- with this filetype is entered, so using non-current `buf_id` can not lead
815
+ --- to desired effect.
816
+ ---
817
+ ---@param buf_id number|nil Buffer identifier (see |bufnr()|) in which function
818
+ --- will operate. Default: 0 for current.
819
+ MiniMisc.use_nested_comments = function(buf_id)
820
+ buf_id = buf_id or 0
821
+
822
+ local commentstring = vim.bo[buf_id].commentstring
823
+ if commentstring == '' then return end
824
+
825
+ -- Extract raw comment leader from 'commentstring' option
826
+ local comment_parts = vim.tbl_filter(function(x) return x ~= '' end, vim.split(commentstring, '%s', true))
827
+
828
+ -- Don't do anything if 'commentstring' is like '/*%s*/' (as in 'json')
829
+ if #comment_parts > 1 then return end
830
+
831
+ -- Get comment leader by removing whitespace
832
+ local leader = vim.trim(comment_parts[1])
833
+
834
+ local comments = vim.bo[buf_id].comments
835
+ vim.bo[buf_id].comments = string.format('n:%s,%s', leader, comments)
836
+ end
837
+
838
+ --- Zoom in and out of a buffer, making it full screen in a floating window
839
+ ---
840
+ --- This function is useful when working with multiple windows but temporarily
841
+ --- needing to zoom into one to see more of the code from that buffer. Call it
842
+ --- again (without arguments) to zoom out.
843
+ ---
844
+ ---@param buf_id number|nil Buffer identifier (see |bufnr()|) to be zoomed.
845
+ --- Default: 0 for current.
846
+ ---@param config table|nil Optional config for window (as for |nvim_open_win()|).
847
+ ---
848
+ ---@return boolean Whether current buffer is zoomed in.
849
+ MiniMisc.zoom = function(buf_id, config)
850
+ -- Hide
851
+ if H.zoom_winid and vim.api.nvim_win_is_valid(H.zoom_winid) then
852
+ pcall(vim.api.nvim_del_augroup_by_name, 'MiniMiscZoom')
853
+ vim.api.nvim_win_close(H.zoom_winid, true)
854
+ H.zoom_winid = nil
855
+ return false
856
+ end
857
+
858
+ -- Show
859
+ local compute_config = function()
860
+ -- Use precise dimensions for no Command line interactions (better scroll)
861
+ local max_width, max_height = vim.o.columns, vim.o.lines - vim.o.cmdheight
862
+ local default_border = (vim.fn.exists('+winborder') == 0 or vim.o.winborder == '') and 'none' or nil
863
+ --stylua: ignore
864
+ local default_config = {
865
+ relative = 'editor', row = 0, col = 0,
866
+ width = max_width, height = max_height,
867
+ title = ' Zoom ', border = default_border,
868
+ }
869
+ local res = vim.tbl_deep_extend('force', default_config, config or {})
870
+
871
+ -- Adjust dimensions to fit actually present border parts
872
+ local bor = res.border == 'none' and { '' } or res.border
873
+ local n = type(bor) == 'table' and #bor or 0
874
+ local height_offset = n == 0 and 2 or ((bor[1 % n + 1] == '' and 0 or 1) + (bor[5 % n + 1] == '' and 0 or 1))
875
+ local width_offset = n == 0 and 2 or ((bor[3 % n + 1] == '' and 0 or 1) + (bor[7 % n + 1] == '' and 0 or 1))
876
+ res.height = math.min(res.height, max_height - height_offset)
877
+ res.width = math.min(res.width, max_width - width_offset)
878
+
879
+ -- Ensure proper title
880
+ if type(res.title) == 'string' then res.title = H.fit_to_width(res.title, res.width) end
881
+
882
+ return res
883
+ end
884
+ H.zoom_winid = vim.api.nvim_open_win(buf_id or 0, true, compute_config())
885
+ vim.wo[H.zoom_winid].winblend = 0
886
+ vim.cmd('normal! zz')
887
+
888
+ -- - Make sure zoom window is adjusting to changes in its hyperparameters
889
+ local gr = vim.api.nvim_create_augroup('MiniMiscZoom', { clear = true })
890
+ local adjust_config = function()
891
+ if not (type(H.zoom_winid) == 'number' and vim.api.nvim_win_is_valid(H.zoom_winid)) then
892
+ pcall(vim.api.nvim_del_augroup_by_name, 'MiniMiscZoom')
893
+ return
894
+ end
895
+ vim.api.nvim_win_set_config(H.zoom_winid, compute_config())
896
+ end
897
+ vim.api.nvim_create_autocmd('VimResized', { group = gr, callback = adjust_config })
898
+ vim.api.nvim_create_autocmd('OptionSet', { group = gr, pattern = 'cmdheight', callback = adjust_config })
899
+ return true
900
+ end
901
+
902
+ -- Helper data ================================================================
903
+ -- Module default config
904
+ H.default_config = vim.deepcopy(MiniMisc.config)
905
+
906
+ -- Window identifier of current zoom (for `zoom()`)
907
+ H.zoom_winid = nil
908
+
909
+ -- Helper functionality =======================================================
910
+ -- Settings -------------------------------------------------------------------
911
+ H.setup_config = function(config)
912
+ H.check_type('config', config, 'table', true)
913
+ -- NOTE: Don't use `tbl_deep_extend` to prefer full input `make_global` array
914
+ -- Needs adjusting if there is a new setting with nested tables
915
+ config = vim.tbl_extend('force', vim.deepcopy(H.default_config), config or {})
916
+
917
+ H.check_type('make_global', config.make_global, 'table')
918
+ for _, v in pairs(config.make_global) do
919
+ if MiniMisc[v] == nil then H.error("`make_global` should be a table with exported 'mini.misc' methods") end
920
+ end
921
+
922
+ return config
923
+ end
924
+
925
+ H.apply_config = function(config)
926
+ MiniMisc.config = config
927
+
928
+ for _, v in pairs(config.make_global) do
929
+ _G[v] = MiniMisc[v]
930
+ end
931
+ end
932
+
933
+ -- Utilities ------------------------------------------------------------------
934
+ H.error = function(msg) error('(mini.misc) ' .. msg) end
935
+
936
+ H.check_type = function(name, val, ref, allow_nil)
937
+ if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
938
+ H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
939
+ end
940
+
941
+ H.notify = function(msg, level) vim.notify('(mini.misc) ' .. msg, vim.log.levels[level]) end
942
+
943
+ H.is_valid_buf = function(buf_id) return type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id) end
944
+
945
+ H.is_array_of = function(x, predicate)
946
+ if not H.islist(x) then return false end
947
+ for _, v in ipairs(x) do
948
+ if not predicate(v) then return false end
949
+ end
950
+ return true
951
+ end
952
+
953
+ H.is_number = function(x) return type(x) == 'number' end
954
+
955
+ H.is_string = function(x) return type(x) == 'string' end
956
+
957
+ H.fit_to_width = function(text, width)
958
+ local t_width = vim.fn.strchars(text)
959
+ return t_width <= width and text or ('…' .. vim.fn.strcharpart(text, t_width - width + 1, width - 1))
960
+ end
961
+
962
+ H.copy_tables = function(x)
963
+ return type(x) == 'table' and setmetatable(vim.tbl_map(H.copy_tables, x), getmetatable(x)) or x
964
+ end
965
+
966
+ -- TODO: Remove after compatibility with Neovim=0.9 is dropped
967
+ H.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist
968
+
969
+ return MiniMisc