The aim of yanky.nvim
is to improve yank and put functionalities for Neovim.
French slogan:
"Vas-y Yanky, c'est bon !" - Yanky Vincent
Or in English:
"Yanky-ki-yay, motherf*cker" - John McYanky
- Yank-ring
- Yank history picker
- Highlight put and yanked text
- Perserve cursor position on yank
- Special put
Requires neovim > 0.7.0
.
Install the plugin with your preferred package manager:
-- Lua
use("gbprod/yanky.nvim")
require("yanky").setup({
-- your configuration comes here
-- or leave it empty to use the default settings
-- refer to the configuration section below
})
" Vim Script
Plug 'gbprod/yanky.nvim'
lua << EOF
require("yanky").setup({
-- your configuration comes here
-- or leave it empty to use the default settings
-- refer to the configuration section below
})
EOF
Yanky comes with the following defaults:
{
ring = {
history_length = 100,
storage = "shada",
sync_with_numbered_registers = true,
cancel_event = "update",
},
picker = {
select = {
action = nil, -- nil to use default put action
},
telescope = {
mappings = nil, -- nil to use default mappings
},
},
system_clipboard = {
sync_with_ring = true,
},
highlight = {
on_put = true,
on_yank = true,
timer = 500,
},
preserve_cursor_position = {
enabled = true,
},
}
This plugin contains no default mappings and will have no effect until you add your own maps to it. You should at least set those keymaps:
vim.keymap.set({"n","x"}, "p", "<Plug>(YankyPutAfter)")
vim.keymap.set({"n","x"}, "P", "<Plug>(YankyPutBefore)")
vim.keymap.set({"n","x"}, "gp", "<Plug>(YankyGPutAfter)")
vim.keymap.set({"n","x"}, "gP", "<Plug>(YankyGPutBefore)")
Some features requires specific mappings, refer to feature documentation section.
Yank-ring allows cycling throught yank history when putting text (like the Emacs "kill-ring" feature). Yanky automatically maintain a history of yanks that you can choose between when pasting.
vim.keymap.set("n", "<c-n>", "<Plug>(YankyCycleForward)")
vim.keymap.set("n", "<c-p>", "<Plug>(YankyCycleBackward)")
With these mappings, after performing a paste, you can cycle through the history
by hitting <c-n>
and <c-p>
. Any modifications done after pasting will cancel
the possibility to cycle.
Note that the swap operations above will only affect the current paste and the history will be unchanged.
require("yanky").setup({
ring = {
history_length = 100,
storage = "shada",
sync_with_numbered_registers = true,
cancel_event = "update",
},
system_clipboard = {
sync_with_ring = true,
},
})
Default : 100
Define the number of yanked items that will be saved and used for ring.
Default : shada
Available : shada
, sqlite
or memory
Define the storage mode for ring values.
Using shada
, this will save pesistantly using Neovim ShaDa feature. This means
that history will be persisted between each session of Neovim.
You can also use this feature to sync the yank history across multiple running instances
of Neovim by updating shada file. If you execute :wshada
in the first instance
and then :rshada
in the second instance, the second instance will be synced with
the yank history in the first instance.
Using memory
, each Neovim instance will have his own history and il will be
lost between sessions.
If you want to use sqlite
as storage, you must add kkharji/sqlite.lua
as dependency:
use({
"gbprod/yanky.nvim",
requires = { "kkharji/sqlite.lua" }
})
Sqlite is more reliable than ShaDa but requires more dependencies.
Default : true
History can also be synchronized with numbered registers. Every time the yank history changes the numbered registers 1 - 9 will be updated to sync with the first 9 entries in the yank history. See here for an explanation of why we would want do do this.
Default: update
Define the event used to cancel ring activation. update
will cancel ring on
next buffer update, move
will cancel ring when moving cursor or content
changed.
Default: true
Yanky can automatically adds to ring history yanks that occurs outside of Neovim.
This works regardless to your &clipboard
setting.
This means, if &clipboard
is set to unnamed
and/or unnamedplus
, if you yank
something outside of Neovim, you can put it immediatly using p
and it will be
added to your yank ring.
If &clipboard
is empty, if you yank something outside of Neovim, this will be
the first value you'll have when cycling through the ring. Basicly, you can do
p
and then <c-p>
to paste yanked text.
You can clear yank history using YankyClearHistory
command.
This allows you to select an entry in your recorded yank history using default
vim.ui.select
neovim prompt (you can use stevearc/dressing.nvim
to customize this) or the awesome telescope.nvim.
It uses the same history as yank ring, so, if you want to increase history size,
just use ring.history_length
option.
To use vim.ui.select
picker, just call YankyRingHistory
command.
To use the yank_history
Telescope picker, register yank_history
as a
Telescope extension in your Neovim config file.
:lua require("telescope").load_extension("yank_history")
After loading the extension, you can access the picker by running:
:Telescope yank_history
Or:
:lua require("telescope").extensions.yank_history.yank_history()
Set the Telescope option dynamic_preview_title
to true
if you want your Telescope preview window to have a
dynamic title showing the register's type.
Default configuration :
require("yanky").setup({
picker = {
select = {
action = nil, -- nil to use default put action
},
telescope = {
mappings = nil, -- nil to use default mappings
},
},
})
Default : nil
This define the action that should be done when selecting an item in the
vim.ui.select
prompt. If you let this option to nil
, this will use the
default action : put selected item after cursor.
Available actions:
require("yanky.picker").actions.put("p") -- put after cursor
require("yanky.picker").actions.put("P") -- put before cursor
require("yanky.picker").actions.put("gp") -- put after cursor and leave the cursor after
require("yanky.picker").actions.put("gP") -- put before cursor and leave the cursor after
require("yanky.picker").actions.delete() -- delete entry from yank history
require("yanky.picker").actions.set_register(regname) -- fill register with selected value
Default : nil
This define the mappings available in Telescope. If you let this option to nil
,
this will use the default mappings :
local utils = require("yanky.utils")
local mapping = require("yanky.telescope.mapping")
require("yanky").setup({
picker = {
telescope = {
mappings = {
default = mapping.put("p"),
i = {
["<c-p>"] = mapping.put("p"),
["<c-k>"] = mapping.put("P"),
["<c-x>"] = mapping.delete(),
["<c-r>"] = mapping.set_register(utils.get_default_register()),
},
n = {
p = mapping.put("p"),
P = mapping.put("P"),
d = mapping.delete(),
r = mapping.set_register(utils.get_default_register())
},
}
}
}
})
Available actions:
require("yanky.telescope.mapping").put("p") -- put after cursor
require("yanky.telescope.mapping").put("P") -- put before cursor
require("yanky.telescope.mapping").put("gp") -- put after cursor and leave the cursor after
require("yanky.telescope.mapping").put("gP") -- put before cursor and leave the cursor after
require("yanky.telescope.mapping").delete() -- delete entry from yank history
require("yanky.telescope.mapping").set_register(regname) -- fill register {regname} with selected value
You can also use any of available special puts like this:
require("yanky.telescope.mapping").special_put("{{ name of the special put }}")
-- eg.
require("yanky.telescope.mapping").special_put("YankyPutAfterCharwiseJoined")
This will give you a visual feedback on put and yank text by highlighting this.
### Configuration
require("yanky").setup({
highlight = {
on_put = true,
on_yank = true,
timer = 500,
},
})
You can override YankyPut
highlight to change colors.
Default : true
Define if highlight put text feature is enabled.
Default : true
Define if highlight yanked text feature is enabled.
Default : 500
Define the duration of highlight.
By default in Neovim, when yanking text, cursor moves to the start of the yanked text. Could be annoying especially when yanking a large text object such as a paragraph or a large text object.
With this feature, yank will function exactly the same as previously with the one difference being that the cursor position will not change after performing a yank.
vim.keymap.set({"n","x"}, "y", "<Plug>(YankyYank)")
require("yanky").setup({
preserve_cursor_position = {
enabled = true,
},
})
Default : true
Define if cursor position should be preserved on yank. This works only if mappings has been defined.
Description | Group | Default |
---|---|---|
Highlight color for put text | YankyPut | link to Search |
Highlight color for yanked text | YankyYanked | link to Search |
gbprod/substitute.nvim
To enable gbprod/substitute.nvim swap when performing a substitution, you can add this to your setup:
require("substitute").setup({
on_substitute = require("yanky.integration").substitute(),
})
anuvyklack/hydra.nvim
To work with anuvyklack/hydra.nvim only setup / mapping when yanky is activated, you can add this to your setup:
local Hydra = require("hydra")
local function t(str)
return api.nvim_replace_termcodes(str, true, true, true)
end
local yanky_hydra = Hydra({
name = "Yank ring",
mode = "n",
heads = {
{ "p", "<Plug>(YankyPutAfter)", { desc = "After" } },
{ "P", "<Plug>(YankyPutBefore)", { desc = "Before" } },
{ "<C-n>", "<Plug>(YankyCycleForward)", { private = true, desc = "↓" } },
{ "<C-p>", "<Plug>(YankyCycleBackward)", { private = true, desc = "↑" } },
},
})
-- choose/change the mappings if you want
for key, putAction in pairs({
["p"] = "<Plug>(YankyPutAfter)",
["P"] = "<Plug>(YankyPutBefore)",
["gp"] = "<Plug>(YankyGPutAfter)",
["gP"] = "<Plug>(YankyGPutBefore)",
}) do
vim.keymap.set({ "n", "x" }, key, function()
vim.fn.feedkeys(t(putAction))
yanky_hydra:activate()
end)
end
-- choose/change the mappings if you want
for key, putAction in pairs({
["]p"] = "<Plug>(YankyPutIndentAfterLinewise)",
["[p"] = "<Plug>(YankyPutIndentBeforeLinewise)",
["]P"] = "<Plug>(YankyPutIndentAfterLinewise)",
["[P"] = "<Plug>(YankyPutIndentBeforeLinewise)",
[">p"] = "<Plug>(YankyPutIndentAfterShiftRight)",
["<p"] = "<Plug>(YankyPutIndentAfterShiftLeft)",
[">P"] = "<Plug>(YankyPutIndentBeforeShiftRight)",
["<P"] = "<Plug>(YankyPutIndentBeforeShiftLeft)",
["=p"] = "<Plug>(YankyPutAfterFilter)",
["=P"] = "<Plug>(YankyPutBeforeFilter)",
}) do
vim.keymap.set("n", key, function()
vim.fn.feedkeys(t(putAction))
yanky_hydra:activate()
end)
end
Yanky comes with special put moves (inspired by tpope/vim-unimpaired):
- Linewise put: this will force put above or below the current line ;
- Shift right/left put: will put above or below the current line and increasing or decreasing indent ;
- Filter put: will put above or below the current line and reindenting.
For basic usage (like with tpope/vim-unimpaired), you can use those bindings:
vim.keymap.set("n", "]p", "<Plug>(YankyPutIndentAfterLinewise)")
vim.keymap.set("n", "[p", "<Plug>(YankyPutIndentBeforeLinewise)")
vim.keymap.set("n", "]P", "<Plug>(YankyPutIndentAfterLinewise)")
vim.keymap.set("n", "[P", "<Plug>(YankyPutIndentBeforeLinewise)")
vim.keymap.set("n", ">p", "<Plug>(YankyPutIndentAfterShiftRight)")
vim.keymap.set("n", "<p", "<Plug>(YankyPutIndentAfterShiftLeft)")
vim.keymap.set("n", ">P", "<Plug>(YankyPutIndentBeforeShiftRight)")
vim.keymap.set("n", "<P", "<Plug>(YankyPutIndentBeforeShiftLeft)")
vim.keymap.set("n", "=p", "<Plug>(YankyPutAfterFilter)")
vim.keymap.set("n", "=P", "<Plug>(YankyPutBeforeFilter)")
To go further, Plug mappings are constructed like this: Yanky(put-type)(modifier)(rewriter)
.
put-type
can be:
PutAfter
: put after your cursor (asp
key) ;PutBefore
: put before your cursor (asP
key) ;GPutAfter
: likePutAfter
but leave the cursor after the new text (asgp
key) ;GPutBefore
: likePutBefore
but leave the cursor after the new text (asgP
key) ;PutIndentAfter
: likePutAfter
but adjust the indent to the current line (as]p
key) ;PutIndentBefore
: likePutBefore
but adjust the indent to the current line (as[p
key) ;
modifier
(optional) can be:
Linewise
: put in linewise mode ;Charwise
: put in charwise mode ;Blockwise
: put in blockwise mode ;ShiftRight
: increase indent ;ShiftLeft
: decrease indent.
rewriter
(optional) can be:
Joined
: put lines trimed and joined.
All special puts
<Plug>(YankyPutAfter)
<Plug>(YankyPutAfterBlockwise)
<Plug>(YankyPutAfterBlockwiseJoined)
<Plug>(YankyPutAfterCharwise)
<Plug>(YankyPutAfterCharwiseJoined)
<Plug>(YankyPutAfterFilter)
<Plug>(YankyPutAfterFilterJoined)
<Plug>(YankyPutAfterJoined)
<Plug>(YankyPutAfterLinewise)
<Plug>(YankyPutAfterLinewiseJoined)
<Plug>(YankyPutAfterShiftLeft)
<Plug>(YankyPutAfterShiftLeftJoined)
<Plug>(YankyPutAfterShiftRight)
<Plug>(YankyPutAfterShiftRightJoined)
<Plug>(YankyPutBefore)
<Plug>(YankyPutBeforeBlockwise)
<Plug>(YankyPutBeforeBlockwiseJoined)
<Plug>(YankyPutBeforeCharwise)
<Plug>(YankyPutBeforeCharwiseJoined)
<Plug>(YankyPutBeforeFilter)
<Plug>(YankyPutBeforeFilterJoined)
<Plug>(YankyPutBeforeJoined)
<Plug>(YankyPutBeforeLinewise)
<Plug>(YankyPutBeforeLinewiseJoined)
<Plug>(YankyPutBeforeShiftLeft)
<Plug>(YankyPutBeforeShiftLeftJoined)
<Plug>(YankyPutBeforeShiftRight)
<Plug>(YankyPutBeforeShiftRightJoined)
<Plug>(YankyGPutAfter)
<Plug>(YankyGPutAfterBlockwise)
<Plug>(YankyGPutAfterBlockwiseJoined)
<Plug>(YankyGPutAfterCharwise)
<Plug>(YankyGPutAfterCharwiseJoined)
<Plug>(YankyGPutAfterFilter)
<Plug>(YankyGPutAfterFilterJoined)
<Plug>(YankyGPutAfterJoined)
<Plug>(YankyGPutAfterLinewise)
<Plug>(YankyGPutAfterLinewiseJoined)
<Plug>(YankyGPutAfterShiftLeft)
<Plug>(YankyGPutAfterShiftLeftJoined)
<Plug>(YankyGPutAfterShiftRight)
<Plug>(YankyGPutAfterShiftRightJoined)
<Plug>(YankyGPutBefore)
<Plug>(YankyGPutBeforeBlockwise)
<Plug>(YankyGPutBeforeBlockwiseJoined)
<Plug>(YankyGPutBeforeCharwise)
<Plug>(YankyGPutBeforeCharwiseJoined)
<Plug>(YankyGPutBeforeFilter)
<Plug>(YankyGPutBeforeFilterJoined)
<Plug>(YankyGPutBeforeJoined)
<Plug>(YankyGPutBeforeLinewise)
<Plug>(YankyGPutBeforeLinewiseJoined)
<Plug>(YankyGPutBeforeShiftLeft)
<Plug>(YankyGPutBeforeShiftLeftJoined)
<Plug>(YankyGPutBeforeShiftRight)
<Plug>(YankyGPutBeforeShiftRightJoined)
<Plug>(YankyPutIndentAfter)
<Plug>(YankyPutIndentAfterBlockwise)
<Plug>(YankyPutIndentAfterBlockwiseJoined)
<Plug>(YankyPutIndentAfterCharwise)
<Plug>(YankyPutIndentAfterCharwiseJoined)
<Plug>(YankyPutIndentAfterFilter)
<Plug>(YankyPutIndentAfterFilterJoined)
<Plug>(YankyPutIndentAfterJoined)
<Plug>(YankyPutIndentAfterLinewise)
<Plug>(YankyPutIndentAfterLinewiseJoined)
<Plug>(YankyPutIndentAfterShiftLeft)
<Plug>(YankyPutIndentAfterShiftLeftJoined)
<Plug>(YankyPutIndentAfterShiftRight)
<Plug>(YankyPutIndentAfterShiftRightJoined)
<Plug>(YankyPutIndentBefore)
<Plug>(YankyPutIndentBeforeBlockwise)
<Plug>(YankyPutIndentBeforeBlockwiseJoined)
<Plug>(YankyPutIndentBeforeCharwise)
<Plug>(YankyPutIndentBeforeCharwiseJoined)
<Plug>(YankyPutIndentBeforeFilter)
<Plug>(YankyPutIndentBeforeFilterJoined)
<Plug>(YankyPutIndentBeforeJoined)
<Plug>(YankyPutIndentBeforeLinewise)
<Plug>(YankyPutIndentBeforeLinewiseJoined)
<Plug>(YankyPutIndentBeforeShiftLeft)
<Plug>(YankyPutIndentBeforeShiftLeftJoined)
<Plug>(YankyPutIndentBeforeShiftRight)
<Plug>(YankyPutIndentBeforeShiftRightJoined)
This plugin is mostly a lua version of svermeulen/vim-yoink awesome plugin.
Other inspiration :
- bfredl/nvim-miniyank
- maxbrunsfeld/vim-yankstack
- svermeulen/vim-easyclip
- bkoropoff/yankee.vim
- svban/YankAssassin.vim
- tpope/vim-unimpaired
- tpope/vim-unimpaired
- inkarkat/vim-UnconditionalPaste
Thanks to m00qek lua plugin template.