···5---@return table
6function M.get_entry(i)
7 return {
8- yank_text = YANKS[i],
9- reg_type = REG_TYPES[i],
10 }
11end
12···14---@return table
15function M.get_all()
16 local out = {}
17- for i, v in ipairs(YANKS) do
18 table.insert(out, {
19 yank_text = v,
20- reg_type = REG_TYPES[i],
21 })
22 end
23 return out
···33--- remove entry from yankbank by index
34---@param i integer index to remove
35function M.remove_entry(i)
36- local yank_text = table.remove(YANKS, i)
37- table.remove(REG_TYPES, i)
38- if OPTS.persist_type == "sqlite" then
39 require("yankbank.persistence.sql").data().remove_match(yank_text)
40 end
41end
···5---@return table
6function M.get_entry(i)
7 return {
8+ yank_text = YB_YANKS[i],
9+ reg_type = YB_REG_TYPES[i],
10 }
11end
12···14---@return table
15function M.get_all()
16 local out = {}
17+ for i, v in ipairs(YB_YANKS) do
18 table.insert(out, {
19 yank_text = v,
20+ reg_type = YB_REG_TYPES[i],
21 })
22 end
23 return out
···33--- remove entry from yankbank by index
34---@param i integer index to remove
35function M.remove_entry(i)
36+ local yank_text = table.remove(YB_YANKS, i)
37+ table.remove(YB_REG_TYPES, i)
38+ if YB_OPTS.persist_type == "sqlite" then
39 require("yankbank.persistence.sql").data().remove_match(yank_text)
40 end
41end
+9-9
lua/yankbank/clipboard.lua
···13 end
1415 -- check for duplicate values already inserted
16- for i, entry in ipairs(YANKS) do
17 if entry == text then
18 -- remove matched entry so it can be inserted at 1st position
19- table.remove(YANKS, i)
20- table.remove(REG_TYPES, i)
21 break
22 end
23 end
2425 -- add entry to bank
26- table.insert(YANKS, 1, text)
27- table.insert(REG_TYPES, 1, reg_type)
2829 -- trim table size if necessary
30- if #YANKS > OPTS.max_entries then
31- table.remove(YANKS)
32- table.remove(REG_TYPES)
33 end
3435 -- add entry to persistent store
···62 })
6364 -- poll registers when vim is focused (check for new clipboard activity)
65- if OPTS.focus_gain_poll == true then
66 vim.api.nvim_create_autocmd("FocusGained", {
67 callback = function()
68 -- get register information
···13 end
1415 -- check for duplicate values already inserted
16+ for i, entry in ipairs(YB_YANKS) do
17 if entry == text then
18 -- remove matched entry so it can be inserted at 1st position
19+ table.remove(YB_YANKS, i)
20+ table.remove(YB_REG_TYPES, i)
21 break
22 end
23 end
2425 -- add entry to bank
26+ table.insert(YB_YANKS, 1, text)
27+ table.insert(YB_REG_TYPES, 1, reg_type)
2829 -- trim table size if necessary
30+ if #YB_YANKS > YB_OPTS.max_entries then
31+ table.remove(YB_YANKS)
32+ table.remove(YB_REG_TYPES)
33 end
3435 -- add entry to persistent store
···62 })
6364 -- poll registers when vim is focused (check for new clipboard activity)
65+ if YB_OPTS.focus_gain_poll == true then
66 vim.api.nvim_create_autocmd("FocusGained", {
67 callback = function()
68 -- get register information
+5-5
lua/yankbank/data.lua
···8 local yank_num = 0
910 -- calculate the maximum width needed for the yank numbers
11- local max_digits = #tostring(#YANKS)
1213 -- assumes yanks is table of strings
14- for i, yank in ipairs(YANKS) do
15 yank_num = yank_num + 1
1617 local yank_lines = yank
···48 table.insert(line_yank_map, i)
49 end
5051- if i < #YANKS then
52 -- Add a visual separator between yanks, aligned with the yank content
53- if OPTS.sep ~= "" then
54 table.insert(
55 display_lines,
56- string.rep(" ", max_digits + 2) .. OPTS.sep
57 )
58 end
59 table.insert(line_yank_map, false)
···8 local yank_num = 0
910 -- calculate the maximum width needed for the yank numbers
11+ local max_digits = #tostring(#YB_YANKS)
1213 -- assumes yanks is table of strings
14+ for i, yank in ipairs(YB_YANKS) do
15 yank_num = yank_num + 1
1617 local yank_lines = yank
···48 table.insert(line_yank_map, i)
49 end
5051+ if i < #YB_YANKS then
52 -- Add a visual separator between yanks, aligned with the yank content
53+ if YB_OPTS.sep ~= "" then
54 table.insert(
55 display_lines,
56+ string.rep(" ", max_digits + 2) .. YB_OPTS.sep
57 )
58 end
59 table.insert(line_yank_map, false)
+4-3
lua/yankbank/helpers.lua
···43 vim.api.nvim_win_set_cursor(0, { 1, 0 })
44end
4546---- customized paste function that functions like 'p'
47---@param text string|table
48---@param reg_type string
49-function M.smart_paste(text, reg_type)
050 local lines = {}
51 if type(text) == "string" then
52 -- convert text string to string list
···61 lines = text
62 end
6364- vim.api.nvim_put(lines, reg_type, true, true)
65end
6667return M
···43 vim.api.nvim_win_set_cursor(0, { 1, 0 })
44end
4546+--- customized paste function that functions like 'p' or 'P'
47---@param text string|table
48---@param reg_type string
49+---@param after boolean define if text should be pasted after 'p' or before 'P'
50+function M.smart_paste(text, reg_type, after)
51 local lines = {}
52 if type(text) == "string" then
53 -- convert text string to string list
···62 lines = text
63 end
6465+ vim.api.nvim_put(lines, reg_type, after, true)
66end
6768return M
+8-7
lua/yankbank/init.lua
···1local M = {}
2000003-- local imports
4local menu = require("yankbank.menu")
5local clipboard = require("yankbank.clipboard")
6local persistence = require("yankbank.persistence")
78-YANKS = {}
9-REG_TYPES = {}
10-OPTS = {}
11-12-- default plugin options
13local default_opts = {
14 max_entries = 10,
···2425--- wrapper function for main plugin functionality
26local function show_yank_bank()
27- YANKS = persistence.get_yanks() or YANKS
2829 -- initialize buffer and populate bank
30 local buf_data = menu.create_and_fill_buffer()
···43---@param opts? table
44function M.setup(opts)
45 -- merge opts with default options table
46- OPTS = vim.tbl_deep_extend("keep", opts or {}, default_opts)
4748 -- enable persistence based on opts (needs to be called before autocmd setup)
49- YANKS, REG_TYPES = persistence.setup()
5051 -- create clipboard autocmds
52 clipboard.setup_yank_autocmd()
···1local M = {}
23+-- define global variables
4+YB_YANKS = {}
5+YB_REG_TYPES = {}
6+YB_OPTS = {}
7+8-- local imports
9local menu = require("yankbank.menu")
10local clipboard = require("yankbank.clipboard")
11local persistence = require("yankbank.persistence")
12000013-- default plugin options
14local default_opts = {
15 max_entries = 10,
···2526--- wrapper function for main plugin functionality
27local function show_yank_bank()
28+ YB_YANKS = persistence.get_yanks() or YB_YANKS
2930 -- initialize buffer and populate bank
31 local buf_data = menu.create_and_fill_buffer()
···44---@param opts? table
45function M.setup(opts)
46 -- merge opts with default options table
47+ YB_OPTS = vim.tbl_deep_extend("keep", opts or {}, default_opts)
4849 -- enable persistence based on opts (needs to be called before autocmd setup)
50+ YB_YANKS, YB_REG_TYPES = persistence.setup()
5152 -- create clipboard autocmds
53 clipboard.setup_yank_autocmd()
+44-26
lua/yankbank/menu.lua
···8 navigation_next = "j",
9 navigation_prev = "k",
10 paste = "<CR>",
011 yank = "yy",
12 close = { "<Esc>", "<C-c>", "q" },
13}
···17 yank_register = "+",
18}
19000000000020--- Container class for YankBank buffer related variables
21---@class YankBankBufData
22---@field bufnr integer
···28---@return YankBankBufData?
29function M.create_and_fill_buffer()
30 -- stop if yanks or register types table is empty
31- if #YANKS == 0 or #REG_TYPES == 0 then
32 print("No yanks to show.")
33 return nil
34 end
···105 -- key mappings for selection and closing the popup
106 local map_opts = { noremap = true, silent = true, buffer = b.bufnr }
107108- -- merge default and options keymap tables
109- local k = vim.tbl_deep_extend("force", default_keymaps, OPTS.keymaps or {})
110-111- -- merge default and options keymap tables
112- OPTS.registers =
113- vim.tbl_deep_extend("force", default_registers, OPTS.registers or {})
114-115- -- check table for number behavior option (prefix or jump, default to prefix)
116- OPTS.num_behavior = OPTS.num_behavior or "prefix"
117-118 -- popup buffer navigation binds
119- if OPTS.num_behavior == "prefix" then
120 vim.keymap.set("n", k.navigation_next, function()
121 local count = vim.v.count1 > 0 and vim.v.count1 or 1
122 helpers.next_numbered_item(count)
···126 local count = vim.v.count1 > 0 and vim.v.count1 or 1
127 helpers.prev_numbered_item(count)
128 return ""
129- end, { noremap = true, silent = true, buffer = b.bufnr })
130 else
131 vim.keymap.set(
132 "n",
133 k.navigation_next,
134 helpers.next_numbered_item,
135- { noremap = true, silent = true, buffer = b.bufnr }
136 )
137 vim.keymap.set(
138 "n",
139 k.navigation_prev,
140 helpers.prev_numbered_item,
141- { noremap = true, silent = true, buffer = b.bufnr }
142 )
143 end
144145- -- Map number keys to jump to entry if num_behavior is 'jump'
146- if OPTS.num_behavior == "jump" then
147- for i = 1, OPTS.max_entries do
148 vim.keymap.set("n", tostring(i), function()
149 local target_line = nil
150 for line_num, yank_num in pairs(b.line_yank_map) do
···166 -- use the mapping to find the original yank
167 local yankIndex = b.line_yank_map[cursor]
168 if yankIndex then
169- -- retrieve the full yank, including all lines
170- local text = YANKS[yankIndex]
171-00000000000000172 -- close window upon selection
173 vim.api.nvim_win_close(b.win_id, true)
174- helpers.smart_paste(text, REG_TYPES[yankIndex])
0000175 else
176 print("Error: Invalid selection")
177 end
178- end, { buffer = b.bufnr })
179180 -- bind yank behavior
181 vim.keymap.set("n", k.yank, function()
182 local cursor = vim.api.nvim_win_get_cursor(b.win_id)[1]
183 local yankIndex = b.line_yank_map[cursor]
184 if yankIndex then
185- local text = YANKS[yankIndex]
186- vim.fn.setreg(OPTS.registers.yank_register, text)
187 vim.api.nvim_win_close(b.win_id, true)
188 end
189- end, { buffer = b.bufnr })
190191 -- close popup keybinds
192 -- REFACTOR: check if close keybind is string, handle differently
···8 navigation_next = "j",
9 navigation_prev = "k",
10 paste = "<CR>",
11+ paste_back = "P",
12 yank = "yy",
13 close = { "<Esc>", "<C-c>", "q" },
14}
···18 yank_register = "+",
19}
2021+-- merge default and options keymap tables
22+local k = vim.tbl_deep_extend("force", default_keymaps, YB_OPTS.keymaps or {})
23+24+-- merge default and options register tables
25+YB_OPTS.registers =
26+ vim.tbl_deep_extend("force", default_registers, YB_OPTS.registers or {})
27+28+-- check table for number behavior option (prefix or jump, default to prefix)
29+YB_OPTS.num_behavior = YB_OPTS.num_behavior or "prefix"
30+31--- Container class for YankBank buffer related variables
32---@class YankBankBufData
33---@field bufnr integer
···39---@return YankBankBufData?
40function M.create_and_fill_buffer()
41 -- stop if yanks or register types table is empty
42+ if #YB_YANKS == 0 or #YB_REG_TYPES == 0 then
43 print("No yanks to show.")
44 return nil
45 end
···116 -- key mappings for selection and closing the popup
117 local map_opts = { noremap = true, silent = true, buffer = b.bufnr }
1180000000000119 -- popup buffer navigation binds
120+ if YB_OPTS.num_behavior == "prefix" then
121 vim.keymap.set("n", k.navigation_next, function()
122 local count = vim.v.count1 > 0 and vim.v.count1 or 1
123 helpers.next_numbered_item(count)
···127 local count = vim.v.count1 > 0 and vim.v.count1 or 1
128 helpers.prev_numbered_item(count)
129 return ""
130+ end, map_opts)
131 else
132 vim.keymap.set(
133 "n",
134 k.navigation_next,
135 helpers.next_numbered_item,
136+ map_opts
137 )
138 vim.keymap.set(
139 "n",
140 k.navigation_prev,
141 helpers.prev_numbered_item,
142+ map_opts
143 )
144 end
145146+ -- map number keys to jump to entry if num_behavior is 'jump'
147+ if YB_OPTS.num_behavior == "jump" then
148+ for i = 1, YB_OPTS.max_entries do
149 vim.keymap.set("n", tostring(i), function()
150 local target_line = nil
151 for line_num, yank_num in pairs(b.line_yank_map) do
···167 -- use the mapping to find the original yank
168 local yankIndex = b.line_yank_map[cursor]
169 if yankIndex then
170+ -- close window upon selection
171+ vim.api.nvim_win_close(b.win_id, true)
172+ helpers.smart_paste(
173+ YB_YANKS[yankIndex],
174+ YB_REG_TYPES[yankIndex],
175+ true
176+ )
177+ else
178+ print("Error: Invalid selection")
179+ end
180+ end, map_opts)
181+ -- paste backwards
182+ vim.keymap.set("n", k.paste_back, function()
183+ local cursor = vim.api.nvim_win_get_cursor(b.win_id)[1]
184+ -- use the mapping to find the original yank
185+ local yankIndex = b.line_yank_map[cursor]
186+ if yankIndex then
187 -- close window upon selection
188 vim.api.nvim_win_close(b.win_id, true)
189+ helpers.smart_paste(
190+ YB_YANKS[yankIndex],
191+ YB_REG_TYPES[yankIndex],
192+ false
193+ )
194 else
195 print("Error: Invalid selection")
196 end
197+ end, map_opts)
198199 -- bind yank behavior
200 vim.keymap.set("n", k.yank, function()
201 local cursor = vim.api.nvim_win_get_cursor(b.win_id)[1]
202 local yankIndex = b.line_yank_map[cursor]
203 if yankIndex then
204+ vim.fn.setreg(YB_OPTS.registers.yank_register, YB_YANKS[yankIndex])
0205 vim.api.nvim_win_close(b.win_id, true)
206 end
207+ end, map_opts)
208209 -- close popup keybinds
210 -- REFACTOR: check if close keybind is string, handle differently
+4-4
lua/yankbank/persistence.lua
···6---@param entry string
7---@param reg_type string
8function M.add_entry(entry, reg_type)
9- if OPTS.persist_type == "sqlite" then
10 persistence:insert_yank(entry, reg_type)
11 end
12end
1314--- get current state of yanks in persistent storage
15function M.get_yanks()
16- if OPTS.persist_type == "sqlite" then
17 return persistence:get_bank()
18 end
19end
···22---@return table
23---@return table
24function M.setup()
25- if not OPTS.persist_type then
26 return {}, {}
27- elseif OPTS.persist_type == "sqlite" then
28 persistence = require("yankbank.persistence.sql").setup()
29 return persistence:get_bank()
30 else
···6---@param entry string
7---@param reg_type string
8function M.add_entry(entry, reg_type)
9+ if YB_OPTS.persist_type == "sqlite" then
10 persistence:insert_yank(entry, reg_type)
11 end
12end
1314--- get current state of yanks in persistent storage
15function M.get_yanks()
16+ if YB_OPTS.persist_type == "sqlite" then
17 return persistence:get_bank()
18 end
19end
···22---@return table
23---@return table
24function M.setup()
25+ if not YB_OPTS.persist_type then
26 return {}, {}
27+ elseif YB_OPTS.persist_type == "sqlite" then
28 persistence = require("yankbank.persistence.sql").setup()
29 return persistence:get_bank()
30 else
+4-4
lua/yankbank/persistence/sql.lua
···102--- set up database persistence
103---@return sqlite_tbl data
104function M.setup()
105- max_entries = OPTS.max_entries
106107 vim.api.nvim_create_user_command("YankBankClearDB", function()
108 data:remove()
109- YANKS = {}
110- REG_TYPES = {}
111 end, {})
112113- if OPTS.debug == true then
114 vim.api.nvim_create_user_command("YankBankViewDB", function()
115 print(vim.inspect(data:get()))
116 end, {})
···102--- set up database persistence
103---@return sqlite_tbl data
104function M.setup()
105+ max_entries = YB_OPTS.max_entries
106107 vim.api.nvim_create_user_command("YankBankClearDB", function()
108 data:remove()
109+ YB_YANKS = {}
110+ YB_REG_TYPES = {}
111 end, {})
112113+ if YB_OPTS.debug == true then
114 vim.api.nvim_create_user_command("YankBankViewDB", function()
115 print(vim.inspect(data:get()))
116 end, {})