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,1660 @@
|
|
|
1
|
+
--- *mini.deps* Plugin manager
|
|
2
|
+
---
|
|
3
|
+
--- MIT License Copyright (c) 2024 Evgeni Chasnovski
|
|
4
|
+
|
|
5
|
+
--- *MiniDeps-dev-freeze*
|
|
6
|
+
--- As Neovim=0.12 introduced a built-in plugin manager |vim.pack| (which used this
|
|
7
|
+
--- module as a design reference), development of |mini.deps| is frozen. It means:
|
|
8
|
+
---
|
|
9
|
+
--- - On Neovim>=0.12 it is recommended to use |vim.pack| for plugin management
|
|
10
|
+
--- and |MiniMisc.safely()| as |MiniDeps.now()| and |MiniDeps.later()| alternative.
|
|
11
|
+
--- See https://echasnovski.com/vim-pack-guide for more details, including
|
|
12
|
+
--- recommendations about migration from |mini.deps|.
|
|
13
|
+
---
|
|
14
|
+
--- - This module will remain a part of |mini.nvim| at least until Neovim=0.11 is
|
|
15
|
+
--- supported. It might receive critical fixes, but likely no new features.
|
|
16
|
+
---
|
|
17
|
+
--- Features:
|
|
18
|
+
---
|
|
19
|
+
--- - Manage plugins utilizing Git and built-in |packages| with these actions:
|
|
20
|
+
--- - Add plugin to current session, download if absent. See |MiniDeps.add()|.
|
|
21
|
+
--- - Update with/without confirm, with/without parallel download of new data.
|
|
22
|
+
--- See |MiniDeps.update()|.
|
|
23
|
+
--- - Delete unused plugins with/without confirm. See |MiniDeps.clean()|.
|
|
24
|
+
--- - Get / set / save / load snapshot. See `MiniDeps.snap_*()` functions.
|
|
25
|
+
---
|
|
26
|
+
--- All main actions are available both as Lua functions and user commands
|
|
27
|
+
--- (see |MiniDeps-commands|).
|
|
28
|
+
---
|
|
29
|
+
--- - Minimal yet flexible plugin |MiniDeps-plugin-specification|:
|
|
30
|
+
--- - Plugin source.
|
|
31
|
+
--- - Name of target plugin directory.
|
|
32
|
+
--- - Checkout target: branch, commit, tag, etc.
|
|
33
|
+
--- - Monitor branch to track updates without checking out.
|
|
34
|
+
--- - Dependencies to be set up prior to the target plugin.
|
|
35
|
+
--- - Hooks to call before/after plugin is created/changed.
|
|
36
|
+
---
|
|
37
|
+
--- - Helpers implementing two-stage startup: |MiniDeps.now()| and |MiniDeps.later()|.
|
|
38
|
+
--- See |MiniDeps-overview| for how to implement basic lazy loading with them.
|
|
39
|
+
---
|
|
40
|
+
--- What it doesn't do:
|
|
41
|
+
---
|
|
42
|
+
--- - Manage plugins which are developed without Git. The suggested approach is
|
|
43
|
+
--- to create a separate package (see |packages|).
|
|
44
|
+
---
|
|
45
|
+
--- - Provide ways to completely remove or update plugin's functionality in
|
|
46
|
+
--- current session. Although this is partially doable, it can not be done
|
|
47
|
+
--- in full (yet) because plugins can have untraceable side effects
|
|
48
|
+
--- (autocmmands, mappings, etc.).
|
|
49
|
+
--- The suggested approach is to restart Nvim.
|
|
50
|
+
---
|
|
51
|
+
--- Sources with more details:
|
|
52
|
+
--- - |MiniDeps-overview|
|
|
53
|
+
--- - |MiniDeps-plugin-specification|
|
|
54
|
+
--- - |MiniDeps-commands|
|
|
55
|
+
---
|
|
56
|
+
--- # Dependencies ~
|
|
57
|
+
---
|
|
58
|
+
--- For most of its functionality this plugin relies on `git` CLI tool.
|
|
59
|
+
--- See https://git-scm.com/ for more information about how to install it.
|
|
60
|
+
--- Actual knowledge of Git is not required but helpful.
|
|
61
|
+
---
|
|
62
|
+
--- # Setup ~
|
|
63
|
+
---
|
|
64
|
+
--- This module needs a setup with `require('mini.deps').setup({})` (replace
|
|
65
|
+
--- `{}` with your `config` table). It will create global Lua table `MiniDeps`
|
|
66
|
+
--- which you can use for scripting or manually (with `:lua MiniDeps.*`).
|
|
67
|
+
---
|
|
68
|
+
--- See |MiniDeps.config| for `config` structure and default values.
|
|
69
|
+
---
|
|
70
|
+
--- You can override runtime config settings locally to buffer inside
|
|
71
|
+
--- `vim.b.minideps_config` which should have same structure as
|
|
72
|
+
--- `MiniDeps.config`. See |mini.nvim-buffer-local-config| for more details.
|
|
73
|
+
---
|
|
74
|
+
--- # Comparisons ~
|
|
75
|
+
---
|
|
76
|
+
--- - [folke/lazy.nvim](https://github.com/folke/lazy.nvim):
|
|
77
|
+
--- - More feature-rich and complex.
|
|
78
|
+
--- - Uses table specification with dedicated functions to add plugins,
|
|
79
|
+
--- while this module uses direct function call approach
|
|
80
|
+
--- (calling |MiniDeps.add()| ensures that plugin is usable).
|
|
81
|
+
--- - Uses version tags by default, while this module is more designed towards
|
|
82
|
+
--- tracking branches. Using tags is possible too (see |MiniDeps-overview|).
|
|
83
|
+
---
|
|
84
|
+
--- - [savq/paq-nvim](https://github.com/savq/paq-nvim):
|
|
85
|
+
--- - Overall less feature-rich than this module (by design).
|
|
86
|
+
--- - Uses array of plugin specifications inside `setup()` call to define which
|
|
87
|
+
--- plugins should be installed. Requires separate `:PaqInstall` call to
|
|
88
|
+
--- actually install them. This module ensures installation on first load.
|
|
89
|
+
---
|
|
90
|
+
--- - [junegunn/vim-plug](https://github.com/junegunn/vim-plug):
|
|
91
|
+
--- - Written in Vimscript, while this module is in Lua.
|
|
92
|
+
--- - Similar approach to defining and installing plugins as `savq/paq-nvim`.
|
|
93
|
+
--- - Has basic lazy-loading built-in, while this module does not (by design).
|
|
94
|
+
---
|
|
95
|
+
--- # Highlight groups ~
|
|
96
|
+
--- *MiniDeps-hl-groups*
|
|
97
|
+
---
|
|
98
|
+
--- Highlight groups are used inside confirmation buffers after
|
|
99
|
+
--- default |MiniDeps.update()| and |MiniDeps.clean()|.
|
|
100
|
+
---
|
|
101
|
+
--- - `MiniDepsChangeAdded` - added change (commit) during update.
|
|
102
|
+
--- - `MiniDepsChangeRemoved` - removed change (commit) during update.
|
|
103
|
+
--- - `MiniDepsHint` - various hints.
|
|
104
|
+
--- - `MiniDepsInfo` - various information.
|
|
105
|
+
--- - `MiniDepsMsgBreaking` - message for (conventional commit) breaking change.
|
|
106
|
+
--- - `MiniDepsPlaceholder` - placeholder when there is no valuable information.
|
|
107
|
+
--- - `MiniDepsTitle` - various titles.
|
|
108
|
+
--- - `MiniDepsTitleError` - title when plugin had errors during update.
|
|
109
|
+
--- - `MiniDepsTitleSame` - title when plugin has no changes to update.
|
|
110
|
+
--- - `MiniDepsTitleUpdate` - title when plugin has changes to update.
|
|
111
|
+
---
|
|
112
|
+
--- To change any highlight group, set it directly with |nvim_set_hl()|.
|
|
113
|
+
---@tag MiniDeps
|
|
114
|
+
|
|
115
|
+
--- # Directory structure ~
|
|
116
|
+
---
|
|
117
|
+
--- This module uses built-in |packages| to make plugins usable in current session.
|
|
118
|
+
--- It works with "pack/deps" package inside `config.path.package` directory.
|
|
119
|
+
---
|
|
120
|
+
--- By default "opt" subdirectory is used to install optional plugins which are
|
|
121
|
+
--- loaded on demand with |MiniDeps.add()|.
|
|
122
|
+
--- Non-optional plugins in "start" subdirectory are supported but only if moved
|
|
123
|
+
--- there manually after initial install. Use it if you know what you are doing.
|
|
124
|
+
---
|
|
125
|
+
--- # Add plugin ~
|
|
126
|
+
---
|
|
127
|
+
--- Use |MiniDeps.add()| to add plugin to current session. Supply plugin's URL
|
|
128
|
+
--- source as a string or |MiniDeps-plugin-specification| in general. If plugin is
|
|
129
|
+
--- not present in "pack/deps" package, it will be created (a.k.a. installed)
|
|
130
|
+
--- before processing anything else.
|
|
131
|
+
---
|
|
132
|
+
--- The recommended way of adding a plugin is by calling |MiniDeps.add()| in the
|
|
133
|
+
--- |init.lua| file (make sure |MiniDeps.setup()| is called prior): >lua
|
|
134
|
+
---
|
|
135
|
+
--- local add = MiniDeps.add
|
|
136
|
+
---
|
|
137
|
+
--- -- Add to current session (install if absent)
|
|
138
|
+
--- add({
|
|
139
|
+
--- source = 'neovim/nvim-lspconfig',
|
|
140
|
+
--- -- Supply dependencies near target plugin
|
|
141
|
+
--- depends = { 'williamboman/mason.nvim' },
|
|
142
|
+
--- })
|
|
143
|
+
---
|
|
144
|
+
--- add({
|
|
145
|
+
--- source = 'nvim-treesitter/nvim-treesitter',
|
|
146
|
+
--- -- Use 'master' while monitoring updates in 'main'
|
|
147
|
+
--- checkout = 'master',
|
|
148
|
+
--- monitor = 'main',
|
|
149
|
+
--- -- Perform action after every checkout
|
|
150
|
+
--- hooks = { post_checkout = function() vim.cmd('TSUpdate') end },
|
|
151
|
+
--- })
|
|
152
|
+
--- -- Possible to immediately execute code which depends on the added plugin
|
|
153
|
+
--- require('nvim-treesitter.configs').setup({
|
|
154
|
+
--- ensure_installed = { 'lua', 'vimdoc' },
|
|
155
|
+
--- highlight = { enable = true },
|
|
156
|
+
--- })
|
|
157
|
+
--- <
|
|
158
|
+
--- NOTE:
|
|
159
|
+
--- - To increase performance, `add()` only ensures presence on disk and
|
|
160
|
+
--- nothing else. In particular, it doesn't ensure `opts.checkout` state.
|
|
161
|
+
--- Update or modify plugin state explicitly (see later sections).
|
|
162
|
+
---
|
|
163
|
+
--- # Lazy loading ~
|
|
164
|
+
---
|
|
165
|
+
--- Any lazy-loading is assumed to be done manually by calling |MiniDeps.add()|
|
|
166
|
+
--- at appropriate time. This module provides helpers implementing special safe
|
|
167
|
+
--- two-stage loading:
|
|
168
|
+
--- - |MiniDeps.now()| safely executes code immediately. Use it to load plugins
|
|
169
|
+
--- with UI necessary to make initial screen draw.
|
|
170
|
+
--- - |MiniDeps.later()| schedules code to be safely executed later, preserving
|
|
171
|
+
--- order. Use it (with caution) for everything else which doesn't need
|
|
172
|
+
--- precisely timed effect, as it will be executed some time soon on one of
|
|
173
|
+
--- the next event loops. >lua
|
|
174
|
+
---
|
|
175
|
+
--- local now, later = MiniDeps.now, MiniDeps.later
|
|
176
|
+
---
|
|
177
|
+
--- -- Safely execute immediately
|
|
178
|
+
--- now(function() vim.cmd('colorscheme miniwinter') end)
|
|
179
|
+
--- now(function() require('mini.statusline').setup() end)
|
|
180
|
+
---
|
|
181
|
+
--- -- Safely execute later
|
|
182
|
+
--- later(function() require('mini.pick').setup() end)
|
|
183
|
+
--- <
|
|
184
|
+
--- # Update ~
|
|
185
|
+
---
|
|
186
|
+
--- To update plugins from current session with new data from their sources,
|
|
187
|
+
--- use |:DepsUpdate|. This will download updates (utilizing multiple cores) and
|
|
188
|
+
--- show confirmation buffer. Follow instructions at its top to finish an update.
|
|
189
|
+
---
|
|
190
|
+
--- NOTE: This updates plugins on disk which most likely won't affect current
|
|
191
|
+
--- session. Restart Nvim to have them properly loaded.
|
|
192
|
+
---
|
|
193
|
+
--- # Modify ~
|
|
194
|
+
---
|
|
195
|
+
--- To change plugin's specification (like set different `checkout`, etc.):
|
|
196
|
+
--- - Update corresponding |MiniDeps.add()| call.
|
|
197
|
+
--- - Run `:DepsUpdateOffline <plugin_name>`.
|
|
198
|
+
--- - Review changes and confirm.
|
|
199
|
+
--- - Restart Nvim.
|
|
200
|
+
---
|
|
201
|
+
--- NOTE: if `add()` prior used a single source string, make sure to convert
|
|
202
|
+
--- its argument to `{ source = '<previous_argument>', checkout = '<state>'}`
|
|
203
|
+
---
|
|
204
|
+
--- # Snapshots ~
|
|
205
|
+
---
|
|
206
|
+
--- Use |:DepsSnapSave| to save state of all plugins from current session into
|
|
207
|
+
--- a snapshot file (see `config.path.snapshot`).
|
|
208
|
+
---
|
|
209
|
+
--- Use |:DepsSnapLoad| to load snapshot. This will change (without confirmation)
|
|
210
|
+
--- state on disk. Plugins present in both snapshot file and current session
|
|
211
|
+
--- will be affected. Restart Nvim to see the effect.
|
|
212
|
+
---
|
|
213
|
+
--- NOTE: loading snapshot does not change plugin's specification defined inside
|
|
214
|
+
--- |MiniDeps.add()| call. This means that next update might change plugin's state.
|
|
215
|
+
--- To make it permanent, freeze plugin in target state manually.
|
|
216
|
+
---
|
|
217
|
+
--- # Freeze ~
|
|
218
|
+
---
|
|
219
|
+
--- Modify plugin's specification to have `checkout` pointing to a static
|
|
220
|
+
--- target: tag, state (commit hash), or `'HEAD'` (to freeze in current state).
|
|
221
|
+
---
|
|
222
|
+
--- Frozen plugins will not receive updates. You can monitor any new changes from
|
|
223
|
+
--- its source by "subscribing" to `monitor` branch which will be shown inside
|
|
224
|
+
--- confirmation buffer after |:DepsUpdate|.
|
|
225
|
+
---
|
|
226
|
+
--- Example: use `checkout = 'v0.10.0'` to freeze plugin at tag "v0.10.0" while
|
|
227
|
+
--- monitoring new versions in the log from `monitor` (usually default) branch.
|
|
228
|
+
---
|
|
229
|
+
--- # Rollback ~
|
|
230
|
+
---
|
|
231
|
+
--- To roll back after an unfortunate update:
|
|
232
|
+
--- - Get identifier of latest working state:
|
|
233
|
+
--- - Use |:DepsShowLog| to see update log, look for plugin's name, and copy
|
|
234
|
+
--- identifier listed as "State before:".
|
|
235
|
+
--- - See previously saved snapshot file for plugin's name and copy
|
|
236
|
+
--- identifier next to it.
|
|
237
|
+
--- - Freeze plugin at that state while monitoring appropriate branch.
|
|
238
|
+
--- Revert to previous shape of |MiniDeps.add()| call to resume updating.
|
|
239
|
+
---
|
|
240
|
+
--- # Remove ~
|
|
241
|
+
---
|
|
242
|
+
--- - Make sure that target plugin is not registered in current session.
|
|
243
|
+
--- Usually it means removing corresponding |MiniDeps.add()| call.
|
|
244
|
+
--- - Run |:DepsClean|. This will show confirmation buffer with a list of plugins to
|
|
245
|
+
--- be deleted from disk. Follow instructions at its top to finish cleaning.
|
|
246
|
+
---
|
|
247
|
+
--- Alternatively, manually delete plugin's directory from "pack/deps" package.
|
|
248
|
+
---@tag MiniDeps-overview
|
|
249
|
+
|
|
250
|
+
--- Each plugin dependency is managed based on its specification (a.k.a. "spec").
|
|
251
|
+
--- See |MiniDeps-overview| for some examples.
|
|
252
|
+
---
|
|
253
|
+
--- Specification can be a single string which is inferred as:
|
|
254
|
+
--- - Plugin <name> if it doesn't contain "/".
|
|
255
|
+
--- - Plugin <source> otherwise.
|
|
256
|
+
---
|
|
257
|
+
--- Primarily, specification is a table with the following fields:
|
|
258
|
+
---
|
|
259
|
+
--- - <source> `(string|nil)` - field with URI of plugin source used during creation
|
|
260
|
+
--- or update. Can be anything allowed by `git clone`.
|
|
261
|
+
--- Default: `nil` to rely on source set up during install.
|
|
262
|
+
--- Notes:
|
|
263
|
+
--- - It is required for creating plugin, but can be omitted afterwards.
|
|
264
|
+
--- - As the most common case, URI of the format "user/repo" (if it contains
|
|
265
|
+
--- valid characters) is transformed into "https://github.com/user/repo".
|
|
266
|
+
---
|
|
267
|
+
--- - <name> `(string|nil)` - directory basename of where to put plugin source.
|
|
268
|
+
--- It is put in "pack/deps/opt" subdirectory of `config.path.package`.
|
|
269
|
+
--- Default: basename of <source> if it is present, otherwise should be
|
|
270
|
+
--- provided explicitly.
|
|
271
|
+
---
|
|
272
|
+
--- - <checkout> `(string|nil)` - checkout target used to set state during update.
|
|
273
|
+
--- Can be anything supported by `git checkout` - branch, commit, tag, etc.
|
|
274
|
+
--- Default: `nil` for default branch (usually "main" or "master").
|
|
275
|
+
---
|
|
276
|
+
--- - <monitor> `(string|nil)` - monitor branch used to track new changes from
|
|
277
|
+
--- different target than `checkout`. Should be a name of present Git branch.
|
|
278
|
+
--- Default: `nil` for default branch (usually "main" or "master").
|
|
279
|
+
---
|
|
280
|
+
--- - <depends> `(table|nil)` - array of plugin specifications (strings or tables)
|
|
281
|
+
--- to be added prior to the target.
|
|
282
|
+
--- Default: `nil` for no dependencies.
|
|
283
|
+
---
|
|
284
|
+
--- - <hooks> `(table|nil)` - table with callable hooks to call on certain events.
|
|
285
|
+
--- Possible hook names:
|
|
286
|
+
--- - <pre_install> - before creating plugin directory.
|
|
287
|
+
--- - <post_install> - after creating plugin directory (before |:packadd|).
|
|
288
|
+
--- - <pre_checkout> - before making change in existing plugin.
|
|
289
|
+
--- - <post_checkout> - after making change in existing plugin.
|
|
290
|
+
--- Each hook is executed with the following table as an argument:
|
|
291
|
+
--- - <path> (`string`) - absolute path to plugin's directory
|
|
292
|
+
--- (might not yet exist on disk).
|
|
293
|
+
--- - <source> (`string`) - resolved <source> from spec.
|
|
294
|
+
--- - <name> (`string`) - resolved <name> from spec.
|
|
295
|
+
--- Default: `nil` for no hooks.
|
|
296
|
+
---@tag MiniDeps-plugin-specification
|
|
297
|
+
|
|
298
|
+
--- Note: Most commands have a Lua function alternative which they rely on.
|
|
299
|
+
--- Like |:DepsAdd| uses |MiniDeps.add()|, etc.
|
|
300
|
+
---
|
|
301
|
+
--- # :DepsAdd ~
|
|
302
|
+
---
|
|
303
|
+
--- *:DepsAdd* with `user/repo` argument makes plugin https://github.com/user/repo
|
|
304
|
+
--- available in the current session (also creates it, if it is not present).
|
|
305
|
+
--- `:DepsAdd name` adds already installed plugin `name` to current session.
|
|
306
|
+
--- Accepts only single string compatible with |MiniDeps-plugin-specification|.
|
|
307
|
+
--- To add plugin in every session, put |MiniDeps.add()| in |init.lua|.
|
|
308
|
+
---
|
|
309
|
+
--- # :DepsUpdate ~
|
|
310
|
+
---
|
|
311
|
+
--- *:DepsUpdate* synchronizes plugins with their session specifications and
|
|
312
|
+
--- updates them with new changes from sources. It shows confirmation buffer in
|
|
313
|
+
--- a separate |tabpage| with information about an upcoming update to review
|
|
314
|
+
--- and (selectively) apply. See |MiniDeps.update()| for more info.
|
|
315
|
+
---
|
|
316
|
+
--- `:DepsUpdate name` updates plugin `name`. Any number of names is allowed.
|
|
317
|
+
---
|
|
318
|
+
--- `:DepsUpdate!` and `:DepsUpdate! name` update without confirmation.
|
|
319
|
+
--- You can see what was done in the log file afterwards (|:DepsShowLog|).
|
|
320
|
+
---
|
|
321
|
+
--- # :DepsUpdateOffline ~
|
|
322
|
+
---
|
|
323
|
+
--- *:DepsUpdateOffline* is same as |:DepsUpdate| but doesn't download new updates
|
|
324
|
+
--- from sources. Useful to only synchronize plugin specification in code and
|
|
325
|
+
--- on disk without unnecessary downloads.
|
|
326
|
+
---
|
|
327
|
+
--- # :DepsShowLog ~
|
|
328
|
+
---
|
|
329
|
+
--- *:DepsShowLog* opens log file to review.
|
|
330
|
+
---
|
|
331
|
+
--- # :DepsClean ~
|
|
332
|
+
---
|
|
333
|
+
--- *:DepsClean* deletes plugins from disk not added to current session. It shows
|
|
334
|
+
--- confirmation buffer in a separate |tabpage| with information about an upcoming
|
|
335
|
+
--- deletes to review and (selectively) apply. See |MiniDeps.clean()| for more info.
|
|
336
|
+
---
|
|
337
|
+
--- `:DepsClean!` deletes plugins without confirmation.
|
|
338
|
+
---
|
|
339
|
+
--- # :DepsSnapSave ~
|
|
340
|
+
---
|
|
341
|
+
--- *:DepsSnapSave* creates snapshot file in default location (see |MiniDeps.config|).
|
|
342
|
+
--- `:DepsSnapSave path` creates snapshot file at `path`.
|
|
343
|
+
---
|
|
344
|
+
--- # :DepsSnapLoad ~
|
|
345
|
+
---
|
|
346
|
+
--- *:DepsSnapLoad* loads snapshot file from default location (see |MiniDeps.config|).
|
|
347
|
+
--- `:DepsSnapLoad path` loads snapshot file at `path`.
|
|
348
|
+
---@tag MiniDeps-commands
|
|
349
|
+
|
|
350
|
+
---@diagnostic disable:undefined-field
|
|
351
|
+
---@diagnostic disable:discard-returns
|
|
352
|
+
---@diagnostic disable:unused-local
|
|
353
|
+
---@diagnostic disable:cast-local-type
|
|
354
|
+
---@diagnostic disable:undefined-doc-name
|
|
355
|
+
---@diagnostic disable:luadoc-miss-type-name
|
|
356
|
+
|
|
357
|
+
-- Module definition ==========================================================
|
|
358
|
+
local MiniDeps = {}
|
|
359
|
+
local H = {}
|
|
360
|
+
|
|
361
|
+
--- Module setup
|
|
362
|
+
---
|
|
363
|
+
--- Calling this function creates user commands described in |MiniDeps-commands|.
|
|
364
|
+
---
|
|
365
|
+
---@param config table|nil Module config table. See |MiniDeps.config|.
|
|
366
|
+
---
|
|
367
|
+
---@usage >lua
|
|
368
|
+
--- require('mini.deps').setup() -- use default config
|
|
369
|
+
--- -- OR
|
|
370
|
+
--- require('mini.deps').setup({}) -- replace {} with your config table
|
|
371
|
+
--- <
|
|
372
|
+
MiniDeps.setup = function(config)
|
|
373
|
+
-- TODO: Remove after Neovim=0.9 support is dropped
|
|
374
|
+
if vim.fn.has('nvim-0.10') == 0 then
|
|
375
|
+
vim.notify(
|
|
376
|
+
'(mini.deps) Neovim<0.10 is soft deprecated (module works but is not supported).'
|
|
377
|
+
.. " It will be deprecated after the next 'mini.nvim' release (module might not work)."
|
|
378
|
+
.. ' Please update your Neovim version.'
|
|
379
|
+
)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
-- Export module
|
|
383
|
+
_G.MiniDeps = MiniDeps
|
|
384
|
+
|
|
385
|
+
-- Setup config
|
|
386
|
+
config = H.setup_config(config)
|
|
387
|
+
|
|
388
|
+
-- Apply config
|
|
389
|
+
H.apply_config(config)
|
|
390
|
+
|
|
391
|
+
-- Define behavior
|
|
392
|
+
H.create_autocommands()
|
|
393
|
+
|
|
394
|
+
-- Create default highlighting
|
|
395
|
+
H.create_default_hl()
|
|
396
|
+
|
|
397
|
+
-- Create user commands
|
|
398
|
+
H.create_user_commands()
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
--stylua: ignore
|
|
402
|
+
--- Defaults ~
|
|
403
|
+
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
|
|
404
|
+
---@text # Job ~
|
|
405
|
+
---
|
|
406
|
+
--- `config.job` defines how CLI jobs are run.
|
|
407
|
+
---
|
|
408
|
+
--- `job.n_threads` is a maximum number of parallel jobs used when needed.
|
|
409
|
+
--- Default: 80% of all available.
|
|
410
|
+
---
|
|
411
|
+
--- `job.timeout` is a duration (in ms) from job start until it is forced to stop.
|
|
412
|
+
--- Default: 30000.
|
|
413
|
+
---
|
|
414
|
+
--- # Paths ~
|
|
415
|
+
---
|
|
416
|
+
--- `config.path` defines main paths used in this module.
|
|
417
|
+
---
|
|
418
|
+
--- `path.package` is a string with path inside which "pack/deps" package is stored
|
|
419
|
+
--- (see |MiniDeps-overview|).
|
|
420
|
+
--- Default: "site" subdirectory of "data" standard path (see |stdpath()|).
|
|
421
|
+
---
|
|
422
|
+
--- `path.snapshot` is a string with default path for snapshot.
|
|
423
|
+
--- See |:DepsSnapSave| and |:DepsSnapLoad|.
|
|
424
|
+
--- Default: "mini-deps-snap" file in "config" standard path (see |stdpath()|).
|
|
425
|
+
---
|
|
426
|
+
--- `path.log` is a string with path containing log of operations done by module.
|
|
427
|
+
--- In particular, it contains all changes done after making an update.
|
|
428
|
+
--- Default: "mini-deps.log" file in "log" standard path (see |stdpath()|).
|
|
429
|
+
---
|
|
430
|
+
--- # Silent ~
|
|
431
|
+
---
|
|
432
|
+
--- `config.silent` is a boolean controlling whether to suppress non-error feedback.
|
|
433
|
+
--- Default: `false`.
|
|
434
|
+
MiniDeps.config = {
|
|
435
|
+
-- Parameters of CLI jobs
|
|
436
|
+
job = {
|
|
437
|
+
-- Number of parallel threads to use. Default: 80% of all available.
|
|
438
|
+
n_threads = nil,
|
|
439
|
+
|
|
440
|
+
-- Timeout (in ms) for each job before force quit
|
|
441
|
+
timeout = 30000,
|
|
442
|
+
},
|
|
443
|
+
|
|
444
|
+
-- Paths describing where to store data
|
|
445
|
+
path = {
|
|
446
|
+
-- Directory for built-in package.
|
|
447
|
+
-- All plugins are actually stored in 'pack/deps' subdirectory.
|
|
448
|
+
package = vim.fn.stdpath('data') .. '/site',
|
|
449
|
+
|
|
450
|
+
-- Default file path for a snapshot
|
|
451
|
+
snapshot = vim.fn.stdpath('config') .. '/mini-deps-snap',
|
|
452
|
+
|
|
453
|
+
-- Log file
|
|
454
|
+
--minidoc_replace_start log = vim.fn.stdpath('log') .. '/mini-deps.log'
|
|
455
|
+
log = vim.fn.stdpath('log') .. '/mini-deps.log',
|
|
456
|
+
--minidoc_replace_end
|
|
457
|
+
},
|
|
458
|
+
|
|
459
|
+
-- Whether to disable showing non-error feedback
|
|
460
|
+
silent = false,
|
|
461
|
+
}
|
|
462
|
+
--minidoc_afterlines_end
|
|
463
|
+
|
|
464
|
+
--- Add plugin to current session
|
|
465
|
+
---
|
|
466
|
+
--- - Process specification by expanding dependencies into single spec array.
|
|
467
|
+
--- - Ensure plugin is present on disk along with its dependencies by installing
|
|
468
|
+
--- (in parallel) absent ones:
|
|
469
|
+
--- - Execute `opts.hooks.pre_install`.
|
|
470
|
+
--- - Use `git clone` to clone plugin from its source URI into "pack/deps/opt".
|
|
471
|
+
--- - Set state according to `opts.checkout`.
|
|
472
|
+
--- - Execute `opts.hooks.post_install`.
|
|
473
|
+
--- - Register spec(s) in current session.
|
|
474
|
+
--- - Make sure plugin(s) can be used in current session (see |:packadd|).
|
|
475
|
+
--- - If not during startup and is needed, source all "after/plugin/" scripts.
|
|
476
|
+
---
|
|
477
|
+
--- Notes:
|
|
478
|
+
--- - Presence of plugin is checked by its name which is the same as the name
|
|
479
|
+
--- of its directory inside "pack/deps" package (see |MiniDeps-overview|).
|
|
480
|
+
--- - To increase performance, this function only ensures presence on disk and
|
|
481
|
+
--- nothing else. In particular, it doesn't ensure `opts.checkout` state.
|
|
482
|
+
--- Use |MiniDeps.update()| or |:DepsUpdateOffline| explicitly.
|
|
483
|
+
--- - Adding plugin several times updates its session specs.
|
|
484
|
+
---
|
|
485
|
+
---@param spec table|string Plugin specification. See |MiniDeps-plugin-specification|.
|
|
486
|
+
---@param opts table|nil Options. Possible fields:
|
|
487
|
+
--- - <bang> `(boolean)` - whether to use `:packadd!` instead of plain |:packadd|.
|
|
488
|
+
MiniDeps.add = function(spec, opts)
|
|
489
|
+
opts = opts or {}
|
|
490
|
+
if type(opts) ~= 'table' then H.error('`opts` should be table.') end
|
|
491
|
+
if opts.source or opts.name or opts.checkout then H.error('`add()` accepts only single spec.') end
|
|
492
|
+
|
|
493
|
+
-- Normalize
|
|
494
|
+
local plugs = {}
|
|
495
|
+
H.expand_spec(plugs, spec)
|
|
496
|
+
|
|
497
|
+
-- Process
|
|
498
|
+
local plugs_to_install = {}
|
|
499
|
+
for i, p in ipairs(plugs) do
|
|
500
|
+
local path, is_present = H.get_plugin_path(p.name)
|
|
501
|
+
p.path = path
|
|
502
|
+
if not is_present then table.insert(plugs_to_install, vim.deepcopy(p)) end
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
-- Install
|
|
506
|
+
if #plugs_to_install > 0 then
|
|
507
|
+
H.ensure_git_exec()
|
|
508
|
+
for _, p in ipairs(plugs_to_install) do
|
|
509
|
+
p.job = H.cli_new_job({}, vim.fn.getcwd())
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
H.notify(string.format('Installing `%s`', plugs[#plugs].name))
|
|
513
|
+
H.plugs_exec_hooks(plugs_to_install, 'pre_install')
|
|
514
|
+
H.plugs_install(plugs_to_install)
|
|
515
|
+
H.plugs_exec_hooks(plugs_to_install, 'post_install')
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
-- Add plugins to current session
|
|
519
|
+
local cmd = 'packadd' .. (opts.bang and '!' or '') .. ' '
|
|
520
|
+
for _, p in ipairs(plugs) do
|
|
521
|
+
-- Register in 'mini.deps' session
|
|
522
|
+
table.insert(H.session, p)
|
|
523
|
+
|
|
524
|
+
-- Add to 'runtimepath'
|
|
525
|
+
vim.cmd(cmd .. p.name)
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
-- Execute 'after/' scripts if not during startup (when they will be sourced
|
|
529
|
+
-- automatically), as `:packadd` only sources plain 'plugin/' files.
|
|
530
|
+
-- See https://github.com/vim/vim/issues/1994.
|
|
531
|
+
-- Deliberately do so after executing all currently known 'plugin/' files.
|
|
532
|
+
local should_load_after_dir = vim.v.vim_did_enter == 1 and not opts.bang and vim.o.loadplugins
|
|
533
|
+
if not should_load_after_dir then return end
|
|
534
|
+
for _, p in ipairs(plugs) do
|
|
535
|
+
-- NOTE: This sources first lua and then vim, not how it is done during
|
|
536
|
+
-- startup (`:h loadplugins`) for speed (one `glob()` instead of two).
|
|
537
|
+
local after_paths = vim.fn.glob(p.path .. '/after/plugin/**/*.{vim,lua}', false, true)
|
|
538
|
+
vim.tbl_map(H.source, after_paths)
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
--- Update plugins
|
|
543
|
+
---
|
|
544
|
+
--- - Synchronize specs with state of plugins on disk (set `source`, etc.).
|
|
545
|
+
--- - Infer data before downloading updates.
|
|
546
|
+
--- - If not offline, download updates (in parallel).
|
|
547
|
+
--- - Infer data after downloading updates.
|
|
548
|
+
--- - If update is forced, apply all changes immediately while updating log
|
|
549
|
+
--- file (at `config.path.log`; use |:DepsShowLog| to review).
|
|
550
|
+
--- Otherwise show confirmation buffer with instructions on how to proceed.
|
|
551
|
+
---
|
|
552
|
+
---@param names table|nil Array of plugin names to update.
|
|
553
|
+
--- Default: all plugins from current session (see |MiniDeps.get_session()|).
|
|
554
|
+
---@param opts table|nil Options. Possible fields:
|
|
555
|
+
--- - <force> `(boolean)` - whether to force update without confirmation.
|
|
556
|
+
--- Default: `false`.
|
|
557
|
+
--- - <offline> `(boolean)` - whether to skip downloading updates from sources.
|
|
558
|
+
--- Default: `false`.
|
|
559
|
+
MiniDeps.update = function(names, opts)
|
|
560
|
+
opts = vim.tbl_deep_extend('force', { force = false, offline = false }, opts or {})
|
|
561
|
+
|
|
562
|
+
-- Compute array of plugin data to be reused in update. Each contains a CLI
|
|
563
|
+
-- job "assigned" to plugin's path which stops execution after first error.
|
|
564
|
+
local plugs = H.plugs_from_names(names)
|
|
565
|
+
if #plugs == 0 then return H.notify('Nothing to update') end
|
|
566
|
+
|
|
567
|
+
-- Prepare repositories and specifications
|
|
568
|
+
H.ensure_git_exec()
|
|
569
|
+
H.plugs_ensure_origin_source(plugs)
|
|
570
|
+
|
|
571
|
+
-- Preprocess before downloading
|
|
572
|
+
H.plugs_infer_head(plugs)
|
|
573
|
+
H.plugs_ensure_target_refs(plugs)
|
|
574
|
+
H.plugs_infer_commit(plugs, 'monitor', 'monitor_from')
|
|
575
|
+
|
|
576
|
+
-- Download data if asked
|
|
577
|
+
if not opts.offline then H.plugs_download_updates(plugs) end
|
|
578
|
+
|
|
579
|
+
-- Process data for update
|
|
580
|
+
H.plugs_infer_commit(plugs, 'checkout', 'checkout_to')
|
|
581
|
+
H.plugs_infer_commit(plugs, 'monitor', 'monitor_to')
|
|
582
|
+
H.plugs_infer_log(plugs, 'head', 'checkout_to', 'checkout_log')
|
|
583
|
+
H.plugs_infer_log(plugs, 'monitor_from', 'monitor_to', 'monitor_log')
|
|
584
|
+
|
|
585
|
+
-- Checkout if asked (before feedback to include possible checkout errors)
|
|
586
|
+
if opts.force then H.plugs_checkout(plugs) end
|
|
587
|
+
|
|
588
|
+
-- Make feedback
|
|
589
|
+
local lines = H.update_compute_feedback_lines(plugs)
|
|
590
|
+
local feedback = opts.force and H.update_feedback_log or H.update_feedback_confirm
|
|
591
|
+
feedback(lines)
|
|
592
|
+
|
|
593
|
+
-- Show job warnings and errors
|
|
594
|
+
H.plugs_show_job_notifications(plugs, 'update')
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
--- Clean plugins
|
|
598
|
+
---
|
|
599
|
+
--- - Compute absent plugins: not registered in current session
|
|
600
|
+
--- (see |MiniDeps.get_session()|) but present on disk in dedicated "pack/deps"
|
|
601
|
+
--- package (inside `config.path.package`).
|
|
602
|
+
--- - If cleaning is forced, delete all absent plugins from disk.
|
|
603
|
+
--- Otherwise show confirmation buffer with instructions on how to proceed.
|
|
604
|
+
---
|
|
605
|
+
---@param opts table|nil Options. Possible fields:
|
|
606
|
+
--- - <force> `(boolean)` - whether to force delete without confirmation.
|
|
607
|
+
--- Default: `false`.
|
|
608
|
+
MiniDeps.clean = function(opts)
|
|
609
|
+
opts = vim.tbl_deep_extend('force', { force = false }, opts or {})
|
|
610
|
+
|
|
611
|
+
-- Compute path candidates to delete
|
|
612
|
+
local is_in_session = {}
|
|
613
|
+
for _, s in ipairs(MiniDeps.get_session()) do
|
|
614
|
+
is_in_session[s.path] = true
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
local is_absent_plugin = function(x) return vim.fn.isdirectory(x) == 1 and not is_in_session[x] end
|
|
618
|
+
local absent_paths = vim.tbl_filter(is_absent_plugin, H.get_all_plugin_paths())
|
|
619
|
+
|
|
620
|
+
-- Clean
|
|
621
|
+
if #absent_paths == 0 then return H.notify('Nothing to clean') end
|
|
622
|
+
local clean_fun = opts.force and H.clean_delete or H.clean_confirm
|
|
623
|
+
clean_fun(absent_paths)
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
--- Compute snapshot
|
|
627
|
+
---
|
|
628
|
+
---@return table A snapshot table: plugin names as keys and state as values.
|
|
629
|
+
--- All plugins in current session are processed.
|
|
630
|
+
MiniDeps.snap_get = function()
|
|
631
|
+
local plugs = H.plugs_from_names()
|
|
632
|
+
H.ensure_git_exec()
|
|
633
|
+
H.plugs_infer_head(plugs)
|
|
634
|
+
H.plugs_show_job_notifications(plugs, 'computing snapshot')
|
|
635
|
+
|
|
636
|
+
local snap = {}
|
|
637
|
+
for _, p in ipairs(plugs) do
|
|
638
|
+
if p.head ~= '' then snap[p.name] = p.head end
|
|
639
|
+
end
|
|
640
|
+
return snap
|
|
641
|
+
end
|
|
642
|
+
|
|
643
|
+
--- Apply snapshot
|
|
644
|
+
---
|
|
645
|
+
--- Notes:
|
|
646
|
+
--- - Checking out states from snapshot does not update session plugin spec
|
|
647
|
+
--- (`checkout` field in particular). Among others, it means that next call
|
|
648
|
+
--- to |MiniDeps.update()| might override the result of this function.
|
|
649
|
+
--- To make changes permanent, set `checkout` spec field to state from snapshot.
|
|
650
|
+
---
|
|
651
|
+
---@param snap table A snapshot table: plugin names as keys and state as values.
|
|
652
|
+
--- Only plugins in current session are processed.
|
|
653
|
+
MiniDeps.snap_set = function(snap)
|
|
654
|
+
if type(snap) ~= 'table' then H.error('Snapshot should be a table.') end
|
|
655
|
+
|
|
656
|
+
-- Construct current session plugin data with `checkout` from snapshot
|
|
657
|
+
for k, v in pairs(snap) do
|
|
658
|
+
if not (type(k) == 'string' and type(v) == 'string') then snap[k] = nil end
|
|
659
|
+
end
|
|
660
|
+
local plugs = H.plugs_from_names(vim.tbl_keys(snap))
|
|
661
|
+
for _, p in ipairs(plugs) do
|
|
662
|
+
p.checkout = snap[p.name]
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
-- Checkout
|
|
666
|
+
H.ensure_git_exec()
|
|
667
|
+
H.plugs_checkout(plugs)
|
|
668
|
+
H.plugs_show_job_notifications(plugs, 'applying snapshot')
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
--- Save snapshot
|
|
672
|
+
---
|
|
673
|
+
---@param path string|nil A valid path on disk where to write snapshot computed
|
|
674
|
+
--- with |MiniDeps.snap_get()|.
|
|
675
|
+
--- Default: `config.path.snapshot`.
|
|
676
|
+
MiniDeps.snap_save = function(path)
|
|
677
|
+
path = path or H.full_path(H.get_config().path.snapshot)
|
|
678
|
+
if type(path) ~= 'string' then H.error('`path` should be string.') end
|
|
679
|
+
|
|
680
|
+
-- Compute snapshot
|
|
681
|
+
local snap = MiniDeps.snap_get()
|
|
682
|
+
|
|
683
|
+
-- Write snapshot
|
|
684
|
+
local lines = vim.split(vim.inspect(snap), '\n')
|
|
685
|
+
lines[1] = 'return ' .. lines[1]
|
|
686
|
+
vim.fn.mkdir(vim.fn.fnamemodify(path, ':h'), 'p')
|
|
687
|
+
vim.fn.writefile(lines, path)
|
|
688
|
+
|
|
689
|
+
H.notify('Created snapshot at ' .. vim.inspect(path))
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
--- Load snapshot file
|
|
693
|
+
---
|
|
694
|
+
--- Notes from |MiniDeps.snap_set()| also apply here.
|
|
695
|
+
---
|
|
696
|
+
---@param path string|nil A valid path on disk from where to read snapshot.
|
|
697
|
+
--- Default: `config.path.snapshot`.
|
|
698
|
+
MiniDeps.snap_load = function(path)
|
|
699
|
+
path = path or H.full_path(H.get_config().path.snapshot)
|
|
700
|
+
if vim.fn.filereadable(path) ~= 1 then H.error('`path` should be path to a readable file.') end
|
|
701
|
+
|
|
702
|
+
local ok, snap = pcall(dofile, H.full_path(path))
|
|
703
|
+
if not (ok and type(snap) == 'table') then H.error('`path` is not a path to proper snapshot.') end
|
|
704
|
+
|
|
705
|
+
MiniDeps.snap_set(snap)
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
--- Get session
|
|
709
|
+
---
|
|
710
|
+
--- Plugin is registered in current session if it either:
|
|
711
|
+
--- - Was added with |MiniDeps.add()| (preserving order of calls).
|
|
712
|
+
--- - Is a "start" plugin and present in |'runtimepath'|.
|
|
713
|
+
---
|
|
714
|
+
---@return table Array with specifications of all plugins registered in
|
|
715
|
+
--- current session.
|
|
716
|
+
MiniDeps.get_session = function()
|
|
717
|
+
-- Normalize `H.session` allowing specs for same plugin
|
|
718
|
+
local res, plugin_ids = {}, {}
|
|
719
|
+
local add_spec = function(spec)
|
|
720
|
+
local id = plugin_ids[spec.path] or (#res + 1)
|
|
721
|
+
-- Treat `depends` differently as it is an array and direct merge is bad
|
|
722
|
+
-- Also: https://github.com/neovim/neovim/pull/15094#discussion_r671663938
|
|
723
|
+
local depends = vim.deepcopy((res[id] or {}).depends or {})
|
|
724
|
+
vim.list_extend(depends, spec.depends or {})
|
|
725
|
+
res[id] = vim.tbl_deep_extend('force', res[id] or {}, spec)
|
|
726
|
+
res[id].depends = depends
|
|
727
|
+
|
|
728
|
+
plugin_ids[spec.path] = id
|
|
729
|
+
end
|
|
730
|
+
vim.tbl_map(add_spec, H.session)
|
|
731
|
+
H.session = res
|
|
732
|
+
|
|
733
|
+
-- Add 'start/' plugins that are in 'rtp'. NOTE: not whole session concept is
|
|
734
|
+
-- built around presence in 'rtp' to 100% ensure to preserve the order in
|
|
735
|
+
-- which user called `add()`.
|
|
736
|
+
local start_path = H.full_path(H.get_package_path() .. '/pack/deps/start')
|
|
737
|
+
local pattern = string.format('^%s/([^/]+)$', vim.pesc(start_path))
|
|
738
|
+
for _, runtime_path in ipairs(vim.api.nvim_list_runtime_paths()) do
|
|
739
|
+
-- Make sure plugin path is normalized (matters on Windows)
|
|
740
|
+
local path = H.full_path(runtime_path)
|
|
741
|
+
local name = string.match(path, pattern)
|
|
742
|
+
if name ~= nil then add_spec({ path = path, name = name, hooks = {}, depends = {} }) end
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
-- Return copy to not allow modification in place
|
|
746
|
+
return vim.deepcopy(res)
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
--- Execute function now
|
|
750
|
+
---
|
|
751
|
+
--- Safely execute function immediately. Errors are shown with |vim.notify()|
|
|
752
|
+
--- later, after all queued functions (including with |MiniDeps.later()|)
|
|
753
|
+
--- are executed, thus not blocking execution of next code in file.
|
|
754
|
+
---
|
|
755
|
+
--- Assumed to be used as a first step during two-stage config execution to
|
|
756
|
+
--- load plugins immediately during startup. See |MiniDeps-overview|.
|
|
757
|
+
---
|
|
758
|
+
---@param f function Callable to execute.
|
|
759
|
+
MiniDeps.now = function(f)
|
|
760
|
+
local ok, err = pcall(f)
|
|
761
|
+
if not ok then table.insert(H.cache.exec_errors, err) end
|
|
762
|
+
H.schedule_finish()
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
--- Execute function later
|
|
766
|
+
---
|
|
767
|
+
--- Queue function to be safely executed later without blocking execution of
|
|
768
|
+
--- next code in file. All queued functions are guaranteed to be executed in
|
|
769
|
+
--- order they were added.
|
|
770
|
+
--- Errors are shown with |vim.notify()| after all queued functions are executed.
|
|
771
|
+
---
|
|
772
|
+
--- Assumed to be used as a second step during two-stage config execution to
|
|
773
|
+
--- load plugins "lazily" after startup. See |MiniDeps-overview|.
|
|
774
|
+
---
|
|
775
|
+
---@param f function Callable to execute.
|
|
776
|
+
MiniDeps.later = function(f)
|
|
777
|
+
table.insert(H.cache.later_callback_queue, f)
|
|
778
|
+
H.schedule_finish()
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
-- Helper data ================================================================
|
|
782
|
+
-- Module default config
|
|
783
|
+
H.default_config = MiniDeps.config
|
|
784
|
+
|
|
785
|
+
-- Array of plugin specs
|
|
786
|
+
H.session = {}
|
|
787
|
+
|
|
788
|
+
-- Various cache
|
|
789
|
+
H.cache = {
|
|
790
|
+
-- Whether finish of `now()` or `later()` is already scheduled
|
|
791
|
+
finish_is_scheduled = false,
|
|
792
|
+
|
|
793
|
+
-- Callback queue for `later()`
|
|
794
|
+
later_callback_queue = {},
|
|
795
|
+
|
|
796
|
+
-- Errors during execution of `now()` or `later()`
|
|
797
|
+
exec_errors = {},
|
|
798
|
+
|
|
799
|
+
-- Git version
|
|
800
|
+
git_version = nil,
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
-- Helper functionality =======================================================
|
|
804
|
+
-- Settings -------------------------------------------------------------------
|
|
805
|
+
H.setup_config = function(config)
|
|
806
|
+
H.check_type('config', config, 'table', true)
|
|
807
|
+
config = vim.tbl_deep_extend('force', vim.deepcopy(H.default_config), config or {})
|
|
808
|
+
|
|
809
|
+
H.check_type('job', config.job, 'table')
|
|
810
|
+
H.check_type('job.n_threads', config.job.n_threads, 'number', true)
|
|
811
|
+
H.check_type('job.timeout', config.job.timeout, 'number')
|
|
812
|
+
|
|
813
|
+
H.check_type('path', config.path, 'table')
|
|
814
|
+
H.check_type('path.package', config.path.package, 'string')
|
|
815
|
+
H.check_type('path.snapshot', config.path.snapshot, 'string')
|
|
816
|
+
H.check_type('path.log', config.path.log, 'string')
|
|
817
|
+
|
|
818
|
+
H.check_type('silent', config.silent, 'boolean')
|
|
819
|
+
|
|
820
|
+
return config
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
H.apply_config = function(config)
|
|
824
|
+
MiniDeps.config = config
|
|
825
|
+
|
|
826
|
+
-- Reset current session to allow resourcing script with `setup()` call
|
|
827
|
+
H.session = {}
|
|
828
|
+
|
|
829
|
+
-- Add target package path to 'packpath'
|
|
830
|
+
local pack_path = H.full_path(config.path.package)
|
|
831
|
+
vim.cmd('set packpath^=' .. vim.fn.fnameescape(pack_path))
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
H.get_config = function(config)
|
|
835
|
+
return vim.tbl_deep_extend('force', MiniDeps.config, vim.b.minideps_config or {}, config or {})
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
H.create_autocommands = function()
|
|
839
|
+
local gr = vim.api.nvim_create_augroup('MiniDeps', {})
|
|
840
|
+
vim.api.nvim_create_autocmd('ColorScheme', { group = gr, callback = H.create_default_hl, desc = 'Ensure colors' })
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
--stylua: ignore
|
|
844
|
+
H.create_default_hl = function()
|
|
845
|
+
local hi = function(name, opts)
|
|
846
|
+
opts.default = true
|
|
847
|
+
vim.api.nvim_set_hl(0, name, opts)
|
|
848
|
+
end
|
|
849
|
+
|
|
850
|
+
local has_core_diff_hl = vim.fn.has('nvim-0.10') == 1
|
|
851
|
+
hi('MiniDepsChangeAdded', { link = has_core_diff_hl and 'Added' or 'diffAdded' })
|
|
852
|
+
hi('MiniDepsChangeRemoved', { link = has_core_diff_hl and 'Removed' or 'diffRemoved' })
|
|
853
|
+
hi('MiniDepsHint', { link = 'DiagnosticHint' })
|
|
854
|
+
hi('MiniDepsInfo', { link = 'DiagnosticInfo' })
|
|
855
|
+
hi('MiniDepsMsgBreaking', { link = 'DiagnosticWarn' })
|
|
856
|
+
hi('MiniDepsPlaceholder', { link = 'Comment' })
|
|
857
|
+
hi('MiniDepsTitle', { link = 'Title' })
|
|
858
|
+
hi('MiniDepsTitleError', { link = 'DiffDelete' })
|
|
859
|
+
hi('MiniDepsTitleSame', { link = 'DiffText' })
|
|
860
|
+
hi('MiniDepsTitleUpdate', { link = 'DiffAdd' })
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
H.create_user_commands = function()
|
|
864
|
+
-- Do not create commands immediately to increase startup time
|
|
865
|
+
local new_cmd = vim.schedule_wrap(vim.api.nvim_create_user_command)
|
|
866
|
+
|
|
867
|
+
local complete_session_names = function(arg, _, _)
|
|
868
|
+
local session_names = vim.tbl_map(function(s) return s.name end, MiniDeps.get_session())
|
|
869
|
+
return vim.tbl_filter(function(n) return vim.startswith(n, arg) end, session_names)
|
|
870
|
+
end
|
|
871
|
+
local complete_disk_names = function(arg, _, _)
|
|
872
|
+
local disk_names = vim.tbl_map(function(p) return vim.fn.fnamemodify(p, ':t') end, H.get_all_plugin_paths())
|
|
873
|
+
return vim.tbl_filter(function(n) return vim.startswith(n, arg) end, disk_names)
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
local add = function(input) MiniDeps.add(input.fargs[1]) end
|
|
877
|
+
new_cmd('DepsAdd', add, { nargs = '+', complete = complete_disk_names, desc = 'Add plugin to session' })
|
|
878
|
+
|
|
879
|
+
local make_update_cmd = function(name, offline, desc)
|
|
880
|
+
local callback = function(input)
|
|
881
|
+
local names
|
|
882
|
+
if #input.fargs > 0 then names = input.fargs end
|
|
883
|
+
MiniDeps.update(names, { force = input.bang, offline = offline })
|
|
884
|
+
end
|
|
885
|
+
local opts = { bang = true, complete = complete_session_names, nargs = '*', desc = desc }
|
|
886
|
+
new_cmd(name, callback, opts)
|
|
887
|
+
end
|
|
888
|
+
make_update_cmd('DepsUpdate', false, 'Update plugins')
|
|
889
|
+
make_update_cmd('DepsUpdateOffline', true, 'Update plugins without downloading from source')
|
|
890
|
+
|
|
891
|
+
local show_log = function()
|
|
892
|
+
H.edit(H.get_config().path.log)
|
|
893
|
+
H.update_add_syntax()
|
|
894
|
+
vim.cmd([[syntax match MiniDepsTitle "^\(==========\).*\1$"]])
|
|
895
|
+
end
|
|
896
|
+
new_cmd('DepsShowLog', show_log, { desc = 'Show log' })
|
|
897
|
+
|
|
898
|
+
local clean = function(input) MiniDeps.clean({ force = input.bang }) end
|
|
899
|
+
new_cmd('DepsClean', clean, { bang = true, desc = 'Delete unused plugins' })
|
|
900
|
+
|
|
901
|
+
local snap_save = function(input) MiniDeps.snap_save(input.fargs[1]) end
|
|
902
|
+
new_cmd('DepsSnapSave', snap_save, { nargs = '*', complete = 'file', desc = 'Save plugin snapshot' })
|
|
903
|
+
|
|
904
|
+
local snap_load = function(input) MiniDeps.snap_load(input.fargs[1]) end
|
|
905
|
+
new_cmd('DepsSnapLoad', snap_load, { nargs = '*', complete = 'file', desc = 'Load plugin snapshot' })
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
-- Git commands ---------------------------------------------------------------
|
|
909
|
+
H.git_cmd = function(cmd_name, ...)
|
|
910
|
+
local args = H.git_args[cmd_name](...)
|
|
911
|
+
if args == nil then return {} end
|
|
912
|
+
|
|
913
|
+
-- Use '-c gc.auto=0' to disable `stderr` "Auto packing..." messages
|
|
914
|
+
return { 'git', '-c', 'gc.auto=0', unpack(args) }
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
--stylua: ignore
|
|
918
|
+
H.git_args = {
|
|
919
|
+
version = function()
|
|
920
|
+
return { 'version' }
|
|
921
|
+
end,
|
|
922
|
+
clone = function(source, path)
|
|
923
|
+
local res = {
|
|
924
|
+
'clone', '--quiet', '--filter=blob:none',
|
|
925
|
+
'--recurse-submodules', '--also-filter-submodules', '--origin', 'origin',
|
|
926
|
+
source, path,
|
|
927
|
+
}
|
|
928
|
+
-- Use `--also-filter-submodules` only with appropriate version
|
|
929
|
+
if not (H.cache.git_version.major >= 2 and H.cache.git_version.minor >= 36) then
|
|
930
|
+
table.remove(res, 5)
|
|
931
|
+
end
|
|
932
|
+
return res
|
|
933
|
+
end,
|
|
934
|
+
stash = function(timestamp)
|
|
935
|
+
return { 'stash', '--quiet', '--message', '(mini.deps) ' .. timestamp .. ' Stash before checkout' }
|
|
936
|
+
end,
|
|
937
|
+
checkout = function(target)
|
|
938
|
+
return { 'checkout', '--quiet', target }
|
|
939
|
+
end,
|
|
940
|
+
-- Using '--tags --force' means conflicting tags will be synced with remote
|
|
941
|
+
fetch = function()
|
|
942
|
+
return { 'fetch', '--quiet', '--tags', '--force', '--recurse-submodules=yes', 'origin' }
|
|
943
|
+
end,
|
|
944
|
+
set_origin = function(source)
|
|
945
|
+
return { 'remote', 'set-url', 'origin', source }
|
|
946
|
+
end,
|
|
947
|
+
get_origin = function()
|
|
948
|
+
return { 'remote', 'get-url', 'origin' }
|
|
949
|
+
end,
|
|
950
|
+
get_default_origin_branch = function()
|
|
951
|
+
return { 'rev-parse', '--abbrev-ref', 'origin/HEAD' }
|
|
952
|
+
end,
|
|
953
|
+
is_origin_branch = function(name)
|
|
954
|
+
-- Returns branch's name if it is present
|
|
955
|
+
return { 'branch', '--list', '--all', '--format=%(refname:short)', 'origin/' .. name }
|
|
956
|
+
end,
|
|
957
|
+
-- Using `rev-list -1` shows a commit of revision, while `rev-parse` shows
|
|
958
|
+
-- hash of revision. Those are different for annotated tags.
|
|
959
|
+
get_hash = function(rev)
|
|
960
|
+
return { 'rev-list', '-1', rev }
|
|
961
|
+
end,
|
|
962
|
+
log = function(from, to)
|
|
963
|
+
if from == nil or to == nil or from == to then return nil end
|
|
964
|
+
-- `--topo-order` makes showing divergent branches nicer
|
|
965
|
+
-- `--decorate-refs` shows only tags near commits (not `origin/main`, etc.)
|
|
966
|
+
--stylua: ignore
|
|
967
|
+
return {
|
|
968
|
+
'log', '--pretty=format:%m %h | %ai | %an%d%n %s%n', '--topo-order', '--decorate-refs=refs/tags',
|
|
969
|
+
from .. '...' .. to,
|
|
970
|
+
}
|
|
971
|
+
end,
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
H.ensure_git_exec = function()
|
|
975
|
+
if H.cache.git_version ~= nil then return end
|
|
976
|
+
local jobs = { H.cli_new_job(H.git_cmd('version'), vim.fn.getcwd()) }
|
|
977
|
+
H.cli_run(jobs)
|
|
978
|
+
if #jobs[1].err > 0 then H.error('Could not find executable `git` CLI tool') end
|
|
979
|
+
local major, minor = string.match(H.cli_stream_tostring(jobs[1].out), '(%d+)%.(%d+)')
|
|
980
|
+
H.cache.git_version = { major = tonumber(major), minor = tonumber(minor) }
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
-- Plugin specification -------------------------------------------------------
|
|
984
|
+
H.expand_spec = function(target, spec)
|
|
985
|
+
-- Prepare
|
|
986
|
+
if type(spec) == 'string' then
|
|
987
|
+
local field = string.find(spec, '/') ~= nil and 'source' or 'name'
|
|
988
|
+
spec = { [field] = spec }
|
|
989
|
+
end
|
|
990
|
+
if type(spec) ~= 'table' then H.error('Plugin spec should be table.') end
|
|
991
|
+
|
|
992
|
+
local has_min_fields = type(spec.source) == 'string' or type(spec.name) == 'string'
|
|
993
|
+
if not has_min_fields then H.error('Plugin spec should have proper `source` or `name`.') end
|
|
994
|
+
|
|
995
|
+
-- Normalize
|
|
996
|
+
spec = vim.deepcopy(spec)
|
|
997
|
+
|
|
998
|
+
if spec.source and type(spec.source) ~= 'string' then H.error('`source` in plugin spec should be string.') end
|
|
999
|
+
local is_user_repo = type(spec.source) == 'string' and spec.source:find('^[%w-]+/[%w-_.]+$') ~= nil
|
|
1000
|
+
if is_user_repo then spec.source = 'https://github.com/' .. spec.source end
|
|
1001
|
+
|
|
1002
|
+
spec.name = spec.name or vim.fn.fnamemodify(spec.source, ':t')
|
|
1003
|
+
if type(spec.name) ~= 'string' then H.error('`name` in plugin spec should be string.') end
|
|
1004
|
+
if string.find(spec.name, '/') ~= nil then H.error('`name` in plugin spec should not contain "/".') end
|
|
1005
|
+
if spec.name == '' then H.error('`name` in plugin spec should not be empty.') end
|
|
1006
|
+
|
|
1007
|
+
if spec.checkout and type(spec.checkout) ~= 'string' then H.error('`checkout` in plugin spec should be string.') end
|
|
1008
|
+
if spec.monitor and type(spec.monitor) ~= 'string' then H.error('`monitor` in plugin spec should be string.') end
|
|
1009
|
+
|
|
1010
|
+
spec.hooks = vim.deepcopy(spec.hooks) or {}
|
|
1011
|
+
if type(spec.hooks) ~= 'table' then H.error('`hooks` in plugin spec should be table.') end
|
|
1012
|
+
local hook_names = { 'pre_install', 'post_install', 'pre_checkout', 'post_checkout' }
|
|
1013
|
+
for _, hook_name in ipairs(hook_names) do
|
|
1014
|
+
local is_not_hook = spec.hooks[hook_name] and not vim.is_callable(spec.hooks[hook_name])
|
|
1015
|
+
if is_not_hook then H.error('`hooks.' .. hook_name .. '` in plugin spec should be callable.') end
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
-- Expand dependencies recursively before adding current spec to target
|
|
1019
|
+
spec.depends = vim.deepcopy(spec.depends) or {}
|
|
1020
|
+
if not H.islist(spec.depends) then H.error('`depends` in plugin spec should be array.') end
|
|
1021
|
+
for _, dep_spec in ipairs(spec.depends) do
|
|
1022
|
+
H.expand_spec(target, dep_spec)
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
table.insert(target, spec)
|
|
1026
|
+
end
|
|
1027
|
+
|
|
1028
|
+
-- Plugin operations ----------------------------------------------------------
|
|
1029
|
+
H.plugs_exec_hooks = function(plugs, name)
|
|
1030
|
+
for _, p in ipairs(plugs) do
|
|
1031
|
+
local has_error = p.job and #p.job.err > 0
|
|
1032
|
+
local should_execute = vim.is_callable(p.hooks[name]) and not has_error
|
|
1033
|
+
if should_execute then
|
|
1034
|
+
local ok, err = pcall(p.hooks[name], { path = p.path, source = p.source, name = p.name })
|
|
1035
|
+
if not ok then
|
|
1036
|
+
local msg = string.format('Error executing %s hook in `%s`:\n%s', name, p.name, err)
|
|
1037
|
+
H.notify(msg, 'ERROR')
|
|
1038
|
+
end
|
|
1039
|
+
end
|
|
1040
|
+
end
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
H.plugs_install = function(plugs)
|
|
1044
|
+
-- Clone
|
|
1045
|
+
local prepare = function(p)
|
|
1046
|
+
if p.source == nil and #p.job.err == 0 then p.job.err = { 'SPECIFICATION HAS NO `source` TO INSTALL PLUGIN.' } end
|
|
1047
|
+
p.job.command = H.git_cmd('clone', p.source or '', p.path)
|
|
1048
|
+
p.job.exit_msg = string.format('Installed `%s`', p.name)
|
|
1049
|
+
end
|
|
1050
|
+
H.plugs_run_jobs(plugs, prepare)
|
|
1051
|
+
|
|
1052
|
+
-- Checkout
|
|
1053
|
+
vim.tbl_map(function(p) p.job.cwd = p.path end, plugs)
|
|
1054
|
+
H.plugs_checkout(plugs, { exec_hooks = false, all_helptags = true })
|
|
1055
|
+
|
|
1056
|
+
-- Show warnings and errors
|
|
1057
|
+
H.plugs_show_job_notifications(plugs, 'installing plugin')
|
|
1058
|
+
end
|
|
1059
|
+
|
|
1060
|
+
H.plugs_download_updates = function(plugs)
|
|
1061
|
+
-- Show actual target number of plugins attempted to fetch
|
|
1062
|
+
local n_noerror = 0
|
|
1063
|
+
for _, p in ipairs(plugs) do
|
|
1064
|
+
if #p.job.err == 0 then n_noerror = n_noerror + 1 end
|
|
1065
|
+
end
|
|
1066
|
+
if n_noerror == 0 then return end
|
|
1067
|
+
H.notify('Downloading ' .. n_noerror .. ' update' .. (n_noerror > 1 and 's' or ''))
|
|
1068
|
+
|
|
1069
|
+
local prepare = function(p)
|
|
1070
|
+
p.job.command = H.git_cmd('fetch')
|
|
1071
|
+
p.job.exit_msg = string.format('Downloaded update for `%s`', p.name)
|
|
1072
|
+
end
|
|
1073
|
+
H.plugs_run_jobs(plugs, prepare)
|
|
1074
|
+
end
|
|
1075
|
+
|
|
1076
|
+
H.plugs_checkout = function(plugs, opts)
|
|
1077
|
+
opts = vim.tbl_deep_extend('force', { exec_hooks = true, all_helptags = false }, opts or {})
|
|
1078
|
+
|
|
1079
|
+
H.plugs_infer_head(plugs)
|
|
1080
|
+
H.plugs_ensure_target_refs(plugs)
|
|
1081
|
+
H.plugs_infer_commit(plugs, 'checkout', 'checkout_to')
|
|
1082
|
+
|
|
1083
|
+
-- Operate only on plugins that actually need checkout
|
|
1084
|
+
local checkout_plugs = vim.tbl_filter(function(p) return p.head ~= p.checkout_to end, plugs)
|
|
1085
|
+
|
|
1086
|
+
-- Stash changes
|
|
1087
|
+
local stash_command = H.git_cmd('stash', H.get_timestamp())
|
|
1088
|
+
local prepare = function(p) p.job.command = stash_command end
|
|
1089
|
+
H.plugs_run_jobs(checkout_plugs, prepare)
|
|
1090
|
+
|
|
1091
|
+
-- Execute pre hooks
|
|
1092
|
+
if opts.exec_hooks then H.plugs_exec_hooks(checkout_plugs, 'pre_checkout') end
|
|
1093
|
+
|
|
1094
|
+
-- Checkout
|
|
1095
|
+
prepare = function(p)
|
|
1096
|
+
p.job.command = H.git_cmd('checkout', p.checkout_to)
|
|
1097
|
+
p.job.exit_msg = string.format('Checked out `%s` in `%s`', p.checkout, p.name)
|
|
1098
|
+
end
|
|
1099
|
+
H.plugs_run_jobs(checkout_plugs, prepare)
|
|
1100
|
+
|
|
1101
|
+
-- Execute post hooks
|
|
1102
|
+
if opts.exec_hooks then H.plugs_exec_hooks(checkout_plugs, 'post_checkout') end
|
|
1103
|
+
|
|
1104
|
+
-- (Re)Generate help tags according to the current help files
|
|
1105
|
+
local help_plugs = opts.all_helptags and plugs or checkout_plugs
|
|
1106
|
+
for _, p in ipairs(help_plugs) do
|
|
1107
|
+
local doc_dir = p.path .. '/doc'
|
|
1108
|
+
-- Completely redo tags
|
|
1109
|
+
vim.fn.delete(doc_dir .. '/tags')
|
|
1110
|
+
local has_help_files = vim.fn.glob(doc_dir .. '/**') ~= ''
|
|
1111
|
+
if has_help_files then pcall(vim.cmd, 'helptags ' .. vim.fn.fnameescape(doc_dir)) end
|
|
1112
|
+
end
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
-- Plugin operation helpers ---------------------------------------------------
|
|
1116
|
+
H.plugs_from_names = function(names)
|
|
1117
|
+
if names and not H.islist(names) then H.error('`names` should be array.') end
|
|
1118
|
+
for _, name in ipairs(names or {}) do
|
|
1119
|
+
if type(name) ~= 'string' then H.error('`names` should contain only strings.') end
|
|
1120
|
+
end
|
|
1121
|
+
|
|
1122
|
+
local res = {}
|
|
1123
|
+
for _, spec in ipairs(MiniDeps.get_session()) do
|
|
1124
|
+
if names == nil or vim.tbl_contains(names, spec.name) then
|
|
1125
|
+
spec.job = H.cli_new_job({}, spec.path)
|
|
1126
|
+
table.insert(res, spec)
|
|
1127
|
+
end
|
|
1128
|
+
end
|
|
1129
|
+
|
|
1130
|
+
return res
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
H.plugs_run_jobs = function(plugs, prepare, process)
|
|
1134
|
+
if vim.is_callable(prepare) then vim.tbl_map(prepare, plugs) end
|
|
1135
|
+
|
|
1136
|
+
H.cli_run(vim.tbl_map(function(p) return p.job end, plugs))
|
|
1137
|
+
|
|
1138
|
+
if vim.is_callable(process) then vim.tbl_map(process, plugs) end
|
|
1139
|
+
|
|
1140
|
+
-- Clean jobs. Preserve errors for jobs to be properly reusable.
|
|
1141
|
+
for _, p in ipairs(plugs) do
|
|
1142
|
+
p.job.command, p.job.exit_msg, p.job.out = {}, nil, {}
|
|
1143
|
+
end
|
|
1144
|
+
end
|
|
1145
|
+
|
|
1146
|
+
H.plugs_show_job_notifications = function(plugs, action_name)
|
|
1147
|
+
for _, p in ipairs(plugs) do
|
|
1148
|
+
local warn = H.cli_stream_tostring(p.job.warn)
|
|
1149
|
+
if warn ~= '' then
|
|
1150
|
+
local msg = string.format('Warnings in `%s` during %s\n%s', p.name, action_name, warn)
|
|
1151
|
+
H.notify(msg, 'WARN')
|
|
1152
|
+
end
|
|
1153
|
+
local err = H.cli_stream_tostring(p.job.err)
|
|
1154
|
+
if err ~= '' then
|
|
1155
|
+
local msg = string.format('Error in `%s` during %s\n%s', p.name, action_name, err)
|
|
1156
|
+
H.notify(msg, 'ERROR')
|
|
1157
|
+
end
|
|
1158
|
+
end
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1161
|
+
H.plugs_ensure_origin_source = function(plugs)
|
|
1162
|
+
local prepare = function(p) p.job.command = p.source and H.git_cmd('set_origin', p.source) or H.git_cmd('get_origin') end
|
|
1163
|
+
local process = function(p) p.source = p.source or H.cli_stream_tostring(p.job.out) end
|
|
1164
|
+
H.plugs_run_jobs(plugs, prepare, process)
|
|
1165
|
+
end
|
|
1166
|
+
|
|
1167
|
+
H.plugs_ensure_target_refs = function(plugs)
|
|
1168
|
+
local prepare = function(p)
|
|
1169
|
+
local needs_infer = p.checkout == nil or p.monitor == nil
|
|
1170
|
+
p.job.command = needs_infer and H.git_cmd('get_default_origin_branch') or {}
|
|
1171
|
+
end
|
|
1172
|
+
local process = function(p)
|
|
1173
|
+
local def_branch = H.cli_stream_tostring(p.job.out):gsub('^origin/', '')
|
|
1174
|
+
p.checkout = p.checkout or def_branch
|
|
1175
|
+
p.monitor = p.monitor or def_branch
|
|
1176
|
+
p.has_monitor = p.checkout ~= p.monitor
|
|
1177
|
+
end
|
|
1178
|
+
H.plugs_run_jobs(plugs, prepare, process)
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
H.plugs_infer_head = function(plugs)
|
|
1182
|
+
local prepare = function(p) p.job.command = p.head == nil and H.git_cmd('get_hash', 'HEAD') or {} end
|
|
1183
|
+
local process = function(p) p.head = p.head or H.cli_stream_tostring(p.job.out) end
|
|
1184
|
+
H.plugs_run_jobs(plugs, prepare, process)
|
|
1185
|
+
end
|
|
1186
|
+
|
|
1187
|
+
H.plugs_infer_commit = function(plugs, field_ref, field_out)
|
|
1188
|
+
-- Determine if reference points to an origin branch (to avoid error later)
|
|
1189
|
+
local prepare = function(p)
|
|
1190
|
+
-- Don't recompute commit if it is already computed
|
|
1191
|
+
-- Don't compute commit for 'monitor' if it won't be used
|
|
1192
|
+
p.should_infer = p[field_out] == nil and (field_ref ~= 'monitor' or p.has_monitor)
|
|
1193
|
+
p.job.command = p.should_infer and H.git_cmd('is_origin_branch', p[field_ref]) or {}
|
|
1194
|
+
end
|
|
1195
|
+
local process = function(p) p.is_ref_origin_branch = H.cli_stream_tostring(p.job.out):find('%S') ~= nil end
|
|
1196
|
+
H.plugs_run_jobs(plugs, prepare, process)
|
|
1197
|
+
|
|
1198
|
+
-- Infer commit depending on whether it points to origin branch
|
|
1199
|
+
prepare = function(p)
|
|
1200
|
+
-- Force `checkout = 'HEAD'` to always point to current commit to freeze
|
|
1201
|
+
-- updates. This is needed because `origin/HEAD` is also present.
|
|
1202
|
+
local is_from_origin = p.is_ref_origin_branch and p[field_ref] ~= 'HEAD'
|
|
1203
|
+
local ref = (is_from_origin and 'origin/' or '') .. p[field_ref]
|
|
1204
|
+
p.job.command = p.should_infer and H.git_cmd('get_hash', ref) or {}
|
|
1205
|
+
end
|
|
1206
|
+
process = function(p)
|
|
1207
|
+
if p.should_infer then p[field_out] = H.cli_stream_tostring(p.job.out) end
|
|
1208
|
+
p.is_ref_origin_branch, p.should_infer = nil, nil
|
|
1209
|
+
end
|
|
1210
|
+
H.plugs_run_jobs(plugs, prepare, process)
|
|
1211
|
+
end
|
|
1212
|
+
|
|
1213
|
+
H.plugs_infer_log = function(plugs, field_from, field_to, field_out)
|
|
1214
|
+
local prepare = function(p) p.job.command = H.git_cmd('log', p[field_from], p[field_to]) end
|
|
1215
|
+
local process = function(p) p[field_out] = H.cli_stream_tostring(p.job.out) end
|
|
1216
|
+
H.plugs_run_jobs(plugs, prepare, process)
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
-- File system ----------------------------------------------------------------
|
|
1220
|
+
H.get_plugin_path = function(name)
|
|
1221
|
+
local package_path = H.get_package_path()
|
|
1222
|
+
|
|
1223
|
+
-- First check for the most common case of name present in 'pack/deps/opt'
|
|
1224
|
+
local opt_path = string.format('%s/pack/deps/opt/%s', package_path, name)
|
|
1225
|
+
if vim.loop.fs_stat(opt_path) ~= nil then return opt_path, true end
|
|
1226
|
+
|
|
1227
|
+
-- Allow processing 'pack/deps/start'
|
|
1228
|
+
local start_path = string.format('%s/pack/deps/start/%s', package_path, name)
|
|
1229
|
+
if vim.loop.fs_stat(start_path) ~= nil then return start_path, true end
|
|
1230
|
+
|
|
1231
|
+
-- Use 'opt' directory by default
|
|
1232
|
+
return opt_path, false
|
|
1233
|
+
end
|
|
1234
|
+
|
|
1235
|
+
H.get_all_plugin_paths = function()
|
|
1236
|
+
local deps_path, res = H.get_package_path() .. '/pack/deps', {}
|
|
1237
|
+
vim.list_extend(res, H.readdir(deps_path .. '/opt'))
|
|
1238
|
+
vim.list_extend(res, H.readdir(deps_path .. '/start'))
|
|
1239
|
+
return res
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1242
|
+
H.get_package_path = function() return H.full_path(H.get_config().path.package) end
|
|
1243
|
+
|
|
1244
|
+
-- Clean ----------------------------------------------------------------------
|
|
1245
|
+
H.clean_confirm = function(paths)
|
|
1246
|
+
-- Compute lines
|
|
1247
|
+
local lines = {
|
|
1248
|
+
'This is a confirmation report before a clean.',
|
|
1249
|
+
'',
|
|
1250
|
+
'Lines `- <plugin>` show plugins to be deleted from disk.',
|
|
1251
|
+
'Remove line to not delete that plugin.',
|
|
1252
|
+
'',
|
|
1253
|
+
'To finish clean, write this buffer (for example, with `:write` command).',
|
|
1254
|
+
'To cancel clean, close this window (for example, with `:close` command).',
|
|
1255
|
+
'',
|
|
1256
|
+
}
|
|
1257
|
+
local n_header = #lines - 1
|
|
1258
|
+
for _, p in ipairs(paths) do
|
|
1259
|
+
table.insert(lines, string.format('- %s (%s)', vim.fn.fnamemodify(p, ':t'), p))
|
|
1260
|
+
end
|
|
1261
|
+
|
|
1262
|
+
-- Show report in new buffer in separate tabpage
|
|
1263
|
+
local finish_clean = function(buf_id)
|
|
1264
|
+
-- Compute plugin paths to update
|
|
1265
|
+
local paths_to_delete = {}
|
|
1266
|
+
for _, l in ipairs(vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)) do
|
|
1267
|
+
local cur_path = string.match(l, '^%- .* %((.*)%)$')
|
|
1268
|
+
if cur_path ~= nil then table.insert(paths_to_delete, cur_path) end
|
|
1269
|
+
end
|
|
1270
|
+
|
|
1271
|
+
if #paths_to_delete == 0 then return H.notify('Nothing to delete') end
|
|
1272
|
+
H.clean_delete(paths_to_delete)
|
|
1273
|
+
end
|
|
1274
|
+
H.show_confirm_buf(lines, { name = 'confirm-clean', exec_on_write = finish_clean })
|
|
1275
|
+
|
|
1276
|
+
-- Define basic highlighting
|
|
1277
|
+
vim.cmd('syntax region MiniDepsHint start="^\\%1l" end="\\%' .. n_header .. 'l$"')
|
|
1278
|
+
|
|
1279
|
+
-- Define conceal to show only name with whole path when cursor is on it
|
|
1280
|
+
vim.cmd('syntax conceal on')
|
|
1281
|
+
vim.cmd([[syntax match MiniDepsInfo "\s\+(.\{-})$"]])
|
|
1282
|
+
vim.cmd('syntax conceal off')
|
|
1283
|
+
vim.cmd('setlocal conceallevel=3')
|
|
1284
|
+
end
|
|
1285
|
+
|
|
1286
|
+
H.clean_delete = function(paths)
|
|
1287
|
+
local n_to_delete = #paths
|
|
1288
|
+
for i, p in ipairs(paths) do
|
|
1289
|
+
vim.fn.delete(p, 'rf')
|
|
1290
|
+
local msg = string.format('(%d/%d) Deleted `%s` from disk', i, n_to_delete, vim.fn.fnamemodify(p, ':t'))
|
|
1291
|
+
H.notify(msg)
|
|
1292
|
+
end
|
|
1293
|
+
end
|
|
1294
|
+
|
|
1295
|
+
-- Update ---------------------------------------------------------------------
|
|
1296
|
+
H.update_compute_feedback_lines = function(plugs)
|
|
1297
|
+
-- Construct lines with metadata for later sort
|
|
1298
|
+
local plug_data = {}
|
|
1299
|
+
for i, p in ipairs(plugs) do
|
|
1300
|
+
local lines = H.update_compute_report_single(p)
|
|
1301
|
+
--stylua: ignore
|
|
1302
|
+
plug_data[i] = {
|
|
1303
|
+
lines = lines, has_error = p.has_error, has_updates = p.has_updates, has_monitor = p.has_monitor, name = p.name, index = i
|
|
1304
|
+
}
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
-- Sort to put first ones with errors, then with updates, then rest
|
|
1308
|
+
local compare = function(a, b)
|
|
1309
|
+
if a.has_error and not b.has_error then return true end
|
|
1310
|
+
if not a.has_error and b.has_error then return false end
|
|
1311
|
+
if a.has_updates and not b.has_updates then return true end
|
|
1312
|
+
if not a.has_updates and b.has_updates then return false end
|
|
1313
|
+
if a.has_monitor and not b.has_monitor then return true end
|
|
1314
|
+
if not a.has_monitor and b.has_monitor then return false end
|
|
1315
|
+
if a.name == 'mini.nvim' then return true end
|
|
1316
|
+
if b.name == 'mini.nvim' then return false end
|
|
1317
|
+
return a.index < b.index
|
|
1318
|
+
end
|
|
1319
|
+
table.sort(plug_data, compare)
|
|
1320
|
+
|
|
1321
|
+
local plug_lines = vim.tbl_map(function(x) return x.lines end, plug_data)
|
|
1322
|
+
return vim.split(table.concat(plug_lines, '\n\n'), '\n')
|
|
1323
|
+
end
|
|
1324
|
+
|
|
1325
|
+
H.update_compute_report_single = function(p)
|
|
1326
|
+
p.has_error, p.has_updates = #p.job.err > 0, p.head ~= p.checkout_to
|
|
1327
|
+
|
|
1328
|
+
local err = H.cli_stream_tostring(p.job.err)
|
|
1329
|
+
if err ~= '' then return string.format('!!! %s !!!\n\n%s', p.name, err) end
|
|
1330
|
+
|
|
1331
|
+
-- Compute title surrounding based on whether plugin needs an update
|
|
1332
|
+
local surrounding = p.has_updates and '+++' or '---'
|
|
1333
|
+
local parts = { string.format('%s %s %s\n', surrounding, p.name, surrounding) }
|
|
1334
|
+
|
|
1335
|
+
if p.head == p.checkout_to then
|
|
1336
|
+
table.insert(parts, 'Path: ' .. p.path .. '\n')
|
|
1337
|
+
table.insert(parts, 'Source: ' .. (p.source or '<None>') .. '\n')
|
|
1338
|
+
table.insert(parts, string.format('State: %s (%s)', p.checkout_to, p.checkout))
|
|
1339
|
+
else
|
|
1340
|
+
table.insert(parts, 'Path: ' .. p.path .. '\n')
|
|
1341
|
+
table.insert(parts, 'Source: ' .. (p.source or '<None>') .. '\n')
|
|
1342
|
+
table.insert(parts, 'State before: ' .. p.head .. '\n')
|
|
1343
|
+
table.insert(parts, string.format('State after: %s (%s)', p.checkout_to, p.checkout))
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1346
|
+
-- Show pending updates only if they are present
|
|
1347
|
+
if p.has_updates then
|
|
1348
|
+
table.insert(parts, string.format('\n\nPending updates from `%s`:\n', p.checkout))
|
|
1349
|
+
table.insert(parts, p.checkout_log)
|
|
1350
|
+
end
|
|
1351
|
+
|
|
1352
|
+
-- Show monitor updates only if user asked for them
|
|
1353
|
+
if p.has_monitor then
|
|
1354
|
+
table.insert(parts, string.format('\n\nMonitor updates from `%s`:\n', p.monitor))
|
|
1355
|
+
table.insert(parts, p.monitor_log ~= '' and p.monitor_log or '<Nothing>')
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1358
|
+
return table.concat(parts, '')
|
|
1359
|
+
end
|
|
1360
|
+
|
|
1361
|
+
H.update_feedback_confirm = function(lines)
|
|
1362
|
+
-- Add helper header
|
|
1363
|
+
local report = {
|
|
1364
|
+
'This is a confirmation report before an update.',
|
|
1365
|
+
'',
|
|
1366
|
+
'Line `+++ <plugin_name> +++` means plugin will be updated.',
|
|
1367
|
+
'See update details below it.',
|
|
1368
|
+
'Changes starting with ">"/"<" will be added/removed.',
|
|
1369
|
+
'Remove the line to not update that plugin.',
|
|
1370
|
+
'',
|
|
1371
|
+
'Line `--- <plugin_name> ---` means plugin has nothing to update.',
|
|
1372
|
+
'',
|
|
1373
|
+
"Line `!!! <plugin_name> !!!` means plugin had an error and won't be updated.",
|
|
1374
|
+
'See error details below it.',
|
|
1375
|
+
'',
|
|
1376
|
+
'Use regular fold keys (`zM`, `zR`, etc.) to manage shorter view.',
|
|
1377
|
+
'To finish update, write this buffer (for example, with `:write` command).',
|
|
1378
|
+
'To cancel update, close this window (for example, with `:close` command).',
|
|
1379
|
+
'',
|
|
1380
|
+
}
|
|
1381
|
+
local n_header = #report - 1
|
|
1382
|
+
vim.list_extend(report, lines)
|
|
1383
|
+
|
|
1384
|
+
-- Show report in new buffer in separate tabpage
|
|
1385
|
+
local finish_update = function(buf_id)
|
|
1386
|
+
-- Compute plugin names to update
|
|
1387
|
+
local names = {}
|
|
1388
|
+
for _, l in ipairs(vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)) do
|
|
1389
|
+
local cur_name = string.match(l, '^%+%+%+ (.*) %+%+%+$')
|
|
1390
|
+
if cur_name ~= nil then table.insert(names, cur_name) end
|
|
1391
|
+
end
|
|
1392
|
+
|
|
1393
|
+
-- Update and delete buffer (in that order, to show that update is done)
|
|
1394
|
+
MiniDeps.update(names, { force = true, offline = true })
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
H.show_confirm_buf(report, { name = 'confirm-update', exec_on_write = finish_update, setup_folds = true })
|
|
1398
|
+
|
|
1399
|
+
-- Define basic highlighting
|
|
1400
|
+
vim.cmd('syntax region MiniDepsHint start="^\\%1l" end="\\%' .. n_header .. 'l$"')
|
|
1401
|
+
H.update_add_syntax()
|
|
1402
|
+
end
|
|
1403
|
+
|
|
1404
|
+
H.update_add_syntax = function()
|
|
1405
|
+
vim.cmd([[
|
|
1406
|
+
syntax match MiniDepsTitleError "^!!! .\+ !!!$"
|
|
1407
|
+
syntax match MiniDepsTitleUpdate "^+++ .\+ +++$"
|
|
1408
|
+
syntax match MiniDepsTitleSame "^--- .\+ ---$"
|
|
1409
|
+
syntax match MiniDepsInfo "^Path: \+\zs[^ ]\+"
|
|
1410
|
+
syntax match MiniDepsInfo "^Source: \+\zs[^ ]\+"
|
|
1411
|
+
syntax match MiniDepsInfo "^State[^:]*: \+\zs[^ ]\+\ze"
|
|
1412
|
+
syntax match MiniDepsHint "\(^State.\+\)\@<=(.\+)$"
|
|
1413
|
+
syntax match MiniDepsChangeAdded "^> .*$"
|
|
1414
|
+
syntax match MiniDepsChangeRemoved "^< .*$"
|
|
1415
|
+
syntax match MiniDepsMsgBreaking "^ \S\+!: .*$"
|
|
1416
|
+
syntax match MiniDepsPlaceholder "^<.*>$"
|
|
1417
|
+
]])
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
H.update_feedback_log = function(lines)
|
|
1421
|
+
local title = string.format('========== Update %s ==========', H.get_timestamp())
|
|
1422
|
+
table.insert(lines, 1, title)
|
|
1423
|
+
table.insert(lines, '')
|
|
1424
|
+
|
|
1425
|
+
local log_path = H.get_config().path.log
|
|
1426
|
+
vim.fn.mkdir(vim.fn.fnamemodify(log_path, ':h'), 'p')
|
|
1427
|
+
vim.fn.writefile(lines, log_path, 'a')
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
-- Confirm --------------------------------------------------------------------
|
|
1431
|
+
H.show_confirm_buf = function(lines, opts)
|
|
1432
|
+
-- Show buffer
|
|
1433
|
+
local buf_id = vim.api.nvim_create_buf(true, true)
|
|
1434
|
+
H.set_buf_name(buf_id, opts.name)
|
|
1435
|
+
vim.api.nvim_buf_set_lines(buf_id, 0, -1, false, lines)
|
|
1436
|
+
vim.cmd('tab sbuffer ' .. buf_id)
|
|
1437
|
+
local tab_num, win_id = vim.api.nvim_tabpage_get_number(0), vim.api.nvim_get_current_win()
|
|
1438
|
+
|
|
1439
|
+
local delete_buffer = vim.schedule_wrap(function()
|
|
1440
|
+
pcall(vim.api.nvim_buf_delete, buf_id, { force = true })
|
|
1441
|
+
pcall(function() vim.cmd('tabclose ' .. tab_num) end)
|
|
1442
|
+
vim.cmd('redraw')
|
|
1443
|
+
end)
|
|
1444
|
+
|
|
1445
|
+
-- Define folding
|
|
1446
|
+
local is_title = function(l) return l:find('^%-%-%-') or l:find('^%+%+%+') or l:find('^%!%!%!') end
|
|
1447
|
+
--stylua: ignore
|
|
1448
|
+
MiniDeps._confirm_foldexpr = function(lnum)
|
|
1449
|
+
if lnum == 1 then return 0 end
|
|
1450
|
+
if is_title(vim.fn.getline(lnum - 1)) then return 1 end
|
|
1451
|
+
if is_title(vim.fn.getline(lnum + 1)) then return 0 end
|
|
1452
|
+
return '='
|
|
1453
|
+
end
|
|
1454
|
+
|
|
1455
|
+
-- Possibly set up folding. Use `:setlocal` for these options to not be
|
|
1456
|
+
-- inherited if some other buffer is opened in the same window.
|
|
1457
|
+
if opts.setup_folds then
|
|
1458
|
+
vim.cmd('setlocal foldenable foldmethod=expr foldlevel=999')
|
|
1459
|
+
vim.cmd('setlocal foldexpr=v:lua.MiniDeps._confirm_foldexpr(v:lnum)')
|
|
1460
|
+
end
|
|
1461
|
+
|
|
1462
|
+
-- Define action on accepting confirm
|
|
1463
|
+
local finish = function()
|
|
1464
|
+
MiniDeps._confirm_foldexpr = nil
|
|
1465
|
+
opts.exec_on_write(buf_id)
|
|
1466
|
+
delete_buffer()
|
|
1467
|
+
end
|
|
1468
|
+
-- - Use `nested` to allow other events (`WinEnter` for 'mini.statusline')
|
|
1469
|
+
vim.api.nvim_create_autocmd('BufWriteCmd', { buffer = buf_id, nested = true, callback = finish })
|
|
1470
|
+
|
|
1471
|
+
-- Define action to cancel confirm
|
|
1472
|
+
local cancel_au_id
|
|
1473
|
+
local on_cancel = function(data)
|
|
1474
|
+
MiniDeps._confirm_foldexpr = nil
|
|
1475
|
+
if tonumber(data.match) ~= win_id then return end
|
|
1476
|
+
pcall(vim.api.nvim_del_autocmd, cancel_au_id)
|
|
1477
|
+
delete_buffer()
|
|
1478
|
+
end
|
|
1479
|
+
cancel_au_id = vim.api.nvim_create_autocmd('WinClosed', { nested = true, callback = on_cancel })
|
|
1480
|
+
|
|
1481
|
+
-- Set buffer-local options last (so that user autocmmands could override)
|
|
1482
|
+
vim.bo.buftype, vim.bo.filetype, vim.bo.modified = 'acwrite', 'minideps-confirm', false
|
|
1483
|
+
end
|
|
1484
|
+
|
|
1485
|
+
-- CLI ------------------------------------------------------------------------
|
|
1486
|
+
H.cli_run = function(jobs)
|
|
1487
|
+
local config_job = H.get_config().job
|
|
1488
|
+
local n_threads = math.max(config_job.n_threads or H.get_n_threads(), 1)
|
|
1489
|
+
|
|
1490
|
+
-- Use only actually runnable jobs
|
|
1491
|
+
local should_run = function(job)
|
|
1492
|
+
-- Run only if there is command to run and previous runs of same reusable
|
|
1493
|
+
-- job did not result into error
|
|
1494
|
+
return type(job.command) == 'table' and #job.command > 0 and #job.err == 0
|
|
1495
|
+
end
|
|
1496
|
+
jobs = vim.tbl_filter(should_run, jobs)
|
|
1497
|
+
|
|
1498
|
+
local n_total, id_started, n_finished = #jobs, 0, 0
|
|
1499
|
+
if n_total == 0 then return end
|
|
1500
|
+
|
|
1501
|
+
local run_next
|
|
1502
|
+
run_next = function()
|
|
1503
|
+
if n_total <= id_started then return end
|
|
1504
|
+
id_started = id_started + 1
|
|
1505
|
+
|
|
1506
|
+
local job = jobs[id_started]
|
|
1507
|
+
local command, cwd, exit_msg = job.command or {}, job.cwd, job.exit_msg
|
|
1508
|
+
|
|
1509
|
+
-- Prepare data for `vim.loop.spawn`
|
|
1510
|
+
local executable, args = command[1], vim.list_slice(command, 2, #command)
|
|
1511
|
+
local process, stdout, stderr = nil, vim.loop.new_pipe(), vim.loop.new_pipe()
|
|
1512
|
+
|
|
1513
|
+
-- - Unset special `GIT_xxx` variables that can affect `git` commands
|
|
1514
|
+
local env_map = vim.fn.environ()
|
|
1515
|
+
env_map.GIT_DIR, env_map.GIT_WORK_TREE = nil, nil
|
|
1516
|
+
local env = {}
|
|
1517
|
+
for k, v in pairs(env_map) do
|
|
1518
|
+
table.insert(env, k .. '=' .. tostring(v))
|
|
1519
|
+
end
|
|
1520
|
+
|
|
1521
|
+
local spawn_opts = { args = args, cwd = cwd, env = env, stdio = { nil, stdout, stderr } }
|
|
1522
|
+
|
|
1523
|
+
local on_exit = function(code)
|
|
1524
|
+
-- Process only not already closing job
|
|
1525
|
+
if process:is_closing() then return end
|
|
1526
|
+
process:close()
|
|
1527
|
+
|
|
1528
|
+
-- Process exit code: if 0 treat `stderr` as warning; error otherwise
|
|
1529
|
+
if code == 0 then
|
|
1530
|
+
vim.list_extend(job.warn, job.err)
|
|
1531
|
+
-- NOTE: This is valid as only jobs with `err = {}` are filtered to run
|
|
1532
|
+
job.err = {}
|
|
1533
|
+
else
|
|
1534
|
+
table.insert(job.err, 1, 'ERROR CODE ' .. code .. '\n')
|
|
1535
|
+
end
|
|
1536
|
+
|
|
1537
|
+
-- Finalize job
|
|
1538
|
+
n_finished = n_finished + 1
|
|
1539
|
+
if type(exit_msg) == 'string' and #job.err == 0 then
|
|
1540
|
+
H.notify(string.format('(%d/%d) %s', n_finished, n_total, exit_msg))
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1543
|
+
-- Start next parallel job
|
|
1544
|
+
run_next()
|
|
1545
|
+
end
|
|
1546
|
+
|
|
1547
|
+
process = vim.loop.spawn(executable, spawn_opts, on_exit)
|
|
1548
|
+
H.cli_read_stream(stdout, job.out)
|
|
1549
|
+
H.cli_read_stream(stderr, job.err)
|
|
1550
|
+
vim.defer_fn(function()
|
|
1551
|
+
if not process:is_active() then return end
|
|
1552
|
+
table.insert(job.err, 'PROCESS REACHED TIMEOUT.')
|
|
1553
|
+
on_exit(1)
|
|
1554
|
+
end, config_job.timeout)
|
|
1555
|
+
end
|
|
1556
|
+
|
|
1557
|
+
for _ = 1, n_threads do
|
|
1558
|
+
run_next()
|
|
1559
|
+
end
|
|
1560
|
+
|
|
1561
|
+
vim.wait(config_job.timeout * n_total, function() return n_total <= n_finished end, 1)
|
|
1562
|
+
end
|
|
1563
|
+
|
|
1564
|
+
H.cli_read_stream = function(stream, feed)
|
|
1565
|
+
local callback = function(err, data)
|
|
1566
|
+
if err then return table.insert(feed, 1, 'ERROR: ' .. err) end
|
|
1567
|
+
if data ~= nil then return table.insert(feed, data) end
|
|
1568
|
+
stream:close()
|
|
1569
|
+
end
|
|
1570
|
+
stream:read_start(callback)
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
H.cli_stream_tostring = function(stream) return (table.concat(stream):gsub('\n+$', '')) end
|
|
1574
|
+
|
|
1575
|
+
H.cli_new_job = function(command, cwd, exit_msg)
|
|
1576
|
+
return { command = command, cwd = cwd, exit_msg = exit_msg, out = {}, warn = {}, err = {} }
|
|
1577
|
+
end
|
|
1578
|
+
|
|
1579
|
+
-- Two-stage execution --------------------------------------------------------
|
|
1580
|
+
H.schedule_finish = function()
|
|
1581
|
+
if H.cache.finish_is_scheduled then return end
|
|
1582
|
+
vim.schedule(H.finish)
|
|
1583
|
+
H.cache.finish_is_scheduled = true
|
|
1584
|
+
end
|
|
1585
|
+
|
|
1586
|
+
H.finish = function()
|
|
1587
|
+
local timer, step_delay = vim.loop.new_timer(), 1
|
|
1588
|
+
local f = nil
|
|
1589
|
+
f = vim.schedule_wrap(function()
|
|
1590
|
+
local callback = H.cache.later_callback_queue[1]
|
|
1591
|
+
if callback == nil then
|
|
1592
|
+
H.cache.finish_is_scheduled, H.cache.later_callback_queue = false, {}
|
|
1593
|
+
H.report_errors()
|
|
1594
|
+
return
|
|
1595
|
+
end
|
|
1596
|
+
|
|
1597
|
+
table.remove(H.cache.later_callback_queue, 1)
|
|
1598
|
+
MiniDeps.now(callback)
|
|
1599
|
+
timer:start(step_delay, 0, f)
|
|
1600
|
+
end)
|
|
1601
|
+
timer:start(step_delay, 0, f)
|
|
1602
|
+
end
|
|
1603
|
+
|
|
1604
|
+
H.report_errors = function()
|
|
1605
|
+
if #H.cache.exec_errors == 0 then return end
|
|
1606
|
+
local error_lines = table.concat(H.cache.exec_errors, '\n\n')
|
|
1607
|
+
H.cache.exec_errors = {}
|
|
1608
|
+
H.notify('There were errors during two-stage execution:\n\n' .. error_lines, 'ERROR')
|
|
1609
|
+
end
|
|
1610
|
+
|
|
1611
|
+
-- Utilities ------------------------------------------------------------------
|
|
1612
|
+
H.error = function(msg) error('(mini.deps) ' .. msg, 0) end
|
|
1613
|
+
|
|
1614
|
+
H.check_type = function(name, val, ref, allow_nil)
|
|
1615
|
+
if type(val) == ref or (ref == 'callable' and vim.is_callable(val)) or (allow_nil and val == nil) then return end
|
|
1616
|
+
H.error(string.format('`%s` should be %s, not %s', name, ref, type(val)))
|
|
1617
|
+
end
|
|
1618
|
+
|
|
1619
|
+
H.set_buf_name = function(buf_id, name) vim.api.nvim_buf_set_name(buf_id, 'minideps://' .. buf_id .. '/' .. name) end
|
|
1620
|
+
|
|
1621
|
+
H.notify = vim.schedule_wrap(function(msg, level)
|
|
1622
|
+
level = level or 'INFO'
|
|
1623
|
+
if H.get_config().silent and level ~= 'ERROR' and level ~= 'WARN' then return end
|
|
1624
|
+
if type(msg) == 'table' then msg = table.concat(msg, '\n') end
|
|
1625
|
+
vim.notify(string.format('(mini.deps) %s', msg), vim.log.levels[level])
|
|
1626
|
+
vim.cmd('redraw')
|
|
1627
|
+
end)
|
|
1628
|
+
|
|
1629
|
+
H.edit = function(path, win_id)
|
|
1630
|
+
if type(path) ~= 'string' then return end
|
|
1631
|
+
local b = vim.api.nvim_win_get_buf(win_id or 0)
|
|
1632
|
+
local try_mimic_buf_reuse = (vim.fn.bufname(b) == '' and vim.bo[b].buftype ~= 'quickfix' and not vim.bo[b].modified)
|
|
1633
|
+
and (#vim.fn.win_findbuf(b) == 1 and vim.deep_equal(vim.fn.getbufline(b, 1, '$'), { '' }))
|
|
1634
|
+
local buf_id = vim.fn.bufadd(vim.fn.fnamemodify(path, ':.'))
|
|
1635
|
+
-- Showing in window also loads. Use `pcall` to not error with swap messages.
|
|
1636
|
+
pcall(vim.api.nvim_win_set_buf, win_id or 0, buf_id)
|
|
1637
|
+
vim.bo[buf_id].buflisted = true
|
|
1638
|
+
if try_mimic_buf_reuse then pcall(vim.api.nvim_buf_delete, b, { unload = false }) end
|
|
1639
|
+
return buf_id
|
|
1640
|
+
end
|
|
1641
|
+
|
|
1642
|
+
H.get_timestamp = function() return vim.fn.strftime('%Y-%m-%d %H:%M:%S') end
|
|
1643
|
+
|
|
1644
|
+
H.get_n_threads = function() return math.floor(0.8 * #(vim.loop.cpu_info() or {})) end
|
|
1645
|
+
|
|
1646
|
+
H.full_path = function(path) return (vim.fn.fnamemodify(path, ':p'):gsub('\\', '/'):gsub('/+', '/'):gsub('(.)/$', '%1')) end
|
|
1647
|
+
|
|
1648
|
+
H.readdir = function(path)
|
|
1649
|
+
if vim.fn.isdirectory(path) ~= 1 then return {} end
|
|
1650
|
+
return vim.tbl_map(function(x) return path .. '/' .. x end, vim.fn.readdir(path))
|
|
1651
|
+
end
|
|
1652
|
+
|
|
1653
|
+
H.source = function(path)
|
|
1654
|
+
pcall(function() vim.cmd('source ' .. vim.fn.fnameescape(path)) end)
|
|
1655
|
+
end
|
|
1656
|
+
|
|
1657
|
+
-- TODO: Remove after compatibility with Neovim=0.9 is dropped
|
|
1658
|
+
H.islist = vim.fn.has('nvim-0.10') == 1 and vim.islist or vim.tbl_islist
|
|
1659
|
+
|
|
1660
|
+
return MiniDeps
|