Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
92d8f8b9ee | |||
443a091e3e | |||
6259250120 | |||
25372aea36 | |||
30e7e05771
|
|||
d7a08ca820
|
|||
d141c762c1
|
|||
3d20ae8d2a
|
@ -1,11 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "Running tests before commit..."
|
|
||||||
|
|
||||||
# run tests
|
|
||||||
make test || {
|
|
||||||
echo "Tests failed. Commit aborted."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "Tests passed. Proceeding with commit."
|
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
doc/tags
|
|
||||||
|
4
LICENSE
4
LICENSE
@ -1,7 +1,7 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2023-2025 squibid
|
(c) 2021 chiya.dev
|
||||||
Copyright (c) 2021-2023 chiya.dev
|
(c) 2024 squibid
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
4
Makefile
4
Makefile
@ -1,4 +0,0 @@
|
|||||||
test:
|
|
||||||
nvim --headless -c "PlenaryBustedDirectory tests/ {minimal_init = './tests/minit.lua'}"
|
|
||||||
|
|
||||||
.PHONY: test
|
|
275
README.md
275
README.md
@ -1,31 +1,20 @@
|
|||||||
# dep
|
# dep
|
||||||
|
> This readme is a work in progress.
|
||||||
|
|
||||||
A versatile, declarative and correct [neovim][2] package manager in [Lua][3].
|
A versatile, declarative and correct [neovim][1] package manager in [Lua][2].
|
||||||
Originally written for personal use by [luaneko][4]. Adapted by [squibid][5] for
|
Originally written for personal use by [luaneko][3].
|
||||||
general use.
|
|
||||||
|
|
||||||
What does that mean?
|
What does that mean?
|
||||||
|
|
||||||
1. `versatile` - packages can be declared in any Lua file in any order of your
|
1. `versatile` - packages can be declared in any Lua file in any order of your liking.
|
||||||
liking.
|
|
||||||
2. `declarative` - packages are declared using simple Lua tables.
|
2. `declarative` - packages are declared using simple Lua tables.
|
||||||
3. `correct` - packages are always loaded in a correct and consistent order
|
3. `correct` - packages are always loaded in a correct and consistent order.
|
||||||
(barring any lazy loading).
|
|
||||||
|
|
||||||
In addition to the above dep has been built to be completely in control of you,
|
|
||||||
the user. With the help of lazy loading you can choose when your plugin loads
|
|
||||||
down to the finest detail (examples may be found below).
|
|
||||||
|
|
||||||
See also squibid's [neovim-config][10] for an example of how dep can be used in
|
|
||||||
practice.
|
|
||||||
|
|
||||||
|
See also squibid's [neovim-configs][5] for an example of how dep can be used in practice.
|
||||||
## Requirements
|
## Requirements
|
||||||
|
- [Neovim][1] 0.6+
|
||||||
- [Neovim][2] 0.8+
|
- [Git][4]
|
||||||
- [Git][6] 2.13+
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. Create `lua/bootstrap.lua` in your neovim config directory.
|
1. Create `lua/bootstrap.lua` in your neovim config directory.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
@ -34,7 +23,7 @@ practice.
|
|||||||
local path = vim.fn.stdpath("data") .. "/site/pack/deps/opt/dep"
|
local path = vim.fn.stdpath("data") .. "/site/pack/deps/opt/dep"
|
||||||
|
|
||||||
if vim.fn.empty(vim.fn.glob(path)) > 0 then
|
if vim.fn.empty(vim.fn.glob(path)) > 0 then
|
||||||
vim.fn.system({ "git", "clone", "--depth=1", "https://git.squi.bid/squibid/dep", path })
|
vim.fn.system({ "git", "clone", "--depth=1", "https://github.com/chiyadev/dep", path })
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.cmd("packadd dep")
|
vim.cmd("packadd dep")
|
||||||
@ -55,8 +44,9 @@ require "dep" {
|
|||||||
cleans removed packages and reloads packages as necessary.
|
cleans removed packages and reloads packages as necessary.
|
||||||
- `:DepClean` - cleans removed packages.
|
- `:DepClean` - cleans removed packages.
|
||||||
- `:DepReload` - reloads all packages.
|
- `:DepReload` - reloads all packages.
|
||||||
|
- `:DepList` - prints the package list, performance metrics and dependency graphs.
|
||||||
- `:DepLog` - opens the log file.
|
- `:DepLog` - opens the log file.
|
||||||
- `:DepUi` - opens the ui.
|
- `:DepConfig` - opens the file that called dep, for convenience.
|
||||||
|
|
||||||
## Package specification
|
## Package specification
|
||||||
|
|
||||||
@ -68,37 +58,28 @@ A package must be declared in the following format.
|
|||||||
-- This is the only required field; all other fields are optional.
|
-- This is the only required field; all other fields are optional.
|
||||||
"user/package",
|
"user/package",
|
||||||
|
|
||||||
|
-- [function] Code to run after the package is loaded into neovim.
|
||||||
|
function()
|
||||||
|
require "package".setup(...)
|
||||||
|
end,
|
||||||
|
|
||||||
-- [function] Code to run before the package is loaded into neovim.
|
-- [function] Code to run before the package is loaded into neovim.
|
||||||
setup = function()
|
setup = function()
|
||||||
vim.g.package_config = ...
|
vim.g.package_config = ...
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- [function] Code to run after the package is loaded into neovim.
|
|
||||||
load = function()
|
|
||||||
require "package".setup(...)
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- [function] Code to run after the package is installed or updated.
|
-- [function] Code to run after the package is installed or updated.
|
||||||
config = function()
|
config = function()
|
||||||
os.execute(...)
|
os.execute(...)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
-- [function|true] Code used to determine when the package should be loaded.
|
|
||||||
lazy = function(load)
|
|
||||||
load:cmd("LoadPackage")
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- [string] Overrides the short name of the package.
|
-- [string] Overrides the short name of the package.
|
||||||
-- Defaults to a substring of the full name after '/'.
|
-- Defaults to a substring of the full name after '/'.
|
||||||
as = "custom_package",
|
as = "custom_package",
|
||||||
|
|
||||||
-- [string] Overrides the URL of the git repository to clone.
|
-- [string] Overrides the URL of the git repository to clone.
|
||||||
-- Defaults to "https://github.com/{full_name}.git".
|
-- Defaults to "https://github.com/{full_name}.git".
|
||||||
url = "https://git.squi.bid/user/package.git",
|
url = "https://git.chiya.dev/user/package.git",
|
||||||
|
|
||||||
-- [string] Overrides the source in which the package is gotten
|
|
||||||
-- from. This is not set by default.
|
|
||||||
path = "~/my-local-package/",
|
|
||||||
|
|
||||||
-- [string] Overrides the name of the branch to clone.
|
-- [string] Overrides the name of the branch to clone.
|
||||||
-- Defaults to whatever the remote configured as their HEAD, which is usually "master".
|
-- Defaults to whatever the remote configured as their HEAD, which is usually "master".
|
||||||
@ -114,9 +95,9 @@ A package must be declared in the following format.
|
|||||||
-- [boolean] Prevents the package from being updated.
|
-- [boolean] Prevents the package from being updated.
|
||||||
pin = true,
|
pin = true,
|
||||||
|
|
||||||
-- [string|array] Specifies requirements that must be loaded before the package.
|
-- [string|array] Specifies dependencies that must be loaded before the package.
|
||||||
-- If given a string, it is wrapped into an array.
|
-- If given a string, it is wrapped into an array.
|
||||||
reqs = {...},
|
requires = {...},
|
||||||
|
|
||||||
-- [string|array] Specifies dependents that must be loaded after the package.
|
-- [string|array] Specifies dependents that must be loaded after the package.
|
||||||
-- If given a string, it is wrapped into an array.
|
-- If given a string, it is wrapped into an array.
|
||||||
@ -142,7 +123,7 @@ combined into one. This is useful when declaring dependencies, which is explored
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/package",
|
"user/package",
|
||||||
reqs = "user/dependency",
|
requires = "user/dependency",
|
||||||
disabled = true,
|
disabled = true,
|
||||||
config = function()
|
config = function()
|
||||||
print "my config hook"
|
print "my config hook"
|
||||||
@ -163,7 +144,7 @@ require "dep" {
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/package",
|
"user/package",
|
||||||
reqs = { "user/dependency", "user/another_dependency" },
|
requires = { "user/dependency", "user/another_dependency" },
|
||||||
deps = "user/dependent",
|
deps = "user/dependent",
|
||||||
disabled = true,
|
disabled = true,
|
||||||
config = function()
|
config = function()
|
||||||
@ -184,10 +165,10 @@ they are combined into one just like normal package specifications.
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/package",
|
"user/package",
|
||||||
reqs = {
|
requires = {
|
||||||
{
|
{
|
||||||
"user/dependency1",
|
"user/dependency1",
|
||||||
reqs = "user/dependency2"
|
requires = "user/dependency2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +191,7 @@ require "dep" {
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/dependency1",
|
"user/dependency1",
|
||||||
reqs = "user/dependency2",
|
requires = "user/dependency2",
|
||||||
deps = "user/package"
|
deps = "user/package"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,11 +200,11 @@ require "dep" {
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/dependency1",
|
"user/dependency1",
|
||||||
reqs = "user/dependency2"
|
requires = "user/dependency2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user/package",
|
"user/package",
|
||||||
reqs = "user/dependency1"
|
requires = "user/dependency1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,11 +231,11 @@ instead of hanging or crashing.
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/package1",
|
"user/package1",
|
||||||
reqs = "user/package2"
|
requires = "user/package2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user/package2",
|
"user/package2",
|
||||||
reqs = "user/package1"
|
requires = "user/package1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -270,12 +251,12 @@ require "dep" {
|
|||||||
{
|
{
|
||||||
"user/package1",
|
"user/package1",
|
||||||
disabled = true, -- implied
|
disabled = true, -- implied
|
||||||
reqs = "user/dependency"
|
requires = "user/dependency"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user/package2",
|
"user/package2",
|
||||||
disabled = true, -- implied
|
disabled = true, -- implied
|
||||||
reqs = "user/dependency"
|
requires = "user/dependency"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -286,172 +267,20 @@ If a dependency fails to load for some reason, all of its dependents are guarant
|
|||||||
require "dep" {
|
require "dep" {
|
||||||
{
|
{
|
||||||
"user/problematic",
|
"user/problematic",
|
||||||
load = function()
|
function()
|
||||||
error("bad hook")
|
error("bad hook")
|
||||||
end
|
end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"user/dependent",
|
"user/dependent",
|
||||||
requires = "user/problematic",
|
requires = "user/problematic",
|
||||||
load = function()
|
function()
|
||||||
print "unreachable"
|
print "unreachable"
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Lazy loading
|
|
||||||
|
|
||||||
Imagine you're using [telescope.nvim][7] and you need to pull it up with a keybind,
|
|
||||||
but you don't want to have it load before that moment. With lazy loading you may
|
|
||||||
choose to only load it when needed using the built in lazy utils which are made
|
|
||||||
available to you as soon as you start using the lazy option.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require "dep" {
|
|
||||||
{ "nvim-telescope/telescope.nvim",
|
|
||||||
lazy = function(load)
|
|
||||||
load:keymap("n", "<leader>f")
|
|
||||||
end,
|
|
||||||
load = function()
|
|
||||||
require("telescope").setup {}
|
|
||||||
vim.keymap.set("n", "<leader>f", require("telescope.builtin").find_files, {})
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Say you wanted to use [gitsigns.nvim][9], but only wanted to load it when
|
|
||||||
in a git directory OR when you call the Gitsigns command. With the power of lazy
|
|
||||||
loading this can be accomplished by simply defining an auto command like so:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require "dep" {
|
|
||||||
{
|
|
||||||
"lewis6991/gitsigns.nvim",
|
|
||||||
lazy = function(load)
|
|
||||||
-- load gitsigns if we're in a git repository
|
|
||||||
load:auto({ "BufEnter", "BufNew" }, {
|
|
||||||
callback = function()
|
|
||||||
local paths = vim.fs.find({ ".git", }, { upward = true })
|
|
||||||
if #paths > 0 then
|
|
||||||
load:cleanup()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
-- load gitsigns if the user trys to run the command
|
|
||||||
load:cmd("Gitsigns")
|
|
||||||
end,
|
|
||||||
load = function()
|
|
||||||
require("gitsigns").setup {}
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're in the need of a deeper understanding of how the utils work go check
|
|
||||||
out `lua/lazy/loader/init.lua` for the source code.
|
|
||||||
|
|
||||||
## Separating code into modules
|
|
||||||
|
|
||||||
Suppose you split your `init.lua` into two files `packages/search.lua` and
|
|
||||||
`packages/vcs.lua`, which declare the packages [telescope.nvim][7] and [vim-fugitive][8] respectively.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- ~/.config/nvim/lua/packages/search.lua:
|
|
||||||
return {
|
|
||||||
{
|
|
||||||
"nvim-telescope/telescope.nvim",
|
|
||||||
reqs = "nvim-lua/plenary.nvim"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- ~/.config/nvim/lua/packages/vcs.lua:
|
|
||||||
return {
|
|
||||||
"tpope/vim-fugitive"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Package specifications from other modules can be loaded using the `modules` option.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
require "dep" {
|
|
||||||
modules = {
|
|
||||||
prefix = "packages"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- the above is equivalent to
|
|
||||||
require "dep" {
|
|
||||||
modules = {
|
|
||||||
prefix = "packages.",
|
|
||||||
"search",
|
|
||||||
"vcs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- or
|
|
||||||
require "dep" {
|
|
||||||
modules = {
|
|
||||||
"packages.search",
|
|
||||||
"packages.vcs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- which is equivalent to
|
|
||||||
local packages = {}
|
|
||||||
|
|
||||||
for _, package in ipairs(require "packages.search") do
|
|
||||||
table.insert(packages, package)
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, package in ipairs(require "packages.vcs") do
|
|
||||||
table.insert(packages, package)
|
|
||||||
end
|
|
||||||
|
|
||||||
require("dep")(packages)
|
|
||||||
|
|
||||||
-- which is ultimately equivalent to
|
|
||||||
require "dep" {
|
|
||||||
{
|
|
||||||
"nvim-telescope/telescope.nvim",
|
|
||||||
reqs = "nvim-lua/plenary.nvim"
|
|
||||||
},
|
|
||||||
"tpope/vim-fugitive"
|
|
||||||
}
|
|
||||||
|
|
||||||
-- all of the above are guaranteed to load plenary.nvim before telescope.nvim.
|
|
||||||
-- order of telescope.nvim and vim-fugitive is consistent but unspecified.
|
|
||||||
```
|
|
||||||
|
|
||||||
Entire modules can be marked as disabled, which disables all top-level packages declared in that module.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
return {
|
|
||||||
disable = true,
|
|
||||||
{
|
|
||||||
"user/package",
|
|
||||||
disabled = true, -- implied by module
|
|
||||||
reqs = {
|
|
||||||
{
|
|
||||||
"user/dependency",
|
|
||||||
-- disabled = true -- not implied
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deps = {
|
|
||||||
{
|
|
||||||
"user/dependent",
|
|
||||||
disabled = true -- implied by dependency
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Miscellaneous configuration
|
## Miscellaneous configuration
|
||||||
|
|
||||||
dep accepts configuration parameters as named fields in the package list.
|
dep accepts configuration parameters as named fields in the package list.
|
||||||
@ -464,43 +293,21 @@ require "dep" {
|
|||||||
-- "always": synchronize all packages on startup
|
-- "always": synchronize all packages on startup
|
||||||
sync = "new",
|
sync = "new",
|
||||||
|
|
||||||
-- [array] Specifies the modules to load package specifications from.
|
-- [function] Callback when dep is (re)loaded
|
||||||
-- Defaults to an empty table.
|
-- if a table is returned it will be read as a table of config specs
|
||||||
-- Items can be either an array of package specifications,
|
load = function()
|
||||||
-- or a string that indicates the name of the module from which the array of package specifications is loaded.
|
end
|
||||||
modules = {
|
|
||||||
-- [string] Prefix string to prepend to all module names.
|
|
||||||
prefix = "",
|
|
||||||
},
|
|
||||||
|
|
||||||
-- list of package specs...
|
-- list of package specs...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Known Issues
|
|
||||||
|
|
||||||
- Lazy loading nvim-cmp doesn't work as the external sources don't get reconized
|
|
||||||
by nvim-cmp when it's loaded.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
When contributing you may choose to run tests before commiting changes, if that
|
|
||||||
is so you may choose to run the following:
|
|
||||||
```sh
|
|
||||||
git config core.hooksPath .githooks
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
dep is licensed under the [MIT License](LICENSE).
|
dep is licensed under the [MIT License](LICENSE).
|
||||||
|
|
||||||
[1]: https://chiya.dev/posts/2021-11-27-why-package-manager
|
[1]: https://neovim.io/
|
||||||
[2]: https://neovim.io/
|
[2]: https://www.lua.org/
|
||||||
[3]: https://www.lua.org/
|
[3]: https://github.com/luaneko
|
||||||
[4]: https://github.com/luaneko
|
[4]: https://git-scm.com/
|
||||||
[5]: https://squi.bid
|
[5]: https://git.squi.bid/nvim
|
||||||
[6]: https://git-scm.com/
|
|
||||||
[7]: https://github.com/nvim-telescope/telescope.nvim
|
|
||||||
[8]: https://github.com/tpope/vim-fugitive
|
|
||||||
[9]: https://github.com/lewis6991/gitsigns.nvim
|
|
||||||
[10]: https://git.squi.bid/nvim
|
|
||||||
|
670
doc/dep.txt
670
doc/dep.txt
@ -1,670 +0,0 @@
|
|||||||
*dep.txt* Declarative Package Manager 02-Jul-2025
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
Table of Contents *dep-table-of-contents*
|
|
||||||
|
|
||||||
1. Introduction |dep|
|
|
||||||
2. Setup |dep-setup|
|
|
||||||
3. Specs |dep-spec|
|
|
||||||
- Package Spec |dep-package-spec|
|
|
||||||
- Module Spec |dep-module-spec|
|
|
||||||
4. Lazy Loading |dep-lazy-loading|
|
|
||||||
- Lazy Loading API |dep-lazy-loading-api|
|
|
||||||
- Lazy Loading API Shorthands |dep-lazy-loading-api-shorthands|
|
|
||||||
5. Commands |dep-commands|
|
|
||||||
6. Examples |dep-examples|
|
|
||||||
- Declaring Dependencies |dep-examples-declaring-dependencies|
|
|
||||||
- Modules |dep-examples-modules|
|
|
||||||
- Lazy Loading |dep-examples-lazy-loading|
|
|
||||||
7. Credits & License |dep-credits|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
1. Introduction *dep*
|
|
||||||
|
|
||||||
A versatile, declarative and correct neovim package manager in Lua. Originally
|
|
||||||
written for personal use by luaneko. Adapted by squibid for general use.
|
|
||||||
|
|
||||||
What does that mean?
|
|
||||||
|
|
||||||
1. `versatile` - packages can be declared in any Lua file in any order of your
|
|
||||||
liking.
|
|
||||||
2. `declarative` - packages are declared using simple Lua tables.
|
|
||||||
3. `correct` - packages are always loaded in a correct and consistent order
|
|
||||||
(barring any lazy loading).
|
|
||||||
|
|
||||||
In addition to the above dep has been built to be completely in control of you,
|
|
||||||
the user. With the help of lazy loading you can choose when your plugin loads
|
|
||||||
down to the finest detail (examples may be found below).
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
2. Setup *dep-setup*
|
|
||||||
|
|
||||||
Put the following anywhere before any actual use of dep.
|
|
||||||
|
|
||||||
>lua
|
|
||||||
local path = vim.fn.stdpath("data") .. "/site/pack/deps/opt/dep"
|
|
||||||
|
|
||||||
if vim.fn.empty(vim.fn.glob(path)) > 0 then
|
|
||||||
vim.fn.system({
|
|
||||||
"git",
|
|
||||||
"clone",
|
|
||||||
"--depth=1",
|
|
||||||
"https://git.squi.bid/squibid/dep",
|
|
||||||
path,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.cmd("packadd dep")
|
|
||||||
<
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
3. Specs *dep-spec*
|
|
||||||
|
|
||||||
dep uses a variation of specifications to ensure everything works smoothly.
|
|
||||||
This includes a basic spec used when setting up dep:
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
-- [string] Specifies when dep should automatically synchronize.
|
|
||||||
-- "never": disable this behavior
|
|
||||||
-- "new": only install newly declared packages (default)
|
|
||||||
-- "always": synchronize all packages on startup
|
|
||||||
sync = "new",
|
|
||||||
|
|
||||||
-- [array] Specifies the modules to load package specifications from.
|
|
||||||
-- Defaults to an empty table.
|
|
||||||
-- Items can be either an array of package specifications,
|
|
||||||
-- or a string that indicates the name of the module from which the array
|
|
||||||
-- of package specifications is loaded.
|
|
||||||
--
|
|
||||||
-- "."'s are added between the prefix and module names as required. In
|
|
||||||
-- addition if there is only a prefix and no modules supplied then dep
|
|
||||||
-- automatically loads all lua files in the directory.
|
|
||||||
modules = {
|
|
||||||
-- [string] Prefix string to prepend to all module names. This is
|
|
||||||
-- optional.
|
|
||||||
prefix = "",
|
|
||||||
|
|
||||||
-- [string] module names
|
|
||||||
...
|
|
||||||
},
|
|
||||||
|
|
||||||
-- [table|string] package specification(s)
|
|
||||||
...
|
|
||||||
}
|
|
||||||
<
|
|
||||||
PACKAGE SPEC *dep-package-spec*
|
|
||||||
>lua
|
|
||||||
{
|
|
||||||
-- [string] Specifies the full name of the package.
|
|
||||||
-- This is the only required field; all other fields are optional.
|
|
||||||
"user/package",
|
|
||||||
|
|
||||||
-- [function] Code to run before the package is loaded into neovim.
|
|
||||||
setup = function()
|
|
||||||
vim.g.package_config = ...
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- [function] Code to run after the package is loaded into neovim.
|
|
||||||
load = function()
|
|
||||||
require "package".setup(...)
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- [function] Code to run after the package is installed or updated.
|
|
||||||
config = function()
|
|
||||||
os.execute(...)
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- [function|true] Code used to determine when the package should be
|
|
||||||
-- loaded.
|
|
||||||
lazy = function(load)
|
|
||||||
load:cmd("LoadPackage")
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- [string] Overrides the short name of the package.
|
|
||||||
-- Defaults to a substring of the full name after '/'.
|
|
||||||
as = "custom_package",
|
|
||||||
|
|
||||||
-- [string] Overrides the URL of the git repository to clone.
|
|
||||||
-- Defaults to "https://github.com/{full_name}.git".
|
|
||||||
url = "https://git.squi.bid/user/package.git",
|
|
||||||
|
|
||||||
-- [string] Overrides the source in which the package is gotten
|
|
||||||
-- from. This is not set by default.
|
|
||||||
path = "~/my-local-package/",
|
|
||||||
|
|
||||||
-- [string] Overrides the name of the branch to clone.
|
|
||||||
-- Defaults to whatever the remote configured as their HEAD, which is
|
|
||||||
-- usually "master".
|
|
||||||
branch = "develop",
|
|
||||||
|
|
||||||
-- [string] Overrides the commit ref to target
|
|
||||||
-- Defaults to the latest commit on the current branch
|
|
||||||
commit = "e76cb03",
|
|
||||||
|
|
||||||
-- [boolean] Prevents the package from being loaded.
|
|
||||||
disable = true,
|
|
||||||
|
|
||||||
-- [boolean] Prevents the package from being updated.
|
|
||||||
pin = true,
|
|
||||||
|
|
||||||
-- [string|array] Specifies requirements that must be loaded before the
|
|
||||||
-- package. If given a string, it is wrapped into an array.
|
|
||||||
reqs = {...},
|
|
||||||
|
|
||||||
-- [string|array] Specifies dependents that must be loaded after the
|
|
||||||
-- package. If given a string, it is wrapped into an array.
|
|
||||||
deps = {...}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
MODULE SPEC *dep-module-spec*
|
|
||||||
>lua
|
|
||||||
{
|
|
||||||
-- [string] Specifies a name for the module
|
|
||||||
name = "a name",
|
|
||||||
|
|
||||||
-- [string] Specifies a description of the module
|
|
||||||
desc = "a description of the module",
|
|
||||||
|
|
||||||
-- [boolean] Prevents all packages in the module from being loaded.
|
|
||||||
disable = false,
|
|
||||||
|
|
||||||
-- [table|string] package specification(s)
|
|
||||||
...
|
|
||||||
}
|
|
||||||
<
|
|
||||||
More information on the package specifications may be found in
|
|
||||||
|dep-package-spec|.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
4. Lazy Loading *dep-lazy-loading*
|
|
||||||
|
|
||||||
Lazy loading is important for making sure neovim can load nice and fast unlike
|
|
||||||
a certain bloated IDE. It has a seperate section in this documentation to
|
|
||||||
ensure that you can use it to it's full extent.
|
|
||||||
|
|
||||||
If you refer to the |dep-package-spec| you'll notice the `lazy` flag which may
|
|
||||||
be used to conditionally load a package. When it is set to a function you
|
|
||||||
choose when it runs and more information on that may be found in
|
|
||||||
|dep-lazy-loading-api|. In addition to setting it to a function you may set it
|
|
||||||
to `true` in which case dep takes care of loading it for you.
|
|
||||||
|
|
||||||
When setting a colorscheme dep checks to make sure that the plugin is loaded,
|
|
||||||
therefore it's recommended that you make use of the `lazy` flags ability to be
|
|
||||||
set to `true` by setting any colorscheme that you have installed, but do not
|
|
||||||
use as your main one to lazy.
|
|
||||||
|
|
||||||
LAZY LOADING API *dep-lazy-loading-api*
|
|
||||||
|
|
||||||
Within the |dep-package-spec| the lazy flag when set to a function takes one
|
|
||||||
argument `load` which is a class containing loading functions. For the
|
|
||||||
following examples assume that `load` is set to the class which may be found
|
|
||||||
within `lua/dep/lazy/loader/init.lua`.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
LOAD:CMD *dep-lazy-loading-api-cmd*
|
|
||||||
|
|
||||||
`load:cmd` is a function which allows you to specify a command for the package
|
|
||||||
to load on. It takes the similar arguments to |nvim_create_user_command()|
|
|
||||||
with a key difference in what the command runs. The following is an example of
|
|
||||||
what arguments the function takes:
|
|
||||||
>lua
|
|
||||||
load:cmd("Command", {})
|
|
||||||
<
|
|
||||||
Notice the missing 'command' argument which is found in
|
|
||||||
|nvim_create_user_command|, this is replaced by a callback function. The above
|
|
||||||
is equivalent to the following:
|
|
||||||
>lua
|
|
||||||
load:cmd("Command", {
|
|
||||||
callback = function()
|
|
||||||
load:cleanup()
|
|
||||||
|
|
||||||
if (rerun) then
|
|
||||||
vim.cmd("Command")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
<
|
|
||||||
If you wish the second argument may be completely ommitted. Note the inclusion
|
|
||||||
of a `rerun` field, this is a parameter which may be passed into the options table
|
|
||||||
to re-run the binding after loading the package. You may choose to disable the
|
|
||||||
built-in logic by passing false.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
LOAD:AUTO *dep-lazy-loading-api-auto*
|
|
||||||
|
|
||||||
`load:auto` is a function which allows you to specify an auto command for the
|
|
||||||
package to load on. It takes the same arguments as |nvim_create_autocmd()|.
|
|
||||||
The following is an example of using it:
|
|
||||||
>lua
|
|
||||||
load:auto("InsertEnter", {})
|
|
||||||
<
|
|
||||||
Just like with |nvim_create_autocmd()| you may choose to pass in a 'callback'
|
|
||||||
by default the above is equivalent to the following:
|
|
||||||
>lua
|
|
||||||
load:auto("InsertEnter", {
|
|
||||||
callback = function()
|
|
||||||
load:cleanup()
|
|
||||||
end
|
|
||||||
})
|
|
||||||
<
|
|
||||||
As with `load:cmd` the second argument may be ommitted.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
LOAD:FT *dep-lazy-loading-api-ft*
|
|
||||||
|
|
||||||
`load:ft` is a function which allows you to specify a filetype for the package
|
|
||||||
to load on. It takes one argument: 'filetype' like so:
|
|
||||||
>lua
|
|
||||||
load:ft("lua")
|
|
||||||
<
|
|
||||||
Which is equivalent to the following:
|
|
||||||
>lua
|
|
||||||
load:auto("FileType", {
|
|
||||||
pattern = "lua",
|
|
||||||
callback = function()
|
|
||||||
load:cleanup()
|
|
||||||
end
|
|
||||||
})
|
|
||||||
<
|
|
||||||
Note that this is just an expansion of `load:auto` for your convenience.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
LOAD:KEYMAP *dep-lazy-loading-api-keymap*
|
|
||||||
|
|
||||||
`load:keymap` is a function which allows you to specify a keymap for the
|
|
||||||
package to load on. It takes the similar arguments to |vim.keymap.set()| with a
|
|
||||||
key difference in what the command runs. The following is an example of what
|
|
||||||
arguments the function takes:
|
|
||||||
>lua
|
|
||||||
load:keymap("n", "<leader>p", {})
|
|
||||||
<
|
|
||||||
Notice the missing 'rhs' argument which is found in |vim.keymap.set|, this is
|
|
||||||
replaced by a callback function. The above is equivalent to the following:
|
|
||||||
>lua
|
|
||||||
load:keymap("n", "<leader>p", {
|
|
||||||
callback = function()
|
|
||||||
-- register keymap unload
|
|
||||||
load:cleanup()
|
|
||||||
|
|
||||||
-- call the keymap after the user has mapped it
|
|
||||||
if type(rerun) == "function" then
|
|
||||||
rerun()
|
|
||||||
elseif rerun then
|
|
||||||
local keys = vim.api.nvim_replace_termcodes(bind, true, false, true)
|
|
||||||
vim.api.nvim_input(keys)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
<
|
|
||||||
Note the inclusion of a `rerun` field, this is a parameter which may be passed
|
|
||||||
into the options table to re-run the binding after loading the package. You
|
|
||||||
may choose to include your own logic by passing a function to the `rerun`
|
|
||||||
field or disable the built-in logic by passing false.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
LOAD:PLUGIN *dep-lazy-loading-api-plugin*
|
|
||||||
|
|
||||||
`load:plugin` is a function which allows you to specify another plugin for the
|
|
||||||
package to load after. It takes two arguments: `plugin` which is the name of
|
|
||||||
the plugin you want to follow like: 'user/package'. The second argument is
|
|
||||||
`opts` which is a table with one option: `callback` which is a function. The
|
|
||||||
following is an example:
|
|
||||||
>lua
|
|
||||||
load:plugin("user/package", {})
|
|
||||||
<
|
|
||||||
Which is the same as:
|
|
||||||
>lua
|
|
||||||
load:plugin("user/package", {
|
|
||||||
callback = function()
|
|
||||||
self:cleanup()
|
|
||||||
end
|
|
||||||
})
|
|
||||||
<
|
|
||||||
When 'user/package' is already loaded the `callback` is called immediately.
|
|
||||||
|
|
||||||
LAZY LOADING API SHORTHANDS *dep-lazy-loading-api-shorthands*
|
|
||||||
|
|
||||||
On occasion you may wish to only define one condition for the package to load.
|
|
||||||
When that is the case you may choose to use the built-in shorthands. By
|
|
||||||
loading them:
|
|
||||||
>lua
|
|
||||||
require("dep.lazy.loader.short")
|
|
||||||
<
|
|
||||||
The shorthands are very similar to those found in |dep-lazy-loading-api| with
|
|
||||||
a key exception: instead of running the functions within the body of a
|
|
||||||
function set as the lazy field to a package specification this is the lazy
|
|
||||||
field and may be use like so:
|
|
||||||
>lua
|
|
||||||
{ "user/package",
|
|
||||||
lazy = require("dep.lazy.loader.short").cmd("Command")
|
|
||||||
}
|
|
||||||
<
|
|
||||||
And you may of course put the shorthands in a variable to make this actually
|
|
||||||
shorter:
|
|
||||||
>lua
|
|
||||||
local short = require("dep.lazy.loader.short")
|
|
||||||
{ "user/package",
|
|
||||||
lazy = short.cmd("Command")
|
|
||||||
}
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
5. Commands *dep-commands*
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
SYNC ALL PLUGINS *:DepSync*
|
|
||||||
- installs new packages, updates packages to the latest versions,
|
|
||||||
cleans removed packages and reloads packages as necessary.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
CLEAN REMOVED PLUGINS *:DepClean*
|
|
||||||
- cleans removed packages.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
RELOAD ALL PLUGINS *:DepReload*
|
|
||||||
- reloads all packages.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
OPEN THE UI *:DepUi*
|
|
||||||
- opens the ui.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
OPEN THE LOG *:DepLog*
|
|
||||||
- opens the log file.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
6. Examples *dep-examples*
|
|
||||||
|
|
||||||
When a string is given where a package specification table is expected, it is
|
|
||||||
assumed to be the package's full name.
|
|
||||||
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
-- these two are equivalent
|
|
||||||
"user/package",
|
|
||||||
{ "user/package" },
|
|
||||||
}
|
|
||||||
<
|
|
||||||
|
|
||||||
A package can be declared multiple times. Multiple declarations of the same
|
|
||||||
package are combined into one. This is useful when declaring dependencies,
|
|
||||||
which is explored later.
|
|
||||||
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
{ "user/package",
|
|
||||||
reqs = "user/dependency",
|
|
||||||
disabled = true,
|
|
||||||
config = function()
|
|
||||||
print("my config hook")
|
|
||||||
end
|
|
||||||
},
|
|
||||||
{ "user/package",
|
|
||||||
requires = "user/another_dependency",
|
|
||||||
deps = "user/dependent",
|
|
||||||
disabled = false,
|
|
||||||
config = function()
|
|
||||||
os.execute("make")
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- the above is equivalent to
|
|
||||||
require("dep") {
|
|
||||||
{ "user/package",
|
|
||||||
reqs = { "user/dependency", "user/another_dependency" },
|
|
||||||
deps = "user/dependent",
|
|
||||||
disabled = true,
|
|
||||||
config = function()
|
|
||||||
print("my config hook")
|
|
||||||
os.execute("make")
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
DECLARING DEPENDENCIES *dep-examples-declaring-dependencies*
|
|
||||||
|
|
||||||
The dependencies and dependents declared in a package specification are
|
|
||||||
themselves package specifications. If a dependency or dependent is declared
|
|
||||||
multiple times, they are combined into one just like normal package
|
|
||||||
specifications.
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
{ "user/package",
|
|
||||||
reqs = {
|
|
||||||
{ "user/dependency1",
|
|
||||||
reqs = "user/dependency2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- the above is equivalent to
|
|
||||||
require("dep") {
|
|
||||||
{ "user/dependency2",
|
|
||||||
deps = {
|
|
||||||
{ "user/dependency1",
|
|
||||||
deps = "user/package"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- which is equivalent to
|
|
||||||
require("dep") {
|
|
||||||
{ "user/dependency1",
|
|
||||||
reqs = "user/dependency2",
|
|
||||||
deps = "user/package"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- which is equivalent to
|
|
||||||
require("dep") {
|
|
||||||
{ "user/dependency1",
|
|
||||||
reqs = "user/dependency2"
|
|
||||||
},
|
|
||||||
{ "user/package",
|
|
||||||
reqs = "user/dependency1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- which is equivalent to
|
|
||||||
require("dep") {
|
|
||||||
{ "user/dependency2",
|
|
||||||
deps = "user/dependency1"
|
|
||||||
},
|
|
||||||
{ "user/dependency1",
|
|
||||||
deps = "user/package"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- all of the above are guaranteed to load in the following order:
|
|
||||||
-- dependency2, dependency1, package
|
|
||||||
<
|
|
||||||
If dep detects a circular dependency cycle, it reports the problematic packages
|
|
||||||
instead of hanging or crashing.
|
|
||||||
>lua
|
|
||||||
-- this throws an error saying package1 depends on package2 which depends on
|
|
||||||
-- package1
|
|
||||||
require("dep") {
|
|
||||||
{ "user/package1",
|
|
||||||
reqs = "user/package2"
|
|
||||||
},
|
|
||||||
{ "user/package2",
|
|
||||||
reqs = "user/package1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
A dependency can be marked as disabled, which disables all dependents
|
|
||||||
automatically.
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
{ "user/dependency",
|
|
||||||
disabled = true
|
|
||||||
},
|
|
||||||
{ "user/package1",
|
|
||||||
disabled = true, -- implied
|
|
||||||
reqs = "user/dependency"
|
|
||||||
},
|
|
||||||
{ "user/package2",
|
|
||||||
disabled = true, -- implied
|
|
||||||
reqs = "user/dependency"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
If a dependency fails to load for some reason, all of its dependents are
|
|
||||||
guaranteed to not load.
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
{ "user/problematic",
|
|
||||||
load = function()
|
|
||||||
error("bad hook")
|
|
||||||
end
|
|
||||||
},
|
|
||||||
{ "user/dependent",
|
|
||||||
requires = "user/problematic",
|
|
||||||
load = function()
|
|
||||||
print "unreachable"
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
|
|
||||||
MODULES *dep-examples-modules*
|
|
||||||
|
|
||||||
Suppose you split your `init.lua` into two files `packages/search.lua` and
|
|
||||||
`packages/vcs.lua`, which declare the packages telescope.nvim and vim-fugitive
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
>lua
|
|
||||||
-- ~/.config/nvim/lua/packages/search.lua:
|
|
||||||
return {
|
|
||||||
{ "nvim-telescope/telescope.nvim",
|
|
||||||
reqs = "nvim-lua/plenary.nvim"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
>lua
|
|
||||||
-- ~/.config/nvim/lua/packages/vcs.lua:
|
|
||||||
return { "tpope/vim-fugitive" }
|
|
||||||
<
|
|
||||||
Package specifications from other modules can be loaded using the `modules`
|
|
||||||
option.
|
|
||||||
>lua
|
|
||||||
require("dep") {
|
|
||||||
modules = {
|
|
||||||
prefix = "packages"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- the above is equivalent to
|
|
||||||
require("dep") {
|
|
||||||
modules = {
|
|
||||||
prefix = "packages.",
|
|
||||||
"search",
|
|
||||||
"vcs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- or
|
|
||||||
require("dep") {
|
|
||||||
modules = {
|
|
||||||
"packages.search",
|
|
||||||
"packages.vcs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- which is equivalent to
|
|
||||||
local packages = {}
|
|
||||||
|
|
||||||
for _, package in ipairs(require "packages.search") do
|
|
||||||
table.insert(packages, package)
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, package in ipairs(require "packages.vcs") do
|
|
||||||
table.insert(packages, package)
|
|
||||||
end
|
|
||||||
|
|
||||||
require("dep")(packages)
|
|
||||||
|
|
||||||
-- which is ultimately equivalent to
|
|
||||||
require("dep") {
|
|
||||||
{ "nvim-telescope/telescope.nvim",
|
|
||||||
reqs = "nvim-lua/plenary.nvim"
|
|
||||||
},
|
|
||||||
"tpope/vim-fugitive"
|
|
||||||
}
|
|
||||||
|
|
||||||
-- all of the above are guaranteed to load plenary.nvim before
|
|
||||||
-- telescope.nvim. order of telescope.nvim and vim-fugitive is consistent but
|
|
||||||
-- unspecified.
|
|
||||||
<
|
|
||||||
Entire modules can be marked as disabled, which disables all top-level packages
|
|
||||||
declared in that module.
|
|
||||||
>lua
|
|
||||||
return {
|
|
||||||
disable = true,
|
|
||||||
{ "user/package",
|
|
||||||
disabled = true, -- implied by module
|
|
||||||
reqs = {
|
|
||||||
{ "user/dependency",
|
|
||||||
-- disabled = true -- not implied
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deps = {
|
|
||||||
{ "user/dependent",
|
|
||||||
disabled = true -- implied by dependency
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<
|
|
||||||
LAZY LOADING *dep-examples-lazy-loading*
|
|
||||||
|
|
||||||
Lazy loading is a very complicated topic, and therefore this part of the
|
|
||||||
documentation assumes you have experience with regular package managment.
|
|
||||||
Let's go over loading order, and how the lazy loader determines what needs to
|
|
||||||
be loaded.
|
|
||||||
|
|
||||||
Let's say we have the following spec:
|
|
||||||
>lua
|
|
||||||
{ "user/package",
|
|
||||||
lazy = true,
|
|
||||||
deps = "user/dependent"
|
|
||||||
}
|
|
||||||
<
|
|
||||||
This is the same as the following:
|
|
||||||
>lua
|
|
||||||
{ "user/package",
|
|
||||||
lazy = true
|
|
||||||
},
|
|
||||||
|
|
||||||
{ "user/dependent",
|
|
||||||
reqs = "user/package",
|
|
||||||
lazy = require("dep.lazy.loader.short").plugin("user/package")
|
|
||||||
}
|
|
||||||
<
|
|
||||||
What you're seeing is implicit lazy loading. By default dep will lazy load
|
|
||||||
dependents who are explicitly defined in the spec. Now if we we're to modify
|
|
||||||
'user/dependent' like so:
|
|
||||||
>lua
|
|
||||||
{ "user/package",
|
|
||||||
lazy = true
|
|
||||||
},
|
|
||||||
|
|
||||||
{ "user/dependent",
|
|
||||||
reqs = "user/package",
|
|
||||||
lazy = function(load)
|
|
||||||
load:plugin("user/package")
|
|
||||||
load:cmd("LoadDependent")
|
|
||||||
end
|
|
||||||
}
|
|
||||||
<
|
|
||||||
If we were to call the command `:LoadDependent` it would first load
|
|
||||||
'user/package', and then load 'user/dependent'.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
7. Credits & License *dep-credits*
|
|
||||||
|
|
||||||
dep is licensed under the MIT License. Check the LICENSE file for more info.
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
|
1004
lua/dep.lua
1004
lua/dep.lua
File diff suppressed because it is too large
Load Diff
@ -1,32 +0,0 @@
|
|||||||
-- TODO: actually use this (ideally make a view that shows startuptime and
|
|
||||||
-- which plugins are currently loaded)
|
|
||||||
-- performance logging
|
|
||||||
|
|
||||||
---@class bench
|
|
||||||
---@field perf number[] list of all perfs
|
|
||||||
local bench = {}
|
|
||||||
local b
|
|
||||||
|
|
||||||
function bench.setup()
|
|
||||||
local o = {}
|
|
||||||
|
|
||||||
o.perf = {}
|
|
||||||
o.inited = true
|
|
||||||
|
|
||||||
b = o
|
|
||||||
end
|
|
||||||
|
|
||||||
--- benchmark a peice of code
|
|
||||||
---@param name string the name of the benchmark
|
|
||||||
---@param f function the code to benchmark
|
|
||||||
---@vararg any args for f
|
|
||||||
---@return any ret the result of f
|
|
||||||
function bench.mark(name, f, ...)
|
|
||||||
local start = os.clock()
|
|
||||||
local ret = f(...)
|
|
||||||
b.perf[name] = os.clock() - start
|
|
||||||
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
return bench
|
|
@ -1,78 +0,0 @@
|
|||||||
local h = require('dep.helpers')
|
|
||||||
local logger = require('dep.log')
|
|
||||||
|
|
||||||
local fs = {}
|
|
||||||
|
|
||||||
--- abstract away fs:link to make calling more intuitive
|
|
||||||
---@param package package package to update
|
|
||||||
---@param cb function callback on success
|
|
||||||
function fs:sync(package, cb)
|
|
||||||
if not package.exists then
|
|
||||||
fs:link(package, cb)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a symlink to a local package
|
|
||||||
---@param package package package to link
|
|
||||||
---@param cb function callback on success
|
|
||||||
function fs:link(package, cb)
|
|
||||||
h.uv.fs_symlink(package.path, package.dir, nil, function(err, _)
|
|
||||||
if err then
|
|
||||||
logger:log("error", "failed to symlink %s; reason: %s", package.id, err)
|
|
||||||
else
|
|
||||||
cb(err)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- clean out old packages
|
|
||||||
---@param package package any package
|
|
||||||
function fs:clean(package)
|
|
||||||
h.uv.fs_scandir(
|
|
||||||
package.get_base_dir(),
|
|
||||||
vim.schedule_wrap(function(err, handle)
|
|
||||||
if err then
|
|
||||||
logger:log("error", "failed to clean; reason: %s", err)
|
|
||||||
else
|
|
||||||
local queue = {}
|
|
||||||
|
|
||||||
while handle do
|
|
||||||
local name = h.uv.fs_scandir_next(handle)
|
|
||||||
if name and name ~= package.get_root().name then
|
|
||||||
queue[name] = package.get_base_dir().."/"..name
|
|
||||||
elseif name == package.get_root().name then
|
|
||||||
-- we need to ensure that there is no chance of nuking dep
|
|
||||||
goto continue
|
|
||||||
elseif name == nil then
|
|
||||||
break
|
|
||||||
else
|
|
||||||
-- if there's a single error bail out
|
|
||||||
logger:log("error", "failed to run clean uv.fs_scandir_next failed")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
|
|
||||||
-- keep packages that still exist
|
|
||||||
for _, pkg in pairs(package.get_packages()) do
|
|
||||||
queue[pkg.name] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- start deleting all of the packages which are chosen for deletion
|
|
||||||
for name, dir in pairs(queue) do
|
|
||||||
local co = coroutine.create(function()
|
|
||||||
local ok = vim.fn.delete(dir, "rf")
|
|
||||||
if ok then
|
|
||||||
logger:log("clean", "deleted %s", name)
|
|
||||||
else
|
|
||||||
logger:log("error", "failed to delete %s", name)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
coroutine.resume(co)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
return fs
|
|
161
lua/dep/git.lua
161
lua/dep/git.lua
@ -1,161 +0,0 @@
|
|||||||
-- TODO: clean this up, it's a mess
|
|
||||||
-- the nesting of all the proc calls is really annoying, and I need to find a
|
|
||||||
-- cleaner way to do it
|
|
||||||
|
|
||||||
local logger = require('dep.log')
|
|
||||||
local proc = require('dep.proc')
|
|
||||||
|
|
||||||
local git = {}
|
|
||||||
|
|
||||||
--- install or update a given package
|
|
||||||
---@param package package package to update/install
|
|
||||||
---@param cb function callback
|
|
||||||
function git.sync(package, cb)
|
|
||||||
local function sync()
|
|
||||||
-- update or install
|
|
||||||
if package.exists then
|
|
||||||
git.update(package, cb)
|
|
||||||
else
|
|
||||||
git.install(package, cb)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle arbitrary branches here
|
|
||||||
if package.branch then
|
|
||||||
proc.git_resolve_branch(package.url, package.branch, function(err, message)
|
|
||||||
if not err then
|
|
||||||
package.branch = message
|
|
||||||
sync()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
sync()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- configure a package
|
|
||||||
---@param package table package spec
|
|
||||||
local function configurepkg(package)
|
|
||||||
package:runhooks("on_config")
|
|
||||||
|
|
||||||
logger:log("config", "package: %s configured", package.id)
|
|
||||||
package.configured = true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- install a given package
|
|
||||||
---@param package package package to install
|
|
||||||
---@param cb function callback
|
|
||||||
function git.install(package, cb)
|
|
||||||
if not package.enabled then
|
|
||||||
cb()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
proc.git_clone(package.dir, package.url, package.branch, function(err, message)
|
|
||||||
if err then
|
|
||||||
logger:log("error", "failed to install %s; reason: %s",
|
|
||||||
package.id, message)
|
|
||||||
else
|
|
||||||
if package.commit then
|
|
||||||
proc.git_checkout(package.dir, package.branch, package.commit, function(err, message)
|
|
||||||
if err then
|
|
||||||
logger:log("error", "failed to checkout %s; reason: %s", package.id, message)
|
|
||||||
else
|
|
||||||
package.exists = true
|
|
||||||
package:unconfiguretree()
|
|
||||||
logger:log("install", "installed %s", package.id)
|
|
||||||
configurepkg(package)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
package.exists = true
|
|
||||||
package:unconfiguretree()
|
|
||||||
logger:log("install", "installed %s", package.id)
|
|
||||||
configurepkg(package)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
cb(err)
|
|
||||||
end)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- update a package
|
|
||||||
---@param package package package to update
|
|
||||||
---@param cb function callback
|
|
||||||
function git.update(package, cb)
|
|
||||||
if not package.enabled then
|
|
||||||
cb()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local function log_err(err)
|
|
||||||
logger:log("error", "failed to update %s; reason: %s", package.id, err)
|
|
||||||
end
|
|
||||||
|
|
||||||
if package.pin then
|
|
||||||
cb()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
proc.git_rev_parse(package.dir, "HEAD", function(err, before)
|
|
||||||
if err then
|
|
||||||
log_err(before)
|
|
||||||
cb(err)
|
|
||||||
else
|
|
||||||
if package.commit then
|
|
||||||
proc.git_checkout(package.dir, package.branch, package.commit, function(err, message)
|
|
||||||
if err then
|
|
||||||
log_err(message)
|
|
||||||
cb(err)
|
|
||||||
else
|
|
||||||
proc.git_rev_parse(package.dir, package.commit, function(err, after)
|
|
||||||
if err then
|
|
||||||
log_err(after)
|
|
||||||
cb(err)
|
|
||||||
elseif before == after then
|
|
||||||
logger:log("skip", "skipped %s", package.id)
|
|
||||||
cb(err)
|
|
||||||
else
|
|
||||||
package:unconfiguretree()
|
|
||||||
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
|
|
||||||
configurepkg(package)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
else
|
|
||||||
proc.git_fetch(package.dir, "origin", package.branch or "HEAD", function(err, message)
|
|
||||||
if err then
|
|
||||||
log_err(message)
|
|
||||||
cb(err)
|
|
||||||
else
|
|
||||||
proc.git_rev_parse(package.dir, "FETCH_HEAD^{commit}", function(err, after)
|
|
||||||
if err then
|
|
||||||
log_err(after)
|
|
||||||
cb(err)
|
|
||||||
elseif before == after then
|
|
||||||
logger:log("skip", "skipped %s", package.id)
|
|
||||||
cb(err)
|
|
||||||
else
|
|
||||||
proc.git_reset(package.dir, after, function(err, message)
|
|
||||||
if err then
|
|
||||||
log_err(message)
|
|
||||||
else
|
|
||||||
package:unconfiguretree()
|
|
||||||
logger:log("update", "updated %s; %s -> %s", package.id, before, after)
|
|
||||||
configurepkg(package)
|
|
||||||
end
|
|
||||||
|
|
||||||
cb(err)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
return git
|
|
@ -1,4 +0,0 @@
|
|||||||
return {
|
|
||||||
-- vim.loop was depricated in nvim 0.10
|
|
||||||
uv = vim.uv or vim.loop
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
local h = require("dep.helpers")
|
|
||||||
local packager = require("dep.package")
|
|
||||||
|
|
||||||
---@class lazy
|
|
||||||
local lazy = {}
|
|
||||||
|
|
||||||
-- since this is already a ridiculous "optimization" we should really be caching
|
|
||||||
-- the results of this for when the user keeps on loading the colorscheme that
|
|
||||||
-- they've lazy loaded, that way we speed up the lazy loading process
|
|
||||||
local function colorscheme()
|
|
||||||
-- if a colorscheme doesn't exist attempt load it prior to it being set
|
|
||||||
vim.api.nvim_create_autocmd("ColorschemePre", {
|
|
||||||
pattern = vim.fn.getcompletion("", "color"),
|
|
||||||
callback = function(e)
|
|
||||||
for _, p in pairs(packager.get_packages()) do
|
|
||||||
if not p.loaded then
|
|
||||||
for _, ext in ipairs({ ".lua", ".vim" }) do
|
|
||||||
local path = p.dir.."/colors/"..e.match..ext
|
|
||||||
if h.uv.fs_stat(path) then
|
|
||||||
p:ensureadded(true)
|
|
||||||
-- break out of here, we've loaded the colorscheme
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
--- setup all lazy handlers
|
|
||||||
function lazy.setup()
|
|
||||||
-- start the colorscheme watcher
|
|
||||||
colorscheme()
|
|
||||||
end
|
|
||||||
|
|
||||||
return lazy
|
|
@ -1,174 +0,0 @@
|
|||||||
local logger = require('dep.log')
|
|
||||||
local packager = require('dep.package')
|
|
||||||
|
|
||||||
---@class lazy_loader
|
|
||||||
---@field load function the function to load the plugin
|
|
||||||
---@field command_ids string[] the commands that have been registered
|
|
||||||
---@field auto_ids number[] the auto commands that have been registered
|
|
||||||
---@field keybind_ids table[] the keybinds that have been registered
|
|
||||||
---@field plugin_ids table[] the plugins that have been registered
|
|
||||||
local lazy_loader = {}
|
|
||||||
|
|
||||||
--- create a new instance of lazy
|
|
||||||
---@return lazy
|
|
||||||
function lazy_loader:new()
|
|
||||||
local o = {}
|
|
||||||
|
|
||||||
setmetatable(o, self)
|
|
||||||
o.command_ids = {}
|
|
||||||
o.auto_ids = {}
|
|
||||||
o.keybind_ids = {}
|
|
||||||
o.plugin_ids = {}
|
|
||||||
|
|
||||||
self.__index = self
|
|
||||||
|
|
||||||
return o
|
|
||||||
end
|
|
||||||
|
|
||||||
--- set the loading callback
|
|
||||||
---@param load function the loader function
|
|
||||||
function lazy_loader:set_load(load)
|
|
||||||
self.load = load
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a usercommand which will trigger the plugin to load
|
|
||||||
---@param name string the name of the command
|
|
||||||
---@param opts vim.api.keyset.user_command? options
|
|
||||||
function lazy_loader:cmd(name, opts)
|
|
||||||
opts = opts or {}
|
|
||||||
|
|
||||||
-- move the rerun arg to a seperate variable because keymap.set doesn't like
|
|
||||||
-- options it doesn't know of
|
|
||||||
local rerun = opts["rerun"] or true
|
|
||||||
opts['rerun'] = nil
|
|
||||||
|
|
||||||
-- load the plugin on completion
|
|
||||||
if not opts["complete"] then
|
|
||||||
opts["complete"] = function(_, line, _)
|
|
||||||
self:cleanup()
|
|
||||||
|
|
||||||
-- return all completions for the current input, we need this to ensure
|
|
||||||
-- that the new completions are loaded from the actual plugin, not our
|
|
||||||
-- definiton of the command
|
|
||||||
return vim.fn.getcompletion(line, "cmdline")
|
|
||||||
end
|
|
||||||
opts["nargs"] = "*"
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.api.nvim_create_user_command(name, opts['callback'] or function(_)
|
|
||||||
self:cleanup()
|
|
||||||
|
|
||||||
-- attempt to rerun the command
|
|
||||||
if not rerun then
|
|
||||||
pcall(vim.cmd, name)
|
|
||||||
end
|
|
||||||
end, opts)
|
|
||||||
|
|
||||||
table.insert(self.command_ids, name)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create an auto command which will trigger the plugin to load
|
|
||||||
---@param event string the event to trigger on
|
|
||||||
---@param opts vim.api.keyset.create_autocmd? options
|
|
||||||
function lazy_loader:auto(event, opts)
|
|
||||||
opts = opts or {}
|
|
||||||
|
|
||||||
opts['callback'] = opts['callback'] or function()
|
|
||||||
self:cleanup()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- create the auto command and save it
|
|
||||||
table.insert(self.auto_ids, vim.api.nvim_create_autocmd(event, opts))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create an auto command which will trigger on filetype
|
|
||||||
---@param filetype string filetype to register the auto on
|
|
||||||
function lazy_loader:ft(filetype)
|
|
||||||
self:auto("FileType", {
|
|
||||||
pattern = filetype
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
---@class lazy.Opts: vim.keymap.set.Opts
|
|
||||||
---@field rerun boolean|function weather to rerun and what to do
|
|
||||||
|
|
||||||
--- create a keybind which will trigger the plugin to load
|
|
||||||
---@param mode string the mode to trigger in
|
|
||||||
---@param bind string the binding to use
|
|
||||||
---@param opts lazy.Opts? options
|
|
||||||
function lazy_loader:keymap(mode, bind, opts)
|
|
||||||
opts = opts or {}
|
|
||||||
|
|
||||||
-- move the rerun arg to a seperate variable because keymap.set doesn't like
|
|
||||||
-- options it doesn't know of
|
|
||||||
local rerun = opts['rerun'] or true
|
|
||||||
opts['rerun'] = nil
|
|
||||||
|
|
||||||
vim.keymap.set(mode, bind, opts['callback'] or function()
|
|
||||||
-- register keymap unload
|
|
||||||
self:cleanup()
|
|
||||||
|
|
||||||
-- call the keymap after the user has mapped it
|
|
||||||
if type(rerun) == "function" then
|
|
||||||
rerun()
|
|
||||||
elseif rerun then
|
|
||||||
local keys = vim.api.nvim_replace_termcodes(bind, true, false, true)
|
|
||||||
vim.api.nvim_input(keys)
|
|
||||||
end
|
|
||||||
end, opts)
|
|
||||||
|
|
||||||
table.insert(self.keybind_ids, { ['mode'] = mode, ['bind'] = bind })
|
|
||||||
end
|
|
||||||
|
|
||||||
--- load a plugin when another plugin loads
|
|
||||||
---@param plugin string plugin name
|
|
||||||
---@param opts table? options
|
|
||||||
function lazy_loader:plugin(plugin, opts)
|
|
||||||
opts = opts or {}
|
|
||||||
opts["callback"] = opts["callback"] or function()
|
|
||||||
self:cleanup()
|
|
||||||
end
|
|
||||||
|
|
||||||
if packager.get_packages()[plugin].loaded then
|
|
||||||
opts["callback"]()
|
|
||||||
else
|
|
||||||
local on_load = packager.get_packages()[plugin].on_load
|
|
||||||
local on_load_idx = #on_load + 1
|
|
||||||
on_load[on_load_idx] = opts["callback"]
|
|
||||||
|
|
||||||
table.insert(self.plugin_ids, { plugin, on_load_idx })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- cleanup all the callbacks, and load the plugin
|
|
||||||
function lazy_loader:cleanup()
|
|
||||||
-- cleanup user commands
|
|
||||||
for _, command_id in ipairs(self.command_ids) do
|
|
||||||
local ok, err = pcall(vim.api.nvim_del_user_command, command_id)
|
|
||||||
if not ok then
|
|
||||||
logger:log("lazy", err or "failed to delete user command")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- cleanup auto commands
|
|
||||||
for _, auto_id in ipairs(self.auto_ids) do
|
|
||||||
local ok, err = pcall(vim.api.nvim_del_autocmd, auto_id)
|
|
||||||
if not ok then
|
|
||||||
logger:log("lazy", err or "failed to delete auto command")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- cleanup keymaps
|
|
||||||
for _, keybind_id in ipairs(self.keybind_ids) do
|
|
||||||
local ok, err = pcall(vim.keymap.del, keybind_id.mode, keybind_id.bind, {})
|
|
||||||
if not ok then
|
|
||||||
logger:log("lazy", err or "failed to delete keymap")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- cleanup plugins
|
|
||||||
for _, plugin_id in ipairs(self.plugin_ids) do
|
|
||||||
table.remove(packager.get_packages()[plugin_id[1]].on_load, plugin_id[2])
|
|
||||||
end
|
|
||||||
-- load the plugin
|
|
||||||
self:load()
|
|
||||||
end
|
|
||||||
|
|
||||||
return lazy_loader
|
|
@ -1,72 +0,0 @@
|
|||||||
-- This file contains shorthands which rely on the loader core functions. They
|
|
||||||
-- are intended to ease lazy loading condition definitions to use them you may
|
|
||||||
-- do the following:
|
|
||||||
--
|
|
||||||
-- ```lua
|
|
||||||
-- _G.dep_short = require("dep.lazy.loader.short")
|
|
||||||
-- ```
|
|
||||||
--
|
|
||||||
-- Which will allow you to reference it anywhere in your config like so:
|
|
||||||
--
|
|
||||||
-- ```lua
|
|
||||||
-- require("dep") {
|
|
||||||
-- { "some/plugin",
|
|
||||||
-- lazy = dep_short.cmd("TheCommand")
|
|
||||||
-- }
|
|
||||||
-- }
|
|
||||||
-- ```
|
|
||||||
--
|
|
||||||
-- Happy vimming o/
|
|
||||||
local short = {}
|
|
||||||
|
|
||||||
--- create a single command
|
|
||||||
---@param name string the name of the command
|
|
||||||
---@param opts vim.api.keyset.user_command? options
|
|
||||||
---@return function callback
|
|
||||||
function short.cmd(name, opts)
|
|
||||||
return function(load)
|
|
||||||
load:cmd(name, opts)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a single auto command
|
|
||||||
---@param event string the event to trigger on
|
|
||||||
---@param opts vim.api.keyset.create_autocmd? options
|
|
||||||
---@return function callback
|
|
||||||
function short.auto(event, opts)
|
|
||||||
return function(load)
|
|
||||||
load:auto(event, opts)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a single auto command which will trigger on filetype
|
|
||||||
---@param filetype string filetype to register the auto on
|
|
||||||
---@return function callback
|
|
||||||
function short.ft(filetype)
|
|
||||||
return function(load)
|
|
||||||
load:ft(filetype)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a single keybind
|
|
||||||
---@param mode string the mode to trigger in
|
|
||||||
---@param bind string the binding to use
|
|
||||||
---@param opts lazy.Opts? options
|
|
||||||
---@return function callback
|
|
||||||
function short.keymap(mode, bind, opts)
|
|
||||||
return function(load)
|
|
||||||
load:keymap(mode, bind, opts)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a single plugin load event for when another plugin loads
|
|
||||||
---@param plugin string plugin name
|
|
||||||
---@param opts table? options
|
|
||||||
---@return function callback
|
|
||||||
function short.plugin(plugin, opts)
|
|
||||||
return function(load)
|
|
||||||
load:plugin(plugin, opts)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return short
|
|
173
lua/dep/log.lua
173
lua/dep/log.lua
@ -1,30 +1,23 @@
|
|||||||
local h = require('dep.helpers')
|
--
|
||||||
|
-- Copyright (c) 2022 chiya.dev
|
||||||
|
--
|
||||||
|
-- Use of this source code is governed by the MIT License
|
||||||
|
-- which can be found in the LICENSE file and at:
|
||||||
|
--
|
||||||
|
-- https://chiya.dev/licenses/mit.txt
|
||||||
|
--
|
||||||
|
local vim, setmetatable, pcall, debug, string, os, assert = vim, setmetatable, pcall, debug, string, os, assert
|
||||||
|
|
||||||
local logger = {}
|
|
||||||
|
|
||||||
logger.stage_colors = {
|
|
||||||
skip = "Comment",
|
|
||||||
clean = "Boolean",
|
|
||||||
install = "MoreMsg",
|
|
||||||
update = "WarningMsg",
|
|
||||||
delete = "Directory",
|
|
||||||
error = "ErrorMsg",
|
|
||||||
}
|
|
||||||
|
|
||||||
--- create the default logging path
|
|
||||||
---@return string path to the logfile
|
|
||||||
local function default_log_path()
|
local function default_log_path()
|
||||||
-- create cache directory and chmod it if it doesn't already exist
|
-- ensure cache directory exists (#5)
|
||||||
local path = vim.fn.stdpath("cache")
|
local path = vim.fn.stdpath("cache")
|
||||||
if not h.uv.fs_stat(path) then
|
if not vim.loop.fs_stat(path) then
|
||||||
h.uv.fs_mkdir(path, 0x1ff) -- 0777
|
vim.loop.fs_mkdir(path, 0x1ff) -- 0777
|
||||||
end
|
end
|
||||||
|
|
||||||
return vim.fs.normalize(path).."/dep.log"
|
return path .. "/dep.log"
|
||||||
end
|
end
|
||||||
|
|
||||||
--- attempt to format a string
|
|
||||||
---@vararg string formating args
|
|
||||||
local function try_format(...)
|
local function try_format(...)
|
||||||
local ok, s = pcall(string.format, ...)
|
local ok, s = pcall(string.format, ...)
|
||||||
if ok then
|
if ok then
|
||||||
@ -32,71 +25,85 @@ local function try_format(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- setup all logging stuff
|
--- Writes logs to a file and prints pretty status messages.
|
||||||
---@param path string|nil optional alternative path for the log file
|
local Logger = setmetatable({
|
||||||
---@return table
|
__metatable = "Logger",
|
||||||
function logger:setup(path)
|
__index = {
|
||||||
logger.path = path or default_log_path()
|
--- Prints a message associated with a stage.
|
||||||
local pipe
|
log = function(self, stage, message, ...)
|
||||||
|
-- calling function
|
||||||
|
local source = debug.getinfo(2, "Sl").short_src
|
||||||
|
|
||||||
logger.handle = assert(h.uv.fs_open(logger.path, "w", 0x1a4)) -- 0644
|
-- format or stringify message
|
||||||
pipe = h.uv.new_pipe()
|
if type(message) == "string" then
|
||||||
pipe:open(logger.handle)
|
message = try_format(message, ...) or message
|
||||||
|
else
|
||||||
return pipe
|
message = vim.inspect(message)
|
||||||
end
|
|
||||||
|
|
||||||
--- log a message
|
|
||||||
---@param level string error level
|
|
||||||
---@param message any string message to send
|
|
||||||
---@vararg any options to go into the message
|
|
||||||
function logger:log(level, message, ...)
|
|
||||||
-- make sure the message string is actually a string, and formatted
|
|
||||||
-- appropriately
|
|
||||||
if type(message) == "string" then
|
|
||||||
message = try_format(message, ...) or message
|
|
||||||
else
|
|
||||||
message = vim.inspect(message)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get debug info about the current function
|
|
||||||
local source = debug.getinfo(2, "Sl")
|
|
||||||
|
|
||||||
-- schedule a log message to be sent to vim, and the log file
|
|
||||||
vim.schedule(function()
|
|
||||||
if not logger.silent then
|
|
||||||
if level == "error" then
|
|
||||||
vim.api.nvim_echo({ { string.format("[dep] %s", message) } }, true,
|
|
||||||
{ err = true })
|
|
||||||
elseif logger.stage_colors[level] then
|
|
||||||
vim.api.nvim_echo({
|
|
||||||
{ "[dep]", "Identifier" },
|
|
||||||
{ " " },
|
|
||||||
{ message, logger.stage_colors[level] },
|
|
||||||
}, true, {})
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- write to the pipe if it's open
|
-- print and write must be done on the main event loop
|
||||||
if logger.pipe then
|
vim.schedule(function()
|
||||||
logger.pipe:write(string.format("[%s] %s:%s:(%s) %s\n", os.date("%T"),
|
if not self.silent then
|
||||||
source.short_src:gsub('.*%/', ''), source.currentline, level, message))
|
if stage == "error" then
|
||||||
end
|
vim.api.nvim_err_writeln(string.format("[dep] %s", message))
|
||||||
end)
|
elseif self.stage_colors[stage] then
|
||||||
end
|
vim.api.nvim_echo({
|
||||||
|
{ "[dep]", "Identifier" },
|
||||||
|
{ " " },
|
||||||
|
{ message, self.stage_colors[stage] },
|
||||||
|
}, true, {})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- cleanup all logging stuff
|
if self.pipe then
|
||||||
---@param pipe table? pipe
|
self.pipe:write(string.format("[%s] %s: %s\n", os.date(), source, message))
|
||||||
---@param handle table? handle
|
end
|
||||||
function logger:cleanup(pipe, handle)
|
end)
|
||||||
if pipe then
|
end,
|
||||||
pipe:close()
|
|
||||||
pipe = nil
|
|
||||||
end
|
|
||||||
if handle then
|
|
||||||
h.uv.fs_close(logger.handle)
|
|
||||||
handle = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return logger
|
--- Closes the log file handle.
|
||||||
|
close = function(self)
|
||||||
|
if self.pipe then
|
||||||
|
self.pipe:close()
|
||||||
|
self.pipe = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.handle then
|
||||||
|
vim.loop.fs_close(self.handle)
|
||||||
|
self.handle = nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
--- Constructs a new `Logger`.
|
||||||
|
__call = function(mt, path)
|
||||||
|
path = path or default_log_path()
|
||||||
|
|
||||||
|
-- clear and open log file
|
||||||
|
local handle = assert(vim.loop.fs_open(path, "w", 0x1a4)) -- 0644
|
||||||
|
local pipe = vim.loop.new_pipe()
|
||||||
|
pipe:open(handle)
|
||||||
|
|
||||||
|
return setmetatable({
|
||||||
|
path = path,
|
||||||
|
handle = handle,
|
||||||
|
pipe = pipe,
|
||||||
|
silent = false,
|
||||||
|
|
||||||
|
-- TODO: This looks good for me ;) but it should have proper vim color mapping for other people.
|
||||||
|
stage_colors = {
|
||||||
|
skip = "Comment",
|
||||||
|
clean = "Boolean",
|
||||||
|
install = "MoreMsg",
|
||||||
|
update = "WarningMsg",
|
||||||
|
delete = "Directory",
|
||||||
|
error = "ErrorMsg",
|
||||||
|
},
|
||||||
|
}, mt)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
Logger = Logger,
|
||||||
|
global = Logger(),
|
||||||
|
}
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
local h = require('dep.helpers')
|
|
||||||
local logger = require('dep.log')
|
|
||||||
local module = require("dep.modules.module")
|
|
||||||
|
|
||||||
---@class modules
|
|
||||||
---@field modules module[] all modules in dep
|
|
||||||
local modules = {}
|
|
||||||
|
|
||||||
--- Initialize all the modules
|
|
||||||
---@param self table?
|
|
||||||
---@param speclist table
|
|
||||||
---@param overrides spec? overrides
|
|
||||||
---@return modules modules manager
|
|
||||||
---@nodisacard
|
|
||||||
function modules:setup(speclist, overrides, config_path)
|
|
||||||
overrides = overrides or {}
|
|
||||||
|
|
||||||
local o = {}
|
|
||||||
self = {}
|
|
||||||
self.__index = self
|
|
||||||
setmetatable(o, self)
|
|
||||||
|
|
||||||
-- create a list of modules
|
|
||||||
o.modules = {}
|
|
||||||
|
|
||||||
if (speclist.modules[1] == "*" or #speclist.modules == 0)
|
|
||||||
and speclist.modules.prefix then
|
|
||||||
|
|
||||||
local path = vim.fs.joinpath(config_path:gsub("[^/]*$", ""),
|
|
||||||
"lua", (speclist.modules.prefix:gsub("%.", "/"))
|
|
||||||
)
|
|
||||||
|
|
||||||
local handle = h.uv.fs_scandir(path)
|
|
||||||
while handle do
|
|
||||||
local name = h.uv.fs_scandir_next(handle)
|
|
||||||
if name then
|
|
||||||
-- skip non-lua files
|
|
||||||
if name:sub(#name - 3) ~= ".lua" then
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
|
|
||||||
-- remove the file extension from the name so that lua doesn't fail
|
|
||||||
-- when attempting to load it
|
|
||||||
name = name:sub(0, #name - 4)
|
|
||||||
|
|
||||||
-- put the module into the list of modules
|
|
||||||
table.insert(speclist.modules, name)
|
|
||||||
|
|
||||||
::continue::
|
|
||||||
elseif name == nil then
|
|
||||||
-- no more entries
|
|
||||||
break
|
|
||||||
else
|
|
||||||
-- if there's a single error bail out
|
|
||||||
logger:log("error", "failed to run clean uv.fs_scandir_next failed")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- loop through all modules and initialize them
|
|
||||||
for _, modpath in ipairs(speclist.modules) do
|
|
||||||
local mod = module.new(nil, modpath, speclist.modules.prefix, overrides)
|
|
||||||
if not mod then
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(o.modules, mod)
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
return modules
|
|
@ -1,73 +0,0 @@
|
|||||||
local logger = require('dep.log')
|
|
||||||
local spec_man = require("dep.spec")
|
|
||||||
local packager = require("dep.package")
|
|
||||||
|
|
||||||
---@class module
|
|
||||||
---@field name string name of the module
|
|
||||||
---@field desc string description of the module
|
|
||||||
---@field disable boolean weather to disable all the packages inside the module
|
|
||||||
---@field path string path to the module
|
|
||||||
---@field mod table the module
|
|
||||||
---@field packages package[] all packages registed from the module
|
|
||||||
local module = {}
|
|
||||||
|
|
||||||
--- Initialize a module
|
|
||||||
---@param self table?
|
|
||||||
---@param modpath string path to the module
|
|
||||||
---@param prefix string? the prefix to all modules
|
|
||||||
---@param overrides spec? a module override
|
|
||||||
---@return module|false module false on failure to load module
|
|
||||||
---@nodiscard
|
|
||||||
function module:new(modpath, prefix, overrides)
|
|
||||||
overrides = overrides or {}
|
|
||||||
|
|
||||||
local ok, err
|
|
||||||
local o = {}
|
|
||||||
self = {}
|
|
||||||
self.__index = self
|
|
||||||
setmetatable(o, self)
|
|
||||||
|
|
||||||
o.name = "<unnamed module>"
|
|
||||||
o.desc = "<undescribed module>"
|
|
||||||
if type(modpath) == "string" then
|
|
||||||
if prefix ~= nil then
|
|
||||||
if prefix:sub(#prefix) ~= "." and modpath:sub(1, 2) ~= "." then
|
|
||||||
modpath = "."..modpath
|
|
||||||
end
|
|
||||||
o.path = prefix..modpath
|
|
||||||
else
|
|
||||||
o.path = modpath
|
|
||||||
end
|
|
||||||
o.name = modpath
|
|
||||||
ok, o.mod = pcall(require, o.path)
|
|
||||||
if not ok then
|
|
||||||
logger:log("error", "failed to load module: %s", vim.inspect(o.mod))
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
o.name = o.mod.name or o.name
|
|
||||||
o.desc = o.mod.desc or o.desc
|
|
||||||
|
|
||||||
-- ensure the overrides are properly set
|
|
||||||
overrides = vim.tbl_extend("force", overrides, {
|
|
||||||
disable = o.mod.disable or overrides.disable
|
|
||||||
})
|
|
||||||
|
|
||||||
-- allow a module to be a spec
|
|
||||||
if spec_man.check(o.mod, true) ~= false then
|
|
||||||
o.mod = { o.mod }
|
|
||||||
end
|
|
||||||
|
|
||||||
ok, err = pcall(packager.register_speclist, o.mod, overrides)
|
|
||||||
if not ok then
|
|
||||||
logger:log("error", "%s <- %s", err, o.name)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ensure that the module contains the packages that it's created
|
|
||||||
self.packages = err
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
return module
|
|
@ -1,511 +1,258 @@
|
|||||||
local logger = require('dep.log')
|
--
|
||||||
local spec_man = require("dep.spec")
|
-- Copyright (c) 2022 chiya.dev
|
||||||
local bench = require("dep.bench")
|
--
|
||||||
|
-- Use of this source code is governed by the MIT License
|
||||||
|
-- which can be found in the LICENSE file and at:
|
||||||
|
--
|
||||||
|
-- https://chiya.dev/licenses/mit.txt
|
||||||
|
--
|
||||||
|
local require, type, setmetatable, error, table, assert, math, os, debug =
|
||||||
|
require, type, setmetatable, error, table, assert, math, os, debug
|
||||||
|
local logger = require("dep.log").global
|
||||||
|
|
||||||
---@class package
|
local function parse_name_from_id(id)
|
||||||
---@field id string id of the package
|
local name = id:match("^[%w-_.]+/([%w-_.]+)$")
|
||||||
---@field enabled boolean whether it's going to be used
|
if name then
|
||||||
---@field exists boolean if the package exists on the filesystem
|
return name
|
||||||
---@field lazy boolean if the package is lazy loaded in any way
|
|
||||||
---@field added boolean if the package has been added in vim
|
|
||||||
---@field configured boolean if the package has been configured
|
|
||||||
---@field loaded boolean if a package has been loaded
|
|
||||||
---@field subtree_loaded boolean is the subtree has been loaded
|
|
||||||
---@field on_config function[] table of functions to run on config
|
|
||||||
---@field on_setup function[] table of function to run on setup
|
|
||||||
---@field on_load function[] table of functions to run on load
|
|
||||||
---@field lazy_load table table of functions and booleans to run which will tell the package when to load
|
|
||||||
---@field requirements package[] this package's requirements
|
|
||||||
---@field dependents package[] packages that require this package
|
|
||||||
---@field perf table performance metrics for the package
|
|
||||||
---@field name string the name of the package
|
|
||||||
---@field url string the url of the package
|
|
||||||
---@field path string? the path of the package which overrides the url
|
|
||||||
---@field branch string the branch of the package
|
|
||||||
---@field dir string the directory of the package
|
|
||||||
---@field commit string the commit of the package
|
|
||||||
---@field pin boolean whether to pin the package or not
|
|
||||||
local package = {}
|
|
||||||
|
|
||||||
--- the base directory for the packages
|
|
||||||
---@type string
|
|
||||||
local base_dir
|
|
||||||
|
|
||||||
--- the root package
|
|
||||||
---@type package
|
|
||||||
local root
|
|
||||||
|
|
||||||
--- list of all package in dep
|
|
||||||
---@type package[]
|
|
||||||
local packages = {}
|
|
||||||
|
|
||||||
--- tell the parent it has a child and the child it has a parent
|
|
||||||
---@param parent package? parent package if nil defaults to self
|
|
||||||
---@param child package child package
|
|
||||||
function package:link_dependency(parent, child)
|
|
||||||
parent = parent or self
|
|
||||||
|
|
||||||
if not parent.dependents[child.id] then
|
|
||||||
parent.dependents[child.id] = child
|
|
||||||
table.insert(parent.dependents, child)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not child.requirements[parent.id] then
|
|
||||||
child.requirements[parent.id] = parent
|
|
||||||
table.insert(child.requirements, parent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- create a new package instance
|
|
||||||
---@param spec spec|string a package spec to use for the new package
|
|
||||||
---@param overrides spec? a package spec that is used to overried this package
|
|
||||||
---@return package|false package an instance of the package or false on failure
|
|
||||||
---@nodisacard
|
|
||||||
function package:new(spec, overrides)
|
|
||||||
overrides = overrides or {}
|
|
||||||
|
|
||||||
-- ensure that the spec is ok
|
|
||||||
local new_spec = spec_man.check(spec_man.correct_spec(spec))
|
|
||||||
if new_spec == false then
|
|
||||||
logger:log("spec", vim.inspect(spec))
|
|
||||||
logger:log("error", "spec check failed, check DepLog")
|
|
||||||
return false
|
|
||||||
else
|
else
|
||||||
spec = new_spec
|
error(string.format('invalid package name "%s"; must be in the format "user/package"', id))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- start initializing the package
|
local function is_nonempty_str(s)
|
||||||
local id = spec[1]
|
return type(s) == "string" and #s ~= 0
|
||||||
|
end
|
||||||
|
|
||||||
local o = packages[id] or {}
|
--- Package information.
|
||||||
self.__index = self
|
local Package = setmetatable({
|
||||||
setmetatable(o, self)
|
__metatable = "Package",
|
||||||
|
__index = {
|
||||||
-- if package hasn't been registered already, get the inital spec regisitered
|
--- Runs all registered hooks of the given type.
|
||||||
if not o.id then
|
run_hooks = function(self, hook)
|
||||||
o.id = id
|
local hooks = self["on_" .. hook]
|
||||||
o.enabled = true
|
if not hooks or #hooks == 0 then
|
||||||
o.exists = false
|
return true
|
||||||
o.lazy = false
|
|
||||||
o.added = false
|
|
||||||
o.configured = false
|
|
||||||
o.loaded = false
|
|
||||||
o.subtree_loaded = false
|
|
||||||
o.on_config = {}
|
|
||||||
o.on_setup = {}
|
|
||||||
o.on_load = {}
|
|
||||||
o.lazy_load = {}
|
|
||||||
|
|
||||||
o.requirements = {}
|
|
||||||
o.dependents = {}
|
|
||||||
o.perf = {}
|
|
||||||
|
|
||||||
packages[id] = o
|
|
||||||
end
|
|
||||||
|
|
||||||
o.name = spec.as or o.name or spec_man.get_name(spec)
|
|
||||||
o.url = spec.url or o.url or ("https://github.com/"..id..".git")
|
|
||||||
o.path = spec.path and vim.fs.normalize(spec.path) or spec.path
|
|
||||||
o.branch = spec.branch or o.branch
|
|
||||||
o.dir = base_dir.."/"..o.name
|
|
||||||
o.commit = spec.commit
|
|
||||||
o.pin = overrides.pin or spec.pin or o.pin
|
|
||||||
o.enabled = not overrides.disable and not spec.disable and o.enabled
|
|
||||||
o.lazy = spec.lazy ~= nil or o.lazy
|
|
||||||
|
|
||||||
-- make sure that the package exists
|
|
||||||
o.exists = vim.fn.isdirectory(o.dir) ~= 0
|
|
||||||
o.configured = o.exists
|
|
||||||
|
|
||||||
-- register all the callback functions
|
|
||||||
if spec.config ~= nil then
|
|
||||||
table.insert(o.on_config, spec.config)
|
|
||||||
end
|
|
||||||
if spec.setup ~= nil then
|
|
||||||
table.insert(o.on_setup, spec.setup)
|
|
||||||
end
|
|
||||||
if spec.load ~= nil then
|
|
||||||
table.insert(o.on_load, spec.load)
|
|
||||||
end
|
|
||||||
if spec.lazy ~= nil then
|
|
||||||
table.insert(o.lazy_load, spec.lazy)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if the current package isn't the root package then it depends on the root
|
|
||||||
-- package
|
|
||||||
if root and o ~= root then
|
|
||||||
o:link_dependency(root, o)
|
|
||||||
elseif not root then
|
|
||||||
root = o
|
|
||||||
end
|
|
||||||
|
|
||||||
-- link the dependencies
|
|
||||||
if spec.reqs then
|
|
||||||
---it is the correct type as asserted in check_spec()
|
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
|
||||||
for _, req in pairs(spec.reqs) do
|
|
||||||
local pkg = package:new(req)
|
|
||||||
if type(pkg) == "table" then
|
|
||||||
o:link_dependency(pkg, o)
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- and link the dependents
|
local start = os.clock()
|
||||||
if spec.deps then
|
for i = 1, #hooks do
|
||||||
---it is the correct type as asserted in check_spec()
|
local ok, err = xpcall(hooks[i], debug.traceback)
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
|
||||||
for _, dep in pairs(spec.deps) do
|
|
||||||
local pkg = package:new(dep)
|
|
||||||
if not pkg then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
o:link_dependency(o, pkg)
|
|
||||||
|
|
||||||
-- if the child package is lazy loaded make sure the child package
|
|
||||||
-- is only loaded when the parent package has finished loading
|
|
||||||
if o.lazy then
|
|
||||||
-- tell the dep that it's gonna be lazy
|
|
||||||
pkg.lazy = true
|
|
||||||
table.insert(pkg.lazy_load,
|
|
||||||
require("dep.lazy.loader.short").plugin(id))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return o
|
|
||||||
end
|
|
||||||
|
|
||||||
--- set the base directory for packages
|
|
||||||
---@param _base_dir string base directory
|
|
||||||
function package.set_base_dir(_base_dir)
|
|
||||||
base_dir = vim.fs.normalize(_base_dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- get the base directory for packages
|
|
||||||
---@return string base_dir
|
|
||||||
---@nodiscard
|
|
||||||
function package.get_base_dir()
|
|
||||||
return base_dir
|
|
||||||
end
|
|
||||||
|
|
||||||
--- get the root directory
|
|
||||||
---@return package root
|
|
||||||
---@nodiscard
|
|
||||||
function package.get_root()
|
|
||||||
return root
|
|
||||||
end
|
|
||||||
|
|
||||||
--- get the packages in dep
|
|
||||||
---@return package[] packages
|
|
||||||
---@nodiscard
|
|
||||||
function package.get_packages()
|
|
||||||
return packages
|
|
||||||
end
|
|
||||||
|
|
||||||
--- run specified hooks on the current package
|
|
||||||
---@param type "on_load"|"on_config"|"on_setup" which hook to run
|
|
||||||
---@return boolean, string|nil
|
|
||||||
function package:runhooks(type)
|
|
||||||
local hooks = self[type]
|
|
||||||
if #hooks == 0 then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local start = os.clock()
|
|
||||||
|
|
||||||
-- chdir into the package directory to make running external commands
|
|
||||||
-- from hooks easier.
|
|
||||||
local last_cwd = vim.fn.getcwd()
|
|
||||||
vim.fn.chdir(self.dir)
|
|
||||||
|
|
||||||
for i = 1, #hooks do
|
|
||||||
local ok, err = pcall(hooks[i])
|
|
||||||
if not ok then
|
|
||||||
vim.fn.chdir(last_cwd)
|
|
||||||
|
|
||||||
return false, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.fn.chdir(last_cwd)
|
|
||||||
self.perf[type] = os.clock() - start
|
|
||||||
|
|
||||||
logger:log("hook", "triggered %d %s %s for %s", #hooks, type,
|
|
||||||
#hooks == 1 and "hook" or "hooks", self.id)
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- make sure a package has been loaded
|
|
||||||
---@param force boolean? force lazy packages to load
|
|
||||||
---@return boolean|table return true or false if loaded or package spec if lazy loaded
|
|
||||||
function package:ensureadded(force)
|
|
||||||
--- load a package
|
|
||||||
---@param pkg package
|
|
||||||
local function loadpkg(pkg)
|
|
||||||
if not self.enabled then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- make sure to load the dependencies first
|
|
||||||
for _, p in pairs(pkg.requirements) do
|
|
||||||
if not p.loaded then
|
|
||||||
p:ensureadded(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- run setup hooks
|
|
||||||
pkg:runhooks("on_setup")
|
|
||||||
|
|
||||||
-- now start loading our plugin
|
|
||||||
local start = os.clock()
|
|
||||||
|
|
||||||
-- trigger the packadd for the plugin
|
|
||||||
---@diagnostic disable-next-line: param-type-mismatch
|
|
||||||
local ok, err = pcall(vim.cmd, "packadd "..pkg.name)
|
|
||||||
if not ok then
|
|
||||||
return false, err
|
|
||||||
end
|
|
||||||
|
|
||||||
pkg.added = true
|
|
||||||
pkg.perf.pack = os.clock() - start
|
|
||||||
logger:log("vim", "packadd completed for %s", pkg.id)
|
|
||||||
|
|
||||||
-- set the package to loaded
|
|
||||||
pkg.loaded = true
|
|
||||||
logger:log("load", "loaded %s", pkg.id)
|
|
||||||
|
|
||||||
-- trigger the on_load hooks
|
|
||||||
ok, err = pkg:runhooks("on_load")
|
|
||||||
if not ok then
|
|
||||||
logger:log("error", "failed to load %s; reason: %s", pkg.id, err)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- make sure the package is lazy loaded if need be
|
|
||||||
if not self.added and not self.loaded and not self.lazy or force then
|
|
||||||
loadpkg(self)
|
|
||||||
elseif not self.added and self.lazy then
|
|
||||||
logger:log("lazy", "registering %d lazy hooks for %s", #self.lazy_load,
|
|
||||||
self.id)
|
|
||||||
for _, load_cond in pairs(self.lazy_load) do
|
|
||||||
-- configure the lazy loader for the user
|
|
||||||
local l = require('dep.lazy.loader'):new()
|
|
||||||
if l == true then
|
|
||||||
logger:log("lazy", "failed to get lazy utils")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
l:set_load(function()
|
|
||||||
-- ensure that we can't attempt to load a plugin twice via lazy loading
|
|
||||||
if self.loaded then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
logger:log("lazy", "triggered %d lazy hooks for %s", #self.lazy_load,
|
|
||||||
self.id)
|
|
||||||
loadpkg(self)
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- run it if it's not just a stopper to keep the plugin lazy
|
|
||||||
if load_cond ~= true then
|
|
||||||
local ok, err = pcall(load_cond, l)
|
|
||||||
if not ok then
|
if not ok then
|
||||||
logger:log("error", "failed to register lazy load conditions for '%s': %s",
|
return false, err
|
||||||
self.name, err)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
local elapsed = os.clock() - start
|
||||||
end
|
self.perf.hooks[hook] = elapsed
|
||||||
|
|
||||||
--- load all packages in package tree
|
logger:log(
|
||||||
---@param force boolean? force lazy packages to load
|
"hook",
|
||||||
---@return boolean boolean if tree was successfully loaded
|
"triggered %d %s %s for %s in %dms",
|
||||||
---@nodiscard
|
#hooks,
|
||||||
function package:loadtree(force)
|
hook,
|
||||||
-- if the package doesn't exist or isn't enabled then don't load it
|
#hooks == 1 and "hook" or "hooks",
|
||||||
if not self.exists or not self.enabled then
|
self.id,
|
||||||
return false
|
elapsed
|
||||||
end
|
)
|
||||||
|
|
||||||
-- if the subtree is loaded then it's already loaded unless it needs forcing
|
return true
|
||||||
if not force and self.subtree_loaded then
|
end,
|
||||||
return true
|
},
|
||||||
end
|
}, {
|
||||||
|
--- Constructs a new `Package` with the given identifier.
|
||||||
|
__call = function(mt, id)
|
||||||
|
local name = parse_name_from_id(id)
|
||||||
|
return setmetatable({
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
url = "https://github.com/" .. id .. ".git",
|
||||||
|
enabled = true,
|
||||||
|
exists = false,
|
||||||
|
added = false,
|
||||||
|
configured = false,
|
||||||
|
loaded = false,
|
||||||
|
dependencies = {},
|
||||||
|
dependents = {},
|
||||||
|
subtree_configured = false,
|
||||||
|
subtree_loaded = false,
|
||||||
|
on_setup = {},
|
||||||
|
on_config = {},
|
||||||
|
on_load = {},
|
||||||
|
perf = { hooks = {} },
|
||||||
|
}, mt)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
-- if the package isn't lazy check that it's requirements are loaded
|
--- Manages a set of packages.
|
||||||
if not self.lazy then
|
local PackageStore = setmetatable({
|
||||||
for _, requirement in pairs(self.requirements) do
|
__metatable = "PackageStore",
|
||||||
if not requirement.loaded and not requirement.lazy then
|
__index = {
|
||||||
return false
|
--- Links the given packages such that the parent must load before the child.
|
||||||
|
link_dependency = function(self, parent, child)
|
||||||
|
if not parent.dependents[child.id] then
|
||||||
|
parent.dependents[child.id] = child
|
||||||
|
parent.dependents[#parent.dependents + 1] = child
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- if the package isn't loaded and isn't lazy then it should probably be
|
if not child.dependencies[parent.id] then
|
||||||
-- loaded
|
child.dependencies[parent.id] = parent
|
||||||
if not self.loaded then
|
child.dependencies[#child.dependencies + 1] = parent
|
||||||
local ok, err = self:ensureadded(force)
|
end
|
||||||
if not ok then
|
end,
|
||||||
logger:log("error", "failed to load %s; reason: %s", self.id, err)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self.subtree_loaded = true
|
--- Ensures the given package spec table is valid.
|
||||||
|
validate_spec = function(self, spec)
|
||||||
|
assert(spec[1] ~= nil, "package id missing from spec")
|
||||||
|
assert(type(spec[1]) == "string", "package id must be a string")
|
||||||
|
parse_name_from_id(spec[1])
|
||||||
|
|
||||||
-- make sure the dependants are loaded
|
assert(spec.as == nil or is_nonempty_str(spec.as), "package name must be a string")
|
||||||
for _, dependant in pairs(self.dependents) do
|
assert(spec.url == nil or type(spec.url) == "string", "package url must be a string") -- TODO: validate url or path
|
||||||
self.subtree_loaded = dependant:loadtree(force) and self.subtree_loaded
|
assert(spec.branch == nil or is_nonempty_str(spec.branch), "package branch must be a string")
|
||||||
end
|
assert(spec.pin == nil or type(spec.pin) == "boolean", "package pin must be a boolean")
|
||||||
|
assert(spec.disable == nil or type(spec.disable) == "boolean", "package disable must be a boolean")
|
||||||
|
|
||||||
return self.subtree_loaded
|
assert(
|
||||||
end
|
spec.requires == nil or type(spec.requires) == "table" or type(spec.requires) == "string",
|
||||||
|
"package requires must be a string or table"
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
spec.deps == nil or type(spec.deps) == "table" or type(spec.deps) == "string",
|
||||||
|
"package deps must be a string or table"
|
||||||
|
)
|
||||||
|
|
||||||
--- unconfigure a packages tree
|
assert(spec.setup == nil or type(spec.setup) == "function", "package setup must be a function")
|
||||||
function package:unconfiguretree()
|
assert(spec.config == nil or type(spec.config) == "function", "package config must be a function")
|
||||||
-- unconfigure requirements
|
assert(spec[2] == nil or type(spec[2]) == "function", "package loader must be a function")
|
||||||
for _, requirement in pairs(self.requirements) do
|
end,
|
||||||
requirement.subtree_loaded = false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- unconfigure dependents
|
--- Creates or updates a package from the given spec table, and returns that package.
|
||||||
for _, dependant in pairs(self.dependents) do
|
add_spec = function(self, spec, scope)
|
||||||
dependant.loaded = false
|
self:validate_spec(spec)
|
||||||
dependant.added = false
|
scope = scope or {}
|
||||||
dependant.configured = false
|
|
||||||
|
|
||||||
dependant.subtree_loaded = false
|
local id = spec[1]
|
||||||
end
|
local pkg = self[id]
|
||||||
end
|
|
||||||
|
|
||||||
--- check a list of packages for any cycles
|
if not pkg then
|
||||||
---@param pkgs package[] list of packages
|
pkg = Package(id)
|
||||||
---@return package[]|false cycle the cycle that was found or false if not found
|
self[id], self[#self + 1] = pkg, pkg
|
||||||
---@nodisacard
|
end
|
||||||
function package.findcycle(pkgs)
|
|
||||||
local index = 0
|
|
||||||
local indexes = {}
|
|
||||||
local lowlink = {}
|
|
||||||
local stack = {}
|
|
||||||
|
|
||||||
--- use tarjan algorithm to find circular dependencies (strongly connected
|
-- blend package spec with existing package info
|
||||||
--- components)
|
pkg.name = spec.as or pkg.name
|
||||||
---@param pkg package
|
pkg.url = spec.url or pkg.url
|
||||||
local function connect(pkg)
|
pkg.branch = spec.branch or pkg.branch
|
||||||
indexes[pkg.id], lowlink[pkg.id] = index, index
|
pkg.pin = scope.pin or spec.pin or pkg.pin
|
||||||
stack[#stack + 1], stack[pkg.id] = pkg, true
|
pkg.enabled = not scope.disable and not spec.disable and pkg.enabled
|
||||||
index = index + 1
|
|
||||||
|
|
||||||
for i = 1, #pkg.dependents do
|
pkg.on_setup[#pkg.on_setup + 1] = spec.setup
|
||||||
local dependent = pkg.dependents[i]
|
pkg.on_config[#pkg.on_config + 1] = spec.config
|
||||||
|
pkg.on_load[#pkg.on_load + 1] = spec[2]
|
||||||
|
|
||||||
if not indexes[dependent.id] then
|
local requires = type(spec.requires) == "table" and spec.requires or { spec.requires }
|
||||||
local cycle = connect(dependent)
|
local deps = type(spec.deps) == "table" and spec.deps or { spec.deps }
|
||||||
if cycle then
|
|
||||||
return cycle
|
-- recursively add specs for dependencies and dependents
|
||||||
else
|
for i = 1, #requires do
|
||||||
lowlink[pkg.id] = math.min(lowlink[pkg.id], lowlink[dependent.id])
|
self:link_dependency(self:add_spec(requires[i], scope), pkg)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #deps do
|
||||||
|
self:link_dependency(pkg, self:add_spec(deps[i], scope))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
--- Adds the given list of specs.
|
||||||
|
add_specs = function(self, specs, scope)
|
||||||
|
assert(type(specs) == "table", "package list must be a table")
|
||||||
|
assert(specs.pin == nil or type(specs.pin) == "boolean", "package list pin must be a boolean")
|
||||||
|
assert(specs.disable == nil or type(specs.disable) == "boolean", "package list disable must be a boolean")
|
||||||
|
|
||||||
|
scope = scope or {}
|
||||||
|
scope = {
|
||||||
|
-- outer scope takes precedence over inner list's overrides
|
||||||
|
pin = scope.pin or specs.pin,
|
||||||
|
disable = scope.disable or specs.disable,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- add specs in spec list
|
||||||
|
for i = 1, #specs do
|
||||||
|
self:add_spec(specs[i], scope)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
|
--- Ensures there are no circular dependencies in this package store.
|
||||||
|
ensure_acyclic = function(self)
|
||||||
|
-- tarjan's strongly connected components algorithm
|
||||||
|
local idx, indices, lowlink, stack = 0, {}, {}, {}
|
||||||
|
|
||||||
|
local function connect(pkg)
|
||||||
|
indices[pkg.id], lowlink[pkg.id] = idx, idx
|
||||||
|
stack[#stack + 1], stack[pkg.id] = pkg, true
|
||||||
|
idx = idx + 1
|
||||||
|
|
||||||
|
for i = 1, #pkg.dependents do
|
||||||
|
local dependent = pkg.dependents[i]
|
||||||
|
|
||||||
|
if not indices[dependent.id] then
|
||||||
|
local cycle = connect(dependent)
|
||||||
|
if cycle then
|
||||||
|
return cycle
|
||||||
|
else
|
||||||
|
lowlink[pkg.id] = math.min(lowlink[pkg.id], lowlink[dependent.id])
|
||||||
|
end
|
||||||
|
elseif stack[dependent.id] then
|
||||||
|
lowlink[pkg.id] = math.min(lowlink[pkg.id], indices[dependent.id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if lowlink[pkg.id] == indices[pkg.id] then
|
||||||
|
local cycle = { pkg }
|
||||||
|
local node
|
||||||
|
|
||||||
|
repeat
|
||||||
|
node = stack[#stack]
|
||||||
|
stack[#stack], stack[node.id] = nil, nil
|
||||||
|
cycle[#cycle + 1] = node
|
||||||
|
until node == pkg
|
||||||
|
|
||||||
|
-- a node is by definition strongly connected to itself
|
||||||
|
-- ignore single-node components unless the package explicitly specified itself as a dependency (i.e. the user is being weird)
|
||||||
|
if #cycle > 2 or pkg.dependents[pkg.id] then
|
||||||
|
return cycle
|
||||||
|
end
|
||||||
end
|
end
|
||||||
elseif stack[dependent.id] then
|
|
||||||
lowlink[pkg.id] = math.min(lowlink[pkg.id], indexes[dependent.id])
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if lowlink[pkg.id] == indexes[pkg.id] then
|
for i = 1, #self do
|
||||||
local cycle = { pkg }
|
local pkg = self[i]
|
||||||
local node
|
|
||||||
|
|
||||||
repeat
|
if not indices[pkg.id] then
|
||||||
node = stack[#stack]
|
local cycle = connect(pkg)
|
||||||
stack[#stack], stack[node.id] = nil, nil
|
if cycle then
|
||||||
cycle[#cycle + 1] = node
|
-- found dependency cycle
|
||||||
until node == pkg
|
local names = {}
|
||||||
|
for j = 1, #cycle do
|
||||||
-- a node is by definition strongly connected to itself ignore single-node
|
names[j] = cycle[j].id
|
||||||
-- components unless it explicitly specified itself as a dependency
|
end
|
||||||
if #cycle > 2 or pkg.dependents[pkg.id] then
|
error("circular dependency detected in package dependency graph: " .. table.concat(names, " -> "))
|
||||||
return cycle
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end,
|
||||||
end
|
},
|
||||||
|
}, {
|
||||||
|
--- Constructs a new `PackageStore`.
|
||||||
|
__call = function(mt)
|
||||||
|
-- hash part of store maps package ids to packages
|
||||||
|
-- array part of store is a list of packages
|
||||||
|
-- all packages in a store are unique based on their id
|
||||||
|
return setmetatable({}, mt)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
-- actually check the cycle
|
return {
|
||||||
for _, pkg in pairs(pkgs) do
|
Package = Package,
|
||||||
if not indexes[package.id] then
|
PackageStore = PackageStore,
|
||||||
local cycle = connect(pkg)
|
}
|
||||||
if cycle then
|
|
||||||
return cycle
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- recurse over all packages and register them
|
|
||||||
---@param speclist speclist table of specs
|
|
||||||
---@param overrides spec? a package spec that is used to override options
|
|
||||||
---@return package[] packages
|
|
||||||
function package.register_speclist(speclist, overrides)
|
|
||||||
overrides = overrides or {}
|
|
||||||
local packages_from_speclist = {}
|
|
||||||
|
|
||||||
-- recurse the packages
|
|
||||||
local over = overrides
|
|
||||||
for _, spec in ipairs(speclist) do
|
|
||||||
-- make sure the overrides override and take into account the packages spec
|
|
||||||
---@diagnostic disable-next-line: missing-fields
|
|
||||||
over = {
|
|
||||||
pin = overrides.pin or spec.pin,
|
|
||||||
disable = overrides.disable or spec.disable
|
|
||||||
}
|
|
||||||
|
|
||||||
-- While a package can fail to load we just don't care, it will work itself
|
|
||||||
-- out. The goal is to make sure every plugin that can load does load, not
|
|
||||||
-- keep working plugins from loading because an unrelated one doesn't load.
|
|
||||||
local pkg = package:new(spec, over)
|
|
||||||
if not pkg then
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
|
|
||||||
-- we store all the packages in a table so that the caller may keep track of
|
|
||||||
-- their packages, this is not required and therefore the return value may
|
|
||||||
-- be discarded
|
|
||||||
table.insert(packages_from_speclist, pkg)
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
|
|
||||||
return packages_from_speclist
|
|
||||||
end
|
|
||||||
|
|
||||||
--- reload the package
|
|
||||||
---@param self package the package to reload
|
|
||||||
---@param force boolean? force all packages to load
|
|
||||||
function package:reload(force)
|
|
||||||
local reloaded = self:loadtree(force)
|
|
||||||
|
|
||||||
if reloaded then
|
|
||||||
local ok, err
|
|
||||||
-- TODO: make a benchmark function
|
|
||||||
bench.mark("reload", function()
|
|
||||||
ok, err = pcall(vim.cmd,
|
|
||||||
[[
|
|
||||||
silent! helptags ALL
|
|
||||||
silent! UpdateRemotePlugins
|
|
||||||
]])
|
|
||||||
end)
|
|
||||||
|
|
||||||
if not ok then
|
|
||||||
logger:log("error",
|
|
||||||
"failed to reload helptags and remote plugins; reason: %s", err)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return package
|
|
||||||
|
@ -1,19 +1,23 @@
|
|||||||
|
local logger = require("dep.log").global
|
||||||
local proc = {}
|
local proc = {}
|
||||||
|
|
||||||
--- execute a process
|
|
||||||
---@param process string the program
|
|
||||||
---@param args string[] the args
|
|
||||||
---@param cwd string? the pwd
|
|
||||||
---@param env table env
|
|
||||||
---@param cb function callback
|
|
||||||
function proc.exec(process, args, cwd, env, cb)
|
function proc.exec(process, args, cwd, env, cb)
|
||||||
local buffer = {}
|
local buffer = {}
|
||||||
|
|
||||||
local function cb_output(_, data, _)
|
local function cb_output(_, data, _)
|
||||||
table.insert(buffer, table.concat(data))
|
table.insert(buffer, table.concat(data))
|
||||||
end
|
end
|
||||||
local function cb_exit(_, exit_code, _)
|
local function cb_exit(job_id, exit_code, _)
|
||||||
local output = table.concat(buffer)
|
local output = table.concat(buffer)
|
||||||
|
logger:log(
|
||||||
|
process,
|
||||||
|
string.format(
|
||||||
|
'Job %s ["%s"] finished with exitcode %s\n%s',
|
||||||
|
job_id,
|
||||||
|
table.concat(args, '", "'),
|
||||||
|
exit_code,
|
||||||
|
output)
|
||||||
|
)
|
||||||
cb(exit_code ~= 0, output)
|
cb(exit_code ~= 0, output)
|
||||||
end
|
end
|
||||||
table.insert(args, 1, process)
|
table.insert(args, 1, process)
|
||||||
@ -39,7 +43,7 @@ function proc.git_clone(dir, url, branch, cb)
|
|||||||
local args = { "clone", "--depth=1", "--recurse-submodules", "--shallow-submodules", url, dir }
|
local args = { "clone", "--depth=1", "--recurse-submodules", "--shallow-submodules", url, dir }
|
||||||
|
|
||||||
if branch then
|
if branch then
|
||||||
args[#args + 1] = "--branch="..branch
|
args[#args + 1] = "--branch=" .. branch
|
||||||
end
|
end
|
||||||
|
|
||||||
proc.exec("git", args, nil, git_env, cb)
|
proc.exec("git", args, nil, git_env, cb)
|
||||||
@ -67,63 +71,4 @@ function proc.git_checkout(dir, branch, commit, cb)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function proc.git_resolve_branch(url, branch, cb)
|
|
||||||
-- if the branch doesn't contain a * then return the branch
|
|
||||||
if not string.match(branch, "*") then
|
|
||||||
cb(false, branch)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local buffer = {}
|
|
||||||
local function cb_output(_, data, _)
|
|
||||||
if data[1] ~= "" then
|
|
||||||
buffer = data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.fn.jobstart({ "git", "ls-remote", "--tags", "--sort", "v:refname", url },
|
|
||||||
{
|
|
||||||
cwd = nil,
|
|
||||||
env = git_env,
|
|
||||||
stdin = nil,
|
|
||||||
on_stdout = cb_output,
|
|
||||||
on_stderr = cb_output,
|
|
||||||
on_exit = function(_, exit_code, _)
|
|
||||||
if exit_code ~= 0 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get a list of all versions
|
|
||||||
local versions = {}
|
|
||||||
for _, v in pairs(buffer) do
|
|
||||||
local s, e = string.find(v, "refs/tags/.+")
|
|
||||||
if not s or not e then
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
|
|
||||||
local tag = string.sub(v, s, e)
|
|
||||||
tag = tag:gsub("refs/tags/", ""):gsub("%^{}", "")
|
|
||||||
|
|
||||||
table.insert(versions, tag)
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
|
|
||||||
-- match the chosen version against all versions
|
|
||||||
for i = #versions, 1, -1 do
|
|
||||||
if branch == "*" then
|
|
||||||
cb(false, versions[i])
|
|
||||||
return
|
|
||||||
else
|
|
||||||
local r = string.match(versions[i], branch)
|
|
||||||
if r then
|
|
||||||
cb(false, r)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
return proc
|
return proc
|
||||||
|
212
lua/dep/spec.lua
212
lua/dep/spec.lua
@ -1,212 +0,0 @@
|
|||||||
local logger = require("dep.log")
|
|
||||||
|
|
||||||
---@class specmodules
|
|
||||||
---@field prefix string prefix to prepend to the modules
|
|
||||||
---@field [integer] string list of all modules to load
|
|
||||||
|
|
||||||
---@class speclist
|
|
||||||
---@field modules specmodules? a list of modules
|
|
||||||
---@field base_dir string? the base directory for all plugins
|
|
||||||
---@field sync ("new"|"always")? when to sync (defaults to new)
|
|
||||||
---@field [integer] spec a spec
|
|
||||||
|
|
||||||
---@class spec
|
|
||||||
---@field [1] string id
|
|
||||||
---@field setup function? code to run before the package is loaded
|
|
||||||
---@field load function? code to run after the package is loaded
|
|
||||||
---@field config function? code to run after the package is installed/updated
|
|
||||||
---@field lazy function|true? code to run which determines when the package is loaded
|
|
||||||
---@field as string? overrides the short name of the package which is usually set
|
|
||||||
--- to a substring of all the chars after "/" in spec[1]
|
|
||||||
---@field url string? the url to the git repository hosting the package
|
|
||||||
---@field path string? path to local version of plugin, overrides the url
|
|
||||||
---@field branch string? the branch which the version of the package resides
|
|
||||||
---@field commit string? the commit which the version of the package resides
|
|
||||||
---@field disable boolean? if true disables the package from being loaded
|
|
||||||
---@field pin boolean? if true disables the package from being installed/updated
|
|
||||||
---@field reqs spec|spec[]|string? packages that this package requires
|
|
||||||
---@field deps spec|spec[]|string? packages that depend on this package
|
|
||||||
local spec = {}
|
|
||||||
|
|
||||||
--- check if a string seems to be a url
|
|
||||||
---@param url string the "url" to check
|
|
||||||
---@return boolean is_url
|
|
||||||
local function is_url(url)
|
|
||||||
if url:sub(1, 8) == "https://" or
|
|
||||||
url:sub(1, 7) == "http://" then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- get the proper name of a spec
|
|
||||||
---@return string spec.name
|
|
||||||
function spec:get_name()
|
|
||||||
return self[1]:match("^[%w-_.]+/([%w-_.]+)$")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- attempt to correct a spec
|
|
||||||
---@param self table|string spec to check
|
|
||||||
---@return spec spec
|
|
||||||
function spec:correct_spec()
|
|
||||||
if type(self) == "string" then
|
|
||||||
return { self }
|
|
||||||
elseif type(self) == "table" then
|
|
||||||
repeat
|
|
||||||
if type(self[1]) ~= "string" then
|
|
||||||
self = self[1]
|
|
||||||
elseif self[1] == nil then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
until type(self[1]) == "string"
|
|
||||||
end
|
|
||||||
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
-- store the logger temporarily to prevent any logs from being printed when
|
|
||||||
-- being run in silent mode
|
|
||||||
local __logger
|
|
||||||
|
|
||||||
--- check a spec to see if it's correct
|
|
||||||
---@param self table spec to check
|
|
||||||
---@param silent boolean? should the checker report errors
|
|
||||||
---@return spec|false spec if the spec is ok or false
|
|
||||||
function spec:check(silent)
|
|
||||||
if silent == true then
|
|
||||||
__logger = logger
|
|
||||||
logger = { log = function() end }
|
|
||||||
end
|
|
||||||
|
|
||||||
-- make sure all the data is correct
|
|
||||||
do -- spec[1]
|
|
||||||
if type(self[1]) ~= "string" then
|
|
||||||
logger:log("spec", "spec[1] must be a string")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local name = spec.get_name(self)
|
|
||||||
if not name then
|
|
||||||
logger:log("spec", 'invalid name "%s"; must be in the format "user/package"', self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.setup ~= nil then -- spec.setup
|
|
||||||
if type(self.setup) ~= "function" then
|
|
||||||
logger:log("spec", "spec.setup must be a function in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.load ~= nil then -- spec.load
|
|
||||||
if type(self.load) ~= "function" then
|
|
||||||
logger:log("spec", "spec.load must be a function in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.config ~= nil then -- spec.config
|
|
||||||
if type(self.config) ~= "function" then
|
|
||||||
logger:log("spec", "spec.config must be a function in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.lazy ~= nil then -- spec.lazy
|
|
||||||
if type(self.lazy) ~= "function" and self.lazy ~= true then
|
|
||||||
logger:log("spec", "spec.lazy must be a function or boolean in %s",
|
|
||||||
self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.as ~= nil then -- spec.as
|
|
||||||
if type(self.as) ~= "string" then
|
|
||||||
logger:log("spec", "spec.as must be a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.url ~= nil then -- spec.url
|
|
||||||
if type(self.url) ~= "string" then
|
|
||||||
logger:log("spec", "spec.url must be a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
elseif not is_url(self.url) then -- more strict checking on urls
|
|
||||||
logger:log("spec", "spec.url must be a properly formatted url in %s",
|
|
||||||
self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.path ~= nil then -- spec.path
|
|
||||||
if type(self.path) ~= "string" then
|
|
||||||
logger:log("spec", "spec.path must be a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
elseif not vim.fn.isdirectory(self.path) then
|
|
||||||
logger:log("spec", "spec.path must be a valid directory in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.branch ~= nil then -- spec.branch
|
|
||||||
if type(self.branch) ~= "string" then
|
|
||||||
logger:log("spec", "spec.branch must be a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.commit ~= nil then -- spec.commit
|
|
||||||
if type(self.commit) ~= "string" then
|
|
||||||
logger:log("spec", "spec.commit must be a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.disable ~= nil then -- spec.disable
|
|
||||||
if type(self.disable) ~= "boolean" then
|
|
||||||
logger:log("spec", "spec.disable must be a boolean in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.pin ~= nil then -- spec.pin
|
|
||||||
if type(self.pin) ~= "boolean" then
|
|
||||||
logger:log("spec", "spec.pin must be a boolean in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.reqs ~= nil then -- spec.reqs
|
|
||||||
local is = type(self.reqs)
|
|
||||||
if is ~= "table" and is ~= "string" then
|
|
||||||
logger:log("spec", "spec.reqs must be a table or a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- turn an id into a spec
|
|
||||||
if (is == "string") then
|
|
||||||
self.reqs = { self.reqs }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.deps ~= nil then -- spec.deps
|
|
||||||
local is = type(self.deps)
|
|
||||||
if is ~= "table" and is ~= "string" then
|
|
||||||
logger:log("spec", "spec.deps must be a table or a string in %s", self[1])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- turn an id into a spec
|
|
||||||
if (is == "string") then
|
|
||||||
self.deps = { self.deps }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if silent == true then
|
|
||||||
logger = __logger
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end
|
|
||||||
|
|
||||||
return spec
|
|
@ -1,59 +0,0 @@
|
|||||||
local logger = require("dep.log")
|
|
||||||
|
|
||||||
local format = {}
|
|
||||||
|
|
||||||
--- format a boolean to a chunk with highlights
|
|
||||||
---@param b boolean
|
|
||||||
---@return chunk chunk
|
|
||||||
function format.bool(b)
|
|
||||||
return { vim.inspect(b), b and "DiffAdd" or "DiffDelete" }
|
|
||||||
end
|
|
||||||
|
|
||||||
--- format a number to a chunk with highlights
|
|
||||||
---@param n number
|
|
||||||
---@return chunk chunk
|
|
||||||
function format.number(n)
|
|
||||||
return { vim.inspect(n), "Number" }
|
|
||||||
end
|
|
||||||
|
|
||||||
--- format a log line with highlights
|
|
||||||
---@param log_line string log line
|
|
||||||
---@return chunk[] chunks
|
|
||||||
function format.log_line(log_line)
|
|
||||||
-- make sure we don't do operations on nil values
|
|
||||||
if not log_line or log_line == "" then
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- error on any nil values, this should prevent us from parsing an incorrectly
|
|
||||||
-- formatted log line
|
|
||||||
local log_time, colon, log_path, log_path_ln, level, rest
|
|
||||||
local ok = pcall(function()
|
|
||||||
log_time = string.sub(log_line, string.find(log_line, "%[") + 1,
|
|
||||||
string.find(log_line, "%]") - 1)
|
|
||||||
colon = string.find(log_line, ":", 11)
|
|
||||||
log_path = string.sub(log_line, string.find(log_line, "%]") + 2,
|
|
||||||
colon - 1)
|
|
||||||
log_path_ln = string.sub(log_line, colon + 1,
|
|
||||||
string.find(log_line, ":", colon + 1) - 1)
|
|
||||||
level = string.sub(log_line, string.find(log_line, "%(") + 1,
|
|
||||||
string.find(log_line, "%)") - 1)
|
|
||||||
rest = string.sub(log_line, string.find(log_line, "%)") + 2)
|
|
||||||
end)
|
|
||||||
if not ok then
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
{ "[", "" },
|
|
||||||
{ log_time, "Boolean" },
|
|
||||||
{ "] ", "" },
|
|
||||||
{ log_path, "String" },
|
|
||||||
{ ":", "" },
|
|
||||||
{ log_path_ln, "Number" },
|
|
||||||
{ ": ", "" },
|
|
||||||
{ rest, logger.stage_colors[level] or "" }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return format
|
|
@ -1,207 +0,0 @@
|
|||||||
local h = require("dep.helpers")
|
|
||||||
local page = require("dep.ui.page")
|
|
||||||
local logger = require("dep.log")
|
|
||||||
local format = require("dep.ui.format")
|
|
||||||
|
|
||||||
---@class ui
|
|
||||||
---@field bufnr number
|
|
||||||
---@field winnr number
|
|
||||||
---@field header_bufnr number
|
|
||||||
---@field header_winnr number
|
|
||||||
---@field pages page[]
|
|
||||||
local ui = {}
|
|
||||||
|
|
||||||
-- the active page being displayed
|
|
||||||
local active_page
|
|
||||||
|
|
||||||
-- all the pages
|
|
||||||
local pages = {}
|
|
||||||
|
|
||||||
-- the header ext mark
|
|
||||||
local header_ext_id
|
|
||||||
|
|
||||||
local function page_packages(packager)
|
|
||||||
local p = page:new("Packages", "P")
|
|
||||||
for _, pkg in pairs(packager.get_packages()) do
|
|
||||||
p:new_line({
|
|
||||||
{ pkg.id, "@conditional" },
|
|
||||||
{ " loaded: ", "" },
|
|
||||||
format.bool(pkg.loaded),
|
|
||||||
{ " lazy: ", "" },
|
|
||||||
format.bool(pkg.lazy)
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
return p
|
|
||||||
end
|
|
||||||
|
|
||||||
local function page_log()
|
|
||||||
local p = page:new("Log", "L")
|
|
||||||
local f = io.open(logger.path, "r")
|
|
||||||
if not f then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- put the cursor at the bottom of the page after drawing
|
|
||||||
p.post_draw = function()
|
|
||||||
if ui.winnr then
|
|
||||||
vim.api.nvim_win_set_cursor(ui.winnr, { #p.content, 0 })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- read in the contents of the file, and keep watching for updates
|
|
||||||
local function update_contents()
|
|
||||||
repeat
|
|
||||||
local line = f:read("*l")
|
|
||||||
|
|
||||||
-- if the line isn't empty we shouldn't draw it
|
|
||||||
if line then
|
|
||||||
p:new_line(format.log_line(line))
|
|
||||||
end
|
|
||||||
until not line
|
|
||||||
end
|
|
||||||
|
|
||||||
update_contents()
|
|
||||||
|
|
||||||
local fullpath = vim.api.nvim_call_function(
|
|
||||||
"fnamemodify", { logger.path, ":p" })
|
|
||||||
h.uv.new_fs_event():start(fullpath, {}, vim.schedule_wrap(function()
|
|
||||||
update_contents()
|
|
||||||
|
|
||||||
-- if the log is currently being displayed then make sure to draw it when
|
|
||||||
-- it updates
|
|
||||||
if active_page == p then
|
|
||||||
p:draw(ui.bufnr)
|
|
||||||
end
|
|
||||||
end))
|
|
||||||
|
|
||||||
return p
|
|
||||||
end
|
|
||||||
|
|
||||||
--- set the current page
|
|
||||||
---@param p string|page page to set
|
|
||||||
function ui.set_page(p)
|
|
||||||
if type(p) == "string" then
|
|
||||||
for _, v in ipairs(pages) do
|
|
||||||
if p == v.kb then
|
|
||||||
v:draw(ui.bufnr)
|
|
||||||
active_page = v
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif type(p) == "table" then
|
|
||||||
p:draw(ui.bufnr)
|
|
||||||
active_page = p
|
|
||||||
end
|
|
||||||
|
|
||||||
-- color the header text
|
|
||||||
local txt = vim.api.nvim_buf_get_text(ui.header_bufnr, 0, 0, -1, -1, {})[1]
|
|
||||||
local start_range = (string.find(txt, active_page.name)) - 2
|
|
||||||
local end_range = #active_page.name + start_range + 2
|
|
||||||
|
|
||||||
if header_ext_id then
|
|
||||||
vim.api.nvim_buf_del_extmark(ui.header_bufnr, active_page.hlns, header_ext_id)
|
|
||||||
end
|
|
||||||
header_ext_id = vim.api.nvim_buf_set_extmark(ui.header_bufnr,
|
|
||||||
active_page.hlns, 0, start_range, {
|
|
||||||
hl_mode = "replace",
|
|
||||||
hl_group = "CurSearch",
|
|
||||||
end_col = end_range,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
local setup
|
|
||||||
--- setup all the pages
|
|
||||||
---@param packager package the packager
|
|
||||||
local function setup_pages(packager)
|
|
||||||
if setup then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local header_text = ""
|
|
||||||
|
|
||||||
table.insert(pages, page_packages(packager))
|
|
||||||
table.insert(pages, page_log())
|
|
||||||
|
|
||||||
for _, v in ipairs(pages) do
|
|
||||||
header_text = header_text.." "..v.name.." "
|
|
||||||
|
|
||||||
vim.keymap.set("n", v.kb, function()
|
|
||||||
ui.set_page(v)
|
|
||||||
end, { buffer = ui.bufnr })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set the header text
|
|
||||||
vim.api.nvim_buf_set_lines(ui.header_bufnr, 0, -1, false, { header_text })
|
|
||||||
|
|
||||||
-- add keymaps
|
|
||||||
vim.keymap.set("n", "q", function()
|
|
||||||
vim.api.nvim_win_close(ui.winnr, false)
|
|
||||||
ui.winnr = nil
|
|
||||||
end, { buffer = ui.bufnr })
|
|
||||||
|
|
||||||
setup = true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- setup the ui
|
|
||||||
---@param packager package
|
|
||||||
function ui.open(packager)
|
|
||||||
if not ui.bufnr then
|
|
||||||
ui.bufnr = vim.api.nvim_create_buf(false, true)
|
|
||||||
end
|
|
||||||
if not ui.header_bufnr then
|
|
||||||
ui.header_bufnr = vim.api.nvim_create_buf(false, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
local header_height = 1
|
|
||||||
local width = math.floor(vim.o.columns * 0.8)
|
|
||||||
local height = math.floor(vim.o.lines * 0.8) - header_height
|
|
||||||
|
|
||||||
if not ui.winnr then
|
|
||||||
ui.winnr = vim.api.nvim_open_win(ui.bufnr, true, {
|
|
||||||
relative = "editor",
|
|
||||||
row = (vim.o.lines - height) / 2,
|
|
||||||
col = (vim.o.columns - width) / 2,
|
|
||||||
width = width,
|
|
||||||
height = height,
|
|
||||||
border = "solid",
|
|
||||||
zindex = 998,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
if not ui.header_winnr then
|
|
||||||
ui.header_winnr = vim.api.nvim_open_win(ui.header_bufnr, false, {
|
|
||||||
relative = "editor",
|
|
||||||
row = ((vim.o.lines - height) / 2) - (header_height * 2),
|
|
||||||
col = (vim.o.columns - width) / 2,
|
|
||||||
width = width,
|
|
||||||
height = header_height,
|
|
||||||
border = "solid",
|
|
||||||
zindex = 999,
|
|
||||||
focusable = false
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
vim.api.nvim_win_set_buf(ui.winnr, ui.bufnr)
|
|
||||||
vim.api.nvim_win_set_buf(ui.header_winnr, ui.header_bufnr)
|
|
||||||
|
|
||||||
-- make sure the header closes when the body does and vice versa
|
|
||||||
local function cb()
|
|
||||||
vim.api.nvim_win_close(ui.header_winnr, false)
|
|
||||||
ui.header_winnr = nil
|
|
||||||
vim.api.nvim_win_close(ui.winnr, false)
|
|
||||||
ui.winnr = nil
|
|
||||||
end
|
|
||||||
vim.api.nvim_create_autocmd("WinClosed", {
|
|
||||||
pattern = ui.winnr.."",
|
|
||||||
callback = cb
|
|
||||||
})
|
|
||||||
vim.api.nvim_create_autocmd("WinClosed", {
|
|
||||||
pattern = ui.header_winnr.."",
|
|
||||||
callback = cb
|
|
||||||
})
|
|
||||||
|
|
||||||
setup_pages(packager)
|
|
||||||
end
|
|
||||||
|
|
||||||
return ui
|
|
@ -1,84 +0,0 @@
|
|||||||
---@class chunk: table
|
|
||||||
---@field [1] string text to be displayed
|
|
||||||
---@field [2] string neovim highlight group to use
|
|
||||||
|
|
||||||
---@class page
|
|
||||||
---@field name string name of the ui page
|
|
||||||
---@field kb string keybind of the page
|
|
||||||
---@field content chunk[]|chunk[][] all the chunks
|
|
||||||
---@field hlns number highlight namespace
|
|
||||||
---@field pre_draw function things to do prior to drawing to the buffer
|
|
||||||
---@field post_draw function things to do post drawing to the buffer
|
|
||||||
local page = {}
|
|
||||||
|
|
||||||
--- create a new page
|
|
||||||
---@param name string the name of the page
|
|
||||||
---@param kb string keybind to change to the page
|
|
||||||
---@return page page
|
|
||||||
function page:new(name, kb)
|
|
||||||
local o = {}
|
|
||||||
self.__index = self
|
|
||||||
setmetatable(o, self)
|
|
||||||
|
|
||||||
o.hlns = vim.api.nvim_create_namespace("DepUi")
|
|
||||||
o.name = name
|
|
||||||
o.kb = kb
|
|
||||||
o.content = {}
|
|
||||||
|
|
||||||
return o
|
|
||||||
end
|
|
||||||
|
|
||||||
--- add a new line to the page
|
|
||||||
---@param line chunk|chunk[] new line
|
|
||||||
function page:new_line(line)
|
|
||||||
table.insert(self.content, line)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- draw the page to the given buffer
|
|
||||||
---@param bufnr number buffer number
|
|
||||||
function page:draw(bufnr)
|
|
||||||
-- try to run pre_draw steps
|
|
||||||
if self.pre_draw then
|
|
||||||
self.pre_draw()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ready all information for rendering
|
|
||||||
for i, chunk in ipairs(self.content) do
|
|
||||||
local linenr = i - 1
|
|
||||||
local text = ""
|
|
||||||
local hls = {}
|
|
||||||
|
|
||||||
if type(chunk[1]) == "table" then
|
|
||||||
local j = 0
|
|
||||||
for _, ch in ipairs(chunk) do
|
|
||||||
text = text..ch[1]
|
|
||||||
table.insert(hls, { ch[2], j, j + #ch[1] })
|
|
||||||
j = j + #ch[1]
|
|
||||||
end
|
|
||||||
elseif type(chunk[1]) == "string" then
|
|
||||||
text = chunk[1]
|
|
||||||
table.insert(hls, { chunk[2], 0, #text })
|
|
||||||
end
|
|
||||||
|
|
||||||
-- draw the text to the buffer
|
|
||||||
vim.api.nvim_buf_set_lines(bufnr, linenr, -1, false, { text })
|
|
||||||
|
|
||||||
-- highlight the buffer
|
|
||||||
for _, hl in ipairs(hls) do
|
|
||||||
vim.api.nvim_buf_set_extmark(bufnr, self.hlns, linenr, hl[2], {
|
|
||||||
hl_mode = "replace",
|
|
||||||
hl_group = hl[1],
|
|
||||||
end_col = hl[3],
|
|
||||||
end_row = linenr
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
-- try to run post_draw steps
|
|
||||||
if self.post_draw then
|
|
||||||
self.post_draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return page
|
|
12
lua/dep2.lua
Normal file
12
lua/dep2.lua
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
--
|
||||||
|
-- Copyright (c) 2022 chiya.dev
|
||||||
|
--
|
||||||
|
-- Use of this source code is governed by the MIT License
|
||||||
|
-- which can be found in the LICENSE file and at:
|
||||||
|
--
|
||||||
|
-- https://chiya.dev/licenses/mit.txt
|
||||||
|
--
|
||||||
|
local logger = require("dep.log").global
|
||||||
|
local store = require("dep.package").PackageStore()
|
||||||
|
|
||||||
|
-- placeholder for refactoring
|
2
stylua.toml
Executable file
2
stylua.toml
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
indent_type = "Spaces"
|
||||||
|
indent_width = 2
|
@ -1,63 +0,0 @@
|
|||||||
---@diagnostic disable: undefined-global, undefined-field
|
|
||||||
local dep_ui_format = require("dep.ui.format")
|
|
||||||
local dep_spec_man = require("dep.spec")
|
|
||||||
|
|
||||||
describe("ui log formatting", function()
|
|
||||||
it("returns the proper chunks to print a formatted line", function()
|
|
||||||
assert.same(
|
|
||||||
{
|
|
||||||
{ "[", "" },
|
|
||||||
{ "11:22:33", "Boolean" },
|
|
||||||
{ "] ", "" },
|
|
||||||
{ "file.lua", "String" },
|
|
||||||
{ ":", "" },
|
|
||||||
{ "1", "Number" },
|
|
||||||
{ ": ", "" },
|
|
||||||
{ "some fancy message", "" }
|
|
||||||
},
|
|
||||||
dep_ui_format.log_line("[11:22:33] file.lua:1:(vim) some fancy message")
|
|
||||||
)
|
|
||||||
|
|
||||||
-- malformed log line
|
|
||||||
assert.same({},
|
|
||||||
dep_ui_format.log_line("11:22:33] file.lua:1:(vim) some fancy message"))
|
|
||||||
|
|
||||||
-- test nil values
|
|
||||||
assert.same({}, dep_ui_format.log_line(""))
|
|
||||||
assert.same({}, dep_ui_format.log_line(nil))
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
describe("package specification", function()
|
|
||||||
it("gets the package's name", function()
|
|
||||||
assert.equal(dep_spec_man.get_name({ "user/package" }), "package")
|
|
||||||
assert.equal(dep_spec_man.get_name({ "user/package.git" }), "package.git")
|
|
||||||
end)
|
|
||||||
|
|
||||||
it("ensurses specs are in the proper format", function()
|
|
||||||
local correct = { "user/package" }
|
|
||||||
assert.same(dep_spec_man.correct_spec("user/package"), correct)
|
|
||||||
assert.same(dep_spec_man.correct_spec({ "user/package" }), correct)
|
|
||||||
assert.same(dep_spec_man.correct_spec({ { "user/package" } }), correct)
|
|
||||||
end)
|
|
||||||
|
|
||||||
it("checks a spec for correctness", function()
|
|
||||||
assert.same(
|
|
||||||
dep_spec_man.check({ "user/package" }, true),
|
|
||||||
{ "user/package" }
|
|
||||||
)
|
|
||||||
|
|
||||||
assert.same(
|
|
||||||
dep_spec_man.check({
|
|
||||||
"user/package",
|
|
||||||
deps = "user/dependency"
|
|
||||||
}, true),
|
|
||||||
{
|
|
||||||
"user/package",
|
|
||||||
deps = {
|
|
||||||
"user/dependency"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end)
|
|
||||||
end)
|
|
@ -1 +0,0 @@
|
|||||||
vim.opt.rtp:prepend(".")
|
|
Reference in New Issue
Block a user