# dep [![License](https://img.shields.io/github/license/chiyadev/dep)](LICENSE) [![Maintainer](https://img.shields.io/badge/maintainer-luaneko-pink)][4] [![Issues](https://img.shields.io/github/issues/chiyadev/dep.svg)][8] [![Contributors](https://img.shields.io/github/contributors/chiyadev/dep.svg)][9] > This readme is a work in progress. A versatile, declarative and correct [neovim][2] package manager in [Lua][3]. Originally written for personal use by [luaneko][4]. 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. See also luaneko's [neovim-configs][10] for an example of how dep can be used in practice. ## Requirements - [Neovim][2] 0.6+ - [Git][5] ## Setup 1. Create `lua/bootstrap.lua` in your neovim config directory. ```lua -- ~/.config/nvim/lua/bootstrap.lua: -- automatically install `chiyadev/dep` on startup 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://github.com/chiyadev/dep", path }) end vim.cmd("packadd dep") ``` 2. In `init.lua`, call `dep` with an array of package specifications. ```lua require "bootstrap" require "dep" { -- list of package specs... } ``` ## Commands - `:DepSync` - installs new packages, updates packages to the latest versions, cleans removed packages and reloads packages as necessary. - `:DepClean` - cleans removed packages. - `:DepReload` - reloads all packages. - `:DepList` - prints the package list, performance metrics and dependency graphs. - `:DepLog` - opens the log file. - `:DepConfig` - opens the file that called dep, for convenience. ## Package specification A package must be declared in the following format. ```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 after the package is loaded into neovim. function() require "package".setup(...) end, -- [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 installed or updated. config = function() os.execute(...) 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.chiya.dev/user/package.git", -- [string] Overrides the name of the branch to clone. -- Defaults to whatever the remote configured as their HEAD, which is usually "master". branch = "develop", -- [boolean] Prevents the package from being loaded. disable = true, -- [boolean] Prevents the package from being updated. pin = true, -- [string|array] Specifies dependencies that must be loaded before the package. -- If given a string, it is wrapped into an array. requires = {...}, -- [string|array] Specifies dependents that must be loaded after the package. -- If given a string, it is wrapped into an array. deps = {...} } ``` 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", requires = "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", requires = { "user/dependency", "user/another_dependency" }, deps = "user/dependent", disabled = true, config = function() print "my config hook" os.execute("make") end } } ``` ## 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", requires = { { "user/dependency1", requires = "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", requires = "user/dependency2", deps = "user/package" } } -- which is equivalent to require "dep" { { "user/dependency1", requires = "user/dependency2" }, { "user/package", requires = "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", requires = "user/package2" }, { "user/package2", requires = "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 requires = "user/dependency" }, { "user/package2", disabled = true, -- implied requires = "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", function() error("bad hook") end }, { "user/dependent", requires = "user/problematic", function() print "unreachable" end } } ``` ## Miscellaneous configuration dep accepts configuration parameters as named fields in the package list. ```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", -- [function] Callback when dep is (re)loaded -- if a table is returned it will be read as a table of config specs load = function() end -- list of package specs... } ``` ## License dep is licensed under the [MIT License](LICENSE). [1]: https://chiya.dev/posts/2021-11-27-why-package-manager [2]: https://neovim.io/ [3]: https://www.lua.org/ [4]: https://github.com/luaneko [5]: https://git-scm.com/ [6]: https://github.com/nvim-telescope/telescope.nvim [7]: https://github.com/tpope/vim-fugitive [8]: https://GitHub.com/chiyadev/dep/issues [9]: https://github.com/chiyadev/dep/graphs/contributors [10]: https://github.com/luaneko/neovim-config