Skip to content

Commit

Permalink
feat!: allow customizing keymaps more clearly (#244)
Browse files Browse the repository at this point in the history
* feat!: allow customizing keymaps more clearly

This adds a new configuration option `keymaps` that can be used to
customize the keybindings that are active when yazi is open and focused.
You might want to do this if you have a _yazi_ keymap that conflicts with
a yazi.nvim keymap, or if you just prefer different keybindings.

If you have your lua LSP server setup, you can now get nice
autocompletion for all of the available keymaps.

The current defaults have not changed, and are as follows:

```lua
keymaps = {
  open_file_in_vertical_split = '<c-v>',
  open_file_in_horizontal_split = '<c-x>',
  open_file_in_tab = '<c-t>',
  grep_in_directory = '<c-s>',
  cycle_open_buffers = '<tab>',
},
```

BREAKING CHANGE: If you, for some reason, relied on the fact that
`set_keymappings_function` removed all the built-in keymappings, you
will need to change your configuration. You can get the same behaviour
by setting `keymaps = false`. But realistically I think almost nobody
has done this, so it should be fine.

* fixup! feat!: allow customizing keymaps more clearly

* fixup! feat!: allow customizing keymaps more clearly
  • Loading branch information
mikavilpas authored Jul 23, 2024
1 parent c3974f7 commit f511e64
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 61 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ open yazi in a floating window in Neovim.
- The files are also kept in sync with currently running LSP servers
- Customizable keybindings
- 🆕 Plugin management for Yazi plugins and flavors
([documentation](./documentation/plugin-manager.md)). Please provide your
([documentation](./documentation/plugin-management.md)). Please provide your
feedback!
- Features available if you are using a development version of yazi (see
[installing-yazi-from-source.md](documentation/installing-yazi-from-source.md)):
Expand Down Expand Up @@ -176,11 +176,23 @@ You can optionally configure yazi.nvim by setting any of the options below.

-- what Neovim should do a when a file was opened (selected) in yazi.
-- Defaults to simply opening the file.
open_file_function = function(chosen_file, config) end,
open_file_function = function(chosen_file, config, state) end,

-- customize the keymaps that are active when yazi is open and focused. The
-- defaults are listed below. Also:
-- - use e.g. `open_file_in_tab = false` to disable a keymap
-- - you can customize only some of the keymaps if you want
keymaps = {
open_file_in_vertical_split = '<c-v>',
open_file_in_horizontal_split = '<c-x>',
open_file_in_tab = '<c-t>',
grep_in_directory = '<c-s>',
cycle_open_buffers = '<tab>',
},

-- 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,
set_keymappings_function = function(yazi_buffer_id, config, context) end,

-- the type of border to use for the floating window. Can be many values,
-- including 'none', 'rounded', 'single', 'double', 'shadow', etc. For
Expand All @@ -196,7 +208,7 @@ You can optionally configure yazi.nvim by setting any of the options below.
end,

-- when yazi was successfully closed
yazi_closed_successfully = function(chosen_file, config) end,
yazi_closed_successfully = function(chosen_file, config, state) 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
Expand Down
7 changes: 4 additions & 3 deletions integration-tests/test-environment/test-setup.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ end

-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not (vim.uv or vim.loop).fs_stat(lazypath) then
if not (vim.uv).fs_stat(lazypath) then
local lazyrepo = 'https://github.com/folke/lazy.nvim.git'
vim.fn.system({
'git',
'clone',
'--filter=blob:none',
'--branch=stable',
'--branch=v11.12.0',
lazyrepo,
lazypath,
})
Expand All @@ -42,8 +42,9 @@ vim.o.swapfile = false
---@type LazySpec
local plugins = {
{
'mikavilpas/yazi.nvim',
-- for tests, always use the code from this repository
dir = '../../',
dir = '../..',
event = 'VeryLazy',
keys = {
{
Expand Down
18 changes: 14 additions & 4 deletions lua/yazi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,20 @@ function M.yazi(config, input_path)

config.hooks.yazi_opened(path.filename, win.content_buffer, config)

config.set_keymappings_function(win.content_buffer, config, {
api = yazi_process.api,
input_path = path,
})
local yazi_buffer = win.content_buffer
if config.set_keymappings_function ~= nil then
config.set_keymappings_function(yazi_buffer, config, {
api = yazi_process.api,
input_path = path,
})
end

if config.keymaps ~= false then
require('yazi.config').set_keymappings(yazi_buffer, config, {
api = yazi_process.api,
input_path = path,
})
end

win.on_resized = function(event)
vim.fn.jobresize(
Expand Down
123 changes: 77 additions & 46 deletions lua/yazi/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ function M.default()
use_yazi_client_id_flag = false,
enable_mouse_support = false,
open_file_function = openers.open_file,
set_keymappings_function = M.default_set_keymappings_function,
keymaps = {
open_file_in_vertical_split = '<c-v>',
open_file_in_horizontal_split = '<c-x>',
open_file_in_tab = '<c-t>',
grep_in_directory = '<c-s>',
cycle_open_buffers = '<tab>',
},
set_keymappings_function = nil,
hooks = {
yazi_opened = function() end,
yazi_closed_successfully = function() end,
Expand All @@ -42,56 +49,80 @@ function M.default()
}
end

--- This sets the default keymappings for yazi. If you want to use your own
--- keymappings, you can set the set_keymappings_function in your config. Copy
--- this function as the basis.
---@param yazi_buffer integer
---@param config YaziConfig
---@param context YaziActiveContext
function M.default_set_keymappings_function(yazi_buffer, config, context)
vim.keymap.set({ 't' }, '<c-v>', function()
keybinding_helpers.open_file_in_vertical_split(config)
end, { buffer = yazi_buffer })
vim.keymap.set('t', '<esc>', '<esc>', { buffer = yazi_buffer })

-- LazyVim sets <esc><esc> to forcibly enter normal mode. This has been
-- confusing for some users. Let's disable it when using yazi.nvim only.
vim.keymap.set({ 't' }, '<esc><esc>', '<Nop>', { buffer = yazi_buffer })

vim.keymap.set({ 't' }, '<c-x>', function()
keybinding_helpers.open_file_in_horizontal_split(config)
end, { buffer = yazi_buffer })

vim.keymap.set({ 't' }, '<c-t>', function()
keybinding_helpers.open_file_in_tab(config)
end, { buffer = yazi_buffer })

vim.keymap.set({ 't' }, '<c-s>', function()
keybinding_helpers.select_current_file_and_close_yazi(config, {
on_file_opened = function(_, _, state)
if config.integrations.grep_in_directory == nil then
return
end

local success, result_or_error = pcall(
config.integrations.grep_in_directory,
state.last_directory.filename
)

if not success then
local message = 'yazi.nvim: error searching with telescope.'
vim.notify(message, vim.log.levels.WARN)
require('yazi.log'):debug(
vim.inspect({ message = message, error = result_or_error })
)
end
function M.set_keymappings(yazi_buffer, config, context)
if config.keymaps == false then
return
end

if config.keymaps.open_file_in_vertical_split ~= false then
vim.keymap.set(
{ 't' },
config.keymaps.open_file_in_vertical_split,
function()
keybinding_helpers.open_file_in_vertical_split(config)
end,
})
end, { buffer = yazi_buffer })
{ buffer = yazi_buffer }
)
end

if config.keymaps.open_file_in_horizontal_split ~= false then
vim.keymap.set(
{ 't' },
config.keymaps.open_file_in_horizontal_split,
function()
keybinding_helpers.open_file_in_horizontal_split(config)
end,
{ buffer = yazi_buffer }
)
end

if config.keymaps.grep_in_directory ~= false then
vim.keymap.set({ 't' }, config.keymaps.grep_in_directory, function()
keybinding_helpers.select_current_file_and_close_yazi(config, {
on_file_opened = function(_, _, state)
if config.integrations.grep_in_directory == nil then
return
end

local success, result_or_error = pcall(
config.integrations.grep_in_directory,
state.last_directory.filename
)

vim.keymap.set({ 't' }, '<tab>', function()
keybinding_helpers.cycle_open_buffers(context)
end, { buffer = yazi_buffer })
if not success then
local message = 'yazi.nvim: error searching with telescope.'
vim.notify(message, vim.log.levels.WARN)
require('yazi.log'):debug(
vim.inspect({ message = message, error = result_or_error })
)
end
end,
})
end, { buffer = yazi_buffer })
end

if config.keymaps.open_file_in_tab ~= false then
vim.keymap.set({ 't' }, config.keymaps.open_file_in_tab, function()
keybinding_helpers.open_file_in_tab(config)
end, { buffer = yazi_buffer })
end

if config.keymaps.cycle_open_buffers ~= false then
vim.keymap.set({ 't' }, config.keymaps.cycle_open_buffers, function()
keybinding_helpers.cycle_open_buffers(context)
end, { buffer = yazi_buffer })
end
end

---@param yazi_buffer integer
---@param config YaziConfig
---@param context YaziActiveContext
---@deprecated Prefer using `keymaps` in the config instead of this function. It's a clearer way of doing the exact same thing.
function M.default_set_keymappings_function(yazi_buffer, config, context)
return M.set_keymappings(yazi_buffer, config, context)
end

return M
12 changes: 11 additions & 1 deletion lua/yazi/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
---@field public use_yazi_client_id_flag? boolean "use the `--client-id` flag with yazi, allowing communication with that specific instance as opposed to all yazis on the system"
---@field public enable_mouse_support? boolean
---@field public open_file_function? fun(chosen_file: string, config: YaziConfig, state: YaziClosedState): nil "a function that will be called when a file is chosen in yazi"
---@field public set_keymappings_function? fun(buffer: integer, config: YaziConfig, context: YaziActiveContext): 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 keymaps? YaziKeymaps | false # The keymaps that are available when yazi is open and focused. Set to `false` to disable all default keymaps.
---@field public set_keymappings_function? fun(buffer: integer, config: YaziConfig, context: YaziActiveContext): nil # Can be used to create new, custom keybindings. In most cases it's recommended to use `keymaps` to customize the keybindings that come with yazi.nvim
---@field public hooks? YaziConfigHooks
---@field public highlight_groups? YaziConfigHighlightGroups
---@field public integrations? YaziConfigIntegrations
Expand All @@ -19,6 +20,15 @@
---@field public yazi_floating_window_border? any "the type of border to use. See nvim_open_win() for the values your neovim version supports"
---@field public log_level? yazi.LogLevel

---@alias YaziKeymap string | false # `string` is a keybinding such as "<c-tab>", false means the keybinding is disabled

---@class YaziKeymaps # The keybindings that are set by yazi, and can be overridden by the user. Will be set to a default value if not given explicitly
---@field open_file_in_vertical_split? YaziKeymap # When a file is hovered, open it in a vertical split
---@field open_file_in_horizontal_split? YaziKeymap # When a file is hovered, open it in a horizontal split
---@field open_file_in_tab? YaziKeymap # When a file is hovered, open it in a new tab
---@field grep_in_directory? YaziKeymap # Close yazi and open a grep (default: telescope) narrowed to the directory yazi is in
---@field cycle_open_buffers? YaziKeymap # When Neovim has multiple splits open and visible, make yazi jump to the directory of the next one

---@class (exact) YaziActiveContext # context state for a single yazi session
---@field api YaziProcessApi
---@field input_path Path the path that is first selected by yazi when it's opened
Expand Down
5 changes: 5 additions & 0 deletions lua/yazi/window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ function YaziFloatingWindow:open_and_display()
end,
})

-- LazyVim sets <esc><esc> to forcibly enter normal mode. This has been
-- confusing for some users. Let's disable it when using yazi.nvim only.
vim.keymap.set('t', '<esc>', '<esc>', { buffer = yazi_buffer })
vim.keymap.set({ 't' }, '<esc><esc>', '<Nop>', { buffer = yazi_buffer })

return self
end

Expand Down
6 changes: 3 additions & 3 deletions spec/yazi/yazi_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ describe('opening a file', function()
mock.revert(fake_yazi_process)
package.loaded['yazi.process.yazi_process'] = mock(fake_yazi_process)
plugin.setup({
-- set_keymappings_function can only work with a real yazi process
set_keymappings_function = function() end,
-- keymaps can only work with a real yazi process
keymaps = false,
})
end)

Expand All @@ -34,7 +34,7 @@ describe('opening a file', function()
assert.equals(file, path.filename)
end

it('#focus opens yazi with the current file selected', function()
it('opens yazi with the current file selected', function()
fake_yazi_process.setup_created_instances_to_instantly_exit({})

-- the file name should have a space as well as special characters, in order to test that
Expand Down

0 comments on commit f511e64

Please sign in to comment.