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,1042 @@
1
+ --- *mini.hipatterns* Highlight patterns in text
2
+ ---
3
+ --- MIT License Copyright (c) 2023 Evgeni Chasnovski
4
+
5
+ --- Features:
6
+ --- - Highlight text with configurable patterns and highlight groups (can be
7
+ --- string or callable).
8
+ ---
9
+ --- - Highlighting is updated asynchronously with configurable debounce delay.
10
+ ---
11
+ --- - Function to get matches in a buffer (see |MiniHipatterns.get_matches()|).
12
+ ---
13
+ --- See |MiniHipatterns-examples| for common configuration examples.
14
+ ---
15
+ --- Notes:
16
+ --- - It does not define any highlighters by default. Add to `config.highlighters`
17
+ --- to have a visible effect.
18
+ ---
19
+ --- - Sometimes (especially during frequent buffer updates on same line numbers)
20
+ --- highlighting can be outdated or not applied when it should be. This is due
21
+ --- to asynchronous nature of updates reacting to text changes (via
22
+ --- `on_lines` of |nvim_buf_attach()|).
23
+ --- To make them up to date, use one of the following:
24
+ --- - Scroll window (for example, with |CTRL-E| / |CTRL-Y|). This will ensure
25
+ --- up to date highlighting inside window view.
26
+ --- - Hide and show buffer.
27
+ --- - Execute `:edit` (if you enabled highlighting with |MiniHipatterns.setup()|).
28
+ --- - Manually call |MiniHipatterns.update()|.
29
+ ---
30
+ --- - If you experience flicker when typing near highlighted pattern in Insert
31
+ --- mode, it might be due to `delay` configuration of |mini.completion| or
32
+ --- using built-in completion.
33
+ --- For better experience with |mini.completion|, make sure that its
34
+ --- `delay.completion` is less than this module's `delay.text_change` (which
35
+ --- it is by default).
36
+ --- The reason for this is (currently unresolvable) limitations of Neovim's
37
+ --- built-in completion implementation.
38
+ ---
39
+ --- # Setup ~
40
+ ---
41
+ --- Setting up highlights can be done in two ways:
42
+ --- - Manually for every buffer with `require('mini.hipatterns').enable()`.
43
+ --- This will enable highlighting only in one particular buffer until it is
44
+ --- unloaded (which also includes calling `:edit` on current file).
45
+ ---
46
+ --- - Globally with `require('mini.hipatterns').setup({})` (replace `{}` with
47
+ --- your `config` table). This will auto-enable highlighting in "normal"
48
+ --- buffers (see |'buftype'|). Use |MiniHipatterns.enable()| to manually enable
49
+ --- in other buffers.
50
+ --- It will also create global Lua table `MiniHipatterns` which you can use
51
+ --- for scripting or manually (with `:lua MiniHipatterns.*`).
52
+ ---
53
+ --- See |MiniHipatterns.config| for `config` structure and default values.
54
+ ---
55
+ --- You can override runtime config settings (like highlighters and delays)
56
+ --- locally to buffer inside `vim.b.minihipatterns_config` which should have
57
+ --- same structure as `MiniHipatterns.config`.
58
+ --- See |mini.nvim-buffer-local-config| for more details.
59
+ ---
60
+ --- # Comparisons ~
61
+ ---
62
+ --- - [folke/todo-comments](https://github.com/folke/todo-comments):
63
+ --- - Oriented for "TODO", "NOTE", "FIXME" like patterns, while this module
64
+ --- can work with any Lua patterns and computable highlight groups.
65
+ --- - Has functionality beyond text highlighting (sign placing,
66
+ --- "telescope.nvim" extension, etc.), while this module only focuses on
67
+ --- highlighting text.
68
+ --- - [folke/paint.nvim](https://github.com/folke/paint.nvim):
69
+ --- - Mostly similar to this module, but with slightly less functionality,
70
+ --- such as computed pattern and highlight group, asynchronous delay, etc.
71
+ --- - [NvChad/nvim-colorizer.lua](https://github.com/NvChad/nvim-colorizer.lua):
72
+ --- - Oriented for color highlighting, while this module can work with any
73
+ --- Lua patterns and computable highlight groups.
74
+ --- - Has more built-in color spaces to highlight, while this module out of
75
+ --- the box provides only hex color highlighting
76
+ --- (see |MiniHipatterns.gen_highlighter.hex_color()|). Other types are
77
+ --- also possible to implement.
78
+ --- - [uga-rosa/ccc.nvim](https://github.com/uga-rosa/ccc.nvim):
79
+ --- - Has more than color highlighting functionality, which is compared to
80
+ --- this module in the same way as `NvChad/nvim-colorizer.lua`.
81
+ ---
82
+ --- # Highlight groups ~
83
+ --- *MiniHipatterns-hl-groups*
84
+ ---
85
+ --- - `MiniHipatternsFixme` - suggested group to use for `FIXME`-like patterns.
86
+ --- - `MiniHipatternsHack` - suggested group to use for `HACK`-like patterns.
87
+ --- - `MiniHipatternsTodo` - suggested group to use for `TODO`-like patterns.
88
+ --- - `MiniHipatternsNote` - suggested group to use for `NOTE`-like patterns.
89
+ ---
90
+ --- To change any highlight group, set it directly with |nvim_set_hl()|.
91
+ ---
92
+ --- # Disabling ~
93
+ ---
94
+ --- This module can be disabled in three ways:
95
+ --- - Globally: set `vim.g.minihipatterns_disable` to `true`.
96
+ --- - Locally for buffer permanently: set `vim.b.minihipatterns_disable` to `true`.
97
+ --- - Locally for buffer temporarily (until next auto-enabling event if set up
98
+ --- with |MiniHipatterns.setup()|): call |MiniHipatterns.disable()|.
99
+ ---
100
+ --- Considering high number of different scenarios and customization
101
+ --- intentions, writing exact rules for disabling module's functionality is
102
+ --- left to user. See |mini.nvim-disabling-recipes| for common recipes.
103
+ ---@tag MiniHipatterns
104
+
105
+ --- # Common configuration examples ~
106
+ ---
107
+ --- - Special words used to convey different level of attention: >lua
108
+ ---
109
+ --- require('mini.hipatterns').setup({
110
+ --- highlighters = {
111
+ --- fixme = { pattern = 'FIXME', group = 'MiniHipatternsFixme' },
112
+ --- hack = { pattern = 'HACK', group = 'MiniHipatternsHack' },
113
+ --- todo = { pattern = 'TODO', group = 'MiniHipatternsTodo' },
114
+ --- note = { pattern = 'NOTE', group = 'MiniHipatternsNote' },
115
+ --- }
116
+ --- })
117
+ --- <
118
+ --- - To match only when pattern appears as a standalone word, use frontier
119
+ --- patterns `%f`. For example, instead of `'TODO'` pattern use
120
+ --- `'%f[%w]()TODO()%f[%W]'`. In this case, for example, `TODOING` or `MYTODO`
121
+ --- won't match, but `TODO` and `TODO:` will.
122
+ ---
123
+ --- - Color hex (like `#rrggbb`) highlighting: >lua
124
+ ---
125
+ --- local hipatterns = require('mini.hipatterns')
126
+ --- hipatterns.setup({
127
+ --- highlighters = {
128
+ --- hex_color = hipatterns.gen_highlighter.hex_color(),
129
+ --- }
130
+ --- })
131
+ --- <
132
+ --- You can customize which part of hex color is highlighted by using `style`
133
+ --- field of input options. See |MiniHipatterns.gen_highlighter.hex_color()|.
134
+ ---
135
+ --- - Colored words: >lua
136
+ ---
137
+ --- local words = { red = '#ff0000', green = '#00ff00', blue = '#0000ff' }
138
+ --- local word_color_group = function(_, match)
139
+ --- local hex = words[match]
140
+ --- if hex == nil then return nil end
141
+ --- return MiniHipatterns.compute_hex_color_group(hex, 'bg')
142
+ --- end
143
+ ---
144
+ --- local hipatterns = require('mini.hipatterns')
145
+ --- hipatterns.setup({
146
+ --- highlighters = {
147
+ --- word_color = { pattern = '%S+', group = word_color_group },
148
+ --- },
149
+ --- })
150
+ --- <
151
+ --- - Trailing whitespace (if don't want to use more specific |mini.trailspace|): >lua
152
+ ---
153
+ --- { pattern = '%f[%s]%s*$', group = 'Error' }
154
+ --- <
155
+ --- - Censor certain sensitive information: >lua
156
+ ---
157
+ --- local censor_extmark_opts = function(_, match, _)
158
+ --- local mask = string.rep('x', vim.fn.strchars(match))
159
+ --- return {
160
+ --- virt_text = { { mask, 'Comment' } }, virt_text_pos = 'overlay',
161
+ --- priority = 200, right_gravity = false,
162
+ --- }
163
+ --- end
164
+ ---
165
+ --- require('mini.hipatterns').setup({
166
+ --- highlighters = {
167
+ --- censor = {
168
+ --- pattern = 'password: ()%S+()',
169
+ --- group = '',
170
+ --- extmark_opts = censor_extmark_opts,
171
+ --- },
172
+ --- },
173
+ --- })
174
+ --- <
175
+ --- - Enable only in certain filetypes. There are at least these ways to do it:
176
+ --- - (Suggested) With `vim.b.minihipatterns_config` in |filetype-plugin|.
177
+ --- Basically, create "after/ftplugin/<filetype>.lua" file in your config
178
+ --- directory (see |$XDG_CONFIG_HOME|) and define `vim.b.minihipatterns_config`
179
+ --- there with filetype specific highlighters.
180
+ ---
181
+ --- This assumes `require('mini.hipatterns').setup()` call.
182
+ ---
183
+ --- For example, to highlight keywords in EmmyLua comments in Lua files,
184
+ --- create "after/ftplugin/lua.lua" with the following content: >lua
185
+ ---
186
+ --- vim.b.minihipatterns_config = {
187
+ --- highlighters = {
188
+ --- emmylua = { pattern = '^%s*%-%-%-()@%w+()', group = 'Special' }
189
+ --- }
190
+ --- }
191
+ --- <
192
+ --- - Use callable `pattern` with condition. For example: >lua
193
+ ---
194
+ --- require('mini.hipatterns').setup({
195
+ --- highlighters = {
196
+ --- emmylua = {
197
+ --- pattern = function(buf_id)
198
+ --- if vim.bo[buf_id].filetype ~= 'lua' then return nil end
199
+ --- return '^%s*%-%-%-()@%w+()'
200
+ --- end,
201
+ --- group = 'Special',
202
+ --- },
203
+ --- },
204
+ --- })
205
+ --- <
206
+ --- - Disable only in certain filetypes. Enable with |MiniHipatterns.setup()|
207
+ --- and set `vim.b.minihipatterns_disable` buffer-local variable to `true` for
208
+ --- buffer you want disabled. See |mini.nvim-disabling-recipes| for more examples.
209
+ ---@tag MiniHipatterns-examples
210
+
211
+ ---@alias __hipatterns_buf_id number|nil Buffer identifier in which to enable highlighting.
212
+ --- Default: 0 for current buffer.
213
+
214
+ ---@diagnostic disable:undefined-field
215
+ ---@diagnostic disable:discard-returns
216
+ ---@diagnostic disable:unused-local
217
+
218
+ -- Module definition ==========================================================
219
+ local MiniHipatterns = {}
220
+ local H = {}
221
+
222
+ --- Module setup
223
+ ---
224
+ ---@param config table|nil Module config table. See |MiniHipatterns.config|.
225
+ ---
226
+ ---@usage >lua
227
+ --- require('mini.hipatterns').setup({}) -- replace {} with your config table
228
+ --- -- needs `highlighters` field present
229
+ --- <
230
+ MiniHipatterns.setup = function(config)
231
+ -- TODO: Remove after Neovim=0.9 support is dropped
232
+ if vim.fn.has('nvim-0.10') == 0 then
233
+ vim.notify(
234
+ '(mini.hipatterns) Neovim<0.10 is soft deprecated (module works but is not supported).'
235
+ .. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
236
+ .. ' Please update your Neovim version.'
237
+ )
238
+ end
239
+
240
+ -- Export module
241
+ _G.MiniHipatterns = MiniHipatterns
242
+
243
+ -- Setup config
244
+ config = H.setup_config(config)
245
+
246
+ -- Apply config
247
+ H.apply_config(config)
248
+
249
+ -- Define behavior
250
+ H.create_autocommands()
251
+ for _, win_id in ipairs(vim.api.nvim_list_wins()) do
252
+ H.auto_enable({ buf = vim.api.nvim_win_get_buf(win_id) })
253
+ end
254
+
255
+ -- Create default highlighting
256
+ H.create_default_hl()
257
+ end
258
+
259
+ --- Defaults ~
260
+ ---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
261
+ ---@text # Highlighters ~
262
+ ---
263
+ --- `highlighters` table defines which patterns will be highlighted by placing
264
+ --- |extmark| at the match start. It might or might not have explicitly named
265
+ --- fields, but having them is recommended and is required for proper use of
266
+ --- `vim.b.minihipatterns_config` as buffer-local config. By default it is
267
+ --- empty expecting user definition.
268
+ ---
269
+ --- Each entry defines single highlighter as a table with the following fields:
270
+ --- - <pattern> `(string|function|table)` - Lua pattern to highlight. Can be
271
+ --- either string, callable returning the string, or an array of those.
272
+ --- If string:
273
+ --- - It can have submatch delimited by placing `()` on start and end, NOT
274
+ --- by surrounding it with parenthesis (results in an error containing
275
+ --- `number expected, got string`). Example: `xx()abcd()xx` will match
276
+ --- `abcd` only if `xx` is placed before and after it.
277
+ ---
278
+ --- If callable:
279
+ --- - It will be called for every enabled buffer with its identifier as input.
280
+ --- Should return single string pattern or `nil` (meaning this particular
281
+ --- highlighter will not work in this particular buffer).
282
+ ---
283
+ --- If array:
284
+ --- - Each element is matched and highlighted with the same highlight group.
285
+ ---
286
+ --- Note: matching does not result in overlapping (sub)matches (similarly
287
+ --- to how |cpo-c| works). For example, with line `xxxxxxx`:
288
+ --- - Pattern `xxx` matches columns 1-3, 4-6.
289
+ --- - Pattern `()xx()x` matches columns 1-2, 3-4, 5-6.
290
+ --- - Pattern `x()xx()` matches columns 2-3, 5-6.
291
+ --- - Pattern `x()x()x` matches columns 2-2, 4-4, 6-6.
292
+ ---
293
+ --- - <group> `(string|function)` - name of highlight group to use. Can be either
294
+ --- string or callable returning the string.
295
+ --- If callable:
296
+ --- - It will be called for every pattern match with the following arguments:
297
+ --- - `buf_id` - buffer identifier.
298
+ --- - `match` - string pattern match to be highlighted.
299
+ --- - `data` - extra table with information about the match.
300
+ --- It has at least these fields:
301
+ --- - <full_match> - string with full pattern match.
302
+ --- - <line> - match line number (1-indexed).
303
+ --- - <from_col> - match starting byte column (1-indexed).
304
+ --- - <to_col> - match ending byte column (1-indexed, inclusive).
305
+ ---
306
+ --- - It can return `nil` meaning this particular match will not be highlighted.
307
+ ---
308
+ --- - <extmark_opts> `(table|function|nil)` - optional extra options
309
+ --- for |nvim_buf_set_extmark()|. If callable, will be called in the same way
310
+ --- as callable <group> (`data` will also contain `hl_group` key with <group>
311
+ --- value) and should return a table with all options for extmark (including
312
+ --- `end_row`, `end_col`, `hl_group`, and `priority`).
313
+ ---
314
+ --- See "Common use cases" section for the examples.
315
+ ---
316
+ --- # Delay ~
317
+ ---
318
+ --- `delay` is a table defining delays in milliseconds used for asynchronous
319
+ --- highlighting process.
320
+ ---
321
+ --- `delay.text_change` is used to delay highlighting updates by accumulating
322
+ --- them (in debounce fashion). Smaller values will lead to faster response but
323
+ --- more frequent updates. Bigger - slower response but less frequent updates.
324
+ ---
325
+ --- `delay.scroll` is used to delay updating highlights in current window view
326
+ --- during scrolling (see |WinScrolled| event). These updates are present to
327
+ --- ensure up to date highlighting after scroll.
328
+ MiniHipatterns.config = {
329
+ -- Table with highlighters (see |MiniHipatterns.config| for more details).
330
+ -- Nothing is defined by default. Add manually for visible effect.
331
+ highlighters = {},
332
+
333
+ -- Delays (in ms) defining asynchronous highlighting process
334
+ delay = {
335
+ -- How much to wait for update after every text change
336
+ text_change = 200,
337
+
338
+ -- How much to wait for update after window scroll
339
+ scroll = 50,
340
+ },
341
+ }
342
+ --minidoc_afterlines_end
343
+
344
+ --- Enable highlighting in buffer
345
+ ---
346
+ --- Notes:
347
+ --- - With default config it will highlight nothing, as there are no default
348
+ --- highlighters.
349
+ ---
350
+ --- - Buffer highlighting is enabled until buffer is unloaded from memory
351
+ --- or |MiniHipatterns.disable()| on this buffer is called.
352
+ ---
353
+ --- - `:edit` disables this, as it is mostly equivalent to closing and opening
354
+ --- buffer. In order for highlighting to persist after `:edit`, call
355
+ --- |MiniHipatterns.setup()|.
356
+ ---
357
+ ---@param buf_id __hipatterns_buf_id
358
+ ---@param config table|nil Optional buffer-local config. Should have the same
359
+ --- structure as |MiniHipatterns.config|. Values will be taken in this order:
360
+ --- - From this `config` argument (if supplied).
361
+ --- - From buffer-local config in `vim.b.minihipatterns_config` (if present).
362
+ --- - From global config (if |MiniHipatterns.setup()| was called).
363
+ --- - From default values.
364
+ MiniHipatterns.enable = function(buf_id, config)
365
+ buf_id = H.validate_buf_id(buf_id)
366
+ config = H.validate_config_arg(config)
367
+
368
+ -- Don't enable more than once
369
+ if H.is_buf_enabled(buf_id) then return end
370
+
371
+ -- Register enabled buffer with cached data for performance
372
+ H.update_cache(buf_id, config)
373
+
374
+ -- Add buffer watchers
375
+ vim.api.nvim_buf_attach(buf_id, false, {
376
+ -- Called on every text change (`:h nvim_buf_lines_event`)
377
+ on_lines = function(_, _, _, from_line, _, to_line)
378
+ local buf_cache = H.cache[buf_id]
379
+ -- Properly detach if highlighting is disabled
380
+ if buf_cache == nil then return true end
381
+ H.process_lines(buf_id, from_line + 1, to_line, buf_cache.delay.text_change)
382
+ end,
383
+
384
+ -- Called when buffer content is changed outside of current session
385
+ on_reload = function() pcall(MiniHipatterns.update, buf_id) end,
386
+
387
+ -- Called when buffer is unloaded from memory (`:h nvim_buf_detach_event`),
388
+ -- **including** `:edit` command
389
+ on_detach = function() MiniHipatterns.disable(buf_id) end,
390
+ })
391
+
392
+ -- Add buffer autocommands
393
+ local augroup = vim.api.nvim_create_augroup('MiniHipatternsBuffer' .. buf_id, { clear = true })
394
+ H.cache[buf_id].augroup = augroup
395
+
396
+ local update_buf = vim.schedule_wrap(function()
397
+ if not H.is_buf_enabled(buf_id) then return end
398
+
399
+ H.update_cache(buf_id, config)
400
+
401
+ local delay_ms = H.cache[buf_id].delay.text_change
402
+ H.process_lines(buf_id, 1, vim.api.nvim_buf_line_count(buf_id), delay_ms)
403
+ end)
404
+
405
+ vim.api.nvim_create_autocmd(
406
+ { 'BufWinEnter', 'FileType' },
407
+ { group = augroup, buffer = buf_id, callback = update_buf, desc = 'Update highlighting for whole buffer' }
408
+ )
409
+
410
+ vim.api.nvim_create_autocmd(
411
+ 'WinScrolled',
412
+ { group = augroup, buffer = buf_id, callback = H.update_view, desc = 'Update highlighting in view' }
413
+ )
414
+
415
+ -- Add highlighting to whole buffer
416
+ H.process_lines(buf_id, 1, vim.api.nvim_buf_line_count(buf_id), 0)
417
+ end
418
+
419
+ --- Disable highlighting in buffer
420
+ ---
421
+ --- Note that if |MiniHipatterns.setup()| was called, the effect is present
422
+ --- until the next auto-enabling event. To permanently disable highlighting in
423
+ --- buffer, set `vim.b.minihipatterns_disable` to `true`
424
+ ---
425
+ ---@param buf_id __hipatterns_buf_id
426
+ MiniHipatterns.disable = function(buf_id)
427
+ buf_id = H.validate_buf_id(buf_id)
428
+
429
+ local buf_cache = H.cache[buf_id]
430
+ if buf_cache == nil then return end
431
+ H.cache[buf_id] = nil
432
+
433
+ vim.api.nvim_del_augroup_by_id(buf_cache.augroup)
434
+ for _, ns in pairs(H.ns_id) do
435
+ H.clear_namespace(buf_id, ns, 0, -1)
436
+ end
437
+ end
438
+
439
+ --- Toggle highlighting in buffer
440
+ ---
441
+ --- Call |MiniHipatterns.disable()| if enabled; |MiniHipatterns.enable()| otherwise.
442
+ ---
443
+ ---@param buf_id __hipatterns_buf_id
444
+ ---@param config table|nil Forwarded to |MiniHipatterns.enable()|.
445
+ MiniHipatterns.toggle = function(buf_id, config)
446
+ buf_id = H.validate_buf_id(buf_id)
447
+ config = H.validate_config_arg(config)
448
+
449
+ if H.is_buf_enabled(buf_id) then
450
+ MiniHipatterns.disable(buf_id)
451
+ else
452
+ MiniHipatterns.enable(buf_id, config)
453
+ end
454
+ end
455
+
456
+ --- Update highlighting in range
457
+ ---
458
+ --- Works only in buffer with enabled highlighting. Effect takes immediately
459
+ --- without delay.
460
+ ---
461
+ ---@param buf_id __hipatterns_buf_id
462
+ ---@param from_line number|nil Start line from which to update (1-indexed).
463
+ ---@param to_line number|nil End line from which to update (1-indexed, inclusive).
464
+ MiniHipatterns.update = function(buf_id, from_line, to_line)
465
+ buf_id = H.validate_buf_id(buf_id)
466
+
467
+ if not H.is_buf_enabled(buf_id) then H.error(string.format('Buffer %d is not enabled.', buf_id)) end
468
+
469
+ from_line = from_line or 1
470
+ if type(from_line) ~= 'number' then H.error('`from_line` should be a number.') end
471
+ to_line = to_line or vim.api.nvim_buf_line_count(buf_id)
472
+ if type(to_line) ~= 'number' then H.error('`to_line` should be a number.') end
473
+
474
+ -- Process lines immediately without delay
475
+ H.process_lines(buf_id, from_line, to_line, 0)
476
+ end
477
+
478
+ --- Get an array of enabled buffers
479
+ ---
480
+ ---@return table Array of buffer identifiers with enabled highlighting.
481
+ MiniHipatterns.get_enabled_buffers = function()
482
+ local res = {}
483
+ for buf_id, _ in pairs(H.cache) do
484
+ if vim.api.nvim_buf_is_valid(buf_id) then
485
+ table.insert(res, buf_id)
486
+ else
487
+ -- Clean up if buffer is invalid and for some reason is still enabled
488
+ H.cache[buf_id] = nil
489
+ end
490
+ end
491
+
492
+ -- Ensure consistent order
493
+ table.sort(res)
494
+
495
+ return res
496
+ end
497
+
498
+ --- Get buffer matches
499
+ ---
500
+ ---@param buf_id number|nil Buffer identifier for which to return matches.
501
+ --- Default: `nil` for current buffer.
502
+ ---@param highlighters table|nil Array of highlighter identifiers (as in
503
+ --- `highlighters` field of |MiniHipatterns.config|) for which to return matches.
504
+ --- Default: all available highlighters (ordered by string representation).
505
+ ---
506
+ ---@return table Array of buffer matches which are tables with following fields:
507
+ --- - <bufnr> `(number)` - buffer identifier of a match.
508
+ --- - <highlighter> `(any)` - highlighter identifier which produced the match.
509
+ --- - <lnum> `(number)` - line number of the match start (starts with 1).
510
+ --- - <col> `(number)` - column number of the match start (starts with 1).
511
+ --- - <end_lnum> `(number|nil)` - line number of the match end (starts with 1).
512
+ --- - <end_col> `(number|nil)` - column number next to the match end
513
+ --- (implements end-exclusive region; starts with 1).
514
+ --- - <hl_group> `(string|nil)` - name of match's highlight group.
515
+ ---
516
+ --- Matches are ordered first by supplied `highlighters`, then by line and
517
+ --- column of match start.
518
+ MiniHipatterns.get_matches = function(buf_id, highlighters)
519
+ buf_id = (buf_id == nil or buf_id == 0) and vim.api.nvim_get_current_buf() or buf_id
520
+ if not (type(buf_id) == 'number' and vim.api.nvim_buf_is_valid(buf_id)) then
521
+ H.error('`buf_id` is not valid buffer identifier.')
522
+ end
523
+
524
+ local all_highlighters = H.get_all_highlighters()
525
+ highlighters = highlighters or all_highlighters
526
+ if not H.islist(highlighters) then H.error('`highlighters` should be an array.') end
527
+ highlighters = vim.tbl_filter(function(x) return vim.tbl_contains(all_highlighters, x) end, highlighters)
528
+
529
+ local position_compare = function(a, b) return a[2] < b[2] or (a[2] == b[2] and a[3] < b[3]) end
530
+ local res = {}
531
+ for _, hi_id in ipairs(highlighters) do
532
+ local extmarks = H.get_extmarks(buf_id, H.ns_id[hi_id], 0, -1, { details = true })
533
+ table.sort(extmarks, position_compare)
534
+
535
+ for _, extmark in ipairs(extmarks) do
536
+ local end_lnum, end_col = extmark[4].end_row, extmark[4].end_col
537
+ end_lnum = type(end_lnum) == 'number' and (end_lnum + 1) or end_lnum
538
+ end_col = type(end_col) == 'number' and (end_col + 1) or end_col
539
+ --stylua: ignore
540
+ local entry = {
541
+ bufnr = buf_id, highlighter = hi_id,
542
+ lnum = extmark[2] + 1, col = extmark[3] + 1,
543
+ end_lnum = end_lnum, end_col = end_col,
544
+ hl_group = extmark[4].hl_group,
545
+ }
546
+ table.insert(res, entry)
547
+ end
548
+ end
549
+ return res
550
+ end
551
+
552
+ --- Generate builtin highlighters
553
+ ---
554
+ --- This is a table with function elements. Call to actually get highlighter.
555
+ MiniHipatterns.gen_highlighter = {}
556
+
557
+ --- Highlight hex color string
558
+ ---
559
+ --- This will match color hex string in format `#rrggbb` and highlight it
560
+ --- according to `opts.style` displaying matched color.
561
+ ---
562
+ --- Highlight group is computed using |MiniHipatterns.compute_hex_color_group()|,
563
+ --- so all its usage notes apply here.
564
+ ---
565
+ ---@param opts table|nil Options. Possible fields:
566
+ --- - <style> `(string)` - one of:
567
+ --- - `'full'` - highlight background of whole hex string with it. Default.
568
+ --- - `'#'` - highlight background of only `#`.
569
+ --- - `'line'` - highlight underline with that color.
570
+ --- - `'inline'` - highlight text of <inline_text>.
571
+ --- Note: requires Neovim>=0.10.
572
+ --- - <priority> `(number)` - priority of highlighting. Default: 200.
573
+ --- - <filter> `(function)` - callable object used to filter buffers in which
574
+ --- highlighting will take place. It should take buffer identifier as input
575
+ --- and return `false` or `nil` to not highlight inside this buffer.
576
+ --- - <inline_text> `(string)` - string to be placed and highlighted with color
577
+ --- to the right of match in case <style> is "inline". Default: "█".
578
+ --- - <max_number> `(number)` - as in |MiniHipatterns.compute_hex_color_group()|.
579
+ ---
580
+ ---@return table Highlighter table ready to be used as part of `config.highlighters`.
581
+ --- Both `pattern` and `group` are callable.
582
+ ---
583
+ ---@usage >lua
584
+ --- local hipatterns = require('mini.hipatterns')
585
+ --- hipatterns.setup({
586
+ --- highlighters = {
587
+ --- hex_color = hipatterns.gen_highlighter.hex_color(),
588
+ --- }
589
+ --- })
590
+ --- <
591
+ MiniHipatterns.gen_highlighter.hex_color = function(opts)
592
+ local default_opts = { style = 'full', priority = 200, filter = H.always_true, inline_text = '█', max_number = nil }
593
+ opts = vim.tbl_deep_extend('force', default_opts, opts or {})
594
+
595
+ local style = opts.style
596
+ if style == 'inline' and vim.fn.has('nvim-0.10') == 0 then
597
+ H.error('Style "inline" in `gen_highlighter.hex_color()` requires Neovim>=0.10.')
598
+ end
599
+
600
+ local pattern = style == '#' and '()#()%x%x%x%x%x%x%f[%X]' or '#%x%x%x%x%x%x%f[%X]'
601
+ local hl_style = ({ full = 'bg', ['#'] = 'bg', line = 'line', inline = 'fg' })[style] or 'bg'
602
+
603
+ local extmark_opts = { priority = opts.priority }
604
+ if opts.style == 'inline' then
605
+ local priority, inline_text = opts.priority, opts.inline_text
606
+ ---@diagnostic disable:cast-local-type
607
+ extmark_opts = function(_, _, data)
608
+ local virt_text = { { inline_text, data.hl_group } }
609
+ return { virt_text = virt_text, virt_text_pos = 'inline', priority = priority, right_gravity = false }
610
+ end
611
+ end
612
+
613
+ local hex_opts = { max_number = opts.max_number }
614
+ return {
615
+ pattern = H.wrap_pattern_with_filter(pattern, opts.filter),
616
+ group = function(_, _, data) return MiniHipatterns.compute_hex_color_group(data.full_match, hl_style, hex_opts) end,
617
+ extmark_opts = extmark_opts,
618
+ }
619
+ end
620
+
621
+ --- Compute and create group to highlight hex color string
622
+ ---
623
+ --- Notes:
624
+ --- - This works properly only with enabled |'termguicolors'|.
625
+ ---
626
+ --- - To increase performance, it caches highlight groups per `hex_color` and
627
+ --- `style` combination. Needs a call to |MiniHipatterns.setup()| to have
628
+ --- these groups be persistent across color scheme changes.
629
+ ---
630
+ ---@param hex_color string Hex color string in format `#rrggbb`.
631
+ ---@param style|nil string One of:
632
+ --- - `'bg'` - highlight background with `hex_color` and foreground with black or
633
+ --- white (whichever is more visible). Default.
634
+ --- - `'fg'` - highlight foreground with `hex_color`.
635
+ --- - `'line'` - highlight underline with `hex_color`.
636
+ ---@param opts table|nil Options. Possible fields:
637
+ --- - <max_number> `(number)` - maximum number of different highlight groups
638
+ --- this function is allowed to create. Useful to avoid |E849|.
639
+ --- Default: 10000.
640
+ ---
641
+ ---@return string|nil Name of created highlight group appropriate to show `hex_color`
642
+ --- or `nil` if highlighted groups was not created.
643
+ MiniHipatterns.compute_hex_color_group = function(hex_color, style, opts)
644
+ style = style or 'bg'
645
+ local hex = hex_color:lower():sub(2)
646
+ local group_name = string.format('MiniHipatterns_%s_%s', hex, style)
647
+
648
+ -- Use manually tracked table instead of `vim.fn.hlexists()` because the
649
+ -- latter still returns true for cleared highlights
650
+ if H.hex_color_groups[group_name] then return group_name end
651
+
652
+ -- Limit
653
+ opts = vim.tbl_extend('force', { max_number = 10000 }, opts or {})
654
+ if H.n_hex_color_groups >= opts.max_number then return nil end
655
+
656
+ -- Define highlight group if it is not already defined
657
+ local hl_opts
658
+ -- - Compute opposite color based on Oklab lightness (for better contrast)
659
+ if style == 'bg' then hl_opts = { fg = H.compute_opposite_color(hex), bg = hex_color } end
660
+ if style == 'fg' then hl_opts = { fg = hex_color } end
661
+ if style == 'line' then hl_opts = { sp = hex_color, underline = true } end
662
+
663
+ local ok = pcall(vim.api.nvim_set_hl, 0, group_name, hl_opts)
664
+
665
+ -- Keep track of created groups to properly react on `:hi clear`
666
+ H.hex_color_groups[group_name] = ok
667
+ H.n_hex_color_groups = H.n_hex_color_groups + (ok and 1 or 0)
668
+
669
+ return ok and group_name or nil
670
+ end
671
+
672
+ -- Helper data ================================================================
673
+ -- Module default config
674
+ H.default_config = vim.deepcopy(MiniHipatterns.config)
675
+
676
+ -- Timers
677
+ H.timer_debounce = vim.loop.new_timer()
678
+ H.timer_view = vim.loop.new_timer()
679
+
680
+ -- Namespaces per highlighter name
681
+ H.ns_id = {}
682
+
683
+ -- Cache of queued changes used for debounced highlighting
684
+ H.change_queue = {}
685
+
686
+ -- Cache per enabled buffer
687
+ H.cache = {}
688
+
689
+ -- Data about created highlight groups for hex colors
690
+ H.hex_color_groups = {}
691
+ H.n_hex_color_groups = 0
692
+
693
+ -- Helper functionality =======================================================
694
+ -- Settings -------------------------------------------------------------------
695
+ H.setup_config = function(config)
696
+ H.check_type('config', config, 'table', true)
697
+ config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})
698
+
699
+ H.check_type('highlighters', config.highlighters, 'table')
700
+
701
+ H.check_type('delay', config.delay, 'table')
702
+ H.check_type('delay.text_change', config.delay.text_change, 'number')
703
+ H.check_type('delay.scroll', config.delay.scroll, 'number')
704
+
705
+ return config
706
+ end
707
+
708
+ H.apply_config = function(config) MiniHipatterns.config = config end
709
+
710
+ H.create_autocommands = function()
711
+ local gr = vim.api.nvim_create_augroup('MiniHipatterns', {})
712
+
713
+ local au = function(event, pattern, callback, desc)
714
+ vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })
715
+ end
716
+
717
+ au('BufEnter', '*', H.auto_enable, 'Enable highlighting')
718
+ au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')
719
+ au('ColorScheme', '*', H.on_colorscheme, 'Reload all enabled pattern highlighters')
720
+ end
721
+
722
+ H.create_default_hl = function()
723
+ local hi_link_bold_reverse = function(to, from)
724
+ local data = vim.api.nvim_get_hl(0, { name = from, link = false })
725
+ data.default, data.bold, data.reverse = true, true, true
726
+ data.cterm = { bold = true, reverse = true }
727
+ vim.api.nvim_set_hl(0, to, data)
728
+ end
729
+ hi_link_bold_reverse('MiniHipatternsFixme', 'DiagnosticError')
730
+ hi_link_bold_reverse('MiniHipatternsHack', 'DiagnosticWarn')
731
+ hi_link_bold_reverse('MiniHipatternsTodo', 'DiagnosticInfo')
732
+ hi_link_bold_reverse('MiniHipatternsNote', 'DiagnosticHint')
733
+ end
734
+
735
+ H.is_disabled = function(buf_id)
736
+ local buf_disable = H.get_buf_var(buf_id, 'minihipatterns_disable')
737
+ return vim.g.minihipatterns_disable == true or buf_disable == true
738
+ end
739
+
740
+ H.get_config = function(config, buf_id)
741
+ local buf_config = H.get_buf_var(buf_id, 'minihipatterns_config') or {}
742
+ return vim.tbl_deep_extend('force', MiniHipatterns.config, buf_config, config or {})
743
+ end
744
+
745
+ H.get_buf_var = function(buf_id, name)
746
+ if not vim.api.nvim_buf_is_valid(buf_id) then return nil end
747
+ return vim.b[buf_id or 0][name]
748
+ end
749
+
750
+ -- Autocommands ---------------------------------------------------------------
751
+ H.auto_enable = vim.schedule_wrap(function(data)
752
+ local buf = data.buf
753
+ if not (vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].buftype == '') then return end
754
+ MiniHipatterns.enable(buf)
755
+ end)
756
+
757
+ H.update_view = vim.schedule_wrap(function(data)
758
+ -- Update view only in enabled buffers
759
+ local buf_cache = H.cache[data.buf]
760
+ if buf_cache == nil then return end
761
+
762
+ -- NOTE: due to scheduling (which is necessary for better performance),
763
+ -- current buffer can be not the target one. But as there is no proper (easy
764
+ -- and/or fast) way to get the view of certain buffer (except the current)
765
+ -- accept this approach. The main problem of current buffer having not
766
+ -- enabled highlighting is solved during processing buffer highlighters.
767
+
768
+ -- Debounce without aggregating redraws (only last view should be updated)
769
+ H.timer_view:stop()
770
+ H.timer_view:start(buf_cache.delay.scroll, 0, H.process_view)
771
+ end)
772
+
773
+ H.on_colorscheme = function()
774
+ -- Reset created highlight groups for hex colors, as they are probably
775
+ -- cleared after `:hi clear`
776
+ H.hex_color_groups = {}
777
+ H.n_hex_color_groups = 0
778
+
779
+ -- Reload all currently enabled buffers
780
+ for buf_id, _ in pairs(H.cache) do
781
+ MiniHipatterns.disable(buf_id)
782
+ MiniHipatterns.enable(buf_id)
783
+ end
784
+ end
785
+
786
+ -- Validators -----------------------------------------------------------------
787
+ H.validate_buf_id = function(x)
788
+ if x == nil or x == 0 then return vim.api.nvim_get_current_buf() end
789
+
790
+ if not (type(x) == 'number' and vim.api.nvim_buf_is_valid(x)) then
791
+ H.error('`buf_id` should be `nil` or valid buffer id.')
792
+ end
793
+
794
+ return x
795
+ end
796
+
797
+ H.validate_config_arg = function(x)
798
+ if x == nil or type(x) == 'table' then return x or {} end
799
+ H.error('`config` should be `nil` or table.')
800
+ end
801
+
802
+ H.validate_string = function(x, name)
803
+ if type(x) == 'string' then return x end
804
+ H.error(string.format('`%s` should be string.'))
805
+ end
806
+
807
+ -- Enabling -------------------------------------------------------------------
808
+ H.is_buf_enabled = function(buf_id) return H.cache[buf_id] ~= nil end
809
+
810
+ H.update_cache = function(buf_id, config)
811
+ local buf_cache = H.cache[buf_id] or {}
812
+ local buf_config = H.get_config(config, buf_id)
813
+ buf_cache.highlighters = H.normalize_highlighters(buf_config.highlighters)
814
+ buf_cache.delay = buf_config.delay
815
+
816
+ H.cache[buf_id] = buf_cache
817
+ end
818
+
819
+ H.normalize_highlighters = function(highlighters)
820
+ local res = {}
821
+ for hi_name, hi in pairs(highlighters) do
822
+ -- Allow pattern to be string, callable, or array of those. Convert all
823
+ -- valid cases into array of callables.
824
+ local pattern = type(hi.pattern) == 'string' and function() return hi.pattern end or hi.pattern
825
+ if vim.is_callable(pattern) then pattern = { pattern } end
826
+ local is_pattern_ok = H.islist(pattern)
827
+ if is_pattern_ok then
828
+ for i, pat in ipairs(pattern) do
829
+ pattern[i] = type(pat) == 'string' and function() return pat end or pat
830
+ is_pattern_ok = is_pattern_ok and vim.is_callable(pattern[i])
831
+ end
832
+ end
833
+
834
+ local group = type(hi.group) == 'string' and function() return hi.group end or hi.group
835
+
836
+ local extmark_opts = hi.extmark_opts or { priority = 200 }
837
+ if type(extmark_opts) == 'table' then
838
+ local t = extmark_opts
839
+ ---@diagnostic disable:cast-local-type
840
+ extmark_opts = function(_, _, data)
841
+ local opts = vim.deepcopy(t)
842
+ opts.hl_group = opts.hl_group or data.hl_group
843
+ opts.end_row = opts.end_row or (data.line - 1)
844
+ opts.end_col = opts.end_col or data.to_col
845
+ return opts
846
+ end
847
+ end
848
+
849
+ if is_pattern_ok and vim.is_callable(group) and vim.is_callable(extmark_opts) then
850
+ res[hi_name] = { pattern = pattern, group = group, extmark_opts = extmark_opts }
851
+ H.ns_id[hi_name] = vim.api.nvim_create_namespace('MiniHipatterns-' .. hi_name)
852
+ end
853
+ end
854
+
855
+ return res
856
+ end
857
+
858
+ H.get_all_highlighters = function()
859
+ local hi_arr = vim.tbl_map(function(x) return { x, tostring(x) } end, vim.tbl_keys(H.ns_id))
860
+ table.sort(hi_arr, function(a, b) return a[2] < b[2] end)
861
+ return vim.tbl_map(function(x) return x[1] end, hi_arr)
862
+ end
863
+
864
+ -- Processing -----------------------------------------------------------------
865
+ H.process_lines = vim.schedule_wrap(function(buf_id, from_line, to_line, delay_ms)
866
+ -- Make sure that that at least one line is processed (important to react
867
+ -- after deleting line with extmark non-trivial `extmark_opts`)
868
+ table.insert(H.change_queue, { buf_id, math.min(from_line, to_line), math.max(from_line, to_line) })
869
+
870
+ -- Debounce
871
+ H.timer_debounce:stop()
872
+ H.timer_debounce:start(delay_ms, 0, H.process_change_queue)
873
+ end)
874
+
875
+ H.process_view = vim.schedule_wrap(function()
876
+ table.insert(H.change_queue, { vim.api.nvim_get_current_buf(), vim.fn.line('w0'), vim.fn.line('w$') })
877
+
878
+ -- Process immediately assuming debouncing should be already done
879
+ H.process_change_queue()
880
+ end)
881
+
882
+ H.process_change_queue = vim.schedule_wrap(function()
883
+ local queue = H.normalize_change_queue()
884
+
885
+ for buf_id, lines_to_process in pairs(queue) do
886
+ H.process_buffer_changes(buf_id, lines_to_process)
887
+ end
888
+
889
+ H.change_queue = {}
890
+ end)
891
+
892
+ H.normalize_change_queue = function()
893
+ local res = {}
894
+ for _, change in ipairs(H.change_queue) do
895
+ -- `change` is { buf_id, from_line, to_line }; lines are already 1-indexed
896
+ local buf_id = change[1]
897
+
898
+ local buf_lines_to_process = res[buf_id] or {}
899
+ for i = change[2], change[3] do
900
+ buf_lines_to_process[i] = true
901
+ end
902
+
903
+ res[buf_id] = buf_lines_to_process
904
+ end
905
+
906
+ return res
907
+ end
908
+
909
+ H.process_buffer_changes = vim.schedule_wrap(function(buf_id, lines_to_process)
910
+ -- Return early if buffer is not proper.
911
+ -- Also check if buffer is enabled here mostly for better resilience. It
912
+ -- might be actually needed due to various `schedule_wrap`s leading to change
913
+ -- queue entry with not target (and improper) buffer.
914
+ local buf_cache = H.cache[buf_id]
915
+ if not vim.api.nvim_buf_is_valid(buf_id) or H.is_disabled(buf_id) or buf_cache == nil then return end
916
+
917
+ -- Optimizations are done assuming small-ish number of highlighters and
918
+ -- large-ish number of lines to process
919
+
920
+ -- Process highlighters
921
+ for hi_name, hi in pairs(buf_cache.highlighters) do
922
+ -- Remove current highlights
923
+ local ns = H.ns_id[hi_name]
924
+ for l_num, _ in pairs(lines_to_process) do
925
+ H.clear_namespace(buf_id, ns, l_num - 1, l_num)
926
+ end
927
+
928
+ -- Add new highlights
929
+ for _, pattern in ipairs(hi.pattern) do
930
+ H.apply_highlighter_pattern(pattern(buf_id), hi, buf_id, ns, lines_to_process)
931
+ end
932
+ end
933
+ end)
934
+
935
+ H.apply_highlighter_pattern = vim.schedule_wrap(function(pattern, hi, buf_id, ns, lines_to_process)
936
+ -- Check again because buffer might have become invalid since latest check
937
+ if not vim.api.nvim_buf_is_valid(buf_id) then return end
938
+
939
+ if type(pattern) ~= 'string' then return end
940
+ local group, extmark_opts = hi.group, hi.extmark_opts
941
+ local pattern_has_line_start = pattern:sub(1, 1) == '^'
942
+
943
+ -- Apply per proper line
944
+ for l_num, _ in pairs(lines_to_process) do
945
+ local line = H.get_line(buf_id, l_num)
946
+ local from, to, sub_from, sub_to = line:find(pattern)
947
+
948
+ while from and (from <= to) do
949
+ -- Compute full pattern match
950
+ local full_match = line:sub(from, to)
951
+
952
+ -- Compute (possibly inferred) submatch
953
+ sub_from, sub_to = sub_from or from, sub_to or (to + 1)
954
+ -- - Make last column end-inclusive
955
+ sub_to = sub_to - 1
956
+ local match = line:sub(sub_from, sub_to)
957
+
958
+ -- Set extmark based on submatch
959
+ local data = { full_match = full_match, line = l_num, from_col = sub_from, to_col = sub_to }
960
+ local hl_group = group(buf_id, match, data)
961
+ if hl_group ~= nil then
962
+ data.hl_group = hl_group
963
+ H.set_extmark(buf_id, ns, l_num - 1, sub_from - 1, extmark_opts(buf_id, match, data))
964
+ end
965
+
966
+ -- Overcome an issue that `string.find()` doesn't recognize `^` when
967
+ -- `init` is more than 1
968
+ if pattern_has_line_start then break end
969
+
970
+ from, to, sub_from, sub_to = line:find(pattern, sub_to + 1)
971
+ end
972
+ end
973
+ end)
974
+
975
+ -- Built-in highlighters ------------------------------------------------------
976
+ H.wrap_pattern_with_filter = function(pattern, filter)
977
+ return function(...)
978
+ if not filter(...) then return nil end
979
+ return pattern
980
+ end
981
+ end
982
+
983
+ H.compute_opposite_color = function(hex)
984
+ local dec = tonumber(hex, 16)
985
+ local b = H.correct_channel(math.fmod(dec, 256) / 255)
986
+ local g = H.correct_channel(math.fmod((dec - b) / 256, 256) / 255)
987
+ local r = H.correct_channel(math.floor(dec / 65536) / 255)
988
+
989
+ local l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b
990
+ local m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b
991
+ local s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b
992
+
993
+ local l_, m_, s_ = H.cuberoot(l), H.cuberoot(m), H.cuberoot(s)
994
+
995
+ local L = H.correct_lightness(0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_)
996
+
997
+ return L < 0.5 and '#ffffff' or '#000000'
998
+ end
999
+
1000
+ -- Function for RGB channel correction. Assumes input in [0; 1] range
1001
+ -- https://bottosson.github.io/posts/colorwrong/#what-can-we-do%3F
1002
+ H.correct_channel = function(x) return 0.04045 < x and math.pow((x + 0.055) / 1.055, 2.4) or (x / 12.92) end
1003
+
1004
+ -- Function for lightness correction
1005
+ -- https://bottosson.github.io/posts/colorpicker/#intermission---a-new-lightness-estimate-for-oklab
1006
+ H.correct_lightness = function(x)
1007
+ local k1, k2 = 0.206, 0.03
1008
+ local k3 = (1 + k1) / (1 + k2)
1009
+
1010
+ return 0.5 * (k3 * x - k1 + math.sqrt((k3 * x - k1) ^ 2 + 4 * k2 * k3 * x))
1011
+ end
1012
+
1013
+ -- Utilities ------------------------------------------------------------------
1014
+ H.error = function(msg) error('(mini.hipatterns) ' .. msg, 0) end
1015
+
1016
+ H.check_type = function(name, val, ref, allow_nil)
1017
+ if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
1018
+ H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
1019
+ end
1020
+
1021
+ H.get_line = function(buf_id, line_num)
1022
+ return vim.api.nvim_buf_get_lines(buf_id, line_num - 1, line_num, false)[1] or ''
1023
+ end
1024
+
1025
+ H.set_extmark = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end
1026
+
1027
+ H.get_extmarks = function(...)
1028
+ local ok, res = pcall(vim.api.nvim_buf_get_extmarks, ...)
1029
+ if not ok then return {} end
1030
+ return res
1031
+ end
1032
+
1033
+ H.clear_namespace = function(...) pcall(vim.api.nvim_buf_clear_namespace, ...) end
1034
+
1035
+ H.always_true = function() return true end
1036
+
1037
+ H.cuberoot = function(x) return math.pow(x, 0.333333) end
1038
+
1039
+ -- TODO: Remove after compatibility with Neovim=0.9 is dropped
1040
+ H.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist
1041
+
1042
+ return MiniHipatterns