Skip to content

Commit

Permalink
feat: allow opening the selected file in a vertical split
Browse files Browse the repository at this point in the history
feat: allow adding custom keymaps specific to the yazi buffer

The user can also modify the configuration all of the hooks, giving them
a lot of power to customize the behavior of the plugin.

refactor: the config's default functions are in a separate file
  • Loading branch information
mikavilpas committed Apr 13, 2024
1 parent ac87720 commit 1bb74ca
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 52 deletions.
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ Using lazy.nvim:
---@type YaziConfig
opts = {
-- Below is the default configuration. It is optional to set these values.
-- You can customize the configuration for each yazi call by passing it to
-- yazi() explicitly

-- enable this if you want to open yazi instead of netrw.
-- Note that if you enable this, you need to call yazi.setup() to
-- initialize the plugin.
-- initialize the plugin. lazy.nvim does this for you in certain cases.
open_for_directories = false,

-- the path to a temporary file that will be created by yazi to store the
Expand All @@ -54,20 +56,26 @@ Using lazy.nvim:

-- what neovim should do a when a file was opened (selected) in yazi.
-- Defaults to simply opening the file.
-- If you want to open it in a split / new tab, you can define it here.
open_file_function = function(chosen_file) end,
open_file_function = function(chosen_file, config) end,

-- completely override the keymappings for yazi. This function will be
-- called in the context of the yazi terminal buffer.
set_keymappings_function = function(yazi_buffer_id, config) end,

hooks = {
-- if you want to execute a custom action when yazi has been opened,
-- you can define it here
yazi_opened = function(preselected_path) end,
-- you can define it here.
yazi_opened = function(preselected_path, yazi_buffer_id, config)
-- you can optionally modify the config for this specific yazi
-- invocation if you want to customize the behaviour
end,

-- when yazi was successfully closed
yazi_closed_successfully = function(chosen_file) end,
yazi_closed_successfully = function(chosen_file, config) end,

-- when yazi opened multiple files. The default is to send them to the
-- quickfix list, but if you want to change that, you can define it here
yazi_opened_multiple_files = function(chosen_files) end,
yazi_opened_multiple_files = function(chosen_files, config) end,
},

-- the floating window scaling factor. 1 means 100%, 0.9 means 90%, etc.
Expand All @@ -79,6 +87,12 @@ Using lazy.nvim:
}
```

## Keybindings

These are the default keybindings that are available when yazi is open:

- `<c-v>`: open the selected file in a vertical split

## About my fork

I forked this from <https://github.com/DreamMaoMao/yazi.nvim> for my own use, and also because I wanted to learn neovim plugin development.
Expand All @@ -93,5 +107,6 @@ So far I have done some maintenance work and added a bunch of features:
- feat: files that are renamed, moved, deleted, or trashed in yazi are kept in sync with open buffers (this requires a version of yazi that includes [this](https://github.com/sxyazi/yazi/pull/880) change from 2024-04-06)
- feat: allow customizing the method of opening the selected file in neovim
- feat: can send multiple opened files to the quickfix list
- feat: can open a file in a vertical split

If you'd like to collaborate, contact me via GitHub issues.
8 changes: 5 additions & 3 deletions lua/yazi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function M.yazi(config, path)

local prev_win = vim.api.nvim_get_current_win()

local win, buffer = window.open_floating_window(config)
local win, _, yazi_buffer = window.open_floating_window(config)

os.remove(config.chosen_file_path)
local cmd = string.format(
Expand All @@ -41,16 +41,18 @@ function M.yazi(config, path)
on_exit = function(_job_id, code, _event)
M.yazi_loaded = false
if code ~= 0 then
print('yazi exited with code', code)
return
end

utils.on_yazi_exited(prev_win, win, buffer, config)
utils.on_yazi_exited(prev_win, win, yazi_buffer, config)

event_handling.process_events_emitted_from_yazi(config)
end,
})

config.hooks.yazi_opened(path)
config.hooks.yazi_opened(path, yazi_buffer, config)
config.set_keymappings_function(yazi_buffer, config)
end
vim.schedule(function()
vim.cmd('startinsert')
Expand Down
47 changes: 23 additions & 24 deletions lua/yazi/config.lua
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
local openers = require('yazi.openers')

local M = {}

---@return YaziConfig
function M.default()
---@type YaziConfig
return {
open_for_directories = false,
chosen_file_path = '/tmp/yazi_filechosen',
events_file_path = '/tmp/yazi.nvim.events.txt',
open_file_function = function(chosen_file)
vim.cmd(string.format('edit %s', chosen_file))
end,
open_file_function = openers.open_file,
set_keymappings_function = M.default_set_keymappings_function,
hooks = {
---@diagnostic disable-next-line: unused-local
yazi_opened = function(_preselected_path) end,
---@diagnostic disable-next-line: unused-local
yazi_closed_successfully = function(_chosen_file) end,
yazi_opened_multiple_files = function(chosen_files)
-- show the items in the quickfix list
vim.fn.setqflist({}, 'r', {
title = 'Yazi',
items = vim.tbl_map(function(file)
return {
filename = file,
lnum = 1,
text = file,
}
end, chosen_files),
})

-- open the quickfix window
vim.cmd('copen')
end,
yazi_opened = function() end,
yazi_closed_successfully = function() end,
yazi_opened_multiple_files = openers.send_files_to_quickfix_list,
},

floating_window_scaling_factor = 0.9,
yazi_floating_window_winblend = 0,
}
end

---@param yazi_buffer integer
---@param config YaziConfig
function M.default_set_keymappings_function(yazi_buffer, config)
vim.keymap.set({ 't' }, '<c-v>', function()
config.open_file_function = openers.open_file_in_vertical_split

-- select the current file in yazi and close it (enter is the default
-- keybinding for selecting a file)
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes('<enter>', true, false, true),
'n',
true
)
end, { buffer = yazi_buffer })
end

return M
29 changes: 29 additions & 0 deletions lua/yazi/openers.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
local M = {}

---@param chosen_file string
function M.open_file(chosen_file)
vim.cmd(string.format('edit %s', chosen_file))
end

function M.open_file_in_vertical_split(chosen_file)
vim.cmd(string.format('vsplit %s', chosen_file))
end

---@param chosen_files string[]
function M.send_files_to_quickfix_list(chosen_files)
vim.fn.setqflist({}, 'r', {
title = 'Yazi',
items = vim.tbl_map(function(file)
return {
filename = file,
lnum = 1,
text = file,
}
end, chosen_files),
})

-- open the quickfix window
vim.cmd('copen')
end

return M
9 changes: 5 additions & 4 deletions lua/yazi/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
---@field public open_for_directories? boolean
---@field public chosen_file_path? string "the path to a temporary file that will be created by yazi to store the chosen file path"
---@field public events_file_path? string "the path to a temporary file that will be created by yazi to store events"
---@field public open_file_function? fun(chosen_file: string): nil "a function that will be called when a file is chosen in yazi"
---@field public open_file_function? fun(chosen_file: string, config: YaziConfig): nil "a function that will be called when a file is chosen in yazi"
---@field public set_keymappings_function? fun(buffer: integer, config: YaziConfig): nil "the function that will set the keymappings for the yazi floating window. It will be called after the floating window is created."
---@field public hooks? YaziConfigHooks
---@field public floating_window_scaling_factor? float "the scaling factor for the floating window. 1 means 100%, 0.9 means 90%, etc."
---@field public yazi_floating_window_winblend? float "the transparency of the yazi floating window (0-100). See :h winblend"

---@class YaziConfigHooks
---@field public yazi_opened fun(preselected_path: string | nil): nil
---@field public yazi_closed_successfully fun(chosen_file: string | nil): nil
---@field public yazi_opened_multiple_files fun(chosen_files: string[]): nil
---@field public yazi_opened fun(preselected_path: string | nil, buffer: integer, config: YaziConfig):nil
---@field public yazi_closed_successfully fun(chosen_file: string | nil, config: YaziConfig): nil
---@field public yazi_opened_multiple_files fun(chosen_files: string[], config: YaziConfig): nil

---@alias YaziEvent YaziRenameEvent | YaziMoveEvent | YaziDeleteEvent | YaziTrashEvent

Expand Down
6 changes: 3 additions & 3 deletions lua/yazi/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ function M.on_yazi_exited(
local chosen_files = vim.fn.readfile(config.chosen_file_path)

if #chosen_files > 1 then
config.hooks.yazi_opened_multiple_files(chosen_files)
config.hooks.yazi_opened_multiple_files(chosen_files, config)
else
local chosen_file = chosen_files[1]
config.hooks.yazi_closed_successfully(chosen_file)
config.hooks.yazi_closed_successfully(chosen_file, config)
if chosen_file then
config.open_file_function(chosen_file)
config.open_file_function(chosen_file, config)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lua/yazi/window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local M = {}

--- open a floating window with nice borders
---@param config YaziConfig
---@return integer, integer
---@return integer, integer, integer
function M.open_floating_window(config)
local height = math.ceil(vim.o.lines * config.floating_window_scaling_factor)
- 1
Expand Down Expand Up @@ -66,7 +66,7 @@ function M.open_floating_window(config)
local cmd = [[autocmd WinLeave <buffer> silent! execute 'silent bdelete! %s']]
vim.cmd(cmd:format(border_buffer))

return win, border_window
return win, border_window, yazi_buffer
end

return M
29 changes: 20 additions & 9 deletions tests/yazi/yazi_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ describe('opening a file', function()
local exit_code = 0
vim.fn.writefile({ target_file }, '/tmp/yazi_filechosen')
callback.on_exit('job-id-ignored', exit_code, 'event-ignored')
return 0
end
end)

it('opens the file that the user selected in yazi', function()
plugin.yazi()
plugin.yazi({ set_keymappings_function = function() end })

assert.equals(target_file, vim.fn.expand('%'))
end)
Expand All @@ -68,44 +69,53 @@ describe('opening a file', function()
vim.api.nvim_command('edit /abc/test-file.txt')

plugin.yazi({
set_keymappings_function = function() end,
---@diagnostic disable-next-line: missing-fields
hooks = {
---@diagnostic disable-next-line: assign-type-mismatch
yazi_closed_successfully = spy_hook,
},
})

assert.spy(spy_hook).was_called_with('/abc/test-file.txt')
assert
.spy(spy_hook)
.was_called_with('/abc/test-file.txt', match.is_table())
end
)

it('calls the yazi_opened hook when yazi is opened', function()
local spy_hook = spy.new()
local spy_yazi_opened_hook = spy.new()

vim.api.nvim_command('edit /abc/yazi_opened_hook_file.txt')

plugin.yazi({
set_keymappings_function = function() end,
---@diagnostic disable-next-line: missing-fields
hooks = {
---@diagnostic disable-next-line: assign-type-mismatch
yazi_opened = spy_hook,
yazi_opened = spy_yazi_opened_hook,
},
})

assert.spy(spy_hook).was_called_with('/abc/yazi_opened_hook_file.txt')
assert
.spy(spy_yazi_opened_hook)
.was_called_with('/abc/yazi_opened_hook_file.txt', match.is_number(), match.is_table())
end)

it('calls the open_file_function to open the selected file', function()
local spy_hook = spy.new()
local spy_open_file_function = spy.new()

vim.api.nvim_command('edit /abc/test-file.txt')

plugin.yazi({
set_keymappings_function = function() end,
---@diagnostic disable-next-line: assign-type-mismatch
open_file_function = spy_hook,
open_file_function = spy_open_file_function,
})

assert.spy(spy_hook).was_called_with('/abc/test-file.txt')
assert
.spy(spy_open_file_function)
.was_called_with('/abc/test-file.txt', match.is_table())
end)
end)

Expand All @@ -130,6 +140,7 @@ describe('opening multiple files', function()
it('can open multiple files', function()
local spy_open_multiple_files = spy.new()
plugin.yazi({
set_keymappings_function = function() end,
---@diagnostic disable-next-line: missing-fields
hooks = {
---@diagnostic disable-next-line: assign-type-mismatch
Expand All @@ -141,6 +152,6 @@ describe('opening multiple files', function()
assert.spy(spy_open_multiple_files).was_called_with({
target_file_1,
target_file_2,
})
}, match.is_table())
end)
end)

0 comments on commit 1bb74ca

Please sign in to comment.