Merge remote-tracking branch 'upstream/main' into feat/prioritize-cond

This commit is contained in:
MurdeRM3L0DY 2023-02-23 14:25:24 +01:00
commit 7e39270651
27 changed files with 1212 additions and 905 deletions

View file

@ -16,7 +16,7 @@ body:
required: true required: true
- label: I have searched the existing issues of lazy.nvim - label: I have searched the existing issues of lazy.nvim
required: true required: true
- label: I have searched the exsiting issues of plugins related to this issue - label: I have searched the existing issues of plugins related to this issue
required: true required: true
- type: input - type: input
attributes: attributes:

View file

@ -57,7 +57,7 @@ jobs:
package-name: lazy.nvim package-name: lazy.nvim
extra-files: | extra-files: |
lua/lazy/core/config.lua lua/lazy/core/config.lua
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: tag stable versions - name: tag stable versions
if: ${{ steps.release.outputs.release_created }} if: ${{ steps.release.outputs.release_created }}
run: | run: |

View file

@ -7,7 +7,7 @@
} }
}, },
"lspconfig": { "lspconfig": {
"sumneko_lua": { "lua_ls": {
"Lua.runtime.version": "LuaJIT", "Lua.runtime.version": "LuaJIT",
"Lua.workspace.checkThirdParty": false "Lua.workspace.checkThirdParty": false
} }

View file

@ -1,5 +1,134 @@
# Changelog # Changelog
## [9.8.5](https://github.com/folke/lazy.nvim/compare/v9.8.4...v9.8.5) (2023-02-20)
### Bug Fixes
* **ui:** disable colorcolumn on floating window ([#575](https://github.com/folke/lazy.nvim/issues/575)) ([43496fa](https://github.com/folke/lazy.nvim/commit/43496fa82cd4d68523754c3492660a9883e747d9))
* **ui:** don't close on BufLeave. Fixes [#561](https://github.com/folke/lazy.nvim/issues/561) ([7339145](https://github.com/folke/lazy.nvim/commit/7339145a223dab7e7ddccf0986ffbf9d2cb804e8))
## [9.8.4](https://github.com/folke/lazy.nvim/compare/v9.8.3...v9.8.4) (2023-02-17)
### Bug Fixes
* **spec:** make sure imported specs are sorted alphabetically ([ff76e58](https://github.com/folke/lazy.nvim/commit/ff76e58961509038e3e0365c47580e595977a3a2))
* **ui:** return abort key instead of `<c-c>` ([5cfe156](https://github.com/folke/lazy.nvim/commit/5cfe1560c551720bdc125e68431bacb836eb28d3))
## [9.8.3](https://github.com/folke/lazy.nvim/compare/v9.8.2...v9.8.3) (2023-02-16)
### Bug Fixes
* **cache:** hack to work around plugins trying to load relatve modules. Fixes [#543](https://github.com/folke/lazy.nvim/issues/543) ([e916f41](https://github.com/folke/lazy.nvim/commit/e916f41df26e33b01f1b3ebe28881090da3a7281))
* **ui:** disable folding of floating window ([#550](https://github.com/folke/lazy.nvim/issues/550)) ([6771c7e](https://github.com/folke/lazy.nvim/commit/6771c7e23c3ecdb50a9510c4cd5e1e0d2db9e5ca))
## [9.8.2](https://github.com/folke/lazy.nvim/compare/v9.8.1...v9.8.2) (2023-02-15)
### Bug Fixes
* **cache:** lsmod now also supports lua libs. Fixes [#544](https://github.com/folke/lazy.nvim/issues/544) ([9ca3222](https://github.com/folke/lazy.nvim/commit/9ca3222061fcc07a7ac5f685d80b49944b347a03))
## [9.8.1](https://github.com/folke/lazy.nvim/compare/v9.8.0...v9.8.1) (2023-02-14)
### Bug Fixes
* **keys:** fixed keys types. rhs can be `false` ([6a18404](https://github.com/folke/lazy.nvim/commit/6a18404b7d1c05f0d1f35f7b78bd5c282dff7a89))
### Performance Improvements
* more cache optims ([17a3c3a](https://github.com/folke/lazy.nvim/commit/17a3c3acea400679027e675cc19b738e842a5ea0))
* use modkey instead of modpath ([b1f7ae6](https://github.com/folke/lazy.nvim/commit/b1f7ae68a75401152eb23edbd5827b69761e9bc7))
## [9.8.0](https://github.com/folke/lazy.nvim/compare/v9.7.0...v9.8.0) (2023-02-13)
### Features
* **git:** `Plugin.submodules = false` will now skip fetching git submodules ([0d3f2c4](https://github.com/folke/lazy.nvim/commit/0d3f2c40421f4774c70f631d7b7023f57cba66cd))
### Bug Fixes
* **cmd:** fix Error when trigger on range defined command that doesn't support count ([#519](https://github.com/folke/lazy.nvim/issues/519)) ([a147110](https://github.com/folke/lazy.nvim/commit/a1471103902a9836d88732eeeeabd11d00a2cb3e))
* **icons:** replace an obsolete Nerd icon ([#529](https://github.com/folke/lazy.nvim/issues/529)) ([bc978ca](https://github.com/folke/lazy.nvim/commit/bc978ca9be96b75330336a0427771addaa1ccd50))
* **loader:** don't deactivate when not loaded ([c83d2ae](https://github.com/folke/lazy.nvim/commit/c83d2aeb27fce9cf9f14e779e77a85c63fc3d2c9))
* **util:** executable checks for `Util.open` ([#528](https://github.com/folke/lazy.nvim/issues/528)) ([4917222](https://github.com/folke/lazy.nvim/commit/4917222c7e5c924bf7471b72a5e2d3e661530b40))
### Performance Improvements
* new file-based cache that ensures correct rtp order ([#532](https://github.com/folke/lazy.nvim/issues/532)) ([462633b](https://github.com/folke/lazy.nvim/commit/462633bae11255133f099163dda17180b3a6dc27))
## [9.7.0](https://github.com/folke/lazy.nvim/compare/v9.6.0...v9.7.0) (2023-02-08)
### Features
* deactivate WIP ([57a3960](https://github.com/folke/lazy.nvim/commit/57a3960fafc210f240a07439d1adfaba09d6ff59))
* use "wslview" instead of "xsl-open" if it exsits ([#509](https://github.com/folke/lazy.nvim/issues/509)) ([2451ea4](https://github.com/folke/lazy.nvim/commit/2451ea4e655bc60ef639ad284e69c6fca15da352))
### Bug Fixes
* **install:** dont load the colorscheme again if a `config()` of the colorscheme also loads it. Fixes [#488](https://github.com/folke/lazy.nvim/issues/488) ([49b43de](https://github.com/folke/lazy.nvim/commit/49b43def14f7e130cc27c7041ca2942142a881ed))
* **keys:** feed keys instead of returning expr for Neovim 0.8.x. Fixes [#511](https://github.com/folke/lazy.nvim/issues/511) ([c734d94](https://github.com/folke/lazy.nvim/commit/c734d941b47312baafe3e0429a5fecd25da95f5f))
* **keys:** refactor retrigger mechanism ([#428](https://github.com/folke/lazy.nvim/issues/428)) ([4272d21](https://github.com/folke/lazy.nvim/commit/4272d2100af2384f4b8aba08aef4a7b9a296bce6))
* **keys:** replace keycodes manually ([ddaffa0](https://github.com/folke/lazy.nvim/commit/ddaffa07156a090383bd32ef88669eea1b22c11a))
## [9.6.0](https://github.com/folke/lazy.nvim/compare/v9.5.1...v9.6.0) (2023-02-07)
### Features
* **cmd:** use cmd table instead of trying to create the cmd string. Fixes [#472](https://github.com/folke/lazy.nvim/issues/472) ([3c29f19](https://github.com/folke/lazy.nvim/commit/3c29f196f4b0f083f2b94c3337599a189f4eef84))
## [9.5.1](https://github.com/folke/lazy.nvim/compare/v9.5.0...v9.5.1) (2023-02-06)
### Bug Fixes
* **commands:** sync with plugins list should not delete those plugins. Fixes [#475](https://github.com/folke/lazy.nvim/issues/475) ([0c98031](https://github.com/folke/lazy.nvim/commit/0c980312fd6bce744db499acfa5af47871287151))
* **health:** existing packages on windows. Fixes [#474](https://github.com/folke/lazy.nvim/issues/474) ([527f83c](https://github.com/folke/lazy.nvim/commit/527f83cae50b99d16327447eb813b4f73e09ec0d))
* **log:** properly check if plugin dir is a git repo before running git log ([3d2dcb2](https://github.com/folke/lazy.nvim/commit/3d2dcb2d5ef99106c5ff412da88c6f59a9f8a693))
* **process:** allow overriding GIT_SSH_COMMAND. Fixes [#491](https://github.com/folke/lazy.nvim/issues/491). Fixes [#492](https://github.com/folke/lazy.nvim/issues/492) ([452d4eb](https://github.com/folke/lazy.nvim/commit/452d4eb719c5067f0bae497dc870554cd300758f))
## [9.5.0](https://github.com/folke/lazy.nvim/compare/v9.4.0...v9.5.0) (2023-01-24)
### Features
* **config:** added option to disable git filter. NOT recommended. Fixes [#442](https://github.com/folke/lazy.nvim/issues/442) ([26a67e3](https://github.com/folke/lazy.nvim/commit/26a67e3c48951ca3ce47d208c3216143749b0768))
* **dev:** optionally fallback to git when local plugin doesn't exist ([#446](https://github.com/folke/lazy.nvim/issues/446)) ([772d888](https://github.com/folke/lazy.nvim/commit/772d8888cc6f8e4371c31001197431b24311af48))
* **health:** check for git in health checks ([9b5cc1b](https://github.com/folke/lazy.nvim/commit/9b5cc1bf53f344c8ad829f33c3ac77f5e3ea8da1))
* **util:** utility method to walk over all modules in a directory ([5d9d354](https://github.com/folke/lazy.nvim/commit/5d9d35404f39de5d7c9365cbc2aa39858929cbfc))
### Bug Fixes
* **checker:** dont check for updates when there's tasks with errors ([c32a618](https://github.com/folke/lazy.nvim/commit/c32a6185ace7cb04572db1637a3010b729a7601e))
* **checker:** dont clear tasks when running update check ([ed21070](https://github.com/folke/lazy.nvim/commit/ed210702f5dc8c24ec6531c0f2484881d9ebe6b6))
## [9.4.0](https://github.com/folke/lazy.nvim/compare/v9.3.1...v9.4.0) (2023-01-22)
### Features
* added `config.ui.wrap` and improved wrapping when wrap=true. Fixes [#422](https://github.com/folke/lazy.nvim/issues/422) ([d6fc848](https://github.com/folke/lazy.nvim/commit/d6fc848067d603800b9e63a7b22b7e5853c6bd7a))
* **checker:** checker will now save last check time and only check at configured frequency even after restarting Neovim ([813fc94](https://github.com/folke/lazy.nvim/commit/813fc944d797fe1b43abe12866a9ef7af403c35c))
### Bug Fixes
* **checker:** make sure we show logs when only doing a fast check ([4008b57](https://github.com/folke/lazy.nvim/commit/4008b57d882065814ce27a0f32609d5ea437a6e9))
* **git:** unset GIT_DIR when spawning a process. Fixes [#434](https://github.com/folke/lazy.nvim/issues/434) ([9858001](https://github.com/folke/lazy.nvim/commit/9858001c3cdb5713e8d1aeb0f47c23038084fd7c))
* **render:** get profile_{sort,filter} key bindings from ViewConfig ([#416](https://github.com/folke/lazy.nvim/issues/416)) ([27ca918](https://github.com/folke/lazy.nvim/commit/27ca918bc3d02ea20b3fd901c8919e9925555444))
* **spec:** dont complain about an invalid short url, when a full url is set. Fixes [#421](https://github.com/folke/lazy.nvim/issues/421) ([c389ad5](https://github.com/folke/lazy.nvim/commit/c389ad552bd5c2050783ac6cd6e54f5fbba3c7bc))
## [9.3.1](https://github.com/folke/lazy.nvim/compare/v9.3.0...v9.3.1) (2023-01-17) ## [9.3.1](https://github.com/folke/lazy.nvim/compare/v9.3.0...v9.3.1) (2023-01-17)

View file

@ -53,7 +53,7 @@ vim.opt.rtp:prepend(lazypath)
<!-- bootstrap:end --> <!-- bootstrap:end -->
Next step is to add **lazy.nvim** to the top of your `init.lua` Next step is to add **lazy.nvim** below the code added in the last step in `init.lua`
```lua ```lua
require("lazy").setup(plugins, opts) require("lazy").setup(plugins, opts)
@ -79,32 +79,33 @@ require("lazy").setup({
## 🔌 Plugin Spec ## 🔌 Plugin Spec
| Property | Type | Description | | Property | Type | Description |
| ---------------- | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ---------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `[1]` | `string?` | Short plugin url. Will be expanded using `config.git.url_format` | | `[1]` | `string?` | Short plugin url. Will be expanded using `config.git.url_format` |
| **dir** | `string?` | A directory pointing to a local plugin | | **dir** | `string?` | A directory pointing to a local plugin |
| **url** | `string?` | A custom git url where the plugin is hosted | | **url** | `string?` | A custom git url where the plugin is hosted |
| **name** | `string?` | A custom name for the plugin used for the local plugin directory and as the display name | | **name** | `string?` | A custom name for the plugin used for the local plugin directory and as the display name |
| **dev** | `boolean?` | When `true`, a local plugin directory will be used instead. See `config.dev` | | **dev** | `boolean?` | When `true`, a local plugin directory will be used instead. See `config.dev` |
| **lazy** | `boolean?` | When `true`, the plugin will only be loaded when needed. Lazy-loaded plugins are automatically loaded when their Lua modules are `required`, or when one of the lazy-loading handlers triggers | | **lazy** | `boolean?` | When `true`, the plugin will only be loaded when needed. Lazy-loaded plugins are automatically loaded when their Lua modules are `required`, or when one of the lazy-loading handlers triggers |
| **enabled** | `boolean?` or `fun():boolean` | When `false`, or if the `function` returns false, then this plugin will not be included in the spec | | **enabled** | `boolean?` or `fun():boolean` | When `false`, or if the `function` returns false, then this plugin will not be included in the spec |
| **cond** | `boolean?` or `fun():boolean` | When `false`, or if the `function` returns false, then this plugin will not be loaded. Useful to disable some plugins in vscode, or firenvim for example. | | **cond** | `boolean?` or `fun():boolean` | When `false`, or if the `function` returns false, then this plugin will not be loaded. Useful to disable some plugins in vscode, or firenvim for example. |
| **dependencies** | `LazySpec[]` | A list of plugin names or plugin specs that should be loaded when the plugin loads. Dependencies are always lazy-loaded unless specified otherwise. When specifying a name, make sure the plugin spec has been defined somewhere else. | | **dependencies** | `LazySpec[]` | A list of plugin names or plugin specs that should be loaded when the plugin loads. Dependencies are always lazy-loaded unless specified otherwise. When specifying a name, make sure the plugin spec has been defined somewhere else. |
| **init** | `fun(LazyPlugin)` | `init` functions are always executed during startup | | **init** | `fun(LazyPlugin)` | `init` functions are always executed during startup |
| **opts** | `table` or `fun(LazyPlugin, opts:table)` | `opts` should be a table (will be merged with parent specs), return a table (replaces parent specs) or should change a table. The table will be passed to the `Plugin.config()` function. Setting this value will imply `Plugin.config()` | | **opts** | `table` or `fun(LazyPlugin, opts:table)` | `opts` should be a table (will be merged with parent specs), return a table (replaces parent specs) or should change a table. The table will be passed to the `Plugin.config()` function. Setting this value will imply `Plugin.config()` |
| **config** | `fun(LazyPlugin, opts:table)` or `true` | `config` is executed when the plugin loads. The default implementation will automatically run `require("plugin").setup(opts)`. `"plugin"` will default to `name` if specified, otherwise `lazy.nvim` will do its best to guess the correct plugin name. See also `opts`. To use the default implementation without `opts` set `config` to `true`. | | **config** | `fun(LazyPlugin, opts:table)` or `true` | `config` is executed when the plugin loads. The default implementation will automatically run `require("plugin").setup(opts)`. `"plugin"` will default to `name` if specified, otherwise `lazy.nvim` will do its best to guess the correct plugin name. See also `opts`. To use the default implementation without `opts` set `config` to `true`. |
| **build** | `fun(LazyPlugin)` or `string` or a list of build commands | `build` is executed when a plugin is installed or updated. If it's a string it will be ran as a shell command. When prefixed with `:` it is a Neovim command. You can also specify a list to executed multiple build commands | | **build** | `fun(LazyPlugin)` or `string` or a list of build commands | `build` is executed when a plugin is installed or updated. If it's a string it will be ran as a shell command. When prefixed with `:` it is a Neovim command. You can also specify a list to executed multiple build commands |
| **branch** | `string?` | Branch of the repository | | **branch** | `string?` | Branch of the repository |
| **tag** | `string?` | Tag of the repository | | **tag** | `string?` | Tag of the repository |
| **commit** | `string?` | Commit of the repository | | **commit** | `string?` | Commit of the repository |
| **version** | `string?` | Version to use from the repository. Full [Semver](https://devhints.io/semver) ranges are supported | | **version** | `string?` | Version to use from the repository. Full [Semver](https://devhints.io/semver) ranges are supported |
| **pin** | `boolean?` | When `true`, this plugin will not be included in updates | | **pin** | `boolean?` | When `true`, this plugin will not be included in updates |
| **event** | `string?` or `string[]` or `fun(self:LazyPlugin, event:string[]):string[]` | Lazy-load on event. Events can be specified as `BufEnter` or with a pattern like `BufEnter *.lua` | | `submodules` | `boolean?` | When false, git submodules will not be fetched. Defaults to `true` |
| **cmd** | `string?` or `string[]` or `fun(self:LazyPlugin, cmd:string[]):string[]` | Lazy-load on command | | **event** | `string?` or `string[]` or `fun(self:LazyPlugin, event:string[]):string[]` | Lazy-load on event. Events can be specified as `BufEnter` or with a pattern like `BufEnter *.lua` |
| **ft** | `string?` or `string[]` or `fun(self:LazyPlugin, ft:string[]):string[]` | Lazy-load on filetype | | **cmd** | `string?` or `string[]` or `fun(self:LazyPlugin, cmd:string[]):string[]` | Lazy-load on command |
| **keys** | `string?` or `string[]` or `LazyKeys[]` or `fun(self:LazyPlugin, keys:string[]):(string \| LazyKeys)[]` | Lazy-load on key mapping | | **ft** | `string?` or `string[]` or `fun(self:LazyPlugin, ft:string[]):string[]` | Lazy-load on filetype |
| **module** | `false?` | Do not automatically load this Lua module when it's required somewhere | | **keys** | `string?` or `string[]` or `LazyKeys[]` or `fun(self:LazyPlugin, keys:string[]):(string \| LazyKeys)[]` | Lazy-load on key mapping |
| **priority** | `number?` | Only useful for **start** plugins (`lazy=false`) to force loading certain plugins first. Default priority is `50`. It's recommended to set this to a high number for colorschemes. | | **module** | `false?` | Do not automatically load this Lua module when it's required somewhere |
| **priority** | `number?` | Only useful for **start** plugins (`lazy=false`) to force loading certain plugins first. Default priority is `50`. It's recommended to set this to a high number for colorschemes. |
### Lazy Loading ### Lazy Loading
@ -314,12 +315,17 @@ return {
log = { "--since=3 days ago" }, -- show commits from the last 3 days log = { "--since=3 days ago" }, -- show commits from the last 3 days
timeout = 120, -- kill processes that take more than 2 minutes timeout = 120, -- kill processes that take more than 2 minutes
url_format = "https://github.com/%s.git", url_format = "https://github.com/%s.git",
-- lazy.nvim requires git >=2.19.0. If you really want to use lazy with an older version,
-- then set the below to false. This is should work, but is NOT supported and will
-- increase downloads a lot.
filter = true,
}, },
dev = { dev = {
-- directory where you store your local plugin projects -- directory where you store your local plugin projects
path = "~/projects", path = "~/projects",
---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub ---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub
patterns = {}, -- For example {"folke"} patterns = {}, -- For example {"folke"}
fallback = false, -- Fallback to git when local plugin doesn't exist
}, },
install = { install = {
-- install missing plugins on startup. This doesn't increase startup time. -- install missing plugins on startup. This doesn't increase startup time.
@ -330,6 +336,7 @@ return {
ui = { ui = {
-- a number <1 is a percentage., >1 is a fixed size -- a number <1 is a percentage., >1 is a fixed size
size = { width = 0.8, height = 0.8 }, size = { width = 0.8, height = 0.8 },
wrap = true, -- wrap the lines in the ui
-- The border to use for the UI window. Accepts same border values as |nvim_open_win()|. -- The border to use for the UI window. Accepts same border values as |nvim_open_win()|.
border = "none", border = "none",
icons = { icons = {
@ -340,7 +347,7 @@ return {
init = " ", init = " ",
import = " ", import = " ",
keys = " ", keys = " ",
lazy = " ", lazy = "󰒲 ",
loaded = "●", loaded = "●",
not_loaded = "○", not_loaded = "○",
plugin = " ", plugin = " ",
@ -402,20 +409,12 @@ return {
performance = { performance = {
cache = { cache = {
enabled = true, enabled = true,
path = vim.fn.stdpath("cache") .. "/lazy/cache",
-- Once one of the following events triggers, caching will be disabled.
-- To cache all modules, set this to `{}`, but that is not recommended.
-- The default is to disable on:
-- * VimEnter: not useful to cache anything else beyond startup
-- * BufReadPre: this will be triggered early when opening a file from the command line directly
disable_events = { "UIEnter", "BufReadPre" },
ttl = 3600 * 24 * 5, -- keep unused modules for up to 5 days
}, },
reset_packpath = true, -- reset the package path to improve startup time reset_packpath = true, -- reset the package path to improve startup time
rtp = { rtp = {
reset = true, -- reset the runtime path to $VIMRUNTIME and your config directory reset = true, -- reset the runtime path to $VIMRUNTIME and your config directory
---@type string[] ---@type string[]
paths = {}, -- add any custom paths here that you want to indluce in the rtp paths = {}, -- add any custom paths here that you want to includes in the rtp
---@type string[] list any plugins you want to disable here ---@type string[] list any plugins you want to disable here
disabled_plugins = { disabled_plugins = {
-- "gzip", -- "gzip",
@ -438,6 +437,7 @@ return {
-- only generate markdown helptags for plugins that dont have docs -- only generate markdown helptags for plugins that dont have docs
skip_if_doc_exists = true, skip_if_doc_exists = true,
}, },
state = vim.fn.stdpath("state") .. "/lazy/state.json", -- state info for checker and other things
} }
``` ```
@ -603,7 +603,7 @@ The profiling view shows you why and how long it took to load your plugins.
![image](https://user-images.githubusercontent.com/292349/208301766-5c400561-83c3-4811-9667-1ec4bb3c43b8.png) ![image](https://user-images.githubusercontent.com/292349/208301766-5c400561-83c3-4811-9667-1ec4bb3c43b8.png)
## 🪲 Debug ## 🐛 Debug
See an overview of active lazy-loading handlers and what's in the module cache See an overview of active lazy-loading handlers and what's in the module cache
@ -620,7 +620,7 @@ In practice this means that step 10 of [Neovim Initialization](https://neovim.io
1. all the plugins' `init()` functions are executed 1. all the plugins' `init()` functions are executed
2. all plugins with `lazy=false` are loaded. This includes sourcing `/plugin` and `/ftdetect` files. (`/after` will not be sourced yet) 2. all plugins with `lazy=false` are loaded. This includes sourcing `/plugin` and `/ftdetect` files. (`/after` will not be sourced yet)
3. all files from `/plugin` and `/ftdetect` directories in you rtp are sourced (excluding `/after`) 3. all files from `/plugin` and `/ftdetect` directories in you rtp are sourced (excluding `/after`)
4. all `/after/plugin` files are sourced (this inludes `/after` from plugins) 4. all `/after/plugin` files are sourced (this includes `/after` from plugins)
Files from runtime directories are always sourced in alphabetical order. Files from runtime directories are always sourced in alphabetical order.

View file

@ -1,36 +1,32 @@
*lazy.nvim.txt* For Neovim >= 0.8.0 Last change: 2023 January 19 *lazy.nvim.txt* For Neovim >= 0.8.0 Last change: 2023 February 20
============================================================================== ==============================================================================
Table of Contents *lazy.nvim-table-of-contents* Table of Contents *lazy.nvim-table-of-contents*
1. lazy.nvim |lazy.nvim-lazy.nvim| 1. lazy.nvim |lazy.nvim-lazy.nvim|
- Features |lazy.nvim-features| - Features |lazy.nvim-lazy.nvim-features|
- Requirements |lazy.nvim-requirements| - Requirements |lazy.nvim-lazy.nvim-requirements|
- Installation |lazy.nvim-installation| - Installation |lazy.nvim-lazy.nvim-installation|
- Plugin Spec |lazy.nvim-plugin-spec| - Plugin Spec |lazy.nvim-lazy.nvim-plugin-spec|
- Configuration |lazy.nvim-configuration| - Configuration |lazy.nvim-lazy.nvim-configuration|
- Usage |lazy.nvim-usage| - Usage |lazy.nvim-lazy.nvim-usage|
- Lockfile `lazy-lock.json` |lazy.nvim-lockfile-`lazy-lock.json`| - Lockfile lazy-lock.json |lazy.nvim-lazy.nvim-lockfile-lazy-lock.json|
- Performance |lazy.nvim-performance| - Performance |lazy.nvim-lazy.nvim-performance|
- 🪲 Debug |lazy.nvim-🪲-debug| - Debug |lazy.nvim-lazy.nvim-debug|
- Startup Sequence |lazy.nvim-startup-sequence| - Startup Sequence |lazy.nvim-lazy.nvim-startup-sequence|
- Structuring Your Plugins |lazy.nvim-structuring-your-plugins| - Structuring Your Plugins |lazy.nvim-lazy.nvim-structuring-your-plugins|
- Migration Guide |lazy.nvim-migration-guide| - Migration Guide |lazy.nvim-lazy.nvim-migration-guide|
- Uninstalling |lazy.nvim-uninstalling| - Uninstalling |lazy.nvim-lazy.nvim-uninstalling|
- Highlight Groups |lazy.nvim-highlight-groups| - Highlight Groups |lazy.nvim-lazy.nvim-highlight-groups|
- Other Neovim Plugin Managers in Lua|lazy.nvim-other-neovim-plugin-managers-in-lua| - Other Neovim Plugin Managers in Lua|lazy.nvim-lazy.nvim-other-neovim-plugin-managers-in-lua|
============================================================================== ==============================================================================
1. lazy.nvim *lazy.nvim-lazy.nvim* 1. lazy.nvim *lazy.nvim-lazy.nvim*
**lazy.nvim** is a modern plugin manager for Neovim. **lazy.nvim** is a modern plugin manager for Neovim.
<div class="figure">
<img src="https://user-images.githubusercontent.com/292349/208301737-68fb279c-ba70-43ef-a369-8c3e8367d6b1.png" title="fig:"/>
<p class="caption">image</p>
</div>
FEATURES *lazy.nvim-features* FEATURES *lazy.nvim-lazy.nvim-features*
- Manage all your Neovim plugins with a powerful UI - Manage all your Neovim plugins with a powerful UI
@ -52,15 +48,15 @@ FEATURES *lazy.nvim-features*
- Automatically lazy-loads colorschemes - Automatically lazy-loads colorschemes
REQUIREMENTS *lazy.nvim-requirements* REQUIREMENTS *lazy.nvim-lazy.nvim-requirements*
- Neovim >= **0.8.0** (needs to be built with **LuaJIT**) - Neovim >= **0.8.0** (needs to be built with **LuaJIT**)
- Git >= **2.19.0** (for partial clones support) - Git >= **2.19.0** (for partial clones support)
- a Nerd Font <https://www.nerdfonts.com/> **_(optional)_** - a Nerd Font <https://www.nerdfonts.com/> **(optional)**
INSTALLATION *lazy.nvim-installation* INSTALLATION *lazy.nvim-lazy.nvim-installation*
You can add the following Lua code to your `init.lua` to bootstrap You can add the following Lua code to your `init.lua` to bootstrap
**lazy.nvim** **lazy.nvim**
@ -80,20 +76,18 @@ You can add the following Lua code to your `init.lua` to bootstrap
vim.opt.rtp:prepend(lazypath) vim.opt.rtp:prepend(lazypath)
< <
Next step is to add **lazy.nvim** below the code added in the last step in
Next step is to add **lazy.nvim** to the top of your `init.lua` `init.lua`
>lua >lua
require("lazy").setup(plugins, opts) require("lazy").setup(plugins, opts)
< <
- **plugins**this should be a `table` or a `string`
- **plugins**: this should be a `table` or a `string` - `table`a list with your |lazy.nvim-plugin-spec|
- `table`: a list with your |lazy.nvim-plugin-spec| - `string`a Lua module name that contains your |lazy.nvim-plugin-spec|. See |lazy.nvim-structuring-your-plugins|
- `string`: a Lua module name that contains your |lazy.nvim-plugin-spec|. See |lazy.nvim-structuring-your-plugins| - **opts**see |lazy.nvim-configuration| **(optional)**
- **opts**: see |lazy.nvim-configuration| **_(optional)_**
>lua >lua
-- example using a list of specs with the default options -- example using a list of specs with the default options
@ -106,37 +100,102 @@ Next step is to add **lazy.nvim** to the top of your `init.lua`
}) })
< <
It is recommended to run `:checkhealth lazy` after installation It is recommended to run `:checkhealth lazy` after installation
PLUGIN SPEC *lazy.nvim-plugin-spec*
│ Property │ Type │ Description │ PLUGIN SPEC *lazy.nvim-lazy.nvim-plugin-spec*
│[1] │string? │Short plugin url. Will be expanded using config.git.url_format │
│**dir** │string? │A directory pointing to a local plugin │
│**url** │string? │A custom git url where the plugin is hosted │
│**name** │string? │A custom name for the plugin used for the local plugin directory and as the display name │
│**dev** │boolean? │When true, a local plugin directory will be used instead. See config.dev │
│**lazy** │boolean? │When true, the plugin will only be loaded when needed. Lazy-loaded plugins are automatically loaded when their Lua modules are required, or when one of the lazy-loading handlers triggers │
│**enabled** │boolean? or fun():boolean │When false, or if the function returns false, then this plugin will not be included in the spec │
│**cond** │boolean? or fun():boolean │When false, or if the function returns false, then this plugin will not be loaded. Useful to disable some plugins in vscode, or firenvim for example. │
│**dependencies**│LazySpec[] │A list of plugin names or plugin specs that should be loaded when the plugin loads. Dependencies are always lazy-loaded unless specified otherwise. When specifying a name, make sure the plugin spec has been defined somewhere else. │
│**init** │fun(LazyPlugin) │init functions are always executed during startup │
│**opts** │table or fun(LazyPlugin, opts:table) │opts should be a table (will be merged with parent specs), return a table (replaces parent specs) or should change a table. The table will be passed to the Plugin.config() function. Setting this value will imply Plugin.config() │
│**config** │fun(LazyPlugin, opts:table) or true │config is executed when the plugin loads. The default implementation will automatically run require("plugin").setup(opts). "plugin" will default to name if specified, otherwise lazy.nvim will do its best to guess the correct plugin name. See also opts. To use the default implementation without opts set config to true. │
│**build** │fun(LazyPlugin) or string or a list of build commands │build is executed when a plugin is installed or updated. If its a string it will be ran as a shell command. When prefixed with : it is a Neovim command. You can also specify a list to executed multiple build commands │
│**branch** │string? │Branch of the repository │
│**tag** │string? │Tag of the repository │
│**commit** │string? │Commit of the repository │
│**version** │string? │Version to use from the repository. Full Semver <https://devhints.io/semver> ranges are supported │
│**pin** │boolean? │When true, this plugin will not be included in updates │
│**event** │string? or string[] or fun(self:LazyPlugin, event:string[]):string[] │Lazy-load on event. Events can be specified as BufEnter or with a pattern like BufEnter .lua │
│**cmd** │string? or string[] or fun(self:LazyPlugin, cmd:string[]):string[] │Lazy-load on command │
│**ft** │string? or string[] or fun(self:LazyPlugin, ft:string[]):string[] │Lazy-load on filetype │
│**keys** │string? or string[] or LazyKeys[] or fun(self:LazyPlugin, keys:string[]):(string \| LazyKeys)[] │Lazy-load on key mapping │
│**module** │false? │Do not automatically load this Lua module when its required somewhere │
│**priority** │number? │Only useful for **start** plugins (lazy=false) to force loading certain plugins first. Default priority is 50. Its recommended to set this to a high number for colorschemes. │
--------------------------------------------------------------------------------------------------------------------------------
Property Type Description
-------------- ------------------------------------------------------------ ----------------------------------------------------
[1] string? Short plugin url. Will be expanded using
config.git.url_format
dir string? A directory pointing to a local plugin
url string? A custom git url where the plugin is hosted
name string? A custom name for the plugin used for the local
plugin directory and as the display name
dev boolean? When true, a local plugin directory will be used
instead. See config.dev
lazy boolean? When true, the plugin will only be loaded when
needed. Lazy-loaded plugins are automatically loaded
when their Lua modules are required, or when one of
the lazy-loading handlers triggers
enabled boolean? or fun():boolean When false, or if the function returns false, then
this plugin will not be included in the spec
cond boolean? or fun():boolean When false, or if the function returns false, then
this plugin will not be loaded. Useful to disable
some plugins in vscode, or firenvim for example.
dependencies LazySpec[] A list of plugin names or plugin specs that should
be loaded when the plugin loads. Dependencies are
always lazy-loaded unless specified otherwise. When
specifying a name, make sure the plugin spec has
been defined somewhere else.
init fun(LazyPlugin) init functions are always executed during startup
opts table or fun(LazyPlugin, opts:table) opts should be a table (will be merged with parent
specs), return a table (replaces parent specs) or
should change a table. The table will be passed to
the Plugin.config() function. Setting this value
will imply Plugin.config()
config fun(LazyPlugin, opts:table) or true config is executed when the plugin loads. The
default implementation will automatically run
require("plugin").setup(opts). "plugin" will default
to name if specified, otherwise lazy.nvim will do
its best to guess the correct plugin name. See also
opts. To use the default implementation without opts
set config to true.
build fun(LazyPlugin) or string or a list of build commands build is executed when a plugin is installed or
updated. If its a string it will be ran as a shell
command. When prefixed with it is a Neovim command.
You can also specify a list to executed multiple
build commands
branch string? Branch of the repository
tag string? Tag of the repository
commit string? Commit of the repository
version string? Version to use from the repository. Full Semver
ranges are supported
pin boolean? When true, this plugin will not be included in
updates
submodules boolean? When false, git submodules will not be fetched.
Defaults to true
event string? or string[] or Lazy-load on event. Events can be specified as
fun(self:LazyPlugin, event:string[]):string[] BufEnter or with a pattern like BufEnter .lua
cmd string? or string[] or Lazy-load on command
fun(self:LazyPlugin, cmd:string[]):string[]
ft string? or string[] or Lazy-load on filetype
fun(self:LazyPlugin, ft:string[]):string[]
keys string? or string[] or LazyKeys[] or Lazy-load on key mapping
fun(self:LazyPlugin, keys:string[]):(string \| LazyKeys)[]
module false? Do not automatically load this Lua module when its
required somewhere
priority number? Only useful for start plugins (lazy=false) to force
loading certain plugins first. Default priority is
50. Its recommended to set this to a high number
for colorschemes.
--------------------------------------------------------------------------------------------------------------------------------
LAZY LOADING ~ LAZY LOADING ~
@ -155,45 +214,36 @@ You can configure **lazy.nvim** to lazy-load all plugins by default with
Additionally, you can also lazy-load on **events**, **commands**, **file Additionally, you can also lazy-load on **events**, **commands**, **file
types** and **key mappings**. types** and **key mappings**.
Plugins will be lazy-loaded when one of the following is `true`: Plugins will be lazy-loaded when one of the following is `true`
- the plugin only exists as a dependency in your spec - theplugin only exists as a dependency in your spec
- it has an `event`, `cmd`, `ft` or `keys` key - it has an `event`, `cmd`, `ft` or `keys` key
- `config.defaults.lazy == true` - `config.defaults.lazy == true`
*lazy.nvim-Colorschemes* COLORSCHEMES
Colorschemes Colorscheme plugins can be configured
with `lazy=true`. The plugin will
automagically load when doing
`colorscheme foobar`.
Colorscheme plugins can be configured with `lazy=true`. The plugin will
automagically load when doing `colorscheme foobar`.
**NOTE:** since **start** plugins can possibly change existing highlight **NOTE:** since **start** plugins can possibly change existing highlight
groups, its important to make sure that your main **colorscheme** is loaded groups, its important to make sure that your main **colorscheme** is loaded
first. To ensure this you can use the `priority=1000` field. **_(see the first. To ensure this you can use the `priority=1000` field. **(see the
examples)_** examples)**
LAZY KEY MAPPINGS
The `keys` property can be a `string` or `string[]` for simple normal-mode
mappings, or it can be a `LazyKeys` table with the following key-value pairs:
*lazy.nvim-Lazy-Key-Mappings* - **[1]**(`string`) lhs **(required)**
- **[2]**(`string|fun()`) rhs **(optional)**
Lazy Key Mappings The `keys` property can be a `string` or - **mode**(`string|string[]`) mode **(optional, defaults to "n")**
`string[]` for simple normal-mode
mappings, or it can be a `LazyKeys`
table with the following key-value
pairs:
- **[1]**: (`string`) lhs **_(required)_**
- **[2]**: (`string|fun()`) rhs **_(optional)_**
- **mode**: (`string|string[]`) mode **_(optional, defaults to `"n"`)_**
- any other option valid for `vim.keymap.set` - any other option valid for `vim.keymap.set`
Key mappings will load the plugin the first time they get executed. Key mappings will load the plugin the first time they get executed.
When `[2]` is `nil`, then the real mapping has to be created by the `config()` When `[2]` is `nil`, then the real mapping has to be created by the `config()`
@ -220,22 +270,22 @@ If you want to install a specific revision of a plugin, you can use `commit`,
The `version` property supports Semver <https://semver.org/> ranges. The `version` property supports Semver <https://semver.org/> ranges.
Click to see some examples Click to see some examples ~
- :latest stable version (this excludes pre-release versions) - latest stable version (this excludes pre-release versions)
- `1.2.x`: any version that starts with `1.2`, such as `1.2.0`, `1.2.3`, etc. - `1.2.x`any version that starts with `1.2`, such as `1.2.0`, `1.2.3`, etc.
- `^1.2.3`: any version that is compatible with `1.2.3`, such as `1.3.0`, `1.4.5`, etc., but not `2.0.0`. - `^1.2.3`any version that is compatible with `1.2.3`, such as `1.3.0`, `1.4.5`, etc., but not `2.0.0`.
- `~1.2.3`: any version that is compatible with `1.2.3`, such as `1.2.4`, `1.2.5`, but not `1.3.0`. - `~1.2.3`any version that is compatible with `1.2.3`, such as `1.2.4`, `1.2.5`, but not `1.3.0`.
- `>1.2.3`: any version that is greater than `1.2.3`, such as `1.3.0`, `1.4.5`, etc. - `>1.2.3`any version that is greater than `1.2.3`, such as `1.3.0`, `1.4.5`, etc.
- `>=1.2.3`: any version that is greater than or equal to `1.2.3`, such as `1.2.3`, `1.3.0`, `1.4.5`, etc. - `>=1.2.3`any version that is greater than or equal to `1.2.3`, such as `1.2.3`, `1.3.0`, `1.4.5`, etc.
- `<1.2.3`: any version that is less than `1.2.3`, such as `1.1.0`, `1.0.5`, etc. - `<1.2.3`any version that is less than `1.2.3`, such as `1.1.0`, `1.0.5`, etc.
- `<=1.2.3`: any version that is less than or equal to `1.2.3`, such as `1.2.3`, `1.1.0`, `1.0.5`, etc - `<=1.2.3`any version that is less than or equal to `1.2.3`, such as `1.2.3`, `1.1.0`, `1.0.5`, etc
You can set `config.defaults.version = ""` to install the latest stable version You can set `config.defaults.version = ""` to install the latest stable version
of plugins that support Semver. of plugins that support Semver.
EXAMPLES ~ EXAMPLES ~
>lua >lua
@ -336,7 +386,7 @@ EXAMPLES ~
< <
CONFIGURATION *lazy.nvim-configuration* CONFIGURATION *lazy.nvim-lazy.nvim-configuration*
**lazy.nvim** comes with the following defaults: **lazy.nvim** comes with the following defaults:
@ -358,12 +408,17 @@ CONFIGURATION *lazy.nvim-configuration*
log = { "--since=3 days ago" }, -- show commits from the last 3 days log = { "--since=3 days ago" }, -- show commits from the last 3 days
timeout = 120, -- kill processes that take more than 2 minutes timeout = 120, -- kill processes that take more than 2 minutes
url_format = "https://github.com/%s.git", url_format = "https://github.com/%s.git",
-- lazy.nvim requires git >=2.19.0. If you really want to use lazy with an older version,
-- then set the below to false. This is should work, but is NOT supported and will
-- increase downloads a lot.
filter = true,
}, },
dev = { dev = {
-- directory where you store your local plugin projects -- directory where you store your local plugin projects
path = "~/projects", path = "~/projects",
---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub ---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub
patterns = {}, -- For example {"folke"} patterns = {}, -- For example {"folke"}
fallback = false, -- Fallback to git when local plugin doesn't exist
}, },
install = { install = {
-- install missing plugins on startup. This doesn't increase startup time. -- install missing plugins on startup. This doesn't increase startup time.
@ -374,6 +429,7 @@ CONFIGURATION *lazy.nvim-configuration*
ui = { ui = {
-- a number <1 is a percentage., >1 is a fixed size -- a number <1 is a percentage., >1 is a fixed size
size = { width = 0.8, height = 0.8 }, size = { width = 0.8, height = 0.8 },
wrap = true, -- wrap the lines in the ui
-- The border to use for the UI window. Accepts same border values as |nvim_open_win()|. -- The border to use for the UI window. Accepts same border values as |nvim_open_win()|.
border = "none", border = "none",
icons = { icons = {
@ -384,7 +440,7 @@ CONFIGURATION *lazy.nvim-configuration*
init = " ", init = " ",
import = " ", import = " ",
keys = " ", keys = " ",
lazy = " ", lazy = "󰒲 ",
loaded = "", loaded = "",
not_loaded = "", not_loaded = "",
plugin = " ", plugin = " ",
@ -446,20 +502,12 @@ CONFIGURATION *lazy.nvim-configuration*
performance = { performance = {
cache = { cache = {
enabled = true, enabled = true,
path = vim.fn.stdpath("cache") .. "/lazy/cache",
-- Once one of the following events triggers, caching will be disabled.
-- To cache all modules, set this to `{}`, but that is not recommended.
-- The default is to disable on:
-- VimEnter: not useful to cache anything else beyond startup
-- BufReadPre: this will be triggered early when opening a file from the command line directly
disable_events = { "UIEnter", "BufReadPre" },
ttl = 3600 24 5, -- keep unused modules for up to 5 days
}, },
reset_packpath = true, -- reset the package path to improve startup time reset_packpath = true, -- reset the package path to improve startup time
rtp = { rtp = {
reset = true, -- reset the runtime path to $VIMRUNTIME and your config directory reset = true, -- reset the runtime path to $VIMRUNTIME and your config directory
---@type string[] ---@type string[]
paths = {}, -- add any custom paths here that you want to indluce in the rtp paths = {}, -- add any custom paths here that you want to includes in the rtp
---@type string[] list any plugins you want to disable here ---@type string[] list any plugins you want to disable here
disabled_plugins = { disabled_plugins = {
-- "gzip", -- "gzip",
@ -482,11 +530,11 @@ CONFIGURATION *lazy.nvim-configuration*
-- only generate markdown helptags for plugins that dont have docs -- only generate markdown helptags for plugins that dont have docs
skip_if_doc_exists = true, skip_if_doc_exists = true,
}, },
state = vim.fn.stdpath("state") .. "/lazy/state.json", -- state info for checker and other things
} }
< <
If you dont want to use a Nerd Font, you can replace the icons with Unicode symbols. ~
If you dont want to use a Nerd Font, you can replace the icons with Unicode symbols.
>lua >lua
{ {
@ -510,7 +558,7 @@ If you dont want to use a Nerd Font, you can replace the icons with Unicode s
< <
USAGE *lazy.nvim-usage* USAGE *lazy.nvim-lazy.nvim-usage*
Plugins are managed with the `:Lazy` command. Open the help with `<?>` to see Plugins are managed with the `:Lazy` command. Open the help with `<?>` to see
all the key mappings. all the key mappings.
@ -525,24 +573,43 @@ enabled with `config.checker.enabled = true`.
Any operation can be started from the UI, with a sub command or an API Any operation can be started from the UI, with a sub command or an API
function: function:
│ Command │ Lua │ Description │ --------------------------------------------------------------------------------------------------------------
│:Lazy build {plugins} │require("lazy").build(opts) │Rebuild a plugin │ Command Lua Description
│:Lazy check [plugins] │require("lazy").check(opts?) │Check for updates and show the log (git fetch) │ ------------------------- -------------------------------- ---------------------------------------------------
│:Lazy clean [plugins] │require("lazy").clean(opts?) │Clean plugins that are no longer needed │ :Lazy build {plugins} require("lazy").build(opts) Rebuild a plugin
│:Lazy clear │require("lazy").clear() │Clear finished tasks │
│:Lazy debug │require("lazy").debug() │Show debug information │
│:Lazy health │require("lazy").health() │Run :checkhealth lazy │
│:Lazy help │require("lazy").help() │Toggle this help page │
│:Lazy home │require("lazy").home() │Go back to plugin list │
│:Lazy install [plugins] │require("lazy").install(opts?) │Install missing plugins │
│:Lazy load {plugins} │require("lazy").load(opts) │Load a plugin that has not been loaded yet. Similar to :packadd. Like :Lazy load foo.nvim. Use :Lazy! load to skip cond checks. │
│:Lazy log [plugins] │require("lazy").log(opts?) │Show recent updates │
│:Lazy profile │require("lazy").profile() │Show detailed profiling │
│:Lazy restore [plugins] │require("lazy").restore(opts?) │Updates all plugins to the state in the lockfile. For a single plugin: restore it to the state in the lockfile or to a given commit under the cursor│
│:Lazy sync [plugins] │require("lazy").sync(opts?) │Run install, clean and update │
│:Lazy update [plugins] │require("lazy").update(opts?) │Update plugins. This will also update the lockfile │
:Lazy check [plugins] require("lazy").check(opts?) Check for updates and show the log (git fetch)
:Lazy clean [plugins] require("lazy").clean(opts?) Clean plugins that are no longer needed
:Lazy clear require("lazy").clear() Clear finished tasks
:Lazy debug require("lazy").debug() Show debug information
:Lazy health require("lazy").health() Run :checkhealth lazy
:Lazy help require("lazy").help() Toggle this help page
:Lazy home require("lazy").home() Go back to plugin list
:Lazy install [plugins] require("lazy").install(opts?) Install missing plugins
:Lazy load {plugins} require("lazy").load(opts) Load a plugin that has not been loaded yet. Similar
to :packadd. Like :Lazy load foo.nvim. Use
:Lazy! load to skip cond checks.
:Lazy log [plugins] require("lazy").log(opts?) Show recent updates
:Lazy profile require("lazy").profile() Show detailed profiling
:Lazy restore [plugins] require("lazy").restore(opts?) Updates all plugins to the state in the lockfile.
For a single plugin: restore it to the state in the
lockfile or to a given commit under the cursor
:Lazy sync [plugins] require("lazy").sync(opts?) Run install, clean and update
:Lazy update [plugins] require("lazy").update(opts?) Update plugins. This will also update the lockfile
--------------------------------------------------------------------------------------------------------------
Any command can have a **bang** to make the command wait till it finished. For Any command can have a **bang** to make the command wait till it finished. For
example, if you want to sync lazy from the cmdline, you can use: example, if you want to sync lazy from the cmdline, you can use:
@ -550,15 +617,13 @@ example, if you want to sync lazy from the cmdline, you can use:
$ nvim --headless "+Lazy! sync" +qa $ nvim --headless "+Lazy! sync" +qa
< <
`opts` is a table with the following key-values: `opts` is a table with the following key-values:
- **wait**: when true, then the call will wait till the operation completed - **wait**when true, then the call will wait till the operation completed
- **show**: when false, the UI will not be shown - **show**when false, the UI will not be shown
- **plugins**: a list of plugin names to run the operation on - **plugins**a list of plugin names to run the operation on
- **concurrency**: limit the `number` of concurrently running tasks - **concurrency**limit the `number` of concurrently running tasks
Stats API (`require("lazy").stats()`): Stats API (`require("lazy").stats()`):
@ -577,12 +642,11 @@ Stats API (`require("lazy").stats()`):
} }
< <
**lazy.nvim** provides a statusline component that you can use to show the **lazy.nvim** provides a statusline component that you can use to show the
number of pending updates. Make sure to enable `config.checker.enabled = true` number of pending updates. Make sure to enable `config.checker.enabled = true`
to make this work. to make this work.
Example of configuring <a href="https://github.com/nvim-lualine/lualine.nvim">lualine.nvim</a> Example of configuring lualine.nvim ~
>lua >lua
require("lualine").setup({ require("lualine").setup({
@ -604,20 +668,20 @@ USER EVENTS ~
The following user events will be triggered: The following user events will be triggered:
- **LazyDone**: when lazy has finished starting up and loaded your config - **LazyDone**when lazy has finished starting up and loaded your config
- **LazySync**: after running sync - **LazySync**after running sync
- **LazyInstall**: after an install - **LazyInstall**after an install
- **LazyUpdate**: after an update - **LazyUpdate**after an update
- **LazyClean**: after a clean - **LazyClean**after a clean
- **LazyCheck**: after checking for updates - **LazyCheck**after checking for updates
- **LazyLog**: after running log - **LazyLog**after running log
- **LazyReload**: triggered by change detection after reloading plugin specs - **LazyReload**triggered by change detection after reloading plugin specs
- **VeryLazy**: triggered after `LazyDone` and processing `VimEnter` auto commands - **VeryLazy**triggered after `LazyDone` and processing `VimEnter` auto commands
- **LazyVimStarted**: triggered after `UIEnter` when `require("lazy").stats().startuptime` has been calculated. - **LazyVimStarted**triggered after `UIEnter` when `require("lazy").stats().startuptime` has been calculated.
Useful to update the startuptime on your dashboard. Useful to update the startuptime on your dashboard.
LOCKFILE `LAZY-LOCK.JSON` *lazy.nvim-lockfile-`lazy-lock.json`* LOCKFILE LAZY-LOCK.JSON *lazy.nvim-lazy.nvim-lockfile-lazy-lock.json*
After every **update**, the local lockfile is updated with the installed After every **update**, the local lockfile is updated with the installed
revisions. It is recommended to have this file under version control. revisions. It is recommended to have this file under version control.
@ -628,7 +692,8 @@ ensure that the same version of every plugin is installed.
If you are on another machine, you can do `:Lazy restore`, to update all your If you are on another machine, you can do `:Lazy restore`, to update all your
plugins to the version from the lockfile. plugins to the version from the lockfile.
PERFORMANCE *lazy.nvim-performance*
PERFORMANCE *lazy.nvim-lazy.nvim-performance*
Great care has been taken to make the startup code (`lazy.core`) as efficient Great care has been taken to make the startup code (`lazy.core`) as efficient
as possible. During startup, all Lua files used before `VimEnter` or as possible. During startup, all Lua files used before `VimEnter` or
@ -642,22 +707,14 @@ lazy-loading though :)
improve performance. The profiling view shows you why and how long it took to improve performance. The profiling view shows you why and how long it took to
load your plugins. load your plugins.
<div class="figure">
<img src="https://user-images.githubusercontent.com/292349/208301766-5c400561-83c3-4811-9667-1ec4bb3c43b8.png" title="fig:"/>
<p class="caption">image</p>
</div>
🪲 DEBUG *lazy.nvim-🪲-debug* DEBUG *lazy.nvim-lazy.nvim-debug*
See an overview of active lazy-loading handlers and whats in the module See an overview of active lazy-loading handlers and whats in the module
cache cache
<div class="figure">
<img src="https://user-images.githubusercontent.com/292349/208301790-7eedbfa5-d202-4e70-852e-de68aa47233b.png" title="fig:"/>
<p class="caption">image</p>
</div>
STARTUP SEQUENCE *lazy.nvim-startup-sequence* STARTUP SEQUENCE *lazy.nvim-lazy.nvim-startup-sequence*
**lazy.nvim** does **NOT** use Neovim packages and even disables plugin loading **lazy.nvim** does **NOT** use Neovim packages and even disables plugin loading
completely (`vim.go.loadplugins = false`). It takes over the complete startup completely (`vim.go.loadplugins = false`). It takes over the complete startup
@ -666,15 +723,12 @@ sequence for more flexibility and better performance.
In practice this means that step 10 of |Neovim Initialization| is done by Lazy: In practice this means that step 10 of |Neovim Initialization| is done by Lazy:
1. all the plugins `init()` functions are executed 1. all the plugins `init()` functions are executed2. all plugins with `lazy=false` are loaded. This includes sourcing `/plugin` and `/ftdetect` files. (`/after` will not be sourced yet)3. all files from `/plugin` and `/ftdetect` directories in you rtp are sourced (excluding `/after`)4. all `/after/plugin` files are sourced (this includes `/after` from plugins)
2. all plugins with `lazy=false` are loaded. This includes sourcing `/plugin` and `/ftdetect` files. (`/after` will not be sourced yet)
3. all files from `/plugin` and `/ftdetect` directories in you rtp are sourced (excluding `/after`)
4. all `/after/plugin` files are sourced (this inludes `/after` from plugins)
Files from runtime directories are always sourced in alphabetical order. Files from runtime directories are always sourced in alphabetical order.
STRUCTURING YOUR PLUGINS *lazy.nvim-structuring-your-plugins*
STRUCTURING YOUR PLUGINS *lazy.nvim-lazy.nvim-structuring-your-plugins*
Some users may want to split their plugin specs in multiple files. Instead of Some users may want to split their plugin specs in multiple files. Instead of
passing a spec table to `setup()`, you can use a Lua module. The specs from the passing a spec table to `setup()`, you can use a Lua module. The specs from the
@ -689,21 +743,17 @@ The benefits of using this approach:
- allows for **caching** of all your plugin specs. This becomes important if you have a lot of smaller plugin specs. - allows for **caching** of all your plugin specs. This becomes important if you have a lot of smaller plugin specs.
- spec changes will automatically be **reloaded** when theyre updated, so the `:Lazy` UI is always up to date - spec changes will automatically be **reloaded** when theyre updated, so the `:Lazy` UI is always up to date
Example: Example:
- `~/.config/nvim/init.lua` - `~/.config/nvim/init.lua`
>lua >lua
require("lazy").setup("plugins") require("lazy").setup("plugins")
< <
- `~/.config/nvim/lua/plugins.lua` or `~/.config/nvim/lua/plugins/init.lua` **(this file is optional)**
- `~/.config/nvim/lua/plugins.lua` or `~/.config/nvim/lua/plugins/init.lua` **_(this file is optional)_**
>lua >lua
return { return {
@ -714,10 +764,8 @@ Example:
< <
- any lua file in `~/.config/nvim/lua/plugins/.lua` will be automatically merged in the main plugin spec - any lua file in `~/.config/nvim/lua/plugins/.lua` will be automatically merged in the main plugin spec
For a real-life example, you can check LazyVim For a real-life example, you can check LazyVim
<https://github.com/LazyVim/LazyVim> and more specifically: <https://github.com/LazyVim/LazyVim> and more specifically:
@ -725,7 +773,7 @@ For a real-life example, you can check LazyVim
- lazyvim.plugins <https://github.com/LazyVim/LazyVim/tree/main/lua/lazyvim/plugins> contains all the plugin specs that will be loaded - lazyvim.plugins <https://github.com/LazyVim/LazyVim/tree/main/lua/lazyvim/plugins> contains all the plugin specs that will be loaded
IMPORTING SPECS, `CONFIG` & `OPTS` ~ IMPORTING SPECS, CONFIG & OPTS ~
As part of a spec, you can add `import` statements to import additional plugin As part of a spec, you can add `import` statements to import additional plugin
modules. Both of the `setup()` calls are equivalent: modules. Both of the `setup()` calls are equivalent:
@ -737,7 +785,6 @@ modules. Both of the `setup()` calls are equivalent:
require("lazy").setup({{import = "plugins"}}) require("lazy").setup({{import = "plugins"}})
< <
When you import specs, you can override them by simply adding a spec for the When you import specs, you can override them by simply adding a spec for the
same plugin to your local specs, adding any keys you want to override / merge. same plugin to your local specs, adding any keys you want to override / merge.
@ -745,9 +792,11 @@ same plugin to your local specs, adding any keys you want to override / merge.
the parent spec. Any other property will override the property from the parent the parent spec. Any other property will override the property from the parent
spec. spec.
MIGRATION GUIDE *lazy.nvim-migration-guide*
PACKER.NVIM <HTTPS://GITHUB.COM/WBTHOMASON/PACKER.NVIM> ~ MIGRATION GUIDE *lazy.nvim-lazy.nvim-migration-guide*
PACKER.NVIM ~
- `setup` `init` - `setup` `init`
@ -758,21 +807,19 @@ PACKER.NVIM <HTTPS://GITHUB.COM/WBTHOMASON/PACKER.NVIM> ~
- `lock` `pin` - `lock` `pin`
- `disable=true` `enabled = false` - `disable=true` `enabled = false`
- `tag=''` `version=""` - `tag=''` `version=""`
- `after` **_not needed_** for most use-cases. Use `dependencies` otherwise. - `after` **not needed** for most use-cases. Use `dependencies` otherwise.
- `wants` **_not needed_** for most use-cases. Use `dependencies` otherwise. - `wants` **not needed** for most use-cases. Use `dependencies` otherwise.
- `config` dont support string type, use `fun(LazyPlugin)` instead. - `config` dont support string type, use `fun(LazyPlugin)` instead.
- `module` is auto-loaded. No need to specify - `module` is auto-loaded. No need to specify
- `keys` spec is |lazy.nvim-different| - `keys` spec is |lazy.nvim-different|
- `rtp` can be accomplished with: - `rtp` can be accomplished with:
>lua >lua
config = function(plugin) config = function(plugin)
vim.opt.rtp:append(plugin.dir .. "/custom-rtp") vim.opt.rtp:append(plugin.dir .. "/custom-rtp")
end end
< <
With packer `wants`, `requires` and `after` can be used to manage dependencies. With packer `wants`, `requires` and `after` can be used to manage dependencies.
With lazy, this isnt needed for most of the lua dependencies. They can be With lazy, this isnt needed for most of the lua dependencies. They can be
installed just like normal plugins (even with `lazy=true`) and will be loaded installed just like normal plugins (even with `lazy=true`) and will be loaded
@ -781,7 +828,8 @@ required plugins with the one that requires them. The plugins which are added
as `dependencies` will always be lazy-loaded and loaded when the plugin is as `dependencies` will always be lazy-loaded and loaded when the plugin is
loaded. loaded.
PAQ-NVIM <HTTPS://GITHUB.COM/SAVQ/PAQ-NVIM> ~
PAQ-NVIM ~
- `as` `name` - `as` `name`
@ -789,58 +837,87 @@ PAQ-NVIM <HTTPS://GITHUB.COM/SAVQ/PAQ-NVIM> ~
- `run` `build` - `run` `build`
UNINSTALLING *lazy.nvim-uninstalling* UNINSTALLING *lazy.nvim-lazy.nvim-uninstalling*
To uninstall **lazy.nvim**, you need to remove the following files and To uninstall **lazy.nvim**, you need to remove the following files and
directories: directories:
- **data**: `~/.local/share/nvim/lazy` - **data**`~/.local/share/nvim/lazy`
- **state**: `~/.local/state/nvim/lazy` - **state**`~/.local/state/nvim/lazy`
- **lockfile**: `~/.config/nvim/lazy-lock.json` - **lockfile**`~/.config/nvim/lazy-lock.json`
paths can differ if you changed `XDG` environment variables. paths can differ if you changed `XDG` environment variables.
HIGHLIGHT GROUPS *lazy.nvim-lazy.nvim-highlight-groups*
HIGHLIGHT GROUPS *lazy.nvim-highlight-groups* Click to see all highlight groups ~
Click to see all highlight groups ---------------------------------------------------------------------------------
Highlight Group Default Group Description
------------------- ------------------------ ------------------------------------
LazyButton CursorLine
│ Highlight Group │ Default Group │ Description │ LazyButtonActive Visual
│**LazyButton** │**_CursorLine_** │ │
│**LazyButtonActive** │**_Visual_** │ │
│**LazyComment** │**_Comment_** │ │
│**LazyCommit** │_variable.builtin │commitref │
│**LazyCommitIssue** │**_Number_** │ │
│**LazyCommitScope** │**_Italic_** │conventional commit scope │
│**LazyCommitType** │**_Title_** │conventional commit type │
│**LazyDir** │_text.reference │directory │
│**LazyH1** │**_IncSearch_** │homebutton │
│**LazyH2** │**_Bold_** │titles │
│**LazyNoCond** │**_DiagnosticWarn_**│unloaded icon for a plugin where cond() was false │
│**LazyNormal** │**_NormalFloat_** │ │
│**LazyProgressDone** │**_Constant_** │progress bar done │
│**LazyProgressTodo** │**_LineNr_** │progress bar todo │
│**LazyProp** │**_Conceal_** │property │
│**LazyReasonCmd** │**_Operator_** │ │
│**LazyReasonEvent** │**_Constant_** │ │
│**LazyReasonFt** │**_Character_** │ │
│**LazyReasonImport** │**_Identifier_** │ │
│**LazyReasonKeys** │**_Statement_** │ │
│**LazyReasonPlugin** │**_Special_** │ │
│**LazyReasonRuntime**│_macro │ │
│**LazyReasonSource** │**_Character_** │ │
│**LazyReasonStart** │_field │ │
│**LazySpecial** │_punctuation.special│ │
│**LazyTaskError** │**_ErrorMsg_** │taskerrors │
│**LazyTaskOutput** │**_MsgArea_** │task output │
│**LazyUrl** │_text.reference │url │
│**LazyValue** │_string │valueof a property │
LazyComment Comment
OTHER NEOVIM PLUGIN MANAGERS IN LUA*lazy.nvim-other-neovim-plugin-managers-in-lua* LazyCommit _@variable.builtin_ commitref
LazyCommitIssue Number
LazyCommitScope Italic conventional commit scope
LazyCommitType Title conventional commit type
LazyDir _@text.reference_ directory
LazyH1 IncSearch homebutton
LazyH2 Bold titles
LazyNoCond DiagnosticWarn unloaded icon for a plugin where
cond() was false
LazyNormal NormalFloat
LazyProgressDone Constant progress bar done
LazyProgressTodo LineNr progress bar todo
LazyProp Conceal property
LazyReasonCmd Operator
LazyReasonEvent Constant
LazyReasonFt Character
LazyReasonImport Identifier
LazyReasonKeys Statement
LazyReasonPlugin Special
LazyReasonRuntime _@macro_
LazyReasonSource Character
LazyReasonStart _@field_
LazySpecial _@punctuation.special_
LazyTaskError ErrorMsg taskerrors
LazyTaskOutput MsgArea task output
LazyUrl _@text.reference_ url
LazyValue _@string_ valueof a property
---------------------------------------------------------------------------------
OTHER NEOVIM PLUGIN MANAGERS IN LUA*lazy.nvim-lazy.nvim-other-neovim-plugin-managers-in-lua*
- packer.nvim <https://github.com/wbthomason/packer.nvim> - packer.nvim <https://github.com/wbthomason/packer.nvim>
@ -850,6 +927,12 @@ OTHER NEOVIM PLUGIN MANAGERS IN LUA*lazy.nvim-other-neovim-plugin-managers-in-lu
- optpack.nvim <https://github.com/notomo/optpack.nvim> - optpack.nvim <https://github.com/notomo/optpack.nvim>
- pact.nvim <https://github.com/rktjmp/pact.nvim> - pact.nvim <https://github.com/rktjmp/pact.nvim>
==============================================================================
2. Links *lazy.nvim-links*
1. *image*: https://user-images.githubusercontent.com/292349/208301737-68fb279c-ba70-43ef-a369-8c3e8367d6b1.png
2. *image*: https://user-images.githubusercontent.com/292349/208301766-5c400561-83c3-4811-9667-1ec4bb3c43b8.png
3. *image*: https://user-images.githubusercontent.com/292349/208301790-7eedbfa5-d202-4e70-852e-de68aa47233b.png
Generated by panvimdoc <https://github.com/kdheepak/panvimdoc> Generated by panvimdoc <https://github.com/kdheepak/panvimdoc>

View file

@ -1,524 +1,420 @@
local ffi = require("ffi") local ffi = require("ffi")
---@diagnostic disable-next-line: no-unknown
local uv = vim.loop local uv = vim.loop
local M = {} local M = {}
M.dirty = false
M.VERSION = "1" .. jit.version
---@class LazyCacheConfig
M.config = {
enabled = true,
path = vim.fn.stdpath("cache") .. "/lazy/cache",
-- Once one of the following events triggers, caching will be disabled.
-- To cache all modules, set this to `{}`, but that is not recommended.
-- The default is to disable on:
-- * VimEnter: not useful to cache anything else beyond startup
-- * BufReadPre: this will be triggered early when opening a file from the command line directly
disable_events = { "UIEnter", "BufReadPre" },
ttl = 3600 * 24 * 5, -- keep unused modules for up to 5 days
}
M.debug = false
---@type CacheHash
local cache_hash
---@alias CacheHash {mtime: {sec:number, nsec:number}, size:number} ---@alias CacheHash {mtime: {sec:number, nsec:number}, size:number}
---@alias CacheEntry {hash:CacheHash, modpath:string, chunk:string, used:number} ---@alias CacheEntry {hash:CacheHash, chunk:string}
---@type table<string,CacheEntry?>
M.cache = {} ---@class CacheFindOpts
M.enabled = true ---@field rtp? boolean Search for modname in the runtime path (defaults to `true`)
---@type string[] ---@field patterns? string[] Paterns to use (defaults to `{"/init.lua", ".lua"}`)
M.rtp = nil ---@field paths? string[] Extra paths to search for modname
M.rtp_total = 0
M.VERSION = 2
M.path = vim.fn.stdpath("cache") .. "/lazy/luac"
M.enabled = false
M.stats = { M.stats = {
find = { total = 0, time = 0, rtp = 0, unloaded = 0, index = 0, stat = 0, not_found = 0 }, find = { total = 0, time = 0, not_found = 0 },
autoload = { total = 0, time = 0 },
} }
M.me = debug.getinfo(1, "S").source:sub(2)
M.me = vim.fn.fnamemodify(M.me, ":p:h:h:h:h"):gsub("\\", "/")
---@type table<string, string[]>
M.topmods = { lazy = { M.me } }
---@type table<string, string[]>
M.indexed = { [M.me] = { "lazy" } }
M.indexed_unloaded = false
M.indexed_rtp = 0
-- selene:allow(global_usage)
M._loadfile = _G.loadfile
-- checks whether the cached modpath is still valid ---@class ModuleCache
function M.check_path(modname, modpath) ---@field _rtp string[]
-- HACK: never return packer paths ---@field _rtp_pure string[]
if modpath:find("/site/pack/packer/", 1, true) then ---@field _rtp_key string
return false local Cache = {
end ---@type table<string, table<string,true>>
_indexed = {},
---@type table<string, string[]>
_topmods = {},
_loadfile = loadfile,
}
-- check rtp excluding plugins. This is a very small list, so should be fast function M.track(stat, start)
for _, path in ipairs(M.get_rtp()) do M.stats[stat] = M.stats[stat] or { total = 0, time = 0 }
if modpath:find(path .. "/", 1, true) == 1 then M.stats[stat].total = M.stats[stat].total + 1
return true M.stats[stat].time = M.stats[stat].time + uv.hrtime() - start
end
end
-- the correct lazy path should be part of rtp.
-- so if we get here, this is folke using the local dev instance ;)
if modname and (modname == "lazy" or modname:sub(1, 5) == "lazy.") then
return false
end
return modname and M.check_autoload(modname, modpath)
end end
function M.check_autoload(modname, modpath) -- slightly faster/different version than vim.fs.normalize
local start = uv.hrtime() -- we also need to have it here, since the cache will load vim.fs
M.stats.autoload.total = M.stats.autoload.total + 1 ---@private
function Cache.normalize(path)
if path:sub(1, 1) == "~" then
local home = vim.loop.os_homedir() or "~"
if home:sub(-1) == "\\" or home:sub(-1) == "/" then
home = home:sub(1, -2)
end
path = home .. path:sub(2)
end
path = path:gsub("\\", "/"):gsub("/+", "/")
return path:sub(-1) == "/" and path:sub(1, -2) or path
end
-- check plugins. Again fast, since we check the plugin name from the path. ---@private
-- only needed when the plugin mod has been loaded function Cache.get_rtp()
---@type LazyCorePlugin local start = uv.hrtime()
local Plugin = package.loaded["lazy.core.plugin"] if vim.in_fast_event() then
if Plugin then M.track("get_rtp", start)
local plugin = Plugin.find(modpath) return (Cache._rtp or {}), false
if plugin and modpath:find(plugin.dir, 1, true) == 1 then end
-- we're not interested in loader time, so calculate delta here local updated = false
M.stats.autoload.time = M.stats.autoload.time + uv.hrtime() - start local key = vim.go.rtp
-- don't load if we're loading specs or if the plugin is already loaded if key ~= Cache._rtp_key then
if not (Plugin.loading or plugin._.loaded) then Cache._rtp = {}
if plugin.module == false then for _, path in ipairs(vim.api.nvim_get_runtime_file("", true)) do
error("Plugin " .. plugin.name .. " is not loaded and is configured with module=false") path = Cache.normalize(path)
end -- skip after directories
require("lazy.core.loader").load(plugin, { require = modname }) if path:sub(-6, -1) ~= "/after" and not (Cache._indexed[path] and vim.tbl_isempty(Cache._indexed[path])) then
Cache._rtp[#Cache._rtp + 1] = path
end end
return true end
updated = true
Cache._rtp_key = key
end
M.track("get_rtp", start)
return Cache._rtp, updated
end
---@param name string can be a module name, or a file name
---@private
function Cache.cache_file(name)
local ret = M.path .. "/" .. name:gsub("[/\\:]", "%%")
return ret:sub(-4) == ".lua" and (ret .. "c") or (ret .. ".luac")
end
---@param entry CacheEntry
---@private
function Cache.write(name, entry)
local cname = Cache.cache_file(name)
local f = assert(uv.fs_open(cname, "w", 438))
local header = {
M.VERSION,
entry.hash.size,
entry.hash.mtime.sec,
entry.hash.mtime.nsec,
}
uv.fs_write(f, ffi.string(ffi.new("const uint32_t[4]", header), 16))
uv.fs_write(f, entry.chunk)
uv.fs_close(f)
end
---@return CacheEntry?
---@private
function Cache.read(name)
local start = uv.hrtime()
local cname = Cache.cache_file(name)
local f = uv.fs_open(cname, "r", 438)
if f then
local hash = uv.fs_fstat(f) --[[@as CacheHash]]
local data = uv.fs_read(f, hash.size, 0) --[[@as string]]
uv.fs_close(f)
---@type integer[]|{[0]:integer}
local header = ffi.cast("uint32_t*", ffi.new("const char[16]", data:sub(1, 16)))
if header[0] ~= M.VERSION then
return
end
M.track("read", start)
return {
hash = { size = header[1], mtime = { sec = header[2], nsec = header[3] } },
chunk = data:sub(16 + 1),
}
end
M.track("read", start)
end
---@param modname string
---@private
function Cache.loader(modname)
local start = uv.hrtime()
local modpath, hash = Cache.find(modname)
if modpath then
local chunk, err = M.load(modpath, { hash = hash })
M.track("loader", start)
return chunk or error(err)
end
M.track("loader", start)
return "\nlazy_loader: module " .. modname .. " not found"
end
---@param modname string
---@private
function Cache.loader_lib(modname)
local start = uv.hrtime()
local modpath = Cache.find(modname, { patterns = jit.os:find("Windows") and { ".dll" } or { ".so" } })
---@type function?, string?
if modpath then
-- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is
-- a) strip prefix up to and including the first dash, if any
-- b) replace all dots by underscores
-- c) prepend "luaopen_"
-- So "foo-bar.baz" should result in "luaopen_bar_baz"
local dash = modname:find("-", 1, true)
local funcname = dash and modname:sub(dash + 1) or modname
local chunk, err = package.loadlib(modpath, "luaopen_" .. funcname:gsub("%.", "_"))
M.track("loader_lib", start)
return chunk or error(err)
end
M.track("loader_lib", start)
return "\nlazy_loader_lib: module " .. modname .. " not found"
end
---@param filename? string
---@param mode? "b"|"t"|"bt"
---@param env? table
---@return function?, string? error_message
---@private
function Cache.loadfile(filename, mode, env)
local start = uv.hrtime()
filename = Cache.normalize(filename)
local chunk, err = M.load(filename, { mode = mode, env = env })
M.track("loadfile", start)
return chunk, err
end
---@param h1 CacheHash
---@param h2 CacheHash
---@private
function Cache.eq(h1, h2)
return h1 and h2 and h1.size == h2.size and h1.mtime.sec == h2.mtime.sec and h1.mtime.nsec == h2.mtime.nsec
end
---@param modpath string
---@param opts? {hash?: CacheHash, mode?: "b"|"t"|"bt", env?:table}
---@return function?, string? error_message
---@private
function M.load(modpath, opts)
local start = uv.hrtime()
opts = opts or {}
local hash = opts.hash or uv.fs_stat(modpath)
---@type function?, string?
local chunk, err
if not hash then
-- trigger correct error
chunk, err = Cache._loadfile(modpath, opts.mode, opts.env)
M.track("load", start)
return chunk, err
end
local entry = Cache.read(modpath)
if entry and Cache.eq(entry.hash, hash) then
-- found in cache and up to date
-- selene: allow(incorrect_standard_library_use)
chunk, err = load(entry.chunk --[[@as string]], "@" .. modpath, opts.mode, opts.env)
if not (err and err:find("cannot load incompatible bytecode", 1, true)) then
M.track("load", start)
return chunk, err
end
end
entry = { hash = hash, modpath = modpath }
chunk, err = Cache._loadfile(modpath, opts.mode, opts.env)
if chunk then
entry.chunk = string.dump(chunk)
Cache.write(modpath, entry)
end
M.track("load", start)
return chunk, err
end
---@param modname string
---@param opts? CacheFindOpts
---@return string? modpath, CacheHash? hash, CacheEntry? entry
function Cache.find(modname, opts)
local start = uv.hrtime()
opts = opts or {}
modname = modname:gsub("/", ".")
local basename = modname:gsub("%.", "/")
local idx = modname:find(".", 1, true)
-- HACK: some plugins try to load invalid relative paths (see #543)
if idx == 1 then
modname = modname:gsub("^%.+", "")
basename = modname:gsub("%.", "/")
idx = modname:find(".", 1, true)
end
local topmod = idx and modname:sub(1, idx - 1) or modname
-- OPTIM: search for a directory first when topmod == modname
local patterns = opts.patterns or (topmod == modname and { "/init.lua", ".lua" } or { ".lua", "/init.lua" })
for p, pattern in ipairs(patterns) do
patterns[p] = "/lua/" .. basename .. pattern
end
---@param paths string[]
local function _find(paths)
for _, path in ipairs(paths) do
if M.lsmod(path)[topmod] then
for _, pattern in ipairs(patterns) do
local modpath = path .. pattern
M.stats.find.stat = (M.stats.find.stat or 0) + 1
local hash = uv.fs_stat(modpath)
if hash then
return modpath, hash
end
end
end
end
end
---@type string, CacheHash
local modpath, hash
if opts.rtp ~= false then
modpath, hash = _find(Cache._rtp or {})
if not modpath then
local rtp, updated = Cache.get_rtp()
if updated then
modpath, hash = _find(rtp)
end
end
end
if (not modpath) and opts.paths then
modpath, hash = _find(opts.paths)
end
M.track("find", start)
if modpath then
return modpath, hash
end
-- module not found
M.stats.find.not_found = M.stats.find.not_found + 1
end
--- Resets the topmods cache for the path
---@param path string
function M.reset(path)
Cache._indexed[Cache.normalize(path)] = nil
end
function M.enable()
if M.enabled then
return
end
M.enabled = true
vim.fn.mkdir(vim.fn.fnamemodify(M.path, ":p"), "p")
-- selene: allow(global_usage)
_G.loadfile = Cache.loadfile
-- add lua loader
table.insert(package.loaders, 2, Cache.loader)
-- add libs loader
table.insert(package.loaders, 3, Cache.loader_lib)
-- remove Neovim loader
for l, loader in ipairs(package.loaders) do
if loader == vim._load_package then
table.remove(package.loaders, l)
break
end end
end end
M.stats.autoload.time = M.stats.autoload.time + uv.hrtime() - start
return false
end end
function M.disable() function M.disable()
if not M.enabled then if not M.enabled then
return return
end end
-- selene:allow(global_usage)
_G.loadfile = M._loadfile
M.enabled = false M.enabled = false
if M.debug and vim.tbl_count(M.topmods) > 1 then -- selene: allow(global_usage)
M.log(M.topmods, { level = vim.log.levels.WARN, title = "topmods" }) _G.loadfile = Cache._loadfile
end
if M.debug and false then
local stats = vim.deepcopy(M.stats)
stats.time = (stats.time or 0) / 1e6
stats.find.time = (stats.find.time or 0) / 1e6
stats.autoload.time = (stats.autoload.time or 0) / 1e6
M.log(stats, { title = "stats" })
end
end
---@param msg string|table
---@param opts? LazyNotifyOpts
function M.log(msg, opts)
if M.debug then
msg = vim.deepcopy(msg)
vim.schedule(function()
require("lazy.core.util").debug(msg, opts)
end)
end
end
function M.check_loaded(modname)
---@diagnostic disable-next-line: no-unknown ---@diagnostic disable-next-line: no-unknown
local mod = package.loaded[modname] for l, loader in ipairs(package.loaders) do
if type(mod) == "table" then if loader == Cache.loader or loader == Cache.loader_lib then
return function() table.remove(package.loaders, l)
return mod
end end
end end
table.insert(package.loaders, 2, vim._load_package)
end end
---@param modname string -- Return the top-level `/lua/*` modules for this path
---@return fun()|string ---@return string[]
function M.loader(modname) function M.lsmod(path)
modname = modname:gsub("/", ".") if not Cache._indexed[path] then
local entry = M.cache[modname] local start = uv.hrtime()
Cache._indexed[path] = {}
local chunk, err local handle = vim.loop.fs_scandir(path .. "/lua")
if entry then while handle do
if M.check_path(modname, entry.modpath) then local name, t = vim.loop.fs_scandir_next(handle)
M.stats.find.total = M.stats.find.total + 1 if not name then
chunk, err = M.load(modname, entry.modpath) break
else
M.cache[modname] = nil
M.dirty = true
end
end
if not chunk then
-- find the modpath and load the module
local modpath = M.find(modname)
if modpath then
M.check_autoload(modname, modpath)
if M.enabled then
chunk, err = M.load(modname, modpath)
else
chunk = M.check_loaded(modname)
if not chunk then
chunk, err = M._loadfile(modpath)
end
end end
end -- HACK: type is not always returned due to a bug in luv
end t = t or uv.fs_stat(path .. "/" .. name).type
return chunk or err or ("module " .. modname .. " not found") ---@type string
end
---@param modpath string
---@return any, string?
function M.loadfile(modpath)
modpath = modpath:gsub("\\", "/")
return M.load(modpath, modpath)
end
---@param modkey string
---@param modpath string
---@return function?, string? error_message
function M.load(modkey, modpath)
local chunk, err
chunk = M.check_loaded(modkey)
if chunk then
return chunk
end
modpath = modpath:gsub("\\", "/")
local hash = M.hash(modpath)
if not hash then
-- trigger correct error
return M._loadfile(modpath)
end
local entry = M.cache[modkey]
if entry then
entry.modpath = modpath
entry.used = os.time()
if M.eq(entry.hash, hash) then
-- found in cache and up to date
chunk, err = loadstring(entry.chunk --[[@as string]], "@" .. entry.modpath)
if not (err and err:find("cannot load incompatible bytecode", 1, true)) then
return chunk, err
end
end
else
entry = { hash = hash, modpath = modpath, used = os.time() }
M.cache[modkey] = entry
end
entry.hash = hash
if M.debug then
M.log("`" .. modpath .. "`", { level = vim.log.levels.WARN, title = "Cache.load" })
end
chunk, err = M._loadfile(entry.modpath)
M.dirty = true
if chunk then
entry.chunk = string.dump(chunk)
else
M.cache[modkey] = nil
end
return chunk, err
end
-- index the top-level lua modules for this path
function M._index(path)
if not M.indexed[path] and path:sub(-6, -1) ~= "/after" then
M.stats.find.index = M.stats.find.index + 1
---@type LazyUtilCore
local Util = package.loaded["lazy.core.util"]
if not Util then
return false
end
M.indexed[path] = {}
Util.ls(path .. "/lua", function(_, name, t)
local topname local topname
if name:sub(-4) == ".lua" then local ext = name:sub(-4)
if ext == ".lua" or ext == ".dll" then
topname = name:sub(1, -5) topname = name:sub(1, -5)
elseif name:sub(-3) == ".so" then
topname = name:sub(1, -4)
elseif t == "link" or t == "directory" then elseif t == "link" or t == "directory" then
topname = name topname = name
end end
if topname then if topname then
M.topmods[topname] = M.topmods[topname] or {} Cache._indexed[path][topname] = true
if not vim.tbl_contains(M.topmods[topname], path) then Cache._topmods[topname] = Cache._topmods[topname] or {}
table.insert(M.topmods[topname], path) if not vim.tbl_contains(Cache._topmods[topname], path) then
end table.insert(Cache._topmods[topname], path)
if not vim.tbl_contains(M.indexed[path], topname) then
table.insert(M.indexed[path], topname)
end
end
end)
return true
end
return false
end
function M.get_topmods(path)
M._index(path)
return M.indexed[path] or {}
end
---@param modname string
---@return string?
function M.find_root(modname)
if M.cache[modname] then
-- check if modname is in cache
local modpath = M.cache[modname].modpath
if M.check_path(modname, modpath) and uv.fs_stat(modpath) then
local root = modpath:gsub("/init%.lua$", ""):gsub("%.lua$", "")
return root
end
else
-- in case modname is just a directory and not a real mod,
-- check for any children in the cache
for child, entry in pairs(M.cache) do
if child:find(modname, 1, true) == 1 then
if M.check_path(child, entry.modpath) and uv.fs_stat(entry.modpath) then
local basename = modname:gsub("%.", "/")
local childbase = child:gsub("%.", "/")
local ret = entry.modpath:gsub("/init%.lua$", ""):gsub("%.lua$", "")
local idx = assert(ret:find(childbase, 1, true))
return ret:sub(1, idx - 1) .. basename
end end
end end
end end
M.track("lsmod", start)
end end
return Cache._indexed[path]
-- not found in cache, so find the root with the special pattern
local modpath = M.find(modname, { patterns = { "" } })
if modpath then
local root = modpath:gsub("/init%.lua$", ""):gsub("%.lua$", "")
return root
end
end end
---@param modname string ---@param modname string
---@param opts? {patterns?:string[]} ---@param opts? CacheFindOpts
---@return string? ---@return string? modpath
function M.find(modname, opts) function M.find(modname, opts)
opts = opts or {} local modpath = Cache.find(modname, opts)
M.stats.find.total = M.stats.find.total + 1
local start = uv.hrtime()
local basename = modname:gsub("%.", "/")
local idx = modname:find(".", 1, true)
local topmod = idx and modname:sub(1, idx - 1) or modname
-- search for a directory first when topmod == modname
local patterns = topmod == modname and { "/init.lua", ".lua" } or { ".lua", "/init.lua" }
if opts.patterns then
vim.list_extend(patterns, opts.patterns)
end
-- check top-level mods to find the module
local function _find()
for _, toppath in ipairs(M.topmods[topmod] or {}) do
for _, pattern in ipairs(patterns) do
local path = toppath .. "/lua/" .. basename .. pattern
M.stats.find.stat = M.stats.find.stat + 1
if uv.fs_stat(path) then
return path
end
end
end
end
local modpath = _find()
if not modpath then
-- update rtp
local rtp = M.list_rtp()
if #rtp ~= M.indexed_rtp then
M.indexed_rtp = #rtp
local updated = false
for _, path in ipairs(rtp) do
updated = M._index(path) or updated
end
if updated then
modpath = _find()
end
end
-- update unloaded
if not modpath and not M.indexed_unloaded then
M.indexed_unloaded = true
local updated = false
---@type LazyCoreConfig
local Config = package.loaded["lazy.core.config"]
if Config and Config.spec then
for _, plugin in pairs(Config.spec.plugins) do
if not (M.indexed[plugin.dir] or plugin._.loaded or plugin.module == false) then
updated = M._index(plugin.dir) or updated
end
end
end
if updated then
modpath = _find()
end
end
-- module not found
if not modpath then
M.stats.find.not_found = M.stats.find.not_found + 1
end
end
M.stats.find.time = M.stats.find.time + uv.hrtime() - start
return modpath return modpath
end end
-- returns the cached RTP excluding plugin dirs function M.profile_loaders()
function M.get_rtp() for l, loader in pairs(package.loaders) do
local rtp = M.list_rtp() local loc = debug.getinfo(loader, "Sn").source:sub(2)
if not M.rtp or #rtp ~= M.rtp_total then package.loaders[l] = function(modname)
M.rtp_total = #rtp local start = vim.loop.hrtime()
M.rtp = {} local ret = loader(modname)
---@type table<string,true> M.track("loader " .. l .. ": " .. loc, start)
local skip = {} M.track("loader_all", start)
-- only skip plugins once Config has been setup return ret
---@type LazyCoreConfig
local Config = package.loaded["lazy.core.config"]
if Config then
for _, plugin in pairs(Config.plugins) do
if plugin.name ~= "lazy.nvim" then
skip[plugin.dir] = true
end
end
end end
for _, path in ipairs(rtp) do end
---@type string end
path = path:gsub("\\", "/")
if not skip[path] and not path:find("after/?$") then function M.inspect()
M.rtp[#M.rtp + 1] = path local function ms(nsec)
return math.floor(nsec / 1e6 * 1000 + 0.5) / 1000 .. "ms"
end
local chunks = {} ---@type string[][]
---@type string[]
local stats = vim.tbl_keys(M.stats)
table.sort(stats)
for _, stat in ipairs(stats) do
vim.list_extend(chunks, {
{ "\n" .. stat .. "\n", "Title" },
{ "* total: " },
{ tostring(M.stats[stat].total) .. "\n", "Number" },
{ "* time: " },
{ ms(M.stats[stat].time) .. "\n", "Bold" },
{ "* avg time: " },
{ ms(M.stats[stat].time / M.stats[stat].total) .. "\n", "Bold" },
})
for k, v in pairs(M.stats[stat]) do
if not vim.tbl_contains({ "time", "total" }, k) then
chunks[#chunks + 1] = { "* " .. k .. ":" .. string.rep(" ", 9 - #k) }
chunks[#chunks + 1] = { tostring(v) .. "\n", "Number" }
end end
end end
end end
return M.rtp vim.api.nvim_echo(chunks, true, {})
end end
function M.list_rtp() M._Cache = Cache
return vim.api.nvim_get_runtime_file("", true)
end
---@param opts? LazyConfig
function M.setup(opts)
-- no fancy deep extend here. just set the options
if opts and opts.performance and opts.performance.cache then
---@diagnostic disable-next-line: no-unknown
for k, v in pairs(opts.performance.cache) do
---@diagnostic disable-next-line: no-unknown
M.config[k] = v
end
end
M.debug = opts and opts.debug
M.enabled = M.config.enabled
if M.enabled then
table.insert(package.loaders, 2, M.loader)
M.load_cache()
-- selene:allow(global_usage)
_G.loadfile = M.loadfile
if #M.config.disable_events > 0 then
vim.api.nvim_create_autocmd(M.config.disable_events, { once = true, callback = M.disable })
end
else
-- we need to always add the loader since this will autoload unloaded modules
table.insert(package.loaders, M.loader)
end
return M
end
---@return CacheHash?
function M.hash(file)
local ok, ret = pcall(uv.fs_stat, file)
return ok and ret or nil
end
---@param h1 CacheHash
---@param h2 CacheHash
function M.eq(h1, h2)
return h1 and h2 and h1.size == h2.size and h1.mtime.sec == h2.mtime.sec and h1.mtime.nsec == h2.mtime.nsec
end
function M.save_cache()
vim.fn.mkdir(vim.fn.fnamemodify(M.config.path, ":p:h"), "p")
local f = assert(uv.fs_open(M.config.path, "w", 438))
uv.fs_write(f, M.VERSION)
uv.fs_write(f, "\0")
for modname, entry in pairs(M.cache) do
if entry.used > os.time() - M.config.ttl then
entry.modname = modname
local header = {
entry.hash.size,
entry.hash.mtime.sec,
entry.hash.mtime.nsec,
#modname,
#entry.chunk,
#entry.modpath,
entry.used,
}
uv.fs_write(f, ffi.string(ffi.new("const uint32_t[7]", header), 28))
uv.fs_write(f, modname)
uv.fs_write(f, entry.chunk)
uv.fs_write(f, entry.modpath)
end
end
uv.fs_close(f)
end
function M.load_cache()
M.cache = {}
local f = uv.fs_open(M.config.path, "r", 438)
if f then
cache_hash = uv.fs_fstat(f) --[[@as CacheHash]]
local data = uv.fs_read(f, cache_hash.size, 0) --[[@as string]]
uv.fs_close(f)
local zero = data:find("\0", 1, true)
if not zero then
return
end
if M.VERSION ~= data:sub(1, zero - 1) then
return
end
local offset = zero + 1
while offset + 1 < #data do
local header = ffi.cast("uint32_t*", ffi.new("const char[28]", data:sub(offset, offset + 27)))
offset = offset + 28
local modname = data:sub(offset, offset + header[3] - 1)
offset = offset + header[3]
local chunk = data:sub(offset, offset + header[4] - 1)
offset = offset + header[4]
local file = data:sub(offset, offset + header[5] - 1)
offset = offset + header[5]
M.cache[modname] = {
hash = { size = header[0], mtime = { sec = header[1], nsec = header[2] } },
chunk = chunk,
modpath = file,
used = header[6],
}
end
end
end
function M.autosave()
vim.api.nvim_create_autocmd("VimLeavePre", {
callback = function()
if M.dirty then
local hash = M.hash(M.config.path)
-- abort when the file was changed in the meantime
if hash == nil or M.eq(cache_hash, hash) then
M.save_cache()
end
end
end,
})
end
return M return M

View file

@ -21,12 +21,17 @@ M.defaults = {
log = { "--since=3 days ago" }, -- show commits from the last 3 days log = { "--since=3 days ago" }, -- show commits from the last 3 days
timeout = 120, -- kill processes that take more than 2 minutes timeout = 120, -- kill processes that take more than 2 minutes
url_format = "https://github.com/%s.git", url_format = "https://github.com/%s.git",
-- lazy.nvim requires git >=2.19.0. If you really want to use lazy with an older version,
-- then set the below to false. This is should work, but is NOT supported and will
-- increase downloads a lot.
filter = true,
}, },
dev = { dev = {
-- directory where you store your local plugin projects -- directory where you store your local plugin projects
path = "~/projects", path = "~/projects",
---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub ---@type string[] plugins that match these patterns will use your local versions instead of being fetched from GitHub
patterns = {}, -- For example {"folke"} patterns = {}, -- For example {"folke"}
fallback = false, -- Fallback to git when local plugin doesn't exist
}, },
install = { install = {
-- install missing plugins on startup. This doesn't increase startup time. -- install missing plugins on startup. This doesn't increase startup time.
@ -48,7 +53,7 @@ M.defaults = {
init = "", init = "",
import = "", import = "",
keys = "", keys = "",
lazy = " ", lazy = "󰒲 ",
loaded = "", loaded = "",
not_loaded = "", not_loaded = "",
plugin = "", plugin = "",
@ -108,13 +113,14 @@ M.defaults = {
notify = true, -- get a notification when changes are found notify = true, -- get a notification when changes are found
}, },
performance = { performance = {
---@type LazyCacheConfig cache = {
cache = nil, enabled = true,
},
reset_packpath = true, -- reset the package path to improve startup time reset_packpath = true, -- reset the package path to improve startup time
rtp = { rtp = {
reset = true, -- reset the runtime path to $VIMRUNTIME and your config directory reset = true, -- reset the runtime path to $VIMRUNTIME and your config directory
---@type string[] ---@type string[]
paths = {}, -- add any custom paths here that you want to indluce in the rtp paths = {}, -- add any custom paths here that you want to includes in the rtp
---@type string[] list any plugins you want to disable here ---@type string[] list any plugins you want to disable here
disabled_plugins = { disabled_plugins = {
-- "gzip", -- "gzip",
@ -141,7 +147,7 @@ M.defaults = {
debug = false, debug = false,
} }
M.version = "9.3.1" -- x-release-please-version M.version = "9.8.5" -- x-release-please-version
M.ns = vim.api.nvim_create_namespace("lazy") M.ns = vim.api.nvim_create_namespace("lazy")
@ -221,7 +227,6 @@ function M.setup(opts)
pattern = "VeryLazy", pattern = "VeryLazy",
once = true, once = true,
callback = function() callback = function()
require("lazy.core.cache").autosave()
require("lazy.view.commands").setup() require("lazy.view.commands").setup()
if M.options.change_detection.enabled then if M.options.change_detection.enabled then
require("lazy.manage.reloader").enable() require("lazy.manage.reloader").enable()

View file

@ -14,16 +14,22 @@ end
---@param cmd string ---@param cmd string
function M:_add(cmd) function M:_add(cmd)
vim.api.nvim_create_user_command(cmd, function(event) vim.api.nvim_create_user_command(cmd, function(event)
local command = {
cmd = cmd,
bang = event.bang or nil,
mods = event.smods,
args = event.fargs,
count = event.count >= 0 and event.range == 0 and event.count or nil,
}
if event.range == 1 then
command.range = { event.line1 }
elseif event.range == 2 then
command.range = { event.line1, event.line2 }
end
self:_load(cmd) self:_load(cmd)
vim.cmd( vim.cmd(command)
("%s %s%s%s %s"):format(
event.mods or "",
event.line1 == event.line2 and "" or event.line1 .. "," .. event.line2,
cmd,
event.bang and "!" or "",
event.args or ""
)
)
end, { end, {
bang = true, bang = true,
range = true, range = true,

View file

@ -3,7 +3,7 @@ local Loader = require("lazy.core.loader")
---@class LazyKeys ---@class LazyKeys
---@field [1] string lhs ---@field [1] string lhs
---@field [2]? string|fun() rhs ---@field [2]? string|fun()|false rhs
---@field desc? string ---@field desc? string
---@field mode? string|string[] ---@field mode? string|string[]
---@field noremap? boolean ---@field noremap? boolean
@ -14,42 +14,6 @@ local Loader = require("lazy.core.loader")
---@class LazyKeysHandler:LazyHandler ---@class LazyKeysHandler:LazyHandler
local M = {} local M = {}
---@param feed string
function M.replace_special(feed)
for special, key in pairs({ leader = vim.g.mapleader or "\\", localleader = vim.g.maplocalleader or "\\" }) do
local pattern = "<"
for i = 1, #special do
pattern = pattern .. "[" .. special:sub(i, i) .. special:upper():sub(i, i) .. "]"
end
pattern = pattern .. ">"
feed = feed:gsub(pattern, key)
end
return feed
end
function M.retrigger(keys)
local pending = ""
while true do
---@type number|string
local c = vim.fn.getchar(0)
if c == 0 then
break
end
c = type(c) == "number" and vim.fn.nr2char(c) or c
pending = pending .. c
end
local op = vim.v.operator
if op and op ~= "" and vim.api.nvim_get_mode().mode:find("o") then
keys = "<esc>" .. op .. keys
end
local feed = keys .. pending
feed = M.replace_special(feed)
if vim.v.count ~= 0 then
feed = vim.v.count .. feed
end
vim.api.nvim_input(feed)
end
---@param value string|LazyKeys ---@param value string|LazyKeys
function M.parse(value) function M.parse(value)
local ret = vim.deepcopy(value) local ret = vim.deepcopy(value)
@ -108,9 +72,16 @@ function M:_add(keys)
Util.track({ keys = lhs }) Util.track({ keys = lhs })
Loader.load(plugins, { keys = lhs }) Loader.load(plugins, { keys = lhs })
M.retrigger(lhs)
Util.track() Util.track()
end, opts)
local feed = vim.api.nvim_replace_termcodes("<Ignore>" .. lhs, true, true, true)
-- insert instead of append the lhs
vim.api.nvim_feedkeys(feed, "i", false)
end, {
desc = opts.desc,
-- we do not return anything, but this is still needed to make operator pending mappings work
expr = true,
})
end end
---@param keys LazyKeys ---@param keys LazyKeys

View file

@ -4,6 +4,7 @@ local Handler = require("lazy.core.handler")
local Cache = require("lazy.core.cache") local Cache = require("lazy.core.cache")
local Plugin = require("lazy.core.plugin") local Plugin = require("lazy.core.plugin")
---@class LazyCoreLoader
local M = {} local M = {}
local DEFAULT_PRIORITY = 50 local DEFAULT_PRIORITY = 50
@ -63,7 +64,8 @@ function M.install_missing()
for _, plugin in pairs(Config.plugins) do for _, plugin in pairs(Config.plugins) do
if not (plugin._.installed or Plugin.has_errors(plugin)) then if not (plugin._.installed or Plugin.has_errors(plugin)) then
for _, colorscheme in ipairs(Config.options.install.colorscheme) do for _, colorscheme in ipairs(Config.options.install.colorscheme) do
if pcall(vim.cmd.colorscheme, colorscheme) then M.colorscheme(colorscheme)
if vim.g.colors_name or pcall(vim.cmd.colorscheme, colorscheme) then
break break
end end
end end
@ -71,7 +73,7 @@ function M.install_missing()
-- remove and installed plugins from indexed, so cache will index again -- remove and installed plugins from indexed, so cache will index again
for _, p in pairs(Config.plugins) do for _, p in pairs(Config.plugins) do
if p._.installed then if p._.installed then
Cache.indexed[p.dir] = nil Cache.reset(p.dir)
end end
end end
-- reload plugins -- reload plugins
@ -180,6 +182,82 @@ function M.load(plugins, reason, opts)
end end
end end
---@param plugin LazyPlugin
function M.deactivate(plugin)
if not plugin._.loaded then
return
end
local main = M.get_main(plugin)
if main then
Util.try(function()
local mod = require(main)
if mod.deactivate then
mod.deactivate(plugin)
end
end, "Failed to deactivate plugin " .. plugin.name)
end
-- execute deactivate when needed
if plugin.deactivate then
Util.try(function()
plugin.deactivate(plugin)
end, "Failed to deactivate plugin " .. plugin.name)
end
-- disable handlers
Handler.disable(plugin)
-- remove loaded lua modules
Util.walkmods(plugin.dir .. "/lua", function(modname)
package.loaded[modname] = nil
package.preload[modname] = nil
end)
-- clear vim.g.loaded_ for plugins
Util.ls(plugin.dir .. "/plugin", function(_, name, type)
if type == "file" then
vim.g["loaded_" .. name:gsub("%..*", "")] = nil
end
end)
-- set as not loaded
plugin._.loaded = nil
end
--- reload a plugin
---@param plugin LazyPlugin
function M.reload(plugin)
M.deactivate(plugin)
local load = false -- plugin._.loaded ~= nil
-- enable handlers
Handler.enable(plugin)
-- run init
if plugin.init then
Util.try(function()
plugin.init(plugin)
end, "Failed to run `init` for **" .. plugin.name .. "**")
end
-- if this is a start plugin, load it now
if plugin.lazy == false then
load = true
end
for _, event in ipairs(plugin.event or {}) do
if event == "VimEnter" or event == "UIEnter" or event:find("VeryLazy") then
load = true
break
end
end
if load then
M.load(plugin, { start = "reload" })
end
end
---@param plugin LazyPlugin ---@param plugin LazyPlugin
---@param reason {[string]:string} ---@param reason {[string]:string}
---@param opts? {force:boolean} when force is true, we skip the cond check ---@param opts? {force:boolean} when force is true, we skip the cond check
@ -241,22 +319,11 @@ function M.config(plugin)
plugin.config(plugin, opts) plugin.config(plugin, opts)
end end
else else
local normname = Util.normname(plugin.name) local main = M.get_main(plugin)
---@type string[] if main then
local mods = {}
for _, modname in ipairs(Cache.get_topmods(plugin.dir)) do
mods[#mods + 1] = modname
local modnorm = Util.normname(modname)
-- if we found an exact match, then use that
if modnorm == normname then
mods = { modname }
break
end
end
if #mods == 1 then
fn = function() fn = function()
local opts = Plugin.values(plugin, "opts", false) local opts = Plugin.values(plugin, "opts", false)
require(mods[1]).setup(opts) require(main).setup(opts)
end end
else else
return Util.error( return Util.error(
@ -267,6 +334,26 @@ function M.config(plugin)
Util.try(fn, "Failed to run `config` for " .. plugin.name) Util.try(fn, "Failed to run `config` for " .. plugin.name)
end end
---@param plugin LazyPlugin
function M.get_main(plugin)
if plugin.main then
return plugin.main
end
local normname = Util.normname(plugin.name)
---@type string[]
local mods = {}
for modname, _ in pairs(Cache.lsmod(plugin.dir)) do
mods[#mods + 1] = modname
local modnorm = Util.normname(modname)
-- if we found an exact match, then use that
if modnorm == normname then
mods = { modname }
break
end
end
return #mods == 1 and mods[1] or nil
end
---@param path string ---@param path string
function M.packadd(path) function M.packadd(path)
M.source_runtime(path, "plugin") M.source_runtime(path, "plugin")
@ -364,4 +451,36 @@ function M.colorscheme(name)
end end
end end
function M.auto_load(modname, modpath)
local plugin = Plugin.find(modpath)
if plugin and modpath:find(plugin.dir, 1, true) == 1 then
-- don't load if we're loading specs or if the plugin is already loaded
if not (Plugin.loading or plugin._.loaded) then
if plugin.module == false then
error("Plugin " .. plugin.name .. " is not loaded and is configured with module=false")
end
M.load(plugin, { require = modname })
end
return true
end
return false
end
---@param modname string
function M.loader(modname)
local paths = Util.get_unloaded_rtp(modname)
local modpath, hash = Cache._Cache.find(modname, { rtp = false, paths = paths })
-- print(modname .. " " .. paths[1])
if modpath then
M.auto_load(modname, modpath)
local mod = package.loaded[modname]
if type(mod) == "table" then
return function()
return mod
end
end
return Cache.load(modpath, { hash = hash })
end
end
return M return M

View file

@ -91,7 +91,10 @@ function Spec:add(plugin, results, is_dep)
end end
end end
-- dev plugins -- dev plugins
if plugin.dev then if
plugin.dev
and (not Config.options.dev.fallback or vim.fn.isdirectory(Config.options.dev.path .. "/" .. plugin.name) == 1)
then
plugin.dir = Config.options.dev.path .. "/" .. plugin.name plugin.dir = Config.options.dev.path .. "/" .. plugin.name
else else
-- remote plugin -- remote plugin
@ -251,7 +254,15 @@ function Spec:import(spec)
self.modules[#self.modules + 1] = spec.import self.modules[#self.modules + 1] = spec.import
local imported = 0 local imported = 0
---@type string[]
local modnames = {}
Util.lsmod(spec.import, function(modname) Util.lsmod(spec.import, function(modname)
modnames[#modnames + 1] = modname
end)
table.sort(modnames)
for _, modname in ipairs(modnames) do
imported = imported + 1 imported = imported + 1
Util.track({ import = modname }) Util.track({ import = modname })
self.importing = modname self.importing = modname
@ -270,7 +281,7 @@ function Spec:import(spec)
Util.track() Util.track()
end, end,
}) })
end) end
if imported == 0 then if imported == 0 then
self:error("No specs found for module " .. spec.import) self:error("No specs found for module " .. spec.import)
end end

View file

@ -201,11 +201,62 @@ function M.walk(path, fn)
end) end)
end end
---@param root string
---@param fn fun(modname:string, modpath:string)
---@param modname? string
function M.walkmods(root, fn, modname)
modname = modname and (modname:gsub("%.$", "") .. ".") or ""
M.ls(root, function(path, name, type)
if name == "init.lua" then
fn(modname:gsub("%.$", ""), path)
elseif (type == "file" or type == "link") and name:sub(-4) == ".lua" then
fn(modname .. name:sub(1, -5), path)
elseif type == "directory" then
M.walkmods(path, fn, modname .. name .. ".")
end
end)
end
---@param modname string
function M.get_unloaded_rtp(modname)
modname = modname:gsub("/", ".")
local idx = modname:find(".", 1, true)
local topmod = idx and modname:sub(1, idx - 1) or modname
topmod = M.normname(topmod)
local rtp = {}
local Config = require("lazy.core.config")
if Config.spec then
for _, plugin in pairs(Config.spec.plugins) do
if not (plugin._.loaded or plugin.module == false) then
if topmod == M.normname(plugin.name) then
table.insert(rtp, 1, plugin.dir)
else
table.insert(rtp, plugin.dir)
end
end
end
end
return rtp
end
function M.find_root(modname)
local Cache = require("lazy.core.cache")
local modpath = Cache.find(modname, {
rtp = true,
paths = M.get_unloaded_rtp(modname),
patterns = { "", ".lua" },
})
if modpath then
local root = modpath:gsub("/init%.lua$", ""):gsub("%.lua$", "")
return root
end
end
---@param modname string ---@param modname string
---@param fn fun(modname:string, modpath:string) ---@param fn fun(modname:string, modpath:string)
function M.lsmod(modname, fn) function M.lsmod(modname, fn)
local Cache = require("lazy.core.cache") local root = M.find_root(modname)
local root = Cache.find_root(modname)
if not root then if not root then
return return
end end

View file

@ -14,21 +14,27 @@ end
function M.fix_indent(str) function M.fix_indent(str)
local lines = vim.split(str, "\n") local lines = vim.split(str, "\n")
local first = table.remove(lines, 1)
local width = 120 local width = 120
for _, line in ipairs(lines) do for _, line in ipairs(lines) do
width = math.min(width, #line:match("^%s*")) if not line:find("^%s*$") then
width = math.min(width, #line:match("^%s*"))
end
end end
for l, line in ipairs(lines) do for l, line in ipairs(lines) do
lines[l] = line:sub(width + 1) lines[l] = line:sub(width + 1)
end end
table.insert(lines, 1, first)
return table.concat(lines, "\n") return table.concat(lines, "\n")
end end
---@alias ReadmeBlock {content:string, lang?:string} ---@alias ReadmeBlock {content:string, lang?:string}
---@param contents table<string, ReadmeBlock|string> ---@param contents table<string, ReadmeBlock|string>
function M.save(contents) ---@param readme_file? string
local readme = Util.read_file("README.md") function M.save(contents, readme_file)
local readme = Util.read_file(readme_file or "README.md")
for tag, block in pairs(contents) do for tag, block in pairs(contents) do
if type(block) == "string" then if type(block) == "string" then
block = { content = block, lang = "lua" } block = { content = block, lang = "lua" }
@ -48,7 +54,7 @@ function M.save(contents)
end end
end end
Util.write_file("README.md", readme) Util.write_file(readme_file or "README.md", readme)
vim.cmd.checktime() vim.cmd.checktime()
end end
@ -125,12 +131,7 @@ function M.colors()
end end
function M.update() function M.update()
local cache_config = M.extract("lua/lazy/core/cache.lua", "\nM%.config = ({.-\n})")
local config = M.extract("lua/lazy/core/config.lua", "\nM%.defaults = ({.-\n})") local config = M.extract("lua/lazy/core/config.lua", "\nM%.defaults = ({.-\n})")
config = config:gsub(
"\n%s*%-%-%-@type LazyCacheConfig.*cache = nil,",
"\n" .. M.indent("cache = " .. cache_config .. ",", 4)
)
config = config:gsub("%s*debug = false.\n", "\n") config = config:gsub("%s*debug = false.\n", "\n")
M.save({ M.save({
bootstrap = M.extract("lua/lazy/init.lua", "function M%.bootstrap%(%)\n(.-)\nend"), bootstrap = M.extract("lua/lazy/init.lua", "function M%.bootstrap%(%)\n(.-)\nend"),

View file

@ -5,6 +5,12 @@ local M = {}
function M.check() function M.check()
vim.health.report_start("lazy.nvim") vim.health.report_start("lazy.nvim")
if vim.fn.executable("git") == 1 then
vim.health.report_ok("Git installed")
else
vim.health.report_error("Git not installd?")
end
local sites = vim.opt.packpath:get() local sites = vim.opt.packpath:get()
local default_site = vim.fn.stdpath("data") .. "/site" local default_site = vim.fn.stdpath("data") .. "/site"
if not vim.tbl_contains(sites, default_site) then if not vim.tbl_contains(sites, default_site) then
@ -14,7 +20,7 @@ function M.check()
local existing = false local existing = false
for _, site in pairs(sites) do for _, site in pairs(sites) do
for _, packs in ipairs(vim.fn.expand(site .. "/pack/*", false, true)) do for _, packs in ipairs(vim.fn.expand(site .. "/pack/*", false, true)) do
if not packs:find("/dist$") and vim.loop.fs_stat(packs) then if not packs:find("[/\\]dist$") and vim.loop.fs_stat(packs) then
existing = true existing = true
vim.health.report_warn("found existing packages at `" .. packs .. "`") vim.health.report_warn("found existing packages at `" .. packs .. "`")
end end

View file

@ -34,7 +34,15 @@ function M.setup(spec, opts)
local start = vim.loop.hrtime() local start = vim.loop.hrtime()
-- load module cache before anything else -- load module cache before anything else
require("lazy.core.cache").setup(opts) local enable_cache = not (
opts
and opts.performance
and opts.performance.cache
and opts.performance.cache.enabled == false
)
if enable_cache then
require("lazy.core.cache").enable()
end
require("lazy.stats").track("LazyStart") require("lazy.stats").track("LazyStart")
@ -42,6 +50,12 @@ function M.setup(spec, opts)
local Config = require("lazy.core.config") local Config = require("lazy.core.config")
local Loader = require("lazy.core.loader") local Loader = require("lazy.core.loader")
table.insert(package.loaders, 3, Loader.loader)
if vim.g.profile_loaders then
require("lazy.core.cache").profile_loaders()
end
Util.track({ plugin = "lazy.nvim" }) -- setup start Util.track({ plugin = "lazy.nvim" }) -- setup start
Util.track("module", vim.loop.hrtime() - start) Util.track("module", vim.loop.hrtime() - start)

View file

@ -13,7 +13,14 @@ M.reported = {}
function M.start() function M.start()
M.fast_check() M.fast_check()
M.schedule() if M.schedule() > 0 and not M.has_errors() then
Manage.log({
clear = false,
show = false,
check = true,
concurrency = Config.options.checker.concurrency,
})
end
end end
function M.schedule() function M.schedule()
@ -21,6 +28,7 @@ function M.schedule()
local next_check = State.checker.last_check + Config.options.checker.frequency - os.time() local next_check = State.checker.last_check + Config.options.checker.frequency - os.time()
next_check = math.max(next_check, 0) next_check = math.max(next_check, 0)
vim.defer_fn(M.check, next_check * 1000) vim.defer_fn(M.check, next_check * 1000)
return next_check
end end
---@param opts? {report:boolean} report defaults to true ---@param opts? {report:boolean} report defaults to true
@ -39,20 +47,23 @@ function M.fast_check(opts)
M.report(opts.report ~= false) M.report(opts.report ~= false)
end end
function M.has_errors()
for _, plugin in pairs(Config.plugins) do
if Plugin.has_errors(plugin) then
return true
end
end
return false
end
function M.check() function M.check()
State.checker.last_check = os.time() State.checker.last_check = os.time()
State.write() -- update state State.write() -- update state
local errors = false if M.has_errors() then
for _, plugin in pairs(Config.plugins) do
if Plugin.has_errors(plugin) then
errors = true
break
end
end
if errors then
M.schedule() M.schedule()
else else
Manage.check({ Manage.check({
clear = false,
show = false, show = false,
concurrency = Config.options.checker.concurrency, concurrency = Config.options.checker.concurrency,
}):wait(function() }):wait(function()

View file

@ -136,13 +136,13 @@ function M.check(opts)
}, opts) }, opts)
end end
---@param opts? ManagerOpts ---@param opts? ManagerOpts | {check?:boolean}
function M.log(opts) function M.log(opts)
opts = M.opts(opts, { mode = "log" }) opts = M.opts(opts, { mode = "log" })
return M.run({ return M.run({
pipeline = { pipeline = {
{ "git.origin", check = true }, { "git.origin", check = true },
"git.log", { "git.log", check = opts.check },
}, },
plugins = function(plugin) plugins = function(plugin)
return plugin.url and plugin._.installed return plugin.url and plugin._.installed
@ -174,7 +174,10 @@ function M.sync(opts)
end) end)
opts.show = false opts.show = false
end end
local clean = M.clean(opts)
local clean_opts = vim.deepcopy(opts)
clean_opts.plugins = nil
local clean = M.clean(clean_opts)
local install = M.install(opts) local install = M.install(opts)
local update = M.update(opts) local update = M.update(opts)
clean:wait(function() clean:wait(function()

View file

@ -2,7 +2,7 @@ local Config = require("lazy.core.config")
local M = {} local M = {}
---@type table<vim.loop.Process, true> ---@type table<uv.uv_process_t, true>
M.running = {} M.running = {}
M.signals = { M.signals = {
@ -49,7 +49,7 @@ local uv = vim.loop
---@field on_line? fun(string) ---@field on_line? fun(string)
---@field on_exit? fun(ok:boolean, output:string) ---@field on_exit? fun(ok:boolean, output:string)
---@field timeout? number ---@field timeout? number
---@field env? string[] ---@field env? table<string,string>
---@param opts? ProcessOpts ---@param opts? ProcessOpts
---@param cmd string ---@param cmd string
@ -57,31 +57,31 @@ function M.spawn(cmd, opts)
opts = opts or {} opts = opts or {}
opts.timeout = opts.timeout or (Config.options.git and Config.options.git.timeout * 1000) opts.timeout = opts.timeout or (Config.options.git and Config.options.git.timeout * 1000)
local env = { ---@type table<string, string>
"GIT_TERMINAL_PROMPT=0", local env = vim.tbl_extend("force", {
"GIT_SSH_COMMAND=ssh -oBatchMode=yes", GIT_SSH_COMMAND = "ssh -oBatchMode=yes",
} }, uv.os_environ(), opts.env or {})
if opts.env then env.GIT_DIR = nil
vim.list_extend(env, opts.env) env.GIT_TERMINAL_PROMPT = "0"
---@type string[]
local env_flat = {}
for k, v in pairs(env) do
env_flat[#env_flat + 1] = k .. "=" .. v
end end
for key, value in local stdout = assert(uv.new_pipe())
pairs(uv.os_environ() --[[@as string[] ]]) local stderr = assert(uv.new_pipe())
do
table.insert(env, key .. "=" .. value)
end
local stdout = uv.new_pipe()
local stderr = uv.new_pipe()
local output = "" local output = ""
---@type vim.loop.Process ---@type uv.uv_process_t
local handle = nil local handle = nil
---@type uv.uv_timer_t
local timeout local timeout
local killed = false local killed = false
if opts.timeout then if opts.timeout then
timeout = uv.new_timer() timeout = assert(uv.new_timer())
timeout:start(opts.timeout, 0, function() timeout:start(opts.timeout, 0, function()
if M.kill(handle) then if M.kill(handle) then
killed = true killed = true
@ -93,7 +93,7 @@ function M.spawn(cmd, opts)
stdio = { nil, stdout, stderr }, stdio = { nil, stdout, stderr },
args = opts.args, args = opts.args,
cwd = opts.cwd, cwd = opts.cwd,
env = env, env = env_flat,
}, function(exit_code, signal) }, function(exit_code, signal)
M.running[handle] = nil M.running[handle] = nil
if timeout then if timeout then
@ -103,7 +103,7 @@ function M.spawn(cmd, opts)
handle:close() handle:close()
stdout:close() stdout:close()
stderr:close() stderr:close()
local check = uv.new_check() local check = assert(uv.new_check())
check:start(function() check:start(function()
if not stdout:is_closing() or not stderr:is_closing() then if not stdout:is_closing() or not stderr:is_closing() then
return return

View file

@ -1,4 +1,3 @@
local Cache = require("lazy.core.cache")
local Config = require("lazy.core.config") local Config = require("lazy.core.config")
local Util = require("lazy.util") local Util = require("lazy.util")
local Plugin = require("lazy.core.plugin") local Plugin = require("lazy.core.plugin")
@ -6,12 +5,11 @@ local Loader = require("lazy.core.loader")
local M = {} local M = {}
---@type table<string, CacheHash> ---@type table<string, vim.loop.Stat>
M.files = {} M.files = {}
---@type vim.loop.Timer ---@type vim.loop.Timer
M.timer = nil M.timer = nil
M.root = nil
function M.enable() function M.enable()
if M.timer then if M.timer then
@ -19,7 +17,6 @@ function M.enable()
end end
if #Config.spec.modules > 0 then if #Config.spec.modules > 0 then
M.timer = vim.loop.new_timer() M.timer = vim.loop.new_timer()
M.root = vim.fn.stdpath("config") .. "/lua"
M.check(true) M.check(true)
M.timer:start(2000, 2000, M.check) M.timer:start(2000, 2000, M.check)
end end
@ -32,6 +29,12 @@ function M.disable()
end end
end end
---@param h1 vim.loop.Stat
---@param h2 vim.loop.Stat
function M.eq(h1, h2)
return h1 and h2 and h1.size == h2.size and h1.mtime.sec == h2.mtime.sec and h1.mtime.nsec == h2.mtime.nsec
end
function M.check(start) function M.check(start)
---@type table<string,true> ---@type table<string,true>
local checked = {} local checked = {}
@ -41,10 +44,10 @@ function M.check(start)
-- spec is a module -- spec is a module
local function check(_, modpath) local function check(_, modpath)
checked[modpath] = true checked[modpath] = true
local hash = Cache.hash(modpath) local hash = vim.loop.fs_stat(modpath)
if hash then if hash then
if M.files[modpath] then if M.files[modpath] then
if not Cache.eq(M.files[modpath], hash) then if not M.eq(M.files[modpath], hash) then
M.files[modpath] = hash M.files[modpath] = hash
table.insert(changes, { file = modpath, what = "changed" }) table.insert(changes, { file = modpath, what = "changed" })
end end

View file

@ -15,7 +15,7 @@ M.log = {
return true return true
end end
local stat = vim.loop.fs_stat(plugin.dir .. "/.git") local stat = vim.loop.fs_stat(plugin.dir .. "/.git")
return stat and stat.type ~= "directory" return not (stat and stat.type == "directory")
end, end,
---@param opts {args?: string[], updated?:boolean, check?:boolean} ---@param opts {args?: string[], updated?:boolean, check?:boolean}
run = function(self, opts) run = function(self, opts)
@ -64,11 +64,18 @@ M.clone = {
local args = { local args = {
"clone", "clone",
self.plugin.url, self.plugin.url,
"--filter=blob:none",
"--recurse-submodules",
"--progress",
} }
if Config.options.git.filter then
args[#args + 1] = "--filter=blob:none"
end
if self.plugin.submodules ~= false then
args[#args + 1] = "--recurse-submodules"
end
args[#args + 1] = "--progress"
if self.plugin.branch then if self.plugin.branch then
vim.list_extend(args, { "-b", self.plugin.branch }) vim.list_extend(args, { "-b", self.plugin.branch })
end end
@ -152,6 +159,10 @@ M.fetch = {
"--progress", "--progress",
} }
if self.plugin.submodules == false then
table.remove(args, 2)
end
self:spawn("git", { self:spawn("git", {
args = args, args = args,
cwd = self.plugin.dir, cwd = self.plugin.dir,
@ -203,6 +214,10 @@ M.checkout = {
"--recurse-submodules", "--recurse-submodules",
} }
if self.plugin.submodules == false then
table.remove(args, 3)
end
if lock then if lock then
table.insert(args, lock.commit) table.insert(args, lock.commit)
elseif target.tag then elseif target.tag then

View file

@ -19,6 +19,7 @@
---@class LazyPluginHooks ---@class LazyPluginHooks
---@field init? fun(self:LazyPlugin) Will always be run ---@field init? fun(self:LazyPlugin) Will always be run
---@field deactivate? fun(self:LazyPlugin) Unload/Stop a plugin
---@field config? fun(self:LazyPlugin, opts:table)|true Will be executed when loading the plugin ---@field config? fun(self:LazyPlugin, opts:table)|true Will be executed when loading the plugin
---@field build? string|fun(self:LazyPlugin)|(string|fun(self:LazyPlugin))[] ---@field build? string|fun(self:LazyPlugin)|(string|fun(self:LazyPlugin))[]
---@field opts? PluginOpts ---@field opts? PluginOpts
@ -36,10 +37,12 @@
---@field commit? string ---@field commit? string
---@field version? string ---@field version? string
---@field pin? boolean ---@field pin? boolean
---@field submodules? boolean Defaults to true
---@class LazyPluginBase ---@class LazyPluginBase
---@field [1] string? ---@field [1] string?
---@field name string display name and name used for plugin config files ---@field name string display name and name used for plugin config files
---@field main? string Entry module that has setup & deactivate
---@field url string? ---@field url string?
---@field dir string ---@field dir string
---@field enabled? boolean|(fun():boolean) ---@field enabled? boolean|(fun():boolean)

View file

@ -23,8 +23,10 @@ function M.open(uri)
elseif vim.fn.has("macunix") == 1 then elseif vim.fn.has("macunix") == 1 then
cmd = { "open", uri } cmd = { "open", uri }
else else
if vim.fn.executable("xdg-open") then if vim.fn.executable("xdg-open") == 1 then
cmd = { "xdg-open", uri } cmd = { "xdg-open", uri }
elseif vim.fn.executable("wslview") == 1 then
cmd = { "wslview", uri }
else else
cmd = { "open", uri } cmd = { "open", uri }
end end

View file

@ -53,7 +53,7 @@ function M:init(opts)
} }
self:mount() self:mount()
self:on_key(ViewConfig.keys.close, self.close) self:on_key(ViewConfig.keys.close, self.close)
self:on({ "BufDelete", "BufLeave", "BufHidden" }, self.close, { once = true }) self:on({ "BufDelete", "BufHidden" }, self.close, { once = true })
return self return self
end end
@ -107,9 +107,11 @@ function M:mount()
local function opts() local function opts()
vim.bo[self.buf].bufhidden = "wipe" vim.bo[self.buf].bufhidden = "wipe"
vim.wo[self.win].conceallevel = 3 vim.wo[self.win].conceallevel = 3
vim.wo[self.win].foldenable = false
vim.wo[self.win].spell = false vim.wo[self.win].spell = false
vim.wo[self.win].wrap = true vim.wo[self.win].wrap = true
vim.wo[self.win].winhighlight = "Normal:LazyNormal" vim.wo[self.win].winhighlight = "Normal:LazyNormal"
vim.wo[self.win].colorcolumn = ""
end end
opts() opts()

View file

@ -77,7 +77,7 @@ function M.create()
vim.keymap.set("n", ViewConfig.keys.abort, function() vim.keymap.set("n", ViewConfig.keys.abort, function()
require("lazy.manage.process").abort() require("lazy.manage.process").abort()
return "<c-c>" return ViewConfig.keys.abort
end, { silent = true, buffer = self.buf, expr = true }) end, { silent = true, buffer = self.buf, expr = true })
-- plugin details -- plugin details

View file

@ -160,7 +160,7 @@ end
function M:help() function M:help()
self:append("Help", "LazyH2"):nl():nl() self:append("Help", "LazyH2"):nl():nl()
self:append("Use "):append("<C-c>", "LazySpecial"):append(" to abort all running tasks."):nl():nl() self:append("Use "):append(ViewConfig.keys.abort, "LazySpecial"):append(" to abort all running tasks."):nl():nl()
self:append("You can press "):append("<CR>", "LazySpecial"):append(" on a plugin to show its details."):nl():nl() self:append("You can press "):append("<CR>", "LazySpecial"):append(" on a plugin to show its details."):nl():nl()
@ -670,33 +670,19 @@ function M:debug()
end) end)
self:nl() self:nl()
self:append("Cache.find()", "LazyH2"):nl() Util.foreach(Cache.stats, function(name, stats)
self:props({ self:append(name, "LazyH2"):nl()
{ "total", Cache.stats.find.total, "Number" }, local props = {
{ "time", self:ms(Cache.stats.find.time, 3), "Bold" }, { "total", stats.total or 0, "Number" },
{ "avg time", self:ms(Cache.stats.find.time / Cache.stats.find.total, 3), "Bold" }, { "time", self:ms(stats.time or 0, 3), "Bold" },
{ "index", Cache.stats.find.index, "Number" }, { "avg time", self:ms((stats.time or 0) / (stats.total or 0), 3), "Bold" },
{ "fs_stat", Cache.stats.find.stat, "Number" }, }
{ "not found", Cache.stats.find.not_found, "Number" }, for k, v in pairs(stats) do
}, { indent = 2 }) if k ~= "total" and k ~= "time" then
self:nl() props[#props + 1] = { k, v, "Number" }
end
self:append("Cache.autoload()", "LazyH2"):nl()
self:props({
{ "total", Cache.stats.autoload.total, "Number" },
{ "time", self:ms(Cache.stats.autoload.time, 3), "Bold" },
{ "avg time", self:ms(Cache.stats.autoload.time / Cache.stats.autoload.total, 3), "Bold" },
}, { indent = 2 })
self:nl()
self:append("Cache", "LazyH2"):nl()
local Cache = require("lazy.core.cache")
Util.foreach(Cache.cache, function(modname, entry)
local kb = math.floor(#entry.chunk / 10.24) / 100
self:append("", "LazySpecial", { indent = 2 }):append(modname):append(" " .. kb .. "Kb", "Bold")
if entry.modpath ~= modname then
self:append(" " .. vim.fn.fnamemodify(entry.modpath, ":p:~:."), "LazyComment")
end end
self:props(props, { indent = 2 })
self:nl() self:nl()
end) end)
end end

View file

@ -51,10 +51,8 @@ describe("util", function()
local files = Helpers.fs_create(test.files) local files = Helpers.fs_create(test.files)
-- test with empty cache -- test with empty cache
Cache.cache = {} package.loaded["lazy.core.cache"] = nil
Cache.indexed = {} local root = Util.find_root(test.mod)
Cache.indexed_rtp = false
local root = Cache.find_root(test.mod)
assert(root, "no root found for " .. test.mod .. " (test " .. t .. ")") assert(root, "no root found for " .. test.mod .. " (test " .. t .. ")")
assert.same(Helpers.path(test.root), root) assert.same(Helpers.path(test.root), root)
local mods = {} local mods = {}
@ -65,13 +63,8 @@ describe("util", function()
assert.same(expected, mods) assert.same(expected, mods)
-- fill the cache -- fill the cache
Cache.cache = {} package.loaded["lazy.core.cache"] = nil
for i, file in ipairs(files) do root = Util.find_root(test.mod)
Cache.cache[test.mods[i]] = { modpath = file }
end
Cache.indexed = {}
Cache.indexed_rtp = false
root = Cache.find_root(test.mod)
assert(root, "no root found for " .. test.mod .. " (test " .. t .. ")") assert(root, "no root found for " .. test.mod .. " (test " .. t .. ")")
assert.same(Helpers.path(test.root), root) assert.same(Helpers.path(test.root), root)
mods = {} mods = {}
@ -85,12 +78,12 @@ describe("util", function()
it("find the correct root with dels", function() it("find the correct root with dels", function()
Cache.cache = {} Cache.cache = {}
Cache.indexed = {} Cache._topmods = {}
Cache.indexed_rtp = false Cache.topmods_rtp = false
vim.opt.rtp:append(Helpers.path("old")) vim.opt.rtp:append(Helpers.path("old"))
Helpers.fs_create({ "old/lua/foobar/init.lua" }) Helpers.fs_create({ "old/lua/foobar/init.lua" })
Cache.cache["foobar"] = { modpath = Helpers.path("old/lua/foobar/init.lua") } Cache.cache["foobar"] = { modpath = Helpers.path("old/lua/foobar/init.lua") }
local root = Cache.find_root("foobar") local root = Util.find_root("foobar")
assert(root, "foobar root not found") assert(root, "foobar root not found")
assert.same(Helpers.path("old/lua/foobar"), root) assert.same(Helpers.path("old/lua/foobar"), root)
@ -98,24 +91,22 @@ describe("util", function()
assert(not vim.loop.fs_stat(Helpers.path("old/lua/foobar")), "old/lua/foobar should not exist") assert(not vim.loop.fs_stat(Helpers.path("old/lua/foobar")), "old/lua/foobar should not exist")
-- vim.opt.rtp = rtp -- vim.opt.rtp = rtp
Cache.indexed = {} Cache._topmods = {}
Cache.indexed_rtp = false
vim.opt.rtp:append(Helpers.path("new")) vim.opt.rtp:append(Helpers.path("new"))
Helpers.fs_create({ "new/lua/foobar/init.lua" }) Helpers.fs_create({ "new/lua/foobar/init.lua" })
root = Cache.find_root("foobar") root = Util.find_root("foobar")
assert(root, "foobar root not found") assert(root, "foobar root not found")
assert.same(Helpers.path("new/lua/foobar"), root) assert.same(Helpers.path("new/lua/foobar"), root)
end) end)
it("find the correct root with mod dels", function() it("find the correct root with mod dels", function()
Cache.cache = {} Cache.cache = {}
Cache.indexed = {} Cache._topmods = {}
Cache.indexed_rtp = false
Cache.enabled = true Cache.enabled = true
vim.opt.rtp:append(Helpers.path("old")) vim.opt.rtp:append(Helpers.path("old"))
Helpers.fs_create({ "old/lua/foobar/test.lua" }) Helpers.fs_create({ "old/lua/foobar/test.lua" })
Cache.cache["foobar.test"] = { modpath = Helpers.path("old/lua/foobar/test.lua") } Cache.cache["foobar.test"] = { modpath = Helpers.path("old/lua/foobar/test.lua") }
local root = Cache.find_root("foobar") local root = Util.find_root("foobar")
assert(root, "foobar root not found") assert(root, "foobar root not found")
assert.same(Helpers.path("old/lua/foobar"), root) assert.same(Helpers.path("old/lua/foobar"), root)
assert(not Cache.cache["foobar"], "foobar should not be in cache") assert(not Cache.cache["foobar"], "foobar should not be in cache")
@ -124,11 +115,10 @@ describe("util", function()
Helpers.fs_rm("old") Helpers.fs_rm("old")
-- vim.opt.rtp = rtp -- vim.opt.rtp = rtp
Cache.indexed = {} Cache._topmods = {}
Cache.indexed_rtp = false
vim.opt.rtp:append(Helpers.path("new")) vim.opt.rtp:append(Helpers.path("new"))
Helpers.fs_create({ "new/lua/foobar/test.lua" }) Helpers.fs_create({ "new/lua/foobar/test.lua" })
root = Cache.find_root("foobar") root = Util.find_root("foobar")
assert(root, "foobar root not found") assert(root, "foobar root not found")
assert.same(Helpers.path("new/lua/foobar"), root) assert.same(Helpers.path("new/lua/foobar"), root)
end) end)