diff --git a/.gitignore b/.gitignore index e43b0f9..17402e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +doc/tags diff --git a/doc/dep.txt b/doc/dep.txt new file mode 100644 index 0000000..c6f2cd8 --- /dev/null +++ b/doc/dep.txt @@ -0,0 +1,597 @@ +*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| +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() + end + }) +< +If you wish the second argument may be completely ommitted. + +------------------------------------------------------------------------------ +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", "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", "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. + +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 + } + } + } + } +< +============================================================================== +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: diff --git a/lua/dep.lua b/lua/dep.lua index 96544ca..38c6566 100644 --- a/lua/dep.lua +++ b/lua/dep.lua @@ -90,6 +90,9 @@ return function(opts) bench.setup() lazy.setup() + -- generate doc tags + vim.cmd.helptags(vim.fn.stdpath('data')..'/site/pack/deps/opt/dep/doc') + local initialized, err = pcall(function() packager.set_base_dir(opts.base_dir or vim.fn.stdpath("data").."/site/pack/deps/opt/") bench.mark("load", function()