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.
- package/.conda/retrovim.yaml +259 -0
- package/.conda/terax.icns +0 -0
- package/.conda/terax.ico +0 -0
- package/.conda/terax.png +0 -0
- package/.github/workflows/release.yml +95 -0
- package/.gitmodules +3 -0
- package/.npm/kanata_touchcursor.js +28 -0
- package/.npm/nvim.js +26 -0
- package/.npm/yazi.js +26 -0
- package/.npm/zsh.js +17 -0
- package/.pip/kanata_touchcursor/__init__.py +28 -0
- package/.pip/nvim/__init__.py +31 -0
- package/.pip/yazi/__init__.py +31 -0
- package/.pip/zsh/__init__.py +22 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +674 -0
- package/README.md +336 -0
- package/kanata/touchcursor.kbd +164 -0
- package/nvim/init.lua +813 -0
- package/nvim/plugins/mini.nvim/.github/DISCUSSION_TEMPLATE/q-a.yml +72 -0
- package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/bug-report.yml +136 -0
- package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/nvim/plugins/mini.nvim/.github/ISSUE_TEMPLATE/feature-request.yml +75 -0
- package/nvim/plugins/mini.nvim/.github/PULL_REQUEST_TEMPLATE.md +2 -0
- package/nvim/plugins/mini.nvim/.github/workflows/quality-control.yml +150 -0
- package/nvim/plugins/mini.nvim/.pre-commit-config.yaml +20 -0
- package/nvim/plugins/mini.nvim/.stylua.toml +7 -0
- package/nvim/plugins/mini.nvim/.styluaignore +1 -0
- package/nvim/plugins/mini.nvim/CHANGELOG.md +1894 -0
- package/nvim/plugins/mini.nvim/CODE_OF_CONDUCT.md +132 -0
- package/nvim/plugins/mini.nvim/CONTRIBUTING.md +331 -0
- package/nvim/plugins/mini.nvim/LICENSE +21 -0
- package/nvim/plugins/mini.nvim/MAINTAINING.md +330 -0
- package/nvim/plugins/mini.nvim/Makefile +51 -0
- package/nvim/plugins/mini.nvim/README.md +261 -0
- package/nvim/plugins/mini.nvim/TESTING.md +1011 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/README.md +35 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/benchmark.sh +56 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-alpha.lua +21 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-original.lua +17 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_dashboard-starter.lua +18 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_empty.lua +4 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_starter-default.lua +7 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-alpha.lua +10 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-original.lua +7 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/init-files/init_startify-starter.lua +20 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/install.sh +10 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/make_summary.py +68 -0
- package/nvim/plugins/mini.nvim/benchmarks/starter/startup-summary.md +10 -0
- package/nvim/plugins/mini.nvim/colors/miniautumn.lua +55 -0
- package/nvim/plugins/mini.nvim/colors/minicyan.lua +95 -0
- package/nvim/plugins/mini.nvim/colors/minischeme.lua +95 -0
- package/nvim/plugins/mini.nvim/colors/minispring.lua +53 -0
- package/nvim/plugins/mini.nvim/colors/minisummer.lua +49 -0
- package/nvim/plugins/mini.nvim/colors/miniwinter.lua +51 -0
- package/nvim/plugins/mini.nvim/colors/randomhue.lua +16 -0
- package/nvim/plugins/mini.nvim/doc/mini-ai.txt +889 -0
- package/nvim/plugins/mini.nvim/doc/mini-align.txt +923 -0
- package/nvim/plugins/mini.nvim/doc/mini-animate.txt +937 -0
- package/nvim/plugins/mini.nvim/doc/mini-base16.txt +285 -0
- package/nvim/plugins/mini.nvim/doc/mini-basics.txt +359 -0
- package/nvim/plugins/mini.nvim/doc/mini-bracketed.txt +622 -0
- package/nvim/plugins/mini.nvim/doc/mini-bufremove.txt +123 -0
- package/nvim/plugins/mini.nvim/doc/mini-clue.txt +760 -0
- package/nvim/plugins/mini.nvim/doc/mini-cmdline.txt +392 -0
- package/nvim/plugins/mini.nvim/doc/mini-colors.txt +880 -0
- package/nvim/plugins/mini.nvim/doc/mini-comment.txt +230 -0
- package/nvim/plugins/mini.nvim/doc/mini-completion.txt +477 -0
- package/nvim/plugins/mini.nvim/doc/mini-cursorword.txt +105 -0
- package/nvim/plugins/mini.nvim/doc/mini-deps.txt +590 -0
- package/nvim/plugins/mini.nvim/doc/mini-diff.txt +661 -0
- package/nvim/plugins/mini.nvim/doc/mini-doc.txt +434 -0
- package/nvim/plugins/mini.nvim/doc/mini-extra.txt +856 -0
- package/nvim/plugins/mini.nvim/doc/mini-files.txt +1018 -0
- package/nvim/plugins/mini.nvim/doc/mini-fuzzy.txt +160 -0
- package/nvim/plugins/mini.nvim/doc/mini-git.txt +425 -0
- package/nvim/plugins/mini.nvim/doc/mini-hipatterns.txt +489 -0
- package/nvim/plugins/mini.nvim/doc/mini-hues.txt +420 -0
- package/nvim/plugins/mini.nvim/doc/mini-icons.txt +508 -0
- package/nvim/plugins/mini.nvim/doc/mini-indentscope.txt +485 -0
- package/nvim/plugins/mini.nvim/doc/mini-input.txt +932 -0
- package/nvim/plugins/mini.nvim/doc/mini-jump.txt +202 -0
- package/nvim/plugins/mini.nvim/doc/mini-jump2d.txt +525 -0
- package/nvim/plugins/mini.nvim/doc/mini-keymap.txt +449 -0
- package/nvim/plugins/mini.nvim/doc/mini-map.txt +717 -0
- package/nvim/plugins/mini.nvim/doc/mini-misc.txt +431 -0
- package/nvim/plugins/mini.nvim/doc/mini-move.txt +181 -0
- package/nvim/plugins/mini.nvim/doc/mini-notify.txt +434 -0
- package/nvim/plugins/mini.nvim/doc/mini-nvim.txt +431 -0
- package/nvim/plugins/mini.nvim/doc/mini-operators.txt +472 -0
- package/nvim/plugins/mini.nvim/doc/mini-pairs.txt +346 -0
- package/nvim/plugins/mini.nvim/doc/mini-pick.txt +1535 -0
- package/nvim/plugins/mini.nvim/doc/mini-sessions.txt +239 -0
- package/nvim/plugins/mini.nvim/doc/mini-snippets.txt +1291 -0
- package/nvim/plugins/mini.nvim/doc/mini-splitjoin.txt +536 -0
- package/nvim/plugins/mini.nvim/doc/mini-starter.txt +618 -0
- package/nvim/plugins/mini.nvim/doc/mini-statusline.txt +361 -0
- package/nvim/plugins/mini.nvim/doc/mini-surround.txt +863 -0
- package/nvim/plugins/mini.nvim/doc/mini-tabline.txt +151 -0
- package/nvim/plugins/mini.nvim/doc/mini-test.txt +966 -0
- package/nvim/plugins/mini.nvim/doc/mini-trailspace.txt +91 -0
- package/nvim/plugins/mini.nvim/doc/mini-visits.txt +937 -0
- package/nvim/plugins/mini.nvim/logo.png +0 -0
- package/nvim/plugins/mini.nvim/lua/mini/ai.lua +2244 -0
- package/nvim/plugins/mini.nvim/lua/mini/align.lua +2076 -0
- package/nvim/plugins/mini.nvim/lua/mini/animate.lua +2127 -0
- package/nvim/plugins/mini.nvim/lua/mini/base16.lua +1752 -0
- package/nvim/plugins/mini.nvim/lua/mini/basics.lua +772 -0
- package/nvim/plugins/mini.nvim/lua/mini/bracketed.lua +2013 -0
- package/nvim/plugins/mini.nvim/lua/mini/bufremove.lua +283 -0
- package/nvim/plugins/mini.nvim/lua/mini/clue.lua +2096 -0
- package/nvim/plugins/mini.nvim/lua/mini/cmdline.lua +1182 -0
- package/nvim/plugins/mini.nvim/lua/mini/colors.lua +2483 -0
- package/nvim/plugins/mini.nvim/lua/mini/comment.lua +586 -0
- package/nvim/plugins/mini.nvim/lua/mini/completion.lua +2094 -0
- package/nvim/plugins/mini.nvim/lua/mini/cursorword.lua +311 -0
- package/nvim/plugins/mini.nvim/lua/mini/deps.lua +1660 -0
- package/nvim/plugins/mini.nvim/lua/mini/diff.lua +1938 -0
- package/nvim/plugins/mini.nvim/lua/mini/doc.lua +1371 -0
- package/nvim/plugins/mini.nvim/lua/mini/extra.lua +2290 -0
- package/nvim/plugins/mini.nvim/lua/mini/files.lua +3145 -0
- package/nvim/plugins/mini.nvim/lua/mini/fuzzy.lua +356 -0
- package/nvim/plugins/mini.nvim/lua/mini/git.lua +1737 -0
- package/nvim/plugins/mini.nvim/lua/mini/hipatterns.lua +1042 -0
- package/nvim/plugins/mini.nvim/lua/mini/hues.lua +2088 -0
- package/nvim/plugins/mini.nvim/lua/mini/icons.lua +2254 -0
- package/nvim/plugins/mini.nvim/lua/mini/indentscope.lua +1158 -0
- package/nvim/plugins/mini.nvim/lua/mini/init.lua +427 -0
- package/nvim/plugins/mini.nvim/lua/mini/input.lua +2183 -0
- package/nvim/plugins/mini.nvim/lua/mini/jump.lua +609 -0
- package/nvim/plugins/mini.nvim/lua/mini/jump2d.lua +1244 -0
- package/nvim/plugins/mini.nvim/lua/mini/keymap.lua +880 -0
- package/nvim/plugins/mini.nvim/lua/mini/map.lua +1709 -0
- package/nvim/plugins/mini.nvim/lua/mini/misc.lua +969 -0
- package/nvim/plugins/mini.nvim/lua/mini/move.lua +509 -0
- package/nvim/plugins/mini.nvim/lua/mini/notify.lua +938 -0
- package/nvim/plugins/mini.nvim/lua/mini/operators.lua +1349 -0
- package/nvim/plugins/mini.nvim/lua/mini/pairs.lua +657 -0
- package/nvim/plugins/mini.nvim/lua/mini/pick.lua +3876 -0
- package/nvim/plugins/mini.nvim/lua/mini/sessions.lua +689 -0
- package/nvim/plugins/mini.nvim/lua/mini/snippets.lua +2828 -0
- package/nvim/plugins/mini.nvim/lua/mini/splitjoin.lua +1132 -0
- package/nvim/plugins/mini.nvim/lua/mini/starter.lua +1599 -0
- package/nvim/plugins/mini.nvim/lua/mini/statusline.lua +686 -0
- package/nvim/plugins/mini.nvim/lua/mini/surround.lua +2388 -0
- package/nvim/plugins/mini.nvim/lua/mini/tabline.lua +564 -0
- package/nvim/plugins/mini.nvim/lua/mini/test.lua +2516 -0
- package/nvim/plugins/mini.nvim/lua/mini/trailspace.lua +215 -0
- package/nvim/plugins/mini.nvim/lua/mini/visits.lua +1577 -0
- package/nvim/plugins/mini.nvim/readmes/mini-ai.md +190 -0
- package/nvim/plugins/mini.nvim/readmes/mini-align.md +203 -0
- package/nvim/plugins/mini.nvim/readmes/mini-animate.md +214 -0
- package/nvim/plugins/mini.nvim/readmes/mini-base16.md +198 -0
- package/nvim/plugins/mini.nvim/readmes/mini-basics.md +184 -0
- package/nvim/plugins/mini.nvim/readmes/mini-bracketed.md +193 -0
- package/nvim/plugins/mini.nvim/readmes/mini-bufremove.md +139 -0
- package/nvim/plugins/mini.nvim/readmes/mini-clue.md +260 -0
- package/nvim/plugins/mini.nvim/readmes/mini-cmdline.md +183 -0
- package/nvim/plugins/mini.nvim/readmes/mini-colors.md +169 -0
- package/nvim/plugins/mini.nvim/readmes/mini-comment.md +183 -0
- package/nvim/plugins/mini.nvim/readmes/mini-completion.md +217 -0
- package/nvim/plugins/mini.nvim/readmes/mini-cursorword.md +137 -0
- package/nvim/plugins/mini.nvim/readmes/mini-deps.md +271 -0
- package/nvim/plugins/mini.nvim/readmes/mini-diff.md +289 -0
- package/nvim/plugins/mini.nvim/readmes/mini-doc.md +198 -0
- package/nvim/plugins/mini.nvim/readmes/mini-extra.md +158 -0
- package/nvim/plugins/mini.nvim/readmes/mini-files.md +247 -0
- package/nvim/plugins/mini.nvim/readmes/mini-fuzzy.md +134 -0
- package/nvim/plugins/mini.nvim/readmes/mini-git.md +168 -0
- package/nvim/plugins/mini.nvim/readmes/mini-hipatterns.md +176 -0
- package/nvim/plugins/mini.nvim/readmes/mini-hues.md +285 -0
- package/nvim/plugins/mini.nvim/readmes/mini-icons.md +183 -0
- package/nvim/plugins/mini.nvim/readmes/mini-indentscope.md +191 -0
- package/nvim/plugins/mini.nvim/readmes/mini-input.md +163 -0
- package/nvim/plugins/mini.nvim/readmes/mini-jump.md +161 -0
- package/nvim/plugins/mini.nvim/readmes/mini-jump2d.md +197 -0
- package/nvim/plugins/mini.nvim/readmes/mini-keymap.md +205 -0
- package/nvim/plugins/mini.nvim/readmes/mini-map.md +191 -0
- package/nvim/plugins/mini.nvim/readmes/mini-misc.md +145 -0
- package/nvim/plugins/mini.nvim/readmes/mini-move.md +163 -0
- package/nvim/plugins/mini.nvim/readmes/mini-notify.md +175 -0
- package/nvim/plugins/mini.nvim/readmes/mini-operators.md +193 -0
- package/nvim/plugins/mini.nvim/readmes/mini-pairs.md +158 -0
- package/nvim/plugins/mini.nvim/readmes/mini-pick.md +340 -0
- package/nvim/plugins/mini.nvim/readmes/mini-sessions.md +164 -0
- package/nvim/plugins/mini.nvim/readmes/mini-snippets.md +373 -0
- package/nvim/plugins/mini.nvim/readmes/mini-splitjoin.md +194 -0
- package/nvim/plugins/mini.nvim/readmes/mini-starter.md +176 -0
- package/nvim/plugins/mini.nvim/readmes/mini-statusline.md +155 -0
- package/nvim/plugins/mini.nvim/readmes/mini-surround.md +190 -0
- package/nvim/plugins/mini.nvim/readmes/mini-tabline.md +156 -0
- package/nvim/plugins/mini.nvim/readmes/mini-test.md +175 -0
- package/nvim/plugins/mini.nvim/readmes/mini-trailspace.md +137 -0
- package/nvim/plugins/mini.nvim/readmes/mini-visits.md +243 -0
- package/nvim/plugins/mini.nvim/scripts/dual_log.sh +13 -0
- package/nvim/plugins/mini.nvim/scripts/dual_push.sh +15 -0
- package/nvim/plugins/mini.nvim/scripts/dual_release.sh +102 -0
- package/nvim/plugins/mini.nvim/scripts/dual_sync.sh +115 -0
- package/nvim/plugins/mini.nvim/scripts/init-deps-example.lua +59 -0
- package/nvim/plugins/mini.nvim/scripts/lint-filename-length.sh +16 -0
- package/nvim/plugins/mini.nvim/scripts/lintcommit-ci.sh +18 -0
- package/nvim/plugins/mini.nvim/scripts/lintcommit.lua +393 -0
- package/nvim/plugins/mini.nvim/scripts/minidoc.lua +57 -0
- package/nvim/plugins/mini.nvim/scripts/minimal_init.lua +28 -0
- package/nvim/plugins/mini.nvim/scripts/minitest.lua +4 -0
- package/package.json +16 -0
- package/pyproject.toml +43 -0
- package/yazi/init.lua +12 -0
- package/yazi/keymap.toml +114 -0
- package/yazi/lesskey +5 -0
- package/yazi/plugins/bookmarks.yazi/main.lua +86 -0
- package/yazi/plugins/cd-git-root.yazi/main.lua +31 -0
- package/yazi/plugins/smart-enter.yazi/main.lua +11 -0
- package/yazi/theme.toml +26 -0
- package/yazi/yazi.toml +15 -0
- package/zsh/.zshrc +145 -0
- package/zsh/starship.toml +20 -0
- package/zsh/zsh-patina.toml +2 -0
|
@@ -0,0 +1,1709 @@
|
|
|
1
|
+
--- *mini.map* Window with buffer text overview
|
|
2
|
+
---
|
|
3
|
+
--- MIT License Copyright (c) 2022 Evgeni Chasnovski
|
|
4
|
+
|
|
5
|
+
--- Features:
|
|
6
|
+
--- - Show and manage special floating window displaying automatically updated
|
|
7
|
+
--- overview of current buffer text. Window takes up whole height of Neovim
|
|
8
|
+
--- instance and is fixed to a left/right side. Map content is computed by
|
|
9
|
+
--- taking all current lines, converting it to binary whitespace/non-whitespace
|
|
10
|
+
--- mask, rescaling to appropriate dimensions, and converting back to strings
|
|
11
|
+
--- consisting from special encoding symbols. All this is done very fast and
|
|
12
|
+
--- asynchronously. See |MiniMap.open()|, |MiniMap.refresh()|, |MiniMap.close()|,
|
|
13
|
+
--- |MiniMap.toggle()|, |MiniMap.toggle_side()|.
|
|
14
|
+
--- For a general overview and tips, see |mini.map-usage|.
|
|
15
|
+
---
|
|
16
|
+
--- - Show scrollbar next to map content. It represents current line and view
|
|
17
|
+
--- (top and bottom visible lines). Can be the only thing shown, making map
|
|
18
|
+
--- window a "pure scrollbar". See "Pure scrollbar config" section in
|
|
19
|
+
--- |MiniMap.config|.
|
|
20
|
+
---
|
|
21
|
+
--- - Highlight map lines representing certain data in current buffer. This is
|
|
22
|
+
--- done via extensible set of callables, called integrations (see
|
|
23
|
+
--- "Integrations" section in |MiniMap.config|). There are pre-built generators
|
|
24
|
+
--- for common integrations:
|
|
25
|
+
--- - Builtin search (as result of |/| and similar).
|
|
26
|
+
--- - Builtin diagnostic (taken from |vim.diagnostic.get()|).
|
|
27
|
+
--- - General diff hunks provided by |mini.diff|.
|
|
28
|
+
--- - Hunks computed provided by `lewis6991/gitsigns.nvim`.
|
|
29
|
+
--- For more details see |MiniMap.gen_integration|.
|
|
30
|
+
---
|
|
31
|
+
--- - Focus on map window to quickly browse current (source) buffer. Moving inside
|
|
32
|
+
--- map window updates cursor position in source window enabling fast and
|
|
33
|
+
--- targeted buffer exploration. To focus back, hit `<CR>` to accept current
|
|
34
|
+
--- explored position or `<Esc>` to go back to original position. See
|
|
35
|
+
--- |MiniMap.toggle_focus()|.
|
|
36
|
+
---
|
|
37
|
+
--- - Customizable via |MiniMap.config| and/or `opts` argument of |MiniMap.open()|
|
|
38
|
+
--- or |MiniMap.refresh()|:
|
|
39
|
+
--- - Encoding symbols used to display binary information of different
|
|
40
|
+
--- resolution (default is 3x2). There are pre-built generators for
|
|
41
|
+
--- different basic character families and resolutions. See
|
|
42
|
+
--- |MiniMap.gen_encode_symbols|.
|
|
43
|
+
--- - Scrollbar symbols, separate for line and view. Can have any width
|
|
44
|
+
--- (even zero, which virtually disables scrollbar).
|
|
45
|
+
--- - Integrations producing map line highlights.
|
|
46
|
+
--- - Window options: side (left/right), width, |'winblend'|, and more.
|
|
47
|
+
---
|
|
48
|
+
--- What it doesn't do:
|
|
49
|
+
--- - Automatically refresh when typing in Insert mode. Although it can be done in
|
|
50
|
+
--- non-blocking way, it still might introduce considerable computation overhead
|
|
51
|
+
--- (especially in very large files).
|
|
52
|
+
--- - Has more flexible window configuration. In case a full height floating
|
|
53
|
+
--- window obstructs vision of underlying buffers, use |MiniMap.toggle()| or
|
|
54
|
+
--- |MiniMap.toggle_side()|. Works best with global statusline.
|
|
55
|
+
--- - Provide autoopen functionality. Due to vast differences in user preference
|
|
56
|
+
--- of when map window should be shown, set up of automatic opening is left to
|
|
57
|
+
--- user. A common approach would be to call `MiniMap.open()` on |VimEnter| event.
|
|
58
|
+
--- If you use |mini.starter|, you can modify `<CR>` buffer mapping: >lua
|
|
59
|
+
---
|
|
60
|
+
--- local set_map_keymap = function()
|
|
61
|
+
--- local rhs = function()
|
|
62
|
+
--- MiniStarter.eval_current_item()
|
|
63
|
+
--- MiniMap.open()
|
|
64
|
+
--- end
|
|
65
|
+
--- vim.keymap.set('n', '<CR>', rhs, { buffer = true })
|
|
66
|
+
--- end
|
|
67
|
+
--- local opts = { pattern = 'MiniStarterOpened', callback = set_map_keymap }
|
|
68
|
+
--- vim.api.nvim_create_autocmd('User', opts)
|
|
69
|
+
--- <
|
|
70
|
+
--- # Setup ~
|
|
71
|
+
---
|
|
72
|
+
--- This module needs a setup with `require('mini.map').setup({})` (replace
|
|
73
|
+
--- `{}` with your `config` table). It will create global Lua table `MiniMap`
|
|
74
|
+
--- which you can use for scripting or manually (with `:lua MiniMap.*`).
|
|
75
|
+
---
|
|
76
|
+
--- See |MiniMap.config| for available config settings.
|
|
77
|
+
---
|
|
78
|
+
--- You can override runtime config settings (like `config.modifiers`) locally
|
|
79
|
+
--- to buffer inside `vim.b.minimap_config` which should have same structure
|
|
80
|
+
--- as `MiniMap.config`. See |mini.nvim-buffer-local-config| for more details.
|
|
81
|
+
---
|
|
82
|
+
--- # Dependencies ~
|
|
83
|
+
---
|
|
84
|
+
--- Suggested dependencies (provide extra functionality for integrations):
|
|
85
|
+
--- - Enabled |mini.diff| module for general diff highlighting via
|
|
86
|
+
--- |MiniMap.gen_integration.diff()|. If missing, no highlighting is added.
|
|
87
|
+
--- - Plugin [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim)
|
|
88
|
+
--- for Git status highlighting via |MiniMap.gen_integration.gitsigns()|.
|
|
89
|
+
--- If missing, no highlighting is added.
|
|
90
|
+
---
|
|
91
|
+
--- # Comparisons ~
|
|
92
|
+
---
|
|
93
|
+
--- - [wfxr/minimap.vim](https://github.com/wfxr/minimap.vim):
|
|
94
|
+
--- - |mini.map| doesn't have dependencies while being as fast as written
|
|
95
|
+
--- in Rust dependency of `minimap.vim`.
|
|
96
|
+
--- - |mini.map| uses floating window, while `minimap.vim` uses regular one.
|
|
97
|
+
--- - |mini.map| provides slightly different visual interface with
|
|
98
|
+
--- scrollbar and integration counts.
|
|
99
|
+
--- - |mini.map| allows encode symbols customization, `minimap.vim` does not.
|
|
100
|
+
--- - |mini.map| allows extending highlight integrations, while only
|
|
101
|
+
--- builtin search and git status are supported in `minimap.vim`.
|
|
102
|
+
--- - |mini.map| updates in asynchronous (non-blocking) fashion, `minimap.vim`
|
|
103
|
+
--- does not.
|
|
104
|
+
--- - |mini.map| can be used as a pure scrollbar, `minimap.vim` can not.
|
|
105
|
+
--- - [dstein64/nvim-scrollview](https://github.com/dstein64/nvim-scrollview):
|
|
106
|
+
--- - |mini.map| has two-part scrollbar showing current line and view (with
|
|
107
|
+
--- variable height), while `nvim-scrollview` shows only current view
|
|
108
|
+
--- (with fixed height).
|
|
109
|
+
--- - `nvim-scrollview` respects folds, i.e. shows view of visible lines,
|
|
110
|
+
--- while |mini.map| by design always shows view based on actual lines.
|
|
111
|
+
--- - `nvim-scrollview` creates scrollbar which can be dragged with mouse,
|
|
112
|
+
--- while |mini.nvim| does not, by design (use |MiniMap.toggle_focus()|).
|
|
113
|
+
--- - |mini.map| can show buffer outline, while `nvim-scrollview` can not.
|
|
114
|
+
--- - |mini.map| can show highlight integrations, while `nvim-scrollview`
|
|
115
|
+
--- can not.
|
|
116
|
+
--- - [petertriho/nvim-scrollbar](https://github.com/petertriho/nvim-scrollbar):
|
|
117
|
+
--- - |mini.map| has two-part scrollbar showing current line and view (with
|
|
118
|
+
--- variable height), while `nvim-scrollbar` shows only current view.
|
|
119
|
+
--- - |mini.map| can show buffer outline, while `nvim-scrollbar` can not.
|
|
120
|
+
--- - |mini.map| has fully extendable highlight integrations, while
|
|
121
|
+
--- `nvim-scrollbar` only supports diagnostic and search (with dependency).
|
|
122
|
+
--- - [lewis6991/satellite.nvim](https://github.com/lewis6991/satellite.nvim):
|
|
123
|
+
--- - Almost the same differences as with `dstein64/nvim-scrollview`, except
|
|
124
|
+
--- `satellite.nvim` can display some set of integration highlights.
|
|
125
|
+
---
|
|
126
|
+
--- # Highlight groups ~
|
|
127
|
+
--- *MiniMap-hl-groups*
|
|
128
|
+
---
|
|
129
|
+
--- - `MiniMapNormal` - basic highlight of whole window.
|
|
130
|
+
--- - `MiniMapSymbolCount` - counts of per-line integration items.
|
|
131
|
+
--- - `MiniMapSymbolLine` - scrollbar part representing current line.
|
|
132
|
+
--- - `MiniMapSymbolView` - scrollbar part representing current view.
|
|
133
|
+
---
|
|
134
|
+
--- To change any highlight group, set it directly with |nvim_set_hl()|.
|
|
135
|
+
---
|
|
136
|
+
--- # Disabling ~
|
|
137
|
+
---
|
|
138
|
+
--- To disable, set `vim.g.minimap_disable` (globally) or `vim.b.minimap_disable`
|
|
139
|
+
--- (for a buffer) to `true`. Considering high number of different scenarios
|
|
140
|
+
--- and customization intentions, writing exact rules for disabling module's
|
|
141
|
+
--- functionality is left to user. See |mini.nvim-disabling-recipes| for common
|
|
142
|
+
--- recipes.
|
|
143
|
+
---@tag MiniMap
|
|
144
|
+
|
|
145
|
+
--- # Mappings ~
|
|
146
|
+
---
|
|
147
|
+
--- This module doesn't make mappings, only provides functions for users to map
|
|
148
|
+
--- manually. Here is how one |<Leader>| set of mappings can be constructed: >lua
|
|
149
|
+
---
|
|
150
|
+
--- vim.keymap.set('n', '<Leader>mc', MiniMap.close)
|
|
151
|
+
--- vim.keymap.set('n', '<Leader>mf', MiniMap.toggle_focus)
|
|
152
|
+
--- vim.keymap.set('n', '<Leader>mo', MiniMap.open)
|
|
153
|
+
--- vim.keymap.set('n', '<Leader>mr', MiniMap.refresh)
|
|
154
|
+
--- vim.keymap.set('n', '<Leader>ms', MiniMap.toggle_side)
|
|
155
|
+
--- vim.keymap.set('n', '<Leader>mt', MiniMap.toggle)
|
|
156
|
+
--- <
|
|
157
|
+
--- # How automatic refresh works ~
|
|
158
|
+
---
|
|
159
|
+
--- Automatic refresh is done by calling |MiniMap.refresh()| when appropriate
|
|
160
|
+
--- |events| occur. It is done with specially chosen `parts` argument value (to
|
|
161
|
+
--- avoid unnecessary computations). For example, when only cursor has moved
|
|
162
|
+
--- (|CursorMoved|), only scrollbar is updated; so no recomputation of integrations
|
|
163
|
+
--- or line encoding is done.
|
|
164
|
+
---
|
|
165
|
+
--- To avoid visual clutter, automatic refresh is done only in normal buffers
|
|
166
|
+
--- and help pages (i.e. with |'buftype'| being empty or "help")
|
|
167
|
+
---
|
|
168
|
+
--- When you think content is not up to date, try one of these:
|
|
169
|
+
--- - Call |MiniMap.refresh()| manually. Make mapping to make it easier.
|
|
170
|
+
--- - Save current buffer, for example with |:write|.
|
|
171
|
+
--- - Exit and enter Normal mode (if your Neovim version supports |ModeChanged|).
|
|
172
|
+
---@tag mini.map-usage
|
|
173
|
+
|
|
174
|
+
---@alias __map_opts table|nil Options used to define map configuration. Same structure
|
|
175
|
+
--- as |MiniMap.config|. Will have effect until at least one tabpage has opened
|
|
176
|
+
--- map window. Default values are taken in the following order:
|
|
177
|
+
--- - From `opts` field of |MiniMap.current|.
|
|
178
|
+
--- - From `vim.b.minimap_config`.
|
|
179
|
+
--- - From |MiniMap.config|.
|
|
180
|
+
|
|
181
|
+
---@diagnostic disable:undefined-field
|
|
182
|
+
|
|
183
|
+
-- Module definition ==========================================================
|
|
184
|
+
local MiniMap = {}
|
|
185
|
+
local H = {}
|
|
186
|
+
|
|
187
|
+
--- Module setup
|
|
188
|
+
---
|
|
189
|
+
---@param config table|nil Module config table. See |MiniMap.config|.
|
|
190
|
+
---
|
|
191
|
+
---@usage >lua
|
|
192
|
+
--- require('mini.map').setup() -- use default config
|
|
193
|
+
--- -- OR
|
|
194
|
+
--- require('mini.map').setup({}) -- replace {} with your config table
|
|
195
|
+
--- <
|
|
196
|
+
MiniMap.setup = function(config)
|
|
197
|
+
-- TODO: Remove after Neovim=0.9 support is dropped
|
|
198
|
+
if vim.fn.has('nvim-0.10') == 0 then
|
|
199
|
+
vim.notify(
|
|
200
|
+
'(mini.map) Neovim<0.10 is soft deprecated (module works but is not supported).'
|
|
201
|
+
.. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
|
|
202
|
+
.. ' Please update your Neovim version.'
|
|
203
|
+
)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
-- Export module
|
|
207
|
+
_G.MiniMap = MiniMap
|
|
208
|
+
|
|
209
|
+
-- Setup config
|
|
210
|
+
config = H.setup_config(config)
|
|
211
|
+
|
|
212
|
+
-- Apply config
|
|
213
|
+
H.apply_config(config)
|
|
214
|
+
|
|
215
|
+
-- Define behavior
|
|
216
|
+
H.create_autocommands()
|
|
217
|
+
|
|
218
|
+
-- Create default highlighting
|
|
219
|
+
H.create_default_hl()
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
--stylua: ignore
|
|
223
|
+
--- Defaults ~
|
|
224
|
+
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
|
|
225
|
+
---@text # Symbols ~
|
|
226
|
+
---
|
|
227
|
+
--- Options in `config.symbols` define characters used to display various
|
|
228
|
+
--- information in map window.
|
|
229
|
+
---
|
|
230
|
+
--- ## Encode symbols ~
|
|
231
|
+
---
|
|
232
|
+
--- The `config.symbols.encode` option defines which characters are used to
|
|
233
|
+
--- encode source buffer lines. For details of encode algorithm, see
|
|
234
|
+
--- |MiniMap.encode_strings()|.
|
|
235
|
+
---
|
|
236
|
+
--- This option should be a table with the following structure:
|
|
237
|
+
--- - <resolution> field - table containing <row> and <col> elements with row
|
|
238
|
+
--- and column resolution of each symbol. This defines encoding structure and
|
|
239
|
+
--- number of needed encode symbols.
|
|
240
|
+
--- - Numerical fields 1, 2, ..., 2^(row_resolution * col_resolution). Each symbol
|
|
241
|
+
--- represents a `(row_resolution, col_resolution)` boolean mask (`true` for
|
|
242
|
+
--- non-whitespace, `false` for whitespace), created as (reversed) binary digit:
|
|
243
|
+
--- `true` as 1; `false` as 0. Traversing left-right, top-bottom (top-left is
|
|
244
|
+
--- lowest bit, bottom-right - highest). So first symbol encodes a complete
|
|
245
|
+
--- whitespace, last - complete non-whitespace.
|
|
246
|
+
---
|
|
247
|
+
--- If `nil` (default), output of |MiniMap.gen_encode_symbols.block()| with `'3x2'`
|
|
248
|
+
--- identifier is used.
|
|
249
|
+
---
|
|
250
|
+
--- Example: `{ '1', '2', '3', '4', resolution = { row = 1, col = 2 } }`. This
|
|
251
|
+
--- will encode two characters in each input row. So a string `' a aaa'` will
|
|
252
|
+
--- be encoded as `'1234'`.
|
|
253
|
+
---
|
|
254
|
+
--- There are pre-built generators of encode symbols:
|
|
255
|
+
--- - |MiniMap.gen_encode_symbols.block()|
|
|
256
|
+
--- - |MiniMap.gen_encode_symbols.dot()|
|
|
257
|
+
--- - |MiniMap.gen_encode_symbols.shade()|
|
|
258
|
+
---
|
|
259
|
+
--- ## Scrollbar symbols ~
|
|
260
|
+
---
|
|
261
|
+
--- Options `config.symbols.scroll_line` and `config.symbols.scroll_view` define
|
|
262
|
+
--- strings used to represent current line and current view inside map window.
|
|
263
|
+
--- Can have any length, map window content will adjust.
|
|
264
|
+
---
|
|
265
|
+
--- If supplied window width is small enough so that only (part of) of
|
|
266
|
+
--- scrollbar can be shown, it is called a "pure scrollbar". The behavior differs
|
|
267
|
+
--- slightly from normal map window. See "Pure scrollbar config" later section.
|
|
268
|
+
---
|
|
269
|
+
--- Some suggestions for scrollbar symbols:
|
|
270
|
+
--- - View-line pairs: `'▒'` and `'█'`.
|
|
271
|
+
--- - Line - `'🮚'`, `'▶'`.
|
|
272
|
+
--- - View - `'╎'`, `'┋'`, `'┋'`.
|
|
273
|
+
---
|
|
274
|
+
--- # Integrations ~
|
|
275
|
+
---
|
|
276
|
+
--- Option `config.integrations` is an array of integrations. Each one is used
|
|
277
|
+
--- to define map line highlights representing some important lines in source
|
|
278
|
+
--- buffer. If `nil` (default), no integrations are used.
|
|
279
|
+
---
|
|
280
|
+
--- Each integration should be a callable returning an array with data about
|
|
281
|
+
--- SOURCE BUFFER lines it wants to highlight. Each array element should be
|
|
282
|
+
--- a table with <line> (source buffer line number) and <hl_group> (string with
|
|
283
|
+
--- highlight group name) keys. Note: line number outside of source buffer
|
|
284
|
+
--- count will be converted to a nearest appropriate one.
|
|
285
|
+
---
|
|
286
|
+
--- Example output of single integration: >lua
|
|
287
|
+
---
|
|
288
|
+
--- {
|
|
289
|
+
--- { line = 1, hl_group = 'Search' },
|
|
290
|
+
--- { line = 2, hl_group = 'Operator' },
|
|
291
|
+
--- { line = 9, hl_group = 'Search'}
|
|
292
|
+
--- }
|
|
293
|
+
--- <
|
|
294
|
+
--- Conversion to map highlights is done on a "first seen" basis: actual
|
|
295
|
+
--- highlight group applied to a map line is taken from the first integration
|
|
296
|
+
--- output convertible to that map line. Other outputs with same map line
|
|
297
|
+
--- (after conversion) contribute to integration count shown between scrollbar
|
|
298
|
+
--- and encoded lines (if `config.window.show_integration_count` is `true`).
|
|
299
|
+
---
|
|
300
|
+
--- Previous example output with default `'3x2'` resolution will add |hl-Search|
|
|
301
|
+
--- highlight on map lines 1 and 3, and show integration count 2 on first line.
|
|
302
|
+
---
|
|
303
|
+
--- Every element of integrations array is called one by one from start to end
|
|
304
|
+
--- with their outputs appended to end of single array. This means that more
|
|
305
|
+
--- important integrations should be placed in the beginning of an array, as
|
|
306
|
+
--- this will make them have higher priority in case other integrations will
|
|
307
|
+
--- highlight same map line.
|
|
308
|
+
---
|
|
309
|
+
--- Example of using `config.integrations`: >lua
|
|
310
|
+
---
|
|
311
|
+
--- local map = require('mini.map')
|
|
312
|
+
--- map.setup({
|
|
313
|
+
--- integrations = {
|
|
314
|
+
--- map.gen_integration.builtin_search(),
|
|
315
|
+
--- map.gen_integration.diff(),
|
|
316
|
+
--- map.gen_integration.diagnostic(),
|
|
317
|
+
--- },
|
|
318
|
+
--- })
|
|
319
|
+
--- <
|
|
320
|
+
--- # Window config ~
|
|
321
|
+
---
|
|
322
|
+
--- Option `config.window` defines some properties of map window.
|
|
323
|
+
---
|
|
324
|
+
--- `window.focusable` - whether to allow focusing on map window with other
|
|
325
|
+
--- methods beside |MiniMap.toggle_focus()| (like |:wincmd|, |CTRL-W|, or mouse).
|
|
326
|
+
--- Default: `false`.
|
|
327
|
+
---
|
|
328
|
+
--- `window.side` - which side to stick map window: `'left'` or `'right'` (default).
|
|
329
|
+
---
|
|
330
|
+
--- `window.show_integration_count` - whether to show integration count between
|
|
331
|
+
--- scrollbar and encoded lines. Integration count is a number of integration
|
|
332
|
+
--- outputs which were converted to same map line. When `true`, adds single
|
|
333
|
+
--- cell column with numbers from 2 to 9 and character `+` indicating count
|
|
334
|
+
--- greater than 9. Count 1 is not shown, because it is redundant to highlighted
|
|
335
|
+
--- map line. Default: `true`.
|
|
336
|
+
---
|
|
337
|
+
--- `window.width` - width of floating window, including scrollbar and
|
|
338
|
+
--- integration count column. Default: 10.
|
|
339
|
+
---
|
|
340
|
+
--- `window.winblend` - value of |'winblend'| of floating window. Value 0 makes it
|
|
341
|
+
--- completely non-transparent, 100 - completely transparent (content is still
|
|
342
|
+
--- visible, but with slightly different highlights).
|
|
343
|
+
---
|
|
344
|
+
--- `window.zindex` - z-index of floating window. Default: 10.
|
|
345
|
+
---
|
|
346
|
+
--- # Pure scrollbar config ~
|
|
347
|
+
---
|
|
348
|
+
--- "Pure scrollbar" is a configuration when window width is not enough to show
|
|
349
|
+
--- encoded content. It has following differences from default "map" approach:
|
|
350
|
+
--- - It doesn't perform line encoding with |MiniMap.encode_strings()|
|
|
351
|
+
--- but instead uses encoding with fixed number of lines (equal to window
|
|
352
|
+
--- height).
|
|
353
|
+
--- - Integration highlights are not computed.
|
|
354
|
+
---
|
|
355
|
+
--- Config: >lua
|
|
356
|
+
---
|
|
357
|
+
--- require('mini.map').setup({
|
|
358
|
+
--- -- Customize `symbols` to your liking
|
|
359
|
+
---
|
|
360
|
+
--- window = {
|
|
361
|
+
--- -- Set this to the maximum width of your scroll symbols
|
|
362
|
+
--- width = 1,
|
|
363
|
+
---
|
|
364
|
+
--- -- Set this to your liking. Try values 0, 25, 50, 75, 100
|
|
365
|
+
--- winblend = 100,
|
|
366
|
+
---
|
|
367
|
+
--- -- Don't need extra column
|
|
368
|
+
--- show_integration_count = false,
|
|
369
|
+
--- }
|
|
370
|
+
--- })
|
|
371
|
+
--- <
|
|
372
|
+
MiniMap.config = {
|
|
373
|
+
-- Highlight integrations (none by default)
|
|
374
|
+
integrations = nil,
|
|
375
|
+
|
|
376
|
+
-- Symbols used to display data
|
|
377
|
+
symbols = {
|
|
378
|
+
-- Encode symbols. See `:h MiniMap.config` for specification and
|
|
379
|
+
-- `:h MiniMap.gen_encode_symbols` for pre-built ones.
|
|
380
|
+
-- Default: solid blocks with 3x2 resolution.
|
|
381
|
+
encode = nil,
|
|
382
|
+
|
|
383
|
+
-- Scrollbar parts for view and line. Use empty string to disable any.
|
|
384
|
+
scroll_line = '█',
|
|
385
|
+
scroll_view = '┃',
|
|
386
|
+
},
|
|
387
|
+
|
|
388
|
+
-- Window options
|
|
389
|
+
window = {
|
|
390
|
+
-- Whether window is focusable in normal way (with `wincmd` or mouse)
|
|
391
|
+
focusable = false,
|
|
392
|
+
|
|
393
|
+
-- Side to stick ('left' or 'right')
|
|
394
|
+
side = 'right',
|
|
395
|
+
|
|
396
|
+
-- Whether to show count of multiple integration highlights
|
|
397
|
+
show_integration_count = true,
|
|
398
|
+
|
|
399
|
+
-- Total width
|
|
400
|
+
width = 10,
|
|
401
|
+
|
|
402
|
+
-- Value of 'winblend' option
|
|
403
|
+
winblend = 25,
|
|
404
|
+
|
|
405
|
+
-- Z-index
|
|
406
|
+
zindex = 10,
|
|
407
|
+
},
|
|
408
|
+
}
|
|
409
|
+
--minidoc_afterlines_end
|
|
410
|
+
|
|
411
|
+
--- Table with information about current state of map
|
|
412
|
+
---
|
|
413
|
+
--- At least these keys are supported:
|
|
414
|
+
--- - <buf_data> - table with buffer identifiers. Field <map> contains
|
|
415
|
+
--- identifier of a buffer used to display map. Field <source> - buffer
|
|
416
|
+
--- identifier which content map is displaying (i.e. source buffer).
|
|
417
|
+
--- - <win_data> - table of window identifiers used to display map in certain
|
|
418
|
+
--- tabpage. Keys: tabpage identifier. Values: window identifier.
|
|
419
|
+
--- - <opts> - current options used to control map display. Same structure
|
|
420
|
+
--- as |MiniMap.config|. Takes precedence over global and buffer-local configs.
|
|
421
|
+
--- Is reset when last map window is closed with |MiniMap.close()|.
|
|
422
|
+
MiniMap.current = {
|
|
423
|
+
buf_data = {},
|
|
424
|
+
win_data = {},
|
|
425
|
+
opts = {},
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
-- Module functionality =======================================================
|
|
429
|
+
--- Encode strings
|
|
430
|
+
---
|
|
431
|
+
--- This takes arbitrary array of strings and computes its non-whitespace
|
|
432
|
+
--- outline. Output is an array of strings with configurable array length, string
|
|
433
|
+
--- width, and symbols representing encoding.
|
|
434
|
+
---
|
|
435
|
+
--- Each encode symbol is assumed to have resolution within which it can convey
|
|
436
|
+
--- binary information. For example, resolution `3x2` (row resolution 3,
|
|
437
|
+
--- column - 2) means that each symbol can encode 3 rows and 2 columns of
|
|
438
|
+
--- binary data. Here it is used to encode non-whitespace mask. See more in
|
|
439
|
+
--- "Encode symbols" section of |MiniMap.config|.
|
|
440
|
+
---
|
|
441
|
+
--- Encoding has the following steps:
|
|
442
|
+
--- - Convert strings to boolean mask: 2d boolean array with each row
|
|
443
|
+
--- representing a string. Element in every row subarray is `true` if
|
|
444
|
+
--- respective (possibly multibyte) character in a string is not a whitespace,
|
|
445
|
+
--- `false` otherwise. Note: tabs are expanded into |'tabstop'| spaces.
|
|
446
|
+
--- - Rescale to appropriate dimensions:
|
|
447
|
+
--- - Each output dimension is just enough to encode all input strings, but
|
|
448
|
+
--- not more than supplied dimensions (`opts.n_rows * resolution.row` and
|
|
449
|
+
--- `opts.n_cols * resolution.col` respectively).
|
|
450
|
+
--- - If input dimensions are too big to fit inside output, perform grid
|
|
451
|
+
--- downscaling with loss of information. Input boolean mask is divided
|
|
452
|
+
--- into 2d-bins with as equal as possible dimensions. Each bin then
|
|
453
|
+
--- converted into single boolean value: `true` if bin contains at least
|
|
454
|
+
--- one `true` element, `false` otherwise. This leads to a whitespace
|
|
455
|
+
--- output meaning that ALL entries in a bin are whitespace, while
|
|
456
|
+
--- non-whitespace output means that SOME entry is non-whitespace.
|
|
457
|
+
--- - Convert boolean mask to symbol strings:
|
|
458
|
+
--- - Input rescaled boolean mask is divided into bins with dimensions of
|
|
459
|
+
--- symbol resolution (assuming `false` outer padding).
|
|
460
|
+
--- - Each bin with resolution dimensions is transformed into encode symbol.
|
|
461
|
+
--- Single convertible `(resolution.row, resolution.col)` boolean
|
|
462
|
+
--- mask is treated as (reversed) binary digit: `true` as 1; `false` as 0.
|
|
463
|
+
--- Traversing left-right, top-bottom (top-left is lowest bit,
|
|
464
|
+
--- bottom-right - highest).
|
|
465
|
+
---
|
|
466
|
+
--- Example:
|
|
467
|
+
---
|
|
468
|
+
--- Assume the output should have 3 rows of symbols each with width 2. Encode
|
|
469
|
+
--- symbols are `' '`, `'▌'`, `'▐'`, `'█'` with `1x2` resolution.
|
|
470
|
+
---
|
|
471
|
+
--- Assume input strings: >
|
|
472
|
+
--- aaaaa
|
|
473
|
+
--- b b
|
|
474
|
+
---
|
|
475
|
+
--- d d
|
|
476
|
+
--- e e
|
|
477
|
+
--- <
|
|
478
|
+
--- Steps:
|
|
479
|
+
--- - Convert to boolean mask (each row is a boolean array, "t"/"f" ~ `true`/`false`,
|
|
480
|
+
--- empty spots are equivalent to being `false`): >
|
|
481
|
+
--- ttttt
|
|
482
|
+
--- ftft
|
|
483
|
+
---
|
|
484
|
+
--- ftft
|
|
485
|
+
--- tft
|
|
486
|
+
--- <
|
|
487
|
+
--- - Rescale. Output dimensions are `n_rows * resolution.row = 3 * 1 = 3` rows and
|
|
488
|
+
--- `n_cols * resolution.col = 2 * 2 = 4`. It creates as equal as possible grid
|
|
489
|
+
--- with 3 rows and 4 columns and converts bins to single booleans. Result: >
|
|
490
|
+
--- tttt
|
|
491
|
+
--- tftf
|
|
492
|
+
--- ttff
|
|
493
|
+
--- <
|
|
494
|
+
--- - Convert to symbols. It makes `1x2` bins, treats their input as (reversed)
|
|
495
|
+
--- binary digits (`ff=00=0`, `tf=10=1`, `ft=01=2`, `tt=11=3`) and takes
|
|
496
|
+
--- corresponding symbols from supplied options (value plus 1). Result: >
|
|
497
|
+
--- ██
|
|
498
|
+
--- ▌▌
|
|
499
|
+
--- █
|
|
500
|
+
--- <
|
|
501
|
+
---@param strings table Array of arbitrary strings.
|
|
502
|
+
---@param opts table|nil Options. Possible fields:
|
|
503
|
+
--- - <n_rows> - number of rows in output encoding. If too big, will be
|
|
504
|
+
--- truncated to be maximum needed to encode all input strings (taking into
|
|
505
|
+
--- account symbols row resolution). Default: `math.huge`.
|
|
506
|
+
--- - <n_cols> - width of every encoding string. If too big, will be truncated
|
|
507
|
+
--- to be maximum needed to encode all input strings (taking into account
|
|
508
|
+
--- symbols column resolution). Default: `math.huge`.
|
|
509
|
+
--- - <symbols> - array of symbols with extra `resolution` field. See "Encode
|
|
510
|
+
--- symbols" section of |MiniMap.config| for more details. Default: output
|
|
511
|
+
--- of |MiniMap.gen_encode_symbols.block()| with `'3x2'` identifier.
|
|
512
|
+
---
|
|
513
|
+
---@return table Array of encoded strings.
|
|
514
|
+
MiniMap.encode_strings = function(strings, opts)
|
|
515
|
+
-- Validate input
|
|
516
|
+
if not H.is_array_of(strings, H.is_string) then
|
|
517
|
+
H.error('`strings` argument of `encode_strings()` should be array of strings.')
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
opts = vim.tbl_deep_extend(
|
|
521
|
+
'force',
|
|
522
|
+
{ n_rows = math.huge, n_cols = math.huge, symbols = H.get_config().symbols.encode or H.default_symbols },
|
|
523
|
+
opts or {}
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
-- Compute encoding
|
|
527
|
+
local mask = H.mask_from_strings(strings, opts)
|
|
528
|
+
mask = H.mask_rescale(mask, opts)
|
|
529
|
+
return H.mask_to_symbols(mask, opts)
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
--- Open map window
|
|
533
|
+
---
|
|
534
|
+
--- This creates and shows map window in current tabpage. It basically has
|
|
535
|
+
--- two steps:
|
|
536
|
+
--- - If not already done, create map buffer (used to set lines and other
|
|
537
|
+
--- visual indicators) and map window.
|
|
538
|
+
--- - Call |MiniMap.refresh()|.
|
|
539
|
+
---
|
|
540
|
+
---@param opts __map_opts
|
|
541
|
+
MiniMap.open = function(opts)
|
|
542
|
+
-- Early returns
|
|
543
|
+
if H.is_disabled() then return end
|
|
544
|
+
|
|
545
|
+
-- Normalize input
|
|
546
|
+
opts = H.normalize_opts(opts)
|
|
547
|
+
|
|
548
|
+
-- Allow execution in case of already opened window
|
|
549
|
+
if H.is_window_open() then
|
|
550
|
+
MiniMap.refresh(opts)
|
|
551
|
+
return
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
-- Open buffer and window
|
|
555
|
+
local buf_id = MiniMap.current.buf_data.map
|
|
556
|
+
if buf_id == nil or not vim.api.nvim_buf_is_loaded(buf_id) then
|
|
557
|
+
pcall(vim.api.nvim_buf_delete, buf_id, { force = true })
|
|
558
|
+
buf_id = H.create_map_buffer()
|
|
559
|
+
MiniMap.current.buf_data.map = buf_id
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
local win_id = vim.api.nvim_open_win(buf_id, false, H.normalize_window_options(opts.window))
|
|
563
|
+
H.set_current_map_win(win_id)
|
|
564
|
+
|
|
565
|
+
-- Set buffer and window options. Other important options are handled by
|
|
566
|
+
-- `style = 'minimal'` in `nvim_open_win()`.
|
|
567
|
+
vim.api.nvim_win_call(win_id, function()
|
|
568
|
+
--stylua: ignore
|
|
569
|
+
local options = {
|
|
570
|
+
'buftype=nofile', 'foldcolumn=0', 'foldlevel=999', 'matchpairs=', 'nobuflisted',
|
|
571
|
+
'nomodeline', 'noreadonly', 'noswapfile', 'synmaxcol&', 'nowrap',
|
|
572
|
+
}
|
|
573
|
+
-- Vim's `setlocal` is currently more robust compared to `opt_local`
|
|
574
|
+
-- Use `noautocmd` to make it more invisible for others
|
|
575
|
+
vim.cmd(('silent! noautocmd setlocal %s'):format(table.concat(options, ' ')))
|
|
576
|
+
|
|
577
|
+
-- Override Normal highlighting locally for map window
|
|
578
|
+
vim.cmd('silent! setlocal winhighlight=NormalFloat:MiniMapNormal')
|
|
579
|
+
end)
|
|
580
|
+
|
|
581
|
+
-- Refresh content
|
|
582
|
+
MiniMap.refresh(opts)
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
--- Refresh map window
|
|
586
|
+
---
|
|
587
|
+
--- This function serves two purposes:
|
|
588
|
+
--- - Update current map configuration via `opts`.
|
|
589
|
+
--- - Update parts of displayed content via `parts`.
|
|
590
|
+
---
|
|
591
|
+
---@param opts __map_opts
|
|
592
|
+
---@param parts table|nil Which parts to update. Recognised keys with boolean
|
|
593
|
+
--- values (all `true` by default):
|
|
594
|
+
--- - <integrations> - whether to update integration highlights.
|
|
595
|
+
--- - <lines> - whether to update map lines.
|
|
596
|
+
--- - <scrollbar> - whether to update scrollbar.
|
|
597
|
+
MiniMap.refresh = function(opts, parts)
|
|
598
|
+
-- Early return
|
|
599
|
+
if H.is_disabled() or not H.is_window_open() then return end
|
|
600
|
+
|
|
601
|
+
-- Normalize input
|
|
602
|
+
opts = H.normalize_opts(opts)
|
|
603
|
+
parts = vim.tbl_deep_extend('force', { integrations = true, lines = true, scrollbar = true }, parts or {})
|
|
604
|
+
|
|
605
|
+
-- Update current data
|
|
606
|
+
H.cache.scrollbar_data.offset = math.max(H.str_width(opts.symbols.scroll_line), H.str_width(opts.symbols.scroll_view))
|
|
607
|
+
+ (opts.window.show_integration_count and 1 or 0)
|
|
608
|
+
MiniMap.current.opts = opts
|
|
609
|
+
|
|
610
|
+
-- Update window options
|
|
611
|
+
H.update_window_opts()
|
|
612
|
+
|
|
613
|
+
-- Possibly update parts in asynchronous fashion
|
|
614
|
+
if parts.lines then vim.schedule(H.update_map_lines) end
|
|
615
|
+
if parts.scrollbar then vim.schedule(H.update_map_scrollbar) end
|
|
616
|
+
if parts.integrations then vim.schedule(H.update_map_integrations) end
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
--- Close map window
|
|
620
|
+
---
|
|
621
|
+
--- Also resets `opts` field of |MiniMap.current| after closing last map window
|
|
622
|
+
--- (among possibly several tabpages).
|
|
623
|
+
MiniMap.close = function()
|
|
624
|
+
pcall(vim.api.nvim_win_close, H.get_current_map_win(), true)
|
|
625
|
+
H.set_current_map_win(nil)
|
|
626
|
+
|
|
627
|
+
-- Reset current options if closed last window so as to use config during
|
|
628
|
+
-- next opening
|
|
629
|
+
if vim.tbl_count(MiniMap.current.win_data) == 0 then MiniMap.current.opts = {} end
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
--- Toggle map window
|
|
633
|
+
---
|
|
634
|
+
--- Open if not shown in current tabpage, close otherwise.
|
|
635
|
+
---
|
|
636
|
+
---@param opts table|nil Input for |MiniMap.open()|.
|
|
637
|
+
MiniMap.toggle = function(opts)
|
|
638
|
+
if H.is_window_open() then
|
|
639
|
+
MiniMap.close()
|
|
640
|
+
else
|
|
641
|
+
MiniMap.open(opts)
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
--- Toggle focus to/from map window
|
|
646
|
+
---
|
|
647
|
+
--- When not inside map window, put cursor inside map window; otherwise put
|
|
648
|
+
--- cursor in previous window with source buffer.
|
|
649
|
+
---
|
|
650
|
+
--- When cursor is moving inside map window (but not just after focusing), view of
|
|
651
|
+
--- source window is updated to show first line convertible to current map line.
|
|
652
|
+
--- This allows quick targeted source buffer exploration.
|
|
653
|
+
---
|
|
654
|
+
--- There are at least these extra methods to focus back from map window:
|
|
655
|
+
--- - Press `<CR>` to accept current explored position in source buffer.
|
|
656
|
+
--- Equivalent to calling this function with `false` argument.
|
|
657
|
+
--- - Press `<Esc>` to go back to original position prior focusing on map window.
|
|
658
|
+
--- Equivalent to calling this function with `true` argument.
|
|
659
|
+
---
|
|
660
|
+
---@param use_previous_cursor boolean|nil Whether to focus on source window at
|
|
661
|
+
--- original cursor position (the one prior focusing on map window).
|
|
662
|
+
MiniMap.toggle_focus = function(use_previous_cursor)
|
|
663
|
+
if not H.is_window_open() then return end
|
|
664
|
+
local cur_win, map_win = vim.api.nvim_get_current_win(), H.get_current_map_win()
|
|
665
|
+
|
|
666
|
+
if cur_win == map_win then
|
|
667
|
+
-- Focus on previous window
|
|
668
|
+
vim.api.nvim_set_current_win(H.cache.previous_win.id)
|
|
669
|
+
|
|
670
|
+
-- Use either previous cursor or first non-whitespace character (if this
|
|
671
|
+
-- was the result of cursor movement inside map window)
|
|
672
|
+
if use_previous_cursor and H.cache.previous_win.cursor ~= nil then
|
|
673
|
+
vim.api.nvim_win_set_cursor(0, H.cache.previous_win.cursor)
|
|
674
|
+
elseif H.cache.n_map_cursor_moves > 1 then
|
|
675
|
+
vim.cmd('normal! ^')
|
|
676
|
+
end
|
|
677
|
+
else
|
|
678
|
+
-- Focus on map window. Cursor is set on `BufEnter` to account for other
|
|
679
|
+
-- ways of focusing on buffer (for example, with `<C-w><C-w>`)
|
|
680
|
+
vim.api.nvim_set_current_win(map_win)
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
--- Toggle side of map window
|
|
685
|
+
---
|
|
686
|
+
--- A small convenience wrapper for calling |MiniMap.refresh()| to change the
|
|
687
|
+
--- side of map window.
|
|
688
|
+
MiniMap.toggle_side = function()
|
|
689
|
+
if not H.is_window_open() then return end
|
|
690
|
+
local cur_side = MiniMap.current.opts.window.side
|
|
691
|
+
MiniMap.refresh(
|
|
692
|
+
{ window = { side = cur_side == 'left' and 'right' or 'left' } },
|
|
693
|
+
{ integrations = false, lines = false, scrollbar = false }
|
|
694
|
+
)
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
--- Generate encode symbols
|
|
698
|
+
---
|
|
699
|
+
--- This is a table with function elements. Call to actually get encode symbols.
|
|
700
|
+
---
|
|
701
|
+
--- Each element takes a string resolution identifier of a form `'rxc'` (like `'3x2'`)
|
|
702
|
+
--- where `r` is a row resolution of each symbol (how many rows of binary data it
|
|
703
|
+
--- can encode) and `c` is a column resolution (how many columns it can encode).
|
|
704
|
+
MiniMap.gen_encode_symbols = {}
|
|
705
|
+
|
|
706
|
+
--- Generate block encode symbols
|
|
707
|
+
---
|
|
708
|
+
--- Outputs use solid block to encode binary data. Example: `'🬗'`, `'▟'`, `'█'`.
|
|
709
|
+
---
|
|
710
|
+
---@param id string Resolution identifier.
|
|
711
|
+
--- Available values: `'1x2'`, `'2x1'`, `'2x2'`, `'3x2'` (default in |mini.map|).
|
|
712
|
+
MiniMap.gen_encode_symbols.block = function(id) return H.block_symbols[id] end
|
|
713
|
+
|
|
714
|
+
--- Generate dot encode symbols
|
|
715
|
+
---
|
|
716
|
+
--- Outputs use dots to encode binary data. Example: `'⡪'`, `'⣼'`, `'⣿'`.
|
|
717
|
+
---
|
|
718
|
+
---@param id string Resolution identifier. Available values: `'4x2'`, `'3x2'`.
|
|
719
|
+
MiniMap.gen_encode_symbols.dot = function(id) return H.dot_symbols[id] end
|
|
720
|
+
|
|
721
|
+
--- Generate shade encode symbols
|
|
722
|
+
---
|
|
723
|
+
--- Outputs use whole cell shades to encode binary data. They use same set of
|
|
724
|
+
--- characters (`'░'`, `'▒'`, `'▒'`, `'▓'`), but with different resolution.
|
|
725
|
+
---
|
|
726
|
+
---@param id string Resolution identifier. Available values: `'1x2'`, `'2x1'`.
|
|
727
|
+
MiniMap.gen_encode_symbols.shade = function(id) return H.shade_symbols[id] end
|
|
728
|
+
|
|
729
|
+
--- Generate integrations
|
|
730
|
+
---
|
|
731
|
+
--- This is a table with function elements. Call to actually get encode symbols.
|
|
732
|
+
---
|
|
733
|
+
--- Each element takes a table defining highlight groups used for to highlight
|
|
734
|
+
--- map lines.
|
|
735
|
+
MiniMap.gen_integration = {}
|
|
736
|
+
|
|
737
|
+
--- Builtin search
|
|
738
|
+
---
|
|
739
|
+
--- Highlight lines with matches of current builtin search (like with |/|, |?|, etc.).
|
|
740
|
+
--- Integration count reflects number of actual matches.
|
|
741
|
+
---
|
|
742
|
+
--- It prompts integration highlighting update on every change of |'hlsearch'|
|
|
743
|
+
--- (see |OptionSet|) or |v:hlsearch|. Note that it is not happening for some keys:
|
|
744
|
+
--- - After starting search with |n|, |N|, |star|, or |#|.
|
|
745
|
+
--- To enable highlight update on this keys, make custom mappings. Like this: >lua
|
|
746
|
+
---
|
|
747
|
+
--- for _, key in ipairs({ 'n', 'N', '*', '#' }) do
|
|
748
|
+
--- local rhs = key ..
|
|
749
|
+
--- '<Cmd>lua MiniMap.refresh({}, {lines = false, scrollbar = false})<CR>'
|
|
750
|
+
--- vim.keymap.set('n', key, rhs)
|
|
751
|
+
--- end
|
|
752
|
+
--- <
|
|
753
|
+
---@param hl_groups table|nil Table defining highlight groups. Can have the
|
|
754
|
+
--- following fields:
|
|
755
|
+
--- - <search> - highlight group for search matches. Default: |hl-Search|.
|
|
756
|
+
MiniMap.gen_integration.builtin_search = function(hl_groups)
|
|
757
|
+
if hl_groups == nil then hl_groups = { search = 'Search' } end
|
|
758
|
+
|
|
759
|
+
-- Update when necessary. Not ideal, because it won't react on `n/N/*`, etc.
|
|
760
|
+
-- See https://github.com/neovim/neovim/issues/18879
|
|
761
|
+
local gr = vim.api.nvim_create_augroup('MiniMapBuiltinSearch', {})
|
|
762
|
+
local opts = { group = gr, pattern = 'hlsearch', callback = H.on_integration_update, desc = "On 'hlsearch' update" }
|
|
763
|
+
vim.api.nvim_create_autocmd('OptionSet', opts)
|
|
764
|
+
|
|
765
|
+
-- - NOTE: beware of possible https://github.com/neovim/neovim/issues/21469
|
|
766
|
+
vim.cmd([[
|
|
767
|
+
silent! call dictwatcherdel(v:, 'hlsearch', 'MiniMapOnHLSearchChanged')
|
|
768
|
+
function! MiniMapOnHLSearchChanged(d,k,z)
|
|
769
|
+
lua MiniMap.refresh(nil, { lines = false, scrollbar = false })
|
|
770
|
+
endfunction
|
|
771
|
+
call dictwatcheradd(v:, 'hlsearch', 'MiniMapOnHLSearchChanged')
|
|
772
|
+
]])
|
|
773
|
+
|
|
774
|
+
local search_hl = hl_groups.search
|
|
775
|
+
|
|
776
|
+
return function()
|
|
777
|
+
-- Do nothing of search is not active
|
|
778
|
+
if vim.v.hlsearch == 0 or not vim.o.hlsearch then return {} end
|
|
779
|
+
|
|
780
|
+
-- Do nothing if not inside source buffer (can happen in map buffer, for example)
|
|
781
|
+
if not H.is_source_buffer() then return {} end
|
|
782
|
+
|
|
783
|
+
-- Save window view to later restore, as the only way to get positions of
|
|
784
|
+
-- search matches seems to be consecutive application of `search()` and
|
|
785
|
+
-- retrieving cursor position.
|
|
786
|
+
local win_view = vim.fn.winsaveview()
|
|
787
|
+
|
|
788
|
+
vim.api.nvim_win_set_cursor(0, { 1, 0 })
|
|
789
|
+
local search_count = vim.fn.searchcount({ recompute = true, maxcount = 0 })
|
|
790
|
+
local search_pattern = vim.fn.getreg('/')
|
|
791
|
+
local line_hl = {}
|
|
792
|
+
for _ = 1, (search_count.total or 0) do
|
|
793
|
+
vim.fn.search(search_pattern)
|
|
794
|
+
table.insert(line_hl, { line = vim.fn.line('.'), hl_group = search_hl })
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
vim.fn.winrestview(win_view)
|
|
798
|
+
|
|
799
|
+
return line_hl
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
--- Builtin diagnostic
|
|
804
|
+
---
|
|
805
|
+
--- Highlight lines with matches of current diagnostic items. Items are computed
|
|
806
|
+
--- with |vim.diagnostic.get()| for current (source) buffer.
|
|
807
|
+
---
|
|
808
|
+
--- It prompts integration highlighting update on every |DiagnosticChanged| event.
|
|
809
|
+
--- Diagnostic items with higher severity (see |vim.diagnostic.severity|) have
|
|
810
|
+
--- higher highlight priority (errors will be shown over all others, etc.).
|
|
811
|
+
---
|
|
812
|
+
---@param hl_groups table|nil Table defining highlight groups. Supplied fields
|
|
813
|
+
--- also define which diagnostic severity to highlight.
|
|
814
|
+
--- Can have the following fields:
|
|
815
|
+
--- - <error> - highlight group for error items.
|
|
816
|
+
--- Default: |hl-DiagnosticFloatingError|.
|
|
817
|
+
--- - <warn> - highlight group for warning items. Default: `nil` (not shown).
|
|
818
|
+
--- - <info> - highlight group for info items. Default: `nil` (not shown).
|
|
819
|
+
--- - <hint> - highlight group for hint items. Default: `nil` (not shown).
|
|
820
|
+
---
|
|
821
|
+
---@usage >lua
|
|
822
|
+
--- -- Show all diagnostic levels
|
|
823
|
+
--- local map = require('mini.map')
|
|
824
|
+
--- local diagnostic_integration = map.gen_integration.diagnostic({
|
|
825
|
+
--- error = 'DiagnosticFloatingError',
|
|
826
|
+
--- warn = 'DiagnosticFloatingWarn',
|
|
827
|
+
--- info = 'DiagnosticFloatingInfo',
|
|
828
|
+
--- hint = 'DiagnosticFloatingHint',
|
|
829
|
+
--- })
|
|
830
|
+
--- map.setup({ integrations = { diagnostic_integration } })
|
|
831
|
+
--- <
|
|
832
|
+
MiniMap.gen_integration.diagnostic = function(hl_groups)
|
|
833
|
+
if hl_groups == nil then hl_groups = { error = 'DiagnosticFloatingError' } end
|
|
834
|
+
|
|
835
|
+
-- Precompute ordered array of supported levels. Using keys of
|
|
836
|
+
-- `severity_highlights` is not enough because higher severity should be
|
|
837
|
+
-- processed later in order to appear on top.
|
|
838
|
+
local severity_level_names = vim.tbl_filter(
|
|
839
|
+
function(x) return vim.tbl_contains(vim.tbl_keys(hl_groups), x) end,
|
|
840
|
+
{ 'error', 'warn', 'info', 'hint' }
|
|
841
|
+
)
|
|
842
|
+
local severity_data = vim.tbl_map(
|
|
843
|
+
function(x) return { severity = vim.diagnostic.severity[x:upper()], hl_group = hl_groups[x] } end,
|
|
844
|
+
severity_level_names
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
-- Refresh map when needed
|
|
848
|
+
local augroup = vim.api.nvim_create_augroup('MiniMapDiagnostics', {})
|
|
849
|
+
vim.api.nvim_create_autocmd(
|
|
850
|
+
'DiagnosticChanged',
|
|
851
|
+
{ group = augroup, callback = H.on_integration_update, desc = 'On DiagnosticChanged' }
|
|
852
|
+
)
|
|
853
|
+
|
|
854
|
+
return function()
|
|
855
|
+
local line_hl = {}
|
|
856
|
+
local diagnostic_arr = vim.diagnostic.get(MiniMap.current.buf_data.source)
|
|
857
|
+
for _, data in ipairs(severity_data) do
|
|
858
|
+
local severity_diagnostic_arr = vim.tbl_filter(function(x) return x.severity == data.severity end, diagnostic_arr)
|
|
859
|
+
for _, diag in ipairs(severity_diagnostic_arr) do
|
|
860
|
+
-- Add all diagnostic lines to highlight
|
|
861
|
+
for i = diag.lnum, diag.end_lnum do
|
|
862
|
+
table.insert(line_hl, { line = i + 1, hl_group = data.hl_group })
|
|
863
|
+
end
|
|
864
|
+
end
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
return line_hl
|
|
868
|
+
end
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
--- General diff hunks from |mini.diff|
|
|
872
|
+
---
|
|
873
|
+
--- Highlight lines which are part of current diff.
|
|
874
|
+
--- Requires |mini.diff| as dependency.
|
|
875
|
+
---
|
|
876
|
+
---@param hl_groups table|nil Table defining highlight groups. If `nil` (not
|
|
877
|
+
--- supplied), this status is not highlighted. Can have the following fields:
|
|
878
|
+
--- - <add> - group name for "add" hunks. Default: "MiniDiffSignAdd".
|
|
879
|
+
--- - <change> - group name for "change" hunks. Default: "MiniDiffSignChange".
|
|
880
|
+
--- - <delete> - group name for "delete" hunks. Default: "MiniDiffSignDelete".
|
|
881
|
+
MiniMap.gen_integration.diff = function(hl_groups)
|
|
882
|
+
if hl_groups == nil then
|
|
883
|
+
hl_groups = { add = 'MiniDiffSignAdd', change = 'MiniDiffSignChange', delete = 'MiniDiffSignDelete' }
|
|
884
|
+
end
|
|
885
|
+
|
|
886
|
+
local augroup = vim.api.nvim_create_augroup('MiniMapDiff', {})
|
|
887
|
+
vim.api.nvim_create_autocmd(
|
|
888
|
+
'User',
|
|
889
|
+
{ group = augroup, pattern = 'MiniDiffUpdated', callback = H.on_integration_update, desc = 'On MiniDiffUpdated' }
|
|
890
|
+
)
|
|
891
|
+
|
|
892
|
+
return function()
|
|
893
|
+
local has_diff, diff = pcall(require, 'mini.diff')
|
|
894
|
+
if not has_diff or diff == nil then return {} end
|
|
895
|
+
|
|
896
|
+
local has_buf_data, buf_data = pcall(diff.get_buf_data, MiniMap.current.buf_data.source)
|
|
897
|
+
if not has_buf_data or buf_data == nil then return {} end
|
|
898
|
+
|
|
899
|
+
return H.hunks_to_line_hl(buf_data.hunks, hl_groups)
|
|
900
|
+
end
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
--- Hunks from `lewis6991/gitsigns.nvim`
|
|
904
|
+
---
|
|
905
|
+
--- Highlight lines which have non-trivial Git status.
|
|
906
|
+
--- Requires [lewis6991/gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim).
|
|
907
|
+
---
|
|
908
|
+
---@param hl_groups table|nil Table defining highlight groups. If `nil` (not
|
|
909
|
+
--- supplied), this status is not highlighted. Can have the following fields:
|
|
910
|
+
--- - <add> - group name for added lines. Default: "GitSignsAdd".
|
|
911
|
+
--- - <change> - group name for changed lines. Default: "GitSignsChange".
|
|
912
|
+
--- - <delete> - group name for deleted lines. Default: "GitSignsDelete".
|
|
913
|
+
MiniMap.gen_integration.gitsigns = function(hl_groups)
|
|
914
|
+
if hl_groups == nil then hl_groups = { add = 'GitSignsAdd', change = 'GitSignsChange', delete = 'GitSignsDelete' } end
|
|
915
|
+
|
|
916
|
+
local augroup = vim.api.nvim_create_augroup('MiniMapGitsigns', {})
|
|
917
|
+
vim.api.nvim_create_autocmd(
|
|
918
|
+
'User',
|
|
919
|
+
{ group = augroup, pattern = 'GitSignsUpdate', callback = H.on_integration_update, desc = 'On GitSignsUpdate' }
|
|
920
|
+
)
|
|
921
|
+
|
|
922
|
+
return function()
|
|
923
|
+
local has_gitsigns, gitsigns = pcall(require, 'gitsigns')
|
|
924
|
+
if not has_gitsigns or gitsigns == nil then return {} end
|
|
925
|
+
|
|
926
|
+
local has_hunks, hunks = pcall(gitsigns.get_hunks, MiniMap.current.buf_data.source)
|
|
927
|
+
if not has_hunks or hunks == nil then return {} end
|
|
928
|
+
|
|
929
|
+
local diff_hunks = {}
|
|
930
|
+
for _, h in ipairs(hunks) do
|
|
931
|
+
--stylua: ignore
|
|
932
|
+
table.insert( diff_hunks, {
|
|
933
|
+
type = h.type,
|
|
934
|
+
buf_start = h.added.start, buf_count = h.added.count,
|
|
935
|
+
ref_start = h.removed.start, ref_count = h.removed.count,
|
|
936
|
+
})
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
return H.hunks_to_line_hl(diff_hunks, hl_groups)
|
|
940
|
+
end
|
|
941
|
+
end
|
|
942
|
+
|
|
943
|
+
-- Helper data ================================================================
|
|
944
|
+
-- Module default config
|
|
945
|
+
H.default_config = vim.deepcopy(MiniMap.config)
|
|
946
|
+
|
|
947
|
+
-- Cache for various operations
|
|
948
|
+
H.cache = {
|
|
949
|
+
-- Data about previous window. Used for focus related computations.
|
|
950
|
+
previous_win = {},
|
|
951
|
+
|
|
952
|
+
-- Table with information used for latest buffer lines encoding. Used for
|
|
953
|
+
-- quick conversion between source and map coordinates.
|
|
954
|
+
encode_data = {},
|
|
955
|
+
|
|
956
|
+
-- Table with information about scrollbar. Used for quick scrollbar related
|
|
957
|
+
-- computations.
|
|
958
|
+
scrollbar_data = { view = {}, line = nil },
|
|
959
|
+
|
|
960
|
+
-- Number of cursor movements inside map buffer since focusing. Needed to not
|
|
961
|
+
-- update source buffer view just after focusing.
|
|
962
|
+
n_map_cursor_moves = 0,
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
H.ns_id = {
|
|
966
|
+
integrations = vim.api.nvim_create_namespace('MiniMapIntegrations'),
|
|
967
|
+
scroll_view = vim.api.nvim_create_namespace('MiniMapScrollView'),
|
|
968
|
+
scroll_line = vim.api.nvim_create_namespace('MiniMapScrollLine'),
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
--stylua: ignore start
|
|
972
|
+
H.block_symbols = {}
|
|
973
|
+
|
|
974
|
+
H.block_symbols['1x2'] = { ' ', '▌', '▐', '█', resolution = { row = 1, col = 2 } }
|
|
975
|
+
|
|
976
|
+
H.block_symbols['2x1'] = { ' ', '▀', '▄', '█', resolution = { row = 2, col = 1 } }
|
|
977
|
+
|
|
978
|
+
H.block_symbols['2x2'] = {
|
|
979
|
+
' ', '▘', '▝', '▀', '▖', '▌', '▞', '▛', '▗', '▚', '▐', '▜', '▄', '▙', '▟', '█',
|
|
980
|
+
resolution = { row = 2, col = 2 },
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
H.block_symbols['3x2'] = {
|
|
984
|
+
' ', '🬀', '🬁', '🬂', '🬃', '🬄', '🬅', '🬆', '🬇', '🬈', '🬉', '🬊', '🬋', '🬌', '🬍', '🬎',
|
|
985
|
+
'🬏', '🬐', '🬑', '🬒', '🬓', '▌', '🬔', '🬕', '🬖', '🬗', '🬘', '🬙', '🬚', '🬛', '🬜', '🬝',
|
|
986
|
+
'🬞', '🬟', '🬠', '🬡', '🬢', '🬣', '🬤', '🬥', '🬦', '🬧', '▐', '🬨', '🬩', '🬪', '🬫', '🬬',
|
|
987
|
+
'🬭', '🬮', '🬯', '🬰', '🬱', '🬲', '🬳', '🬴', '🬵', '🬶', '🬷', '🬸', '🬹', '🬺', '🬻', '█',
|
|
988
|
+
resolution = { row = 3, col = 2 },
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
H.dot_symbols = {}
|
|
992
|
+
|
|
993
|
+
H.dot_symbols['4x2'] = {
|
|
994
|
+
'⠀', '⠁', '⠈', '⠉', '⠂', '⠃', '⠊', '⠋', '⠐', '⠑', '⠘', '⠙', '⠒', '⠓', '⠚', '⠛',
|
|
995
|
+
'⠄', '⠅', '⠌', '⠍', '⠆', '⠇', '⠎', '⠏', '⠔', '⠕', '⠜', '⠝', '⠖', '⠗', '⠞', '⠟',
|
|
996
|
+
'⠠', '⠡', '⠨', '⠩', '⠢', '⠣', '⠪', '⠫', '⠰', '⠱', '⠸', '⠹', '⠲', '⠳', '⠺', '⠻',
|
|
997
|
+
'⠤', '⠥', '⠬', '⠭', '⠦', '⠧', '⠮', '⠯', '⠴', '⠵', '⠼', '⠽', '⠶', '⠷', '⠾', '⠿',
|
|
998
|
+
'⡀', '⡁', '⡈', '⡉', '⡂', '⡃', '⡊', '⡋', '⡐', '⡑', '⡘', '⡙', '⡒', '⡓', '⡚', '⡛',
|
|
999
|
+
'⡄', '⡅', '⡌', '⡍', '⡆', '⡇', '⡎', '⡏', '⡔', '⡕', '⡜', '⡝', '⡖', '⡗', '⡞', '⡟',
|
|
1000
|
+
'⡠', '⡡', '⡨', '⡩', '⡢', '⡣', '⡪', '⡫', '⡰', '⡱', '⡸', '⡹', '⡲', '⡳', '⡺', '⡻',
|
|
1001
|
+
'⡤', '⡥', '⡬', '⡭', '⡦', '⡧', '⡮', '⡯', '⡴', '⡵', '⡼', '⡽', '⡶', '⡷', '⡾', '⡿',
|
|
1002
|
+
'⢀', '⢁', '⢈', '⢉', '⢂', '⢃', '⢊', '⢋', '⢐', '⢑', '⢘', '⢙', '⢒', '⢓', '⢚', '⢛',
|
|
1003
|
+
'⢄', '⢅', '⢌', '⢍', '⢆', '⢇', '⢎', '⢏', '⢔', '⢕', '⢜', '⢝', '⢖', '⢗', '⢞', '⢟',
|
|
1004
|
+
'⢠', '⢡', '⢨', '⢩', '⢢', '⢣', '⢪', '⢫', '⢰', '⢱', '⢸', '⢹', '⢲', '⢳', '⢺', '⢻',
|
|
1005
|
+
'⢤', '⢥', '⢬', '⢭', '⢦', '⢧', '⢮', '⢯', '⢴', '⢵', '⢼', '⢽', '⢶', '⢷', '⢾', '⢿',
|
|
1006
|
+
'⣀', '⣁', '⣈', '⣉', '⣂', '⣃', '⣊', '⣋', '⣐', '⣑', '⣘', '⣙', '⣒', '⣓', '⣚', '⣛',
|
|
1007
|
+
'⣄', '⣅', '⣌', '⣍', '⣆', '⣇', '⣎', '⣏', '⣔', '⣕', '⣜', '⣝', '⣖', '⣗', '⣞', '⣟',
|
|
1008
|
+
'⣠', '⣡', '⣨', '⣩', '⣢', '⣣', '⣪', '⣫', '⣰', '⣱', '⣸', '⣹', '⣲', '⣳', '⣺', '⣻',
|
|
1009
|
+
'⣤', '⣥', '⣬', '⣭', '⣦', '⣧', '⣮', '⣯', '⣴', '⣵', '⣼', '⣽', '⣶', '⣷', '⣾', '⣿',
|
|
1010
|
+
resolution = { row = 4, col = 2 },
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
H.dot_symbols['3x2'] = { resolution = { row = 3, col = 2 } }
|
|
1014
|
+
for i = 1,64 do H.dot_symbols['3x2'][i] = H.dot_symbols['4x2'][i] end
|
|
1015
|
+
|
|
1016
|
+
H.shade_symbols = {}
|
|
1017
|
+
|
|
1018
|
+
H.shade_symbols['2x1'] = { '░', '▒', '▒', '▓', resolution = { row = 2, col = 1 } }
|
|
1019
|
+
|
|
1020
|
+
H.shade_symbols['1x2'] = { '░', '▒', '▒', '▓', resolution = { row = 1, col = 2 } }
|
|
1021
|
+
|
|
1022
|
+
H.default_symbols = H.block_symbols['3x2']
|
|
1023
|
+
--stylua: ignore end
|
|
1024
|
+
|
|
1025
|
+
-- Helper functionality =======================================================
|
|
1026
|
+
-- Settings -------------------------------------------------------------------
|
|
1027
|
+
H.setup_config = function(config)
|
|
1028
|
+
H.check_type('config', config, 'table', true)
|
|
1029
|
+
config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})
|
|
1030
|
+
|
|
1031
|
+
local ok_integrations, msg_integrations = H.is_valid_config_integrations(config.integrations, 'integrations')
|
|
1032
|
+
if not ok_integrations then H.error(msg_integrations) end
|
|
1033
|
+
|
|
1034
|
+
local ok_symbols, msg_symbols = H.is_valid_config_symbols(config.symbols, 'symbols')
|
|
1035
|
+
if not ok_symbols then H.error(msg_symbols) end
|
|
1036
|
+
|
|
1037
|
+
local ok_window, msg_window = H.is_valid_config_window(config.window, 'window')
|
|
1038
|
+
if not ok_window then H.error(msg_window) end
|
|
1039
|
+
|
|
1040
|
+
return config
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
H.apply_config = function(config) MiniMap.config = config end
|
|
1044
|
+
|
|
1045
|
+
H.create_autocommands = function()
|
|
1046
|
+
local gr = vim.api.nvim_create_augroup('MiniMap', {})
|
|
1047
|
+
|
|
1048
|
+
local au = function(event, pattern, callback, desc)
|
|
1049
|
+
vim.api.nvim_create_autocmd(event, { group = gr, pattern = pattern, callback = callback, desc = desc })
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
au({ 'BufEnter', 'BufWritePost', 'TextChanged', 'VimResized' }, '*', H.on_content_change, 'On content change')
|
|
1053
|
+
au({ 'CursorMoved', 'WinScrolled' }, '*', H.on_view_change, 'On view change')
|
|
1054
|
+
au('WinLeave', '*', H.on_winleave, 'On WinLeave')
|
|
1055
|
+
au('WinClosed', '*', H.on_winclosed, 'On WinClosed')
|
|
1056
|
+
au('ModeChanged', '*:n', H.on_content_change, 'On return to Normal mode')
|
|
1057
|
+
au('ColorScheme', '*', H.create_default_hl, 'Ensure colors')
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
--stylua: ignore
|
|
1061
|
+
H.create_default_hl = function()
|
|
1062
|
+
local set_default_hl = function(name, data)
|
|
1063
|
+
data.default = true
|
|
1064
|
+
vim.api.nvim_set_hl(0, name, data)
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1067
|
+
set_default_hl('MiniMapNormal', { link = 'NormalFloat' })
|
|
1068
|
+
set_default_hl('MiniMapSymbolCount', { link = 'Special' })
|
|
1069
|
+
set_default_hl('MiniMapSymbolLine', { link = 'Title' })
|
|
1070
|
+
set_default_hl('MiniMapSymbolView', { link = 'Delimiter' })
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
H.is_disabled = function() return vim.g.minimap_disable == true or vim.b.minimap_disable == true end
|
|
1074
|
+
|
|
1075
|
+
H.get_config = function(config)
|
|
1076
|
+
return vim.tbl_deep_extend('force', MiniMap.config, vim.b.minimap_config or {}, config or {})
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
-- Autocommands ---------------------------------------------------------------
|
|
1080
|
+
H.on_content_change = vim.schedule_wrap(function()
|
|
1081
|
+
-- Using `vim.schedule_wrap()` helps computing more precise buffer data.
|
|
1082
|
+
-- Example: if omitted, terminal buffer is recognized as normal and thus map
|
|
1083
|
+
-- is updated.
|
|
1084
|
+
if not H.is_proper_buftype() then return end
|
|
1085
|
+
MiniMap.refresh()
|
|
1086
|
+
end)
|
|
1087
|
+
|
|
1088
|
+
H.on_view_change = vim.schedule_wrap(function()
|
|
1089
|
+
if not (H.is_proper_buftype() and H.is_source_buffer()) then return end
|
|
1090
|
+
MiniMap.refresh({}, { integrations = false, lines = false })
|
|
1091
|
+
end)
|
|
1092
|
+
|
|
1093
|
+
H.on_integration_update = vim.schedule_wrap(function()
|
|
1094
|
+
if not (H.is_proper_buftype() and H.is_source_buffer()) then return end
|
|
1095
|
+
MiniMap.refresh({}, { lines = false, scrollbar = false })
|
|
1096
|
+
end)
|
|
1097
|
+
|
|
1098
|
+
H.on_winleave = function()
|
|
1099
|
+
if not (H.is_proper_buftype() and H.is_source_buffer()) then return end
|
|
1100
|
+
|
|
1101
|
+
H.cache.previous_win.id = vim.api.nvim_get_current_win()
|
|
1102
|
+
H.cache.previous_win.cursor = vim.api.nvim_win_get_cursor(0)
|
|
1103
|
+
end
|
|
1104
|
+
|
|
1105
|
+
H.on_winclosed = function(data)
|
|
1106
|
+
-- Ensure that `H.cache.previous_win` always points to a valid normal window
|
|
1107
|
+
local ok, closed_win_id = pcall(tonumber, data.match)
|
|
1108
|
+
if not ok or closed_win_id ~= H.cache.previous_win.id then return end
|
|
1109
|
+
|
|
1110
|
+
for _, win_id in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
|
1111
|
+
if win_id ~= closed_win_id and vim.api.nvim_win_get_config(win_id).relative == '' then
|
|
1112
|
+
H.cache.previous_win = { id = win_id }
|
|
1113
|
+
return
|
|
1114
|
+
end
|
|
1115
|
+
end
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
H.track_map_cursor = function()
|
|
1119
|
+
-- Operate only inside map window but not just after focusing
|
|
1120
|
+
H.cache.n_map_cursor_moves = H.cache.n_map_cursor_moves + 1
|
|
1121
|
+
local cur_win, map_win = vim.api.nvim_get_current_win(), H.get_current_map_win()
|
|
1122
|
+
if cur_win ~= map_win or H.cache.n_map_cursor_moves <= 1 then return end
|
|
1123
|
+
|
|
1124
|
+
-- Don't allow putting cursor inside offset (where scrollbar is)
|
|
1125
|
+
local cur_pos = vim.api.nvim_win_get_cursor(map_win)
|
|
1126
|
+
if cur_pos[2] < H.cache.scrollbar_data.offset then
|
|
1127
|
+
vim.api.nvim_win_set_cursor(map_win, { cur_pos[1], H.cache.scrollbar_data.offset })
|
|
1128
|
+
end
|
|
1129
|
+
|
|
1130
|
+
-- Synchronize cursors in map and previous window
|
|
1131
|
+
local prev_win_id = H.cache.previous_win.id
|
|
1132
|
+
if prev_win_id == nil then return end
|
|
1133
|
+
|
|
1134
|
+
vim.api.nvim_win_set_cursor(prev_win_id, { H.mapline_to_sourceline(cur_pos[1]), 0 })
|
|
1135
|
+
|
|
1136
|
+
-- Open just enough folds and center cursor
|
|
1137
|
+
vim.api.nvim_win_call(prev_win_id, function() vim.cmd('normal! zvzz') end)
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1140
|
+
H.on_map_enter = function()
|
|
1141
|
+
-- Check if anything is present (window can be not opened because there is
|
|
1142
|
+
-- one buffer, but many possible windows; so this can be executed on second
|
|
1143
|
+
-- `MiniMap.open()` without opened window)
|
|
1144
|
+
if not H.is_window_open() or H.cache.previous_win.cursor == nil then return end
|
|
1145
|
+
|
|
1146
|
+
-- Put cursor in map window at line indicator to the right of scrollbar
|
|
1147
|
+
local map_line = H.sourceline_to_mapline(H.cache.previous_win.cursor[1])
|
|
1148
|
+
local win_id = H.get_current_map_win()
|
|
1149
|
+
|
|
1150
|
+
vim.api.nvim_win_set_cursor(win_id, { map_line, H.cache.scrollbar_data.offset })
|
|
1151
|
+
|
|
1152
|
+
-- Reset number of cursor moves to later check if should track cursor move
|
|
1153
|
+
H.cache.n_map_cursor_moves = 0
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
-- Work with mask -------------------------------------------------------------
|
|
1157
|
+
---@param strings table Array of strings
|
|
1158
|
+
---@return table Non-whitespace mask, boolean 2d array. Each row corresponds to
|
|
1159
|
+
--- string, each column - to whether character with that number is a
|
|
1160
|
+
--- non-whitespace. Respects multibyte characters.
|
|
1161
|
+
---@private
|
|
1162
|
+
H.mask_from_strings = function(strings, _)
|
|
1163
|
+
local tab_space = string.rep(' ', vim.o.tabstop)
|
|
1164
|
+
|
|
1165
|
+
local res = {}
|
|
1166
|
+
for i, s in ipairs(strings) do
|
|
1167
|
+
-- Expand tabs into spaces
|
|
1168
|
+
local s_ext = s:gsub('\t', tab_space)
|
|
1169
|
+
local n_cols = H.str_width(s_ext)
|
|
1170
|
+
local mask_row = H.tbl_repeat(true, n_cols)
|
|
1171
|
+
|
|
1172
|
+
-- Detect whitespace
|
|
1173
|
+
s_ext:gsub('()%s', function(j) mask_row[H.str_utfindex(s_ext, j)] = false end)
|
|
1174
|
+
res[i] = mask_row
|
|
1175
|
+
end
|
|
1176
|
+
|
|
1177
|
+
return res
|
|
1178
|
+
end
|
|
1179
|
+
|
|
1180
|
+
---@param mask table Boolean 2d array.
|
|
1181
|
+
---@return table Boolean 2d array rescaled to be shown by symbols:
|
|
1182
|
+
--- `opts.n_rows` lines and `opts.n_cols` within a row.
|
|
1183
|
+
---@private
|
|
1184
|
+
H.mask_rescale = function(mask, opts)
|
|
1185
|
+
-- Infer output number of rows and columns. Should be multiples of
|
|
1186
|
+
-- `symbols.resolution.row` and `symbols.resolution.col` respectively.
|
|
1187
|
+
local source_rows = #mask
|
|
1188
|
+
local source_cols = 0
|
|
1189
|
+
for _, m_row in ipairs(mask) do
|
|
1190
|
+
source_cols = math.max(source_cols, #m_row)
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
-- Compute effective number of rows and columns in output such that it can
|
|
1194
|
+
-- contain all encoded symbols (taking into account their resolution).
|
|
1195
|
+
-- Don't make it a multiple of resolution at this stage because it can later
|
|
1196
|
+
-- lead to inaccurate representation in some cases. Like with small source
|
|
1197
|
+
-- number of rows it will lead to conversion coefficients greater than 1
|
|
1198
|
+
-- (because `math.ceil()` should be used to round for resolution) and some
|
|
1199
|
+
-- rows in the middle of output will be skipped.
|
|
1200
|
+
local resolution = opts.symbols.resolution
|
|
1201
|
+
local n_rows = math.min(source_rows, opts.n_rows * resolution.row)
|
|
1202
|
+
local n_cols = math.min(source_cols, opts.n_cols * resolution.col)
|
|
1203
|
+
|
|
1204
|
+
-- Rescale. It uses unequal but optimal bins to map source lines/columns to
|
|
1205
|
+
-- boolean encoding (has target dimensions but multiplied by resolution).
|
|
1206
|
+
-- Value within 2d-bin is `true` if at least one value within it is `true`.
|
|
1207
|
+
local res = {}
|
|
1208
|
+
for i = 1, n_rows do
|
|
1209
|
+
res[i] = H.tbl_repeat(false, n_cols)
|
|
1210
|
+
end
|
|
1211
|
+
|
|
1212
|
+
local rows_coeff, cols_coeff = n_rows / source_rows, n_cols / source_cols
|
|
1213
|
+
|
|
1214
|
+
for i, m_row in ipairs(mask) do
|
|
1215
|
+
for j, m in ipairs(m_row) do
|
|
1216
|
+
local res_i = math.floor((i - 1) * rows_coeff) + 1
|
|
1217
|
+
local res_j = math.floor((j - 1) * cols_coeff) + 1
|
|
1218
|
+
res[res_i][res_j] = m or res[res_i][res_j]
|
|
1219
|
+
end
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
return res
|
|
1223
|
+
end
|
|
1224
|
+
|
|
1225
|
+
--- Convert extended map mask to strings. Each bin with resolution dimensions
|
|
1226
|
+
--- is transformed into encode symbol. Single convertible `(resolution.row,
|
|
1227
|
+
--- resolution.col)` boolean mask is treated as binary digit: `true` as 1;
|
|
1228
|
+
--- `false` as 0; traversing left-right, top-bottom (top-left is lowest bit,
|
|
1229
|
+
--- bottom-right - highest).
|
|
1230
|
+
---
|
|
1231
|
+
---@param mask table Boolean 2d array to be shown as symbols.
|
|
1232
|
+
---@return table Array of strings representing input `mask`.
|
|
1233
|
+
---@private
|
|
1234
|
+
H.mask_to_symbols = function(mask, opts)
|
|
1235
|
+
local symbols = opts.symbols
|
|
1236
|
+
local row_resol, col_resol = symbols.resolution.row, symbols.resolution.col
|
|
1237
|
+
|
|
1238
|
+
local powers_of_two = {}
|
|
1239
|
+
for i = 0, (row_resol * col_resol - 1) do
|
|
1240
|
+
powers_of_two[i] = 2 ^ i
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1243
|
+
-- Assumes rectangular table
|
|
1244
|
+
local symbols_n_rows, symbols_n_cols = math.ceil(#mask / row_resol), math.ceil(#mask[1] / col_resol)
|
|
1245
|
+
|
|
1246
|
+
-- Compute symbols array indexes (start from zero)
|
|
1247
|
+
local symbol_ind = {}
|
|
1248
|
+
for i = 1, symbols_n_rows do
|
|
1249
|
+
symbol_ind[i] = H.tbl_repeat(0, symbols_n_cols)
|
|
1250
|
+
end
|
|
1251
|
+
|
|
1252
|
+
for i = 0, #mask - 1 do
|
|
1253
|
+
local row = mask[i + 1]
|
|
1254
|
+
local row_div, row_mod = math.floor(i / row_resol), i % row_resol
|
|
1255
|
+
for j = 0, #row - 1 do
|
|
1256
|
+
local col_div, col_mod = math.floor(j / col_resol), j % col_resol
|
|
1257
|
+
|
|
1258
|
+
local two_power = row_mod * col_resol + col_mod
|
|
1259
|
+
local to_add = row[j + 1] and powers_of_two[two_power] or 0
|
|
1260
|
+
|
|
1261
|
+
local sym_i, sym_j = row_div + 1, col_div + 1
|
|
1262
|
+
symbol_ind[sym_i][sym_j] = symbol_ind[sym_i][sym_j] + to_add
|
|
1263
|
+
end
|
|
1264
|
+
end
|
|
1265
|
+
|
|
1266
|
+
-- Construct symbols strings
|
|
1267
|
+
local res = {}
|
|
1268
|
+
for i, row in ipairs(symbol_ind) do
|
|
1269
|
+
local syms = vim.tbl_map(function(id) return symbols[id + 1] end, row)
|
|
1270
|
+
res[i] = table.concat(syms)
|
|
1271
|
+
end
|
|
1272
|
+
|
|
1273
|
+
return res
|
|
1274
|
+
end
|
|
1275
|
+
|
|
1276
|
+
-- Work with config -----------------------------------------------------------
|
|
1277
|
+
H.normalize_opts = function(x)
|
|
1278
|
+
x = vim.tbl_deep_extend('force', H.get_config(), MiniMap.current.opts or {}, x or {})
|
|
1279
|
+
H.validate_if(H.is_valid_opts, x, 'opts')
|
|
1280
|
+
return x
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1283
|
+
H.is_valid_opts = function(x, x_name)
|
|
1284
|
+
x_name = x_name or 'opts'
|
|
1285
|
+
|
|
1286
|
+
local ok_integrations, msg_integrations = H.is_valid_config_integrations(x.integrations, x_name .. '.integrations')
|
|
1287
|
+
if not ok_integrations then return ok_integrations, msg_integrations end
|
|
1288
|
+
|
|
1289
|
+
local ok_symbols, msg_symbols = H.is_valid_config_symbols(x.symbols, x_name .. '.symbols')
|
|
1290
|
+
if not ok_symbols then return ok_symbols, msg_symbols end
|
|
1291
|
+
|
|
1292
|
+
local ok_window, msg_window = H.is_valid_config_window(x.window, x_name .. '.window')
|
|
1293
|
+
if not ok_window then return ok_window, msg_window end
|
|
1294
|
+
|
|
1295
|
+
return true
|
|
1296
|
+
end
|
|
1297
|
+
|
|
1298
|
+
H.is_valid_config_integrations = function(x, x_name)
|
|
1299
|
+
x_name = x_name or 'config.integrations'
|
|
1300
|
+
|
|
1301
|
+
if x ~= nil then
|
|
1302
|
+
if not H.is_array_of(x, vim.is_callable) then return false, H.msg_config(x_name, 'array of callables') end
|
|
1303
|
+
end
|
|
1304
|
+
|
|
1305
|
+
return true
|
|
1306
|
+
end
|
|
1307
|
+
|
|
1308
|
+
H.is_valid_config_symbols = function(x, x_name)
|
|
1309
|
+
x_name = x_name or 'config.symbols'
|
|
1310
|
+
|
|
1311
|
+
if type(x) ~= 'table' then return false, H.msg_config(x_name, 'table') end
|
|
1312
|
+
|
|
1313
|
+
-- Encode symbols is `nil` by default
|
|
1314
|
+
if x.encode ~= nil then
|
|
1315
|
+
local ok_encode, msg_encode = H.is_encode_symbols(x.encode, x_name .. '.encode')
|
|
1316
|
+
if not ok_encode then return ok_encode, msg_encode end
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
-- Current line
|
|
1320
|
+
if not H.is_string(x.scroll_line) then return false, H.msg_config(x_name .. '.scroll_line', 'string') end
|
|
1321
|
+
|
|
1322
|
+
-- Current view
|
|
1323
|
+
if not H.is_string(x.scroll_view) then return false, H.msg_config(x_name .. '.scroll_view', 'string') end
|
|
1324
|
+
|
|
1325
|
+
return true
|
|
1326
|
+
end
|
|
1327
|
+
|
|
1328
|
+
H.is_valid_config_window = function(x, x_name)
|
|
1329
|
+
x_name = x_name or 'config.window'
|
|
1330
|
+
|
|
1331
|
+
if type(x) ~= 'table' then return false, H.msg_config(x_name, 'table') end
|
|
1332
|
+
|
|
1333
|
+
-- Focusable
|
|
1334
|
+
if type(x.focusable) ~= 'boolean' then return false, H.msg_config(x_name .. '.focusable', 'boolean') end
|
|
1335
|
+
|
|
1336
|
+
-- Side
|
|
1337
|
+
if not (x.side == 'left' or x.side == 'right') then
|
|
1338
|
+
return false, H.msg_config(x_name .. '.side', [[one of 'left', 'right']])
|
|
1339
|
+
end
|
|
1340
|
+
|
|
1341
|
+
-- Width
|
|
1342
|
+
if not (type(x.width) == 'number' and x.width > 0) then
|
|
1343
|
+
return false, H.msg_config(x_name .. '.width', 'positive number')
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
-- Show "more" integration symbols
|
|
1347
|
+
if type(x.show_integration_count) ~= 'boolean' then
|
|
1348
|
+
return false, H.msg_config(x_name .. '.show_integration_count', 'boolean')
|
|
1349
|
+
end
|
|
1350
|
+
|
|
1351
|
+
-- Window local 'winblend'
|
|
1352
|
+
if not (type(x.winblend) == 'number' and 0 <= x.winblend and x.winblend <= 100) then
|
|
1353
|
+
return false, H.msg_config(x_name .. '.winblend', 'number between 0 and 100')
|
|
1354
|
+
end
|
|
1355
|
+
|
|
1356
|
+
-- Z-index
|
|
1357
|
+
if not (type(x.zindex) == 'number' and x.zindex > 0) then
|
|
1358
|
+
return false, H.msg_config(x_name .. '.zindex', 'positive number')
|
|
1359
|
+
end
|
|
1360
|
+
|
|
1361
|
+
return true
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
H.msg_config = function(x_name, msg) return string.format('`%s` should be %s.', x_name, msg) end
|
|
1365
|
+
|
|
1366
|
+
-- Work with map window -------------------------------------------------------
|
|
1367
|
+
H.normalize_window_options = function(win_opts, full)
|
|
1368
|
+
if full == nil then full = true end
|
|
1369
|
+
|
|
1370
|
+
local has_tabline = vim.o.showtabline == 2 or (vim.o.showtabline == 1 and #vim.api.nvim_list_tabpages() > 1)
|
|
1371
|
+
local has_statusline = vim.o.laststatus > 0
|
|
1372
|
+
local anchor, col = 'NE', vim.o.columns
|
|
1373
|
+
if win_opts.side == 'left' then
|
|
1374
|
+
anchor, col = 'NW', 0
|
|
1375
|
+
end
|
|
1376
|
+
|
|
1377
|
+
local res = {
|
|
1378
|
+
relative = 'editor',
|
|
1379
|
+
anchor = anchor,
|
|
1380
|
+
row = has_tabline and 1 or 0,
|
|
1381
|
+
col = col,
|
|
1382
|
+
width = win_opts.width,
|
|
1383
|
+
-- Can be updated at `VimResized` event
|
|
1384
|
+
height = vim.o.lines - vim.o.cmdheight - (has_tabline and 1 or 0) - (has_statusline and 1 or 0),
|
|
1385
|
+
focusable = win_opts.focusable,
|
|
1386
|
+
border = 'none',
|
|
1387
|
+
zindex = win_opts.zindex,
|
|
1388
|
+
}
|
|
1389
|
+
if not full then return res end
|
|
1390
|
+
|
|
1391
|
+
res.style = 'minimal'
|
|
1392
|
+
return res
|
|
1393
|
+
end
|
|
1394
|
+
|
|
1395
|
+
H.get_current_map_win = function() return MiniMap.current.win_data[vim.api.nvim_get_current_tabpage()] end
|
|
1396
|
+
|
|
1397
|
+
H.set_current_map_win = function(win_id) MiniMap.current.win_data[vim.api.nvim_get_current_tabpage()] = win_id end
|
|
1398
|
+
|
|
1399
|
+
H.is_window_open = function()
|
|
1400
|
+
local cur_win_id = H.get_current_map_win()
|
|
1401
|
+
return cur_win_id ~= nil and vim.api.nvim_win_is_valid(cur_win_id)
|
|
1402
|
+
end
|
|
1403
|
+
|
|
1404
|
+
-- Work with map updates ------------------------------------------------------
|
|
1405
|
+
H.create_map_buffer = function()
|
|
1406
|
+
local buf_id = vim.api.nvim_create_buf(false, true)
|
|
1407
|
+
H.set_buf_name(buf_id, 'content')
|
|
1408
|
+
|
|
1409
|
+
-- Set buffer local options (which don't involve `noautocmd`)
|
|
1410
|
+
vim.bo[buf_id].filetype = 'minimap'
|
|
1411
|
+
|
|
1412
|
+
-- Make buffer local mappings
|
|
1413
|
+
vim.keymap.set('n', '<CR>', '<Cmd>lua MiniMap.toggle_focus(false)<CR>', { buffer = buf_id })
|
|
1414
|
+
vim.keymap.set('n', '<Esc>', '<Cmd>lua MiniMap.toggle_focus(true)<CR>', { buffer = buf_id })
|
|
1415
|
+
|
|
1416
|
+
-- Make buffer local autocommands
|
|
1417
|
+
vim.api.nvim_create_autocmd('BufEnter', { buffer = buf_id, callback = H.on_map_enter, desc = 'On map enter' })
|
|
1418
|
+
vim.api.nvim_create_autocmd(
|
|
1419
|
+
'CursorMoved',
|
|
1420
|
+
{ buffer = buf_id, callback = H.track_map_cursor, desc = 'Track map cursor' }
|
|
1421
|
+
)
|
|
1422
|
+
|
|
1423
|
+
-- Make buffer play nicely with other 'mini.nvim' modules
|
|
1424
|
+
vim.api.nvim_buf_set_var(buf_id, 'minicursorword_disable', true)
|
|
1425
|
+
|
|
1426
|
+
return buf_id
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
H.update_window_opts = function()
|
|
1430
|
+
local opts = MiniMap.current.opts
|
|
1431
|
+
local win_id = H.get_current_map_win()
|
|
1432
|
+
|
|
1433
|
+
-- Window config
|
|
1434
|
+
vim.api.nvim_win_set_config(win_id, H.normalize_window_options(opts.window, false))
|
|
1435
|
+
|
|
1436
|
+
-- 'winblend'
|
|
1437
|
+
vim.wo[win_id].winblend = opts.window.winblend
|
|
1438
|
+
end
|
|
1439
|
+
|
|
1440
|
+
H.update_map_lines = function()
|
|
1441
|
+
if not H.is_window_open() then return end
|
|
1442
|
+
|
|
1443
|
+
local buf_id, opts = MiniMap.current.buf_data.map, MiniMap.current.opts
|
|
1444
|
+
local win_id = H.get_current_map_win()
|
|
1445
|
+
|
|
1446
|
+
-- Compute output number of rows and columns to fit currently shown window
|
|
1447
|
+
local offset = H.cache.scrollbar_data.offset
|
|
1448
|
+
local n_cols = vim.api.nvim_win_get_width(win_id) - offset
|
|
1449
|
+
local n_rows = vim.api.nvim_win_get_height(win_id)
|
|
1450
|
+
|
|
1451
|
+
-- Encode lines from current buffer
|
|
1452
|
+
local source_buf_id = vim.api.nvim_get_current_buf()
|
|
1453
|
+
MiniMap.current.buf_data.source = source_buf_id
|
|
1454
|
+
local buf_lines = vim.api.nvim_buf_get_lines(source_buf_id, 0, -1, true)
|
|
1455
|
+
-- Ensure that current buffer has lines (can be not the case when this is
|
|
1456
|
+
-- executed asynchronously during Neovim closing)
|
|
1457
|
+
if #buf_lines == 0 then return end
|
|
1458
|
+
|
|
1459
|
+
local encode_symbols = opts.symbols.encode or H.default_symbols
|
|
1460
|
+
local source_rows, scrollbar_prefix = #buf_lines, string.rep(' ', offset)
|
|
1461
|
+
local encoded_lines, rescaled_rows, resolution_row
|
|
1462
|
+
if n_cols <= 0 then
|
|
1463
|
+
-- Case of "only scroll indicator". Needed to make scrollbar correctly
|
|
1464
|
+
-- travel from buffer top to bottom.
|
|
1465
|
+
encoded_lines = H.tbl_repeat(scrollbar_prefix, n_rows)
|
|
1466
|
+
|
|
1467
|
+
-- Note that full encoding was done with single whitespace per line
|
|
1468
|
+
rescaled_rows, resolution_row = n_rows, 1
|
|
1469
|
+
else
|
|
1470
|
+
-- Case of "full map"
|
|
1471
|
+
local encode_opts = { n_cols = n_cols, n_rows = n_rows, symbols = encode_symbols }
|
|
1472
|
+
encoded_lines = MiniMap.encode_strings(buf_lines, encode_opts)
|
|
1473
|
+
|
|
1474
|
+
-- Add whitespace for scrollbar
|
|
1475
|
+
encoded_lines = vim.tbl_map(function(x) return string.format('%s%s', scrollbar_prefix, x) end, encoded_lines)
|
|
1476
|
+
|
|
1477
|
+
-- Note that actual encoding was done
|
|
1478
|
+
resolution_row = encode_symbols.resolution.row
|
|
1479
|
+
rescaled_rows = math.min(source_rows, n_rows * resolution_row)
|
|
1480
|
+
end
|
|
1481
|
+
|
|
1482
|
+
-- Set map lines. Compute encode data in a way used in mask rescaling
|
|
1483
|
+
vim.api.nvim_buf_set_lines(buf_id, 0, -1, true, encoded_lines)
|
|
1484
|
+
|
|
1485
|
+
-- Cache encode data to speed up most frequent scrollbar computation
|
|
1486
|
+
H.cache.encode_data = {
|
|
1487
|
+
source_rows = source_rows,
|
|
1488
|
+
rescaled_rows = rescaled_rows,
|
|
1489
|
+
resolution_row = resolution_row,
|
|
1490
|
+
map_rows = #encoded_lines,
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
-- Force scrollbar update
|
|
1494
|
+
H.cache.scrollbar_data.view, H.cache.scrollbar_data.line = {}, nil
|
|
1495
|
+
end
|
|
1496
|
+
|
|
1497
|
+
H.update_map_scrollbar = function()
|
|
1498
|
+
if not H.is_window_open() then return end
|
|
1499
|
+
|
|
1500
|
+
local buf_id = MiniMap.current.buf_data.map
|
|
1501
|
+
local cur_view, cur_line = H.cache.scrollbar_data.view or {}, H.cache.scrollbar_data.line
|
|
1502
|
+
local symbols = MiniMap.current.opts.symbols
|
|
1503
|
+
|
|
1504
|
+
-- View
|
|
1505
|
+
local view = { from_line = vim.fn.line('w0'), to_line = vim.fn.line('w$') }
|
|
1506
|
+
if not (view.from_line == cur_view.from_line and view.to_line == cur_view.to_line) then
|
|
1507
|
+
local ns_id = H.ns_id.scroll_view
|
|
1508
|
+
local extmark_opts =
|
|
1509
|
+
{ virt_text = { { symbols.scroll_view, 'MiniMapSymbolView' } }, virt_text_pos = 'overlay', priority = 10 }
|
|
1510
|
+
|
|
1511
|
+
-- Remove previous view
|
|
1512
|
+
vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)
|
|
1513
|
+
|
|
1514
|
+
-- Add current view
|
|
1515
|
+
local map_from_line = H.sourceline_to_mapline(view.from_line)
|
|
1516
|
+
local map_to_line = H.sourceline_to_mapline(view.to_line)
|
|
1517
|
+
|
|
1518
|
+
for i = map_from_line, map_to_line do
|
|
1519
|
+
H.set_extmark_safely(buf_id, ns_id, i - 1, 0, extmark_opts)
|
|
1520
|
+
end
|
|
1521
|
+
|
|
1522
|
+
H.cache.scrollbar_data.view = view
|
|
1523
|
+
end
|
|
1524
|
+
|
|
1525
|
+
-- Current line
|
|
1526
|
+
local scroll_line = vim.fn.line('.')
|
|
1527
|
+
if scroll_line ~= cur_line then
|
|
1528
|
+
local ns_id = H.ns_id.scroll_line
|
|
1529
|
+
-- Set higher priority than view signs to be visible over them
|
|
1530
|
+
local extmark_opts =
|
|
1531
|
+
{ virt_text = { { symbols.scroll_line, 'MiniMapSymbolLine' } }, virt_text_pos = 'overlay', priority = 11 }
|
|
1532
|
+
|
|
1533
|
+
-- Remove previous line
|
|
1534
|
+
vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)
|
|
1535
|
+
|
|
1536
|
+
-- Add new line
|
|
1537
|
+
local map_line = H.sourceline_to_mapline(scroll_line)
|
|
1538
|
+
|
|
1539
|
+
H.set_extmark_safely(buf_id, ns_id, map_line - 1, 0, extmark_opts)
|
|
1540
|
+
H.cache.scrollbar_data.line = scroll_line
|
|
1541
|
+
end
|
|
1542
|
+
end
|
|
1543
|
+
|
|
1544
|
+
H.update_map_integrations = function()
|
|
1545
|
+
if not H.is_window_open() then return end
|
|
1546
|
+
|
|
1547
|
+
local buf_id = MiniMap.current.buf_data.map
|
|
1548
|
+
local integrations = MiniMap.current.opts.integrations or {}
|
|
1549
|
+
|
|
1550
|
+
-- Remove previous highlights and signs
|
|
1551
|
+
local ns_id = H.ns_id.integrations
|
|
1552
|
+
vim.api.nvim_buf_clear_namespace(buf_id, ns_id, 0, -1)
|
|
1553
|
+
|
|
1554
|
+
-- Do nothing more in case of pure scrollbar
|
|
1555
|
+
-- This is after removing "more" signs to allow switching to pure scrollbar
|
|
1556
|
+
-- after such were already visible
|
|
1557
|
+
if H.is_pure_scrollbar() then return end
|
|
1558
|
+
|
|
1559
|
+
-- Add line highlights. Use latest one for every map line.
|
|
1560
|
+
local line_counts = {}
|
|
1561
|
+
for _, integration in ipairs(integrations) do
|
|
1562
|
+
local line_hl = integration()
|
|
1563
|
+
for _, lh in ipairs(line_hl) do
|
|
1564
|
+
local map_line = H.sourceline_to_mapline(lh.line)
|
|
1565
|
+
local cur_count = line_counts[map_line] or 0
|
|
1566
|
+
line_counts[map_line] = cur_count + 1
|
|
1567
|
+
|
|
1568
|
+
-- Actually highlight only first map line occurrence
|
|
1569
|
+
if cur_count == 0 then H.add_line_hl(buf_id, ns_id, lh.hl_group, map_line - 1) end
|
|
1570
|
+
end
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
-- Possibly add integration counts
|
|
1574
|
+
if not MiniMap.current.opts.window.show_integration_count then return end
|
|
1575
|
+
|
|
1576
|
+
local col = H.cache.scrollbar_data.offset - 1
|
|
1577
|
+
for l, count in pairs(line_counts) do
|
|
1578
|
+
if count > 1 then
|
|
1579
|
+
local text = count > 9 and '+' or tostring(count)
|
|
1580
|
+
local extmark_opts = {
|
|
1581
|
+
virt_text = { { text, 'MiniMapSymbolCount' } },
|
|
1582
|
+
virt_text_pos = 'overlay',
|
|
1583
|
+
hl_mode = 'blend',
|
|
1584
|
+
}
|
|
1585
|
+
H.set_extmark_safely(buf_id, ns_id, l - 1, col, extmark_opts)
|
|
1586
|
+
end
|
|
1587
|
+
end
|
|
1588
|
+
end
|
|
1589
|
+
|
|
1590
|
+
H.sourceline_to_mapline = function(source_line)
|
|
1591
|
+
local data = H.cache.encode_data
|
|
1592
|
+
local coef = data.rescaled_rows / data.source_rows
|
|
1593
|
+
local rescaled_row = math.floor(coef * (source_line - 1)) + 1
|
|
1594
|
+
local res = math.floor((rescaled_row - 1) / data.resolution_row) + 1
|
|
1595
|
+
return math.min(math.max(res, 1), data.map_rows)
|
|
1596
|
+
end
|
|
1597
|
+
|
|
1598
|
+
H.mapline_to_sourceline = function(map_line)
|
|
1599
|
+
local data = H.cache.encode_data
|
|
1600
|
+
local coef = data.rescaled_rows / data.source_rows
|
|
1601
|
+
local rescaled_row = (map_line - 1) * data.resolution_row + 1
|
|
1602
|
+
local res = math.ceil((rescaled_row - 1) / coef) + 1
|
|
1603
|
+
return math.min(math.max(res, 1), data.source_rows)
|
|
1604
|
+
end
|
|
1605
|
+
|
|
1606
|
+
-- Hunks ----------------------------------------------------------------------
|
|
1607
|
+
H.hunks_to_line_hl = function(hunks, hl_groups)
|
|
1608
|
+
local res = {}
|
|
1609
|
+
for _, h in ipairs(hunks) do
|
|
1610
|
+
local from_line = h.buf_start
|
|
1611
|
+
local n_added, n_removed = h.buf_count, h.ref_count
|
|
1612
|
+
local n_lines = math.max(n_added, 1)
|
|
1613
|
+
-- Highlight similar to hunk summary logic:
|
|
1614
|
+
-- - Delete - single first line if nothing was added.
|
|
1615
|
+
-- - Change - added lines that are within first removed lines.
|
|
1616
|
+
-- - Added - added lines after first removed lines.
|
|
1617
|
+
for i = 1, n_lines do
|
|
1618
|
+
local hl_type = (n_added < i and 'delete') or (i <= n_removed and 'change' or 'add')
|
|
1619
|
+
local hl_group = hl_groups[hl_type]
|
|
1620
|
+
if hl_group ~= nil then table.insert(res, { line = from_line + i - 1, hl_group = hl_group }) end
|
|
1621
|
+
end
|
|
1622
|
+
end
|
|
1623
|
+
|
|
1624
|
+
return res
|
|
1625
|
+
end
|
|
1626
|
+
|
|
1627
|
+
-- Predicates -----------------------------------------------------------------
|
|
1628
|
+
H.is_array_of = function(x, predicate)
|
|
1629
|
+
if not H.islist(x) then return false end
|
|
1630
|
+
for _, v in ipairs(x) do
|
|
1631
|
+
if not predicate(v) then return false end
|
|
1632
|
+
end
|
|
1633
|
+
return true
|
|
1634
|
+
end
|
|
1635
|
+
|
|
1636
|
+
H.is_string = function(x) return type(x) == 'string' end
|
|
1637
|
+
|
|
1638
|
+
H.is_encode_symbols = function(x, x_name)
|
|
1639
|
+
x_name = x_name or 'symbols'
|
|
1640
|
+
|
|
1641
|
+
if type(x) ~= 'table' then return false, H.msg_config(x_name, 'table') end
|
|
1642
|
+
if type(x.resolution) ~= 'table' then return false, H.msg_config(x_name .. '.resolution', 'table') end
|
|
1643
|
+
if type(x.resolution.col) ~= 'number' then return false, H.msg_config(x_name .. '.resolution.col', 'number') end
|
|
1644
|
+
if type(x.resolution.row) ~= 'number' then return false, H.msg_config(x_name .. '.resolution.row', 'number') end
|
|
1645
|
+
|
|
1646
|
+
local two_power = x.resolution.col * x.resolution.row
|
|
1647
|
+
for i = 1, 2 ^ two_power do
|
|
1648
|
+
if not H.is_string(x[i]) then return false, H.msg_config(string.format('%s[%d]', x_name, i), 'string') end
|
|
1649
|
+
end
|
|
1650
|
+
|
|
1651
|
+
return true
|
|
1652
|
+
end
|
|
1653
|
+
|
|
1654
|
+
H.is_proper_buftype = function()
|
|
1655
|
+
local buf_type = vim.bo.buftype
|
|
1656
|
+
return buf_type == '' or buf_type == 'help'
|
|
1657
|
+
end
|
|
1658
|
+
|
|
1659
|
+
H.is_source_buffer = function() return vim.api.nvim_get_current_buf() == MiniMap.current.buf_data.source end
|
|
1660
|
+
|
|
1661
|
+
H.is_pure_scrollbar = function()
|
|
1662
|
+
local win_id = H.get_current_map_win()
|
|
1663
|
+
local offset = H.cache.scrollbar_data.offset
|
|
1664
|
+
return vim.api.nvim_win_get_width(win_id) <= offset
|
|
1665
|
+
end
|
|
1666
|
+
|
|
1667
|
+
-- Utilities ------------------------------------------------------------------
|
|
1668
|
+
H.error = function(msg) error('(mini.map) ' .. msg, 0) end
|
|
1669
|
+
|
|
1670
|
+
H.check_type = function(name, val, ref, allow_nil)
|
|
1671
|
+
if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
|
|
1672
|
+
H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
|
|
1673
|
+
end
|
|
1674
|
+
|
|
1675
|
+
H.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minimap://' .. buf_id .. '/' .. name) end
|
|
1676
|
+
|
|
1677
|
+
H.validate_if = function(predicate, x, x_name)
|
|
1678
|
+
local is_valid, msg = predicate(x, x_name)
|
|
1679
|
+
if not is_valid then H.error(msg) end
|
|
1680
|
+
end
|
|
1681
|
+
|
|
1682
|
+
H.add_line_hl = function(buf_id, ns_id, hl_group, line)
|
|
1683
|
+
H.set_extmark_safely(buf_id, ns_id, line, H.cache.scrollbar_data.offset, {
|
|
1684
|
+
hl_group = hl_group,
|
|
1685
|
+
end_row = line + 1,
|
|
1686
|
+
end_col = 0,
|
|
1687
|
+
strict = false,
|
|
1688
|
+
})
|
|
1689
|
+
end
|
|
1690
|
+
|
|
1691
|
+
H.set_extmark_safely = function(...) pcall(vim.api.nvim_buf_set_extmark, ...) end
|
|
1692
|
+
|
|
1693
|
+
H.str_utfindex = function(s, i) return vim.str_utfindex(s, 'utf-32', i) end
|
|
1694
|
+
if vim.fn.has('nvim-0.11') == 0 then H.str_utfindex = function(s, i) return (vim.str_utfindex(s, i)) end end
|
|
1695
|
+
|
|
1696
|
+
H.str_width = function(x) return H.str_utfindex(x) end
|
|
1697
|
+
|
|
1698
|
+
H.tbl_repeat = function(x, n)
|
|
1699
|
+
local res = {}
|
|
1700
|
+
for _ = 1, n do
|
|
1701
|
+
table.insert(res, x)
|
|
1702
|
+
end
|
|
1703
|
+
return res
|
|
1704
|
+
end
|
|
1705
|
+
|
|
1706
|
+
-- TODO: Remove after compatibility with Neovim=0.9 is dropped
|
|
1707
|
+
H.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist
|
|
1708
|
+
|
|
1709
|
+
return MiniMap
|