Skip to content

Commit

Permalink
feat(plugins): support including yazi flavors with .build_flavor
Browse files Browse the repository at this point in the history
  • Loading branch information
mikavilpas committed Jun 3, 2024
1 parent aed05d5 commit 7cf7802
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ open yazi in a floating window in Neovim.
buffers in Neovim
- The files are also kept in sync with currently running LSP servers
- Customizable keybindings
- 🆕 Plugin manager for Yazi plugins
- 🆕 Plugin manager for Yazi plugins and flavors
([documentation](./documentation/plugin-manager.md)). Please provide your
feedback!

Expand Down
30 changes: 24 additions & 6 deletions documentation/plugin-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ allows you to fully manage your yazi and neovim plugins from inside neovim.

In this example, we will install the yazi plugin
[DreamMaoMao/keyjump.yazi](https://github.com/DreamMaoMao/keyjump.yazi), which
adds a "jump-to-line" feature to yazi.
adds a "jump-to-line" feature to yazi. We will also install a _flavor_ which
applies a color scheme to yazi.

In your yazi.nvim configuration, add a new lazy.nvim plugin specification for
`DreamMaoMao/keyjump.yazi`:
Expand All @@ -29,24 +30,39 @@ return {
},
},
{
-- example: include a plugin
"DreamMaoMao/keyjump.yazi",
lazy = true,
build = function(plugin)
require("yazi.plugin").build_plugin(plugin)
end,
},
{
-- example: include a flavor
"BennyOe/onedark.yazi",
lazy = true,
build = function(plugin)
require("yazi.plugin").build_flavor(plugin)
end,
},
}
```

Make sure to add the `lazy` and `build` keys to the plugin specification .

Next, run `:Lazy` in neovim to install the plugin.
Next, run `:Lazy` in neovim to install the plugin and flavor.

Finally, make changes in your yazi configuration:

Finally, add a keybinding to your `~/.config/yazi/keymap.toml` according to the
instructions provided by the plugin author.
- add a keybinding to your `~/.config/yazi/keymap.toml` according to the
[instructions](https://github.com/DreamMaoMao/keyjump.yazi?tab=readme-ov-file#usage)
provided by the plugin author.
- include the flavor in your `~/.config/yazi/theme.toml` according to the
[instructions](https://github.com/BennyOe/onedark.yazi?tab=readme-ov-file#%EF%B8%8F-usage)
provided by the flavor author.

You're all set! You can now use the new plugin in yazi, and update it using
lazy.nvim.
You're all set! You can now use the new plugin and flavor in yazi, and update
them using lazy.nvim.

> Demo: installing a new Yazi plugin with lazy.nvim, and then using `<leader>l`
> to view its commits
Expand Down Expand Up @@ -154,3 +170,5 @@ For further reading, please refer to the following resources:

- Yazi plugin documentation <https://yazi-rs.github.io/docs/plugins/overview>
- lazy.nvim documentation <https://github.com/folke/lazy.nvim>
- General discussion on the idea
<https://github.com/folke/lazy.nvim/discussions/1488>
74 changes: 51 additions & 23 deletions lua/yazi/plugin.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
local M = {}

--- A specification that represents information about the plugin or flavor to
--- install. Note that this is compatible with LazyPlugin, the lazy.nvim plugin
--- specification table, so you can just pass that.
---@alias YaziLazyNvimSpec { name: string, dir: string }

---@alias YaziSpecInstallationResultSuccess { message: string, from: string, to: string }
---@alias YaziSpecInstallationResultFailure { message: string, from: string, to?: string, error: string }

--- Helper utility for compatibility with
--- [lazy.nvim](https://github.com/folke/lazy.nvim).
---
Expand All @@ -19,33 +27,61 @@ local M = {}
---
--- For more information, see the yazi.nvim documentation.
---
---@param plugin YaziLazyNvimPlugin
---@param plugin YaziLazyNvimSpec
---@param options? { yazi_dir: string }
---@return YaziPluginInstallationResultSuccess | YaziPluginInstallationResultFailure
function M.build_plugin(plugin, options)
local yazi_dir = options and options.yazi_dir
or vim.fn.expand('~/.config/yazi')
local to = vim.fs.normalize(vim.fs.joinpath(yazi_dir, 'plugins', plugin.name))

local dir = vim.loop.fs_stat(plugin.dir)
---@type string
local yazi_plugins_dir = vim.fn.expand(vim.fs.joinpath(yazi_dir, 'plugins'))
vim.fn.mkdir(yazi_plugins_dir, 'p')

local to = vim.fs.normalize(vim.fs.joinpath(yazi_plugins_dir, plugin.name))

return M.symlink(plugin, to)
end

---@param flavor YaziLazyNvimSpec
---@param options? { yazi_dir: string }
function M.build_flavor(flavor, options)
local yazi_dir = options and options.yazi_dir
or vim.fn.expand('~/.config/yazi')

---@type string
local flavor_dir = vim.fn.expand(vim.fs.joinpath(yazi_dir, 'flavors'))
vim.fn.mkdir(flavor_dir, 'p')

local to = vim.fs.normalize(vim.fs.joinpath(flavor_dir, flavor.name))

return M.symlink(flavor, to)
end

--- A general implementation of a symlink operation. For yazi plugins and
--- flavors, prefer using `build_plugin` and `build_flavor` instead.
---@param spec YaziLazyNvimSpec
---@param to string
---@return YaziSpecInstallationResultSuccess | YaziSpecInstallationResultFailure
function M.symlink(spec, to)
local dir = vim.uv.fs_stat(spec.dir)
if dir == nil or dir.type ~= 'directory' then
---@type YaziPluginInstallationResultFailure
---@type YaziSpecInstallationResultFailure
local result = {
error = 'plugin directory does not exist',
from = plugin.dir,
message = 'yazi.nvim: failed to install plugin',
error = 'yazi plugin/flavor directory does not exist',
from = spec.dir,
message = 'yazi.nvim: failed to install',
}
vim.notify(vim.inspect(result))
return result
end

local success, error = vim.uv.fs_symlink(plugin.dir, to)
local success, error = vim.uv.fs_symlink(spec.dir, to)

if not success then
---@type YaziPluginInstallationResultFailure
---@type YaziSpecInstallationResultFailure
local result = {
message = 'yazi.nvim: failed to install plugin',
from = plugin.dir,
message = 'yazi.nvim: failed to install',
from = spec.dir,
to = to,
error = error or 'unknown error',
}
Expand All @@ -54,23 +90,15 @@ function M.build_plugin(plugin, options)
return result
end

---@type YaziPluginInstallationResultSuccess
---@type YaziSpecInstallationResultSuccess
local result = {
message = 'yazi.nvim: successfully installed plugin ' .. plugin.name,
from = plugin.dir,
message = 'yazi.nvim: successfully installed ' .. spec.name,
from = spec.dir,
to = to,
}

vim.notify(vim.inspect(result))
return result
end

--- Represents information about the plugin to install. Note that this is
--- compatible with LazyPlugin, the lazy.nvim plugin specification table, so
--- you can just pass that.
---@alias YaziLazyNvimPlugin { name: string, dir: string }

---@alias YaziPluginInstallationResultSuccess { message: string, from: string, to: string }
---@alias YaziPluginInstallationResultFailure { message: string, from: string, to?: string, error: string }

return M
76 changes: 49 additions & 27 deletions tests/yazi/plugin_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,41 +15,63 @@ describe('installing a plugin', function()
vim.fn.delete(base_dir, 'rf')
end)

it('can install if everything goes well', function()
local plugin_dir = vim.fs.joinpath(base_dir, 'test-plugin')
local yazi_dir = vim.fs.joinpath(base_dir, 'fake-yazi-dir')
describe('installing a plugin', function()
it('can install if everything goes well', function()
local plugin_dir = vim.fs.joinpath(base_dir, 'test-plugin')
local yazi_dir = vim.fs.joinpath(base_dir, 'fake-yazi-dir')

vim.fn.mkdir(plugin_dir)
vim.fn.mkdir(yazi_dir)
vim.fn.mkdir(vim.fs.joinpath(yazi_dir, 'plugins'))
vim.fn.mkdir(plugin_dir)
vim.fn.mkdir(yazi_dir)
vim.fn.mkdir(vim.fs.joinpath(yazi_dir, 'plugins'))

plugin.build_plugin({
dir = plugin_dir,
name = 'test-plugin',
}, { yazi_dir = yazi_dir })
plugin.build_plugin({
dir = plugin_dir,
name = 'test-plugin',
}, { yazi_dir = yazi_dir })

-- verify that the plugin was symlinked
-- yazi_dir/plugins/test-plugin -> plugin_dir
local symlink =
vim.loop.fs_readlink(vim.fs.joinpath(yazi_dir, 'plugins', 'test-plugin'))
-- verify that the plugin was symlinked
-- yazi_dir/plugins/test-plugin -> plugin_dir
local symlink =
vim.uv.fs_readlink(vim.fs.joinpath(yazi_dir, 'plugins', 'test-plugin'))

assert.are.same(plugin_dir, symlink)
assert.are.same(plugin_dir, symlink)
end)

it('warns the user if the plugin directory does not exist', function()
local plugin_dir = vim.fs.joinpath(base_dir, 'test-plugin')
local yazi_dir = vim.fs.joinpath(base_dir, 'fake-yazi-dir')
vim.fn.mkdir(yazi_dir)

local result = plugin.build_plugin({
dir = plugin_dir,
name = 'test-plugin-2',
}, { yazi_dir = yazi_dir })

assert.is_equal(
result.error,
'yazi plugin/flavor directory does not exist'
)
assert.is_equal(result.from, plugin_dir)
end)
end)

it('warns the user if the plugin directory does not exist', function()
local plugin_dir = vim.fs.joinpath(base_dir, 'test-plugin')
local yazi_dir = vim.fs.joinpath(base_dir, 'fake-yazi-dir')
describe('installing a flavor', function()
it('can install if everything goes well', function()
local flavor_dir = vim.fs.joinpath(base_dir, 'test-flavor')
local yazi_dir = vim.fs.joinpath(base_dir, 'fake-yazi-dir')

vim.fn.mkdir(flavor_dir)
vim.fn.mkdir(yazi_dir)

-- NOTE: we are not creating the plugin directory
-- vim.fn.mkdir(plugin_dir)
vim.fn.mkdir(yazi_dir)
vim.fn.mkdir(vim.fs.joinpath(yazi_dir, 'plugins'))
plugin.build_flavor({
dir = flavor_dir,
name = 'test-flavor',
}, { yazi_dir = yazi_dir })

local result = plugin.build_plugin({
dir = plugin_dir,
name = 'test-plugin-2',
}, { yazi_dir = yazi_dir })
local symlink =
vim.uv.fs_readlink(vim.fs.joinpath(yazi_dir, 'flavors', 'test-flavor'))

assert.is_equal(result.error, 'plugin directory does not exist')
assert.are.same(flavor_dir, symlink)
end)
end)
end)

0 comments on commit 7cf7802

Please sign in to comment.