
It’s possible to configure Vim or Neovim in a way that default commands like yank or delete would use the system clipboard. However, my preference is to have separate registers. The reason is that I don’t want to replace the system buffer when yanking or deleting. Furthermore, I would like to use CMD + C and CMD + V for Vim inside WezTerm. However, WezTerm catches these combinations, and it’s impossible to configure such keys inside Vim. However, I have found the solution. Let’s dive into it.
How can we achieve that?
The idea is as simple as possible. We would create a handler inside WezTerm. In case CMD+C is pressed, we use the default behavior. However, if there is a running Vim or Neovim, we pass a special command. I decided to use <leader> + y for CMD + C and <leader> + p for CMD + V. You can use your own commands here.
WezTerm code
The first step is editing the WezTerm code. Edit ~/.wezterm with your favorite editor; I hope it’s NeoVim. If you don’t have a config at all or you aren’t familiar with it, then I will show you a simple one.
-- Pull in the wezterm API local wezterm = require 'wezterm' -- This will hold the configuration. local config = wezterm.config_builder() -- This would not work, just for example config.some_property = 123 return config
As you can see, creating a config is simple. Now add the following code to create custom actions/events before the final return statement.
-- Make CMD+C and CMD+V work in Vim by using Vim bindings
wezterm.on("copy_or_send_leader_y", function(window, pane)
local process_name = pane:get_foreground_process_name() or ""
if process_name:match("vim") or process_name:match("nvim") then
window:perform_action(wezterm.action.SendKey({ key = "\\" }), pane) -- Leader key
window:perform_action(wezterm.action.SendKey({ key = "y" }), pane) -- 'y' key
else
window:perform_action(wezterm.action.CopyTo("Clipboard"), pane)
end
end)
wezterm.on("paste_or_send_leader_p", function(window, pane)
local process_name = pane:get_foreground_process_name() or ""
if process_name:match("vim") or process_name:match("nvim") then
window:perform_action(wezterm.action.SendKey({ key = "\\" }), pane) -- Leader key
window:perform_action(wezterm.action.SendKey({ key = "p" }), pane) -- 'p' key
else
window:perform_action(wezterm.action.PasteFrom("Clipboard"), pane)
end
end)
Please make sure you specify your own leader key. I use backslash for that. You might have a different one.
Now we have the logic. However, we should remap CMD + C and CMD + V default behavior. We can do it by configuring the keys property of the config.
config.keys = {
{
key = "c",
mods = "CMD",
action = wezterm.action.EmitEvent("copy_or_send_leader_y"),
},
{
key = "v",
mods = "CMD",
action = wezterm.action.EmitEvent("paste_or_send_leader_p"),
},
}
By this code, we remap behavior from default to our actions. That’s it. How are we ready to configure Vim?
Configuring Vim
I’ll show how to do that using my NeoVim configuration as an example. If you use Vim, you will probably need to do that not in Lua. Anyway, you can just get a general idea. It should be enough. Here is my version.
-- Yank to system clipboard
vim.keymap.set({'n','v'}, '<leader>y', '"+y', { noremap = true, desc = "Yank to clipboard" })
vim.keymap.set('n', '<leader>Y', '"+Y', { noremap = true, desc = "Yank line to clipboard" })
-- Delete to system clipboard
vim.keymap.set({'n','v'}, '<leader>d', '"+d', { noremap = true, desc = "Delete to clipboard" })
vim.keymap.set('n', '<leader>D', '"+D', { noremap = true, desc = "Delete line to clipboard" })
-- Paste from system clipboard
vim.keymap.set({'n','v'}, '<leader>p', '"+p', { noremap = true, desc = "Paste from clipboard" })
-- Past in insert mode. Prevent auto indent or comments while pasting a multiline block.
vim.keymap.set({'i'}, '<leader>p', '<C-o>:set paste<CR><C-r>+<C-o>:set nopaste<CR>', { noremap = true, desc = "Paste from clipboard" })
I guess we need some explanation here. So, inside NeoVim, I bind <leader> + y to copy into the buffer. However, as you remember, WezTerm would send this combination if Vim or NeoVim was detected. The insert mode is a little tricky; however, the same approach works here too.
Bonus: Dynamic Leader Key
As you can notice, we have hardcoded the leader key inside WezTerm. That means if we decide to change <leader>, we need to do that in two places. This situation is absolutely uncommon, but nonetheless, it’s better to fix that. Let’s start with a simple thing: I moved my leader key config into a separate file first.

What’s next? Your assumption is probably the right one. Now we can read this file from WezTerm and detect the leader key. First, let’s make a function to check whether the file exists or not.
-- Helper function to check if a file exists
local function file_exists(name)
local f = io.open(name, "r")
if f then
f:close()
return true
else
return false
end
end
Then we can specify default values and try to load the real one.
-- Default leader key value (e.g., backslash)
local vim_leader_key = "\\"
-- Define the path to your custom leader key config file.
local leader_config_file = os.getenv("HOME") .. "/.config/nvim/lua/config/leader.lua"
-- Check if the file exists
if file_exists(leader_config_file) then
-- Use pcall with dofile to safely load the file.
-- It is assumed that the file returns a table with a key `vim_leader_key`
local ok, config = pcall(dofile, leader_config_file)
if ok and config and config.vim_leader_key then
vim_leader_key = config.vim_leader_key
end
end
And now we can finally update our configuration for custom actions.
-- Now use vim_leader_key in your event handlers
wezterm.on("copy_or_send_leader_y", function(window, pane)
local process_name = pane:get_foreground_process_name() or ""
if process_name:match("vim") or process_name:match("nvim") then
window:perform_action(wezterm.action.SendKey({ key = vim_leader_key }), pane)
window:perform_action(wezterm.action.SendKey({ key = "y" }), pane)
else
window:perform_action(wezterm.action.CopyTo("Clipboard"), pane)
end
end)
wezterm.on("paste_or_send_leader_p", function(window, pane)
local process_name = pane:get_foreground_process_name() or ""
if process_name:match("vim") or process_name:match("nvim") then
window:perform_action(wezterm.action.SendKey({ key = vim_leader_key }), pane)
window:perform_action(wezterm.action.SendKey({ key = "p" }), pane)
else
window:perform_action(wezterm.action.PasteFrom("Clipboard"), pane)
end
end)
Final
As far as I can see, there is nothing complex with “CMD + C and CMD + V for Vim inside WezTerm”. It’s quite fun to code in Lua. However, if you have questions, don’t hesitate to ask them. If case you need links, here you go WezTerm, Vim, Neovim.

Comment section