···11local M = {}
2233--- TODO: figure out how api should get 'yanks' and 'reg_types'
44--- - possibly rewrite these to be global variables
55-66---- DOC:
33+--- get a table containg a single yankbank entry by index
74---@param i integer
85---@return table
96function M.get_entry(i)
1010- -- TODO: figure out how tables are being populated for the api
117 return {
128 yank_text = YANKS[i],
139 reg_type = REG_TYPES[i],
1410 }
1511end
16121717---- DOC:
1313+--- get a table containing all yankbank entries
1814---@return table
1915function M.get_all()
2016 local out = {}
···2622 end
2723 return out
2824end
2525+2626+--- add an entry to yankbank
2727+---@param yank_text string yank text to add to YANKS table
2828+---@param reg_type string register type "v", "V", or "^V" for visual, visual-linewise, and visual-block modes respectively.
2929+function M.add_entry(yank_text, reg_type)
3030+ require("yankbank.clipboard").add_yank(yank_text, reg_type)
3131+end
3232+3333+--- remove entry from yankbank by index
3434+---@param i integer index to remove
3535+function M.remove_entry(i)
3636+ local yank_text = table.remove(YANKS, i)
3737+ table.remove(REG_TYPES, i)
3838+ if OPTS.persist_type == "sqlite" then
3939+ require("yankbank.persistence.sql").data():remove_match(yank_text)
4040+ end
4141+end
4242+4343+-- TODO: individual popup keymap setting functions
4444+-- - could just update opts table that is passed into set_keymaps
29453046return M
+7-9
lua/yankbank/clipboard.lua
···66--- Function to add yanked text to table
77---@param text string
88---@param reg_type string
99----@param opts table
1010-function M.add_yank(text, reg_type, opts)
99+function M.add_yank(text, reg_type)
1110 -- avoid adding empty strings
1211 if text == "" and text == " " and text == "\n" then
1312 return
···2827 table.insert(REG_TYPES, 1, reg_type)
29283029 -- trim table size if necessary
3131- if #YANKS > opts.max_entries then
3030+ if #YANKS > OPTS.max_entries then
3231 table.remove(YANKS)
3332 table.remove(REG_TYPES)
3433 end
35343635 -- add entry to persistent store
3737- persistence.add_entry(text, reg_type, opts)
3636+ persistence.add_entry(text, reg_type)
3837end
39384039--- autocommand to listen for yank events
4141----@param opts table
4242-function M.setup_yank_autocmd(opts)
4040+function M.setup_yank_autocmd()
4341 vim.api.nvim_create_autocmd("TextYankPost", {
4442 callback = function()
4543 -- get register information
···5856 return
5957 end
60586161- M.add_yank(yank_text, reg_type, opts)
5959+ M.add_yank(yank_text, reg_type)
6260 end
6361 end,
6462 })
65636664 -- poll registers when vim is focused (check for new clipboard activity)
6767- if opts.focus_gain_poll == true then
6565+ if OPTS.focus_gain_poll == true then
6866 vim.api.nvim_create_autocmd("FocusGained", {
6967 callback = function()
7068 -- get register information
···7977 return
8078 end
81798282- M.add_yank(yank_text, reg_type, opts)
8080+ M.add_yank(yank_text, reg_type)
8381 end,
8482 })
8583 end
+3-4
lua/yankbank/data.lua
···11local M = {}
2233--- reformat yanks table for popup
44----@param opts table
54---@return table, table
66-function M.get_display_lines(opts)
55+function M.get_display_lines()
76 local display_lines = {}
87 local line_yank_map = {}
98 local yank_num = 0
···51505251 if i < #YANKS then
5352 -- Add a visual separator between yanks, aligned with the yank content
5454- if opts.sep ~= "" then
5353+ if OPTS.sep ~= "" then
5554 table.insert(
5655 display_lines,
5757- string.rep(" ", max_digits + 2) .. opts.sep
5656+ string.rep(" ", max_digits + 2) .. OPTS.sep
5857 )
5958 end
6059 table.insert(line_yank_map, false)
+14-22
lua/yankbank/init.lua
···55local clipboard = require("yankbank.clipboard")
66local persistence = require("yankbank.persistence")
7788--- initialize tables
98YANKS = {}
109REG_TYPES = {}
1010+OPTS = {}
11111212-- default plugin options
1313local default_opts = {
···2323}
24242525--- wrapper function for main plugin functionality
2626----@param opts table
2727-local function show_yank_bank(opts)
2828- YANKS = persistence.get_yanks(opts) or YANKS
2626+local function show_yank_bank()
2727+ YANKS = persistence.get_yanks() or YANKS
29283029 -- initialize buffer and populate bank
3131- local bufnr, display_lines, line_yank_map =
3232- menu.create_and_fill_buffer(opts)
3333-3434- -- handle empty bank case
3535- if not bufnr or not display_lines or not line_yank_map then
3030+ local buf_data = menu.create_and_fill_buffer()
3131+ if not buf_data then
3632 return
3733 end
38343939- -- open window and set keybinds
4040- local win_id = menu.open_window(bufnr, display_lines)
4141- menu.set_keymaps(win_id, bufnr, line_yank_map, opts)
3535+ -- open popup window
3636+ buf_data.win_id = menu.open_window(buf_data)
3737+3838+ -- set popup keybinds
3939+ menu.set_keymaps(buf_data)
4240end
43414442-- plugin setup
4543---@param opts? table
4644function M.setup(opts)
4745 -- merge opts with default options table
4848- opts = vim.tbl_deep_extend("keep", opts or {}, default_opts)
4646+ OPTS = vim.tbl_deep_extend("keep", opts or {}, default_opts)
49475048 -- enable persistence based on opts (needs to be called before autocmd setup)
5151- YANKS, REG_TYPES = persistence.setup(opts)
4949+ YANKS, REG_TYPES = persistence.setup()
52505351 -- create clipboard autocmds
5454- clipboard.setup_yank_autocmd(opts)
5252+ clipboard.setup_yank_autocmd()
55535654 -- create user command
5755 vim.api.nvim_create_user_command("YankBank", function()
5858- show_yank_bank(opts)
5656+ show_yank_bank()
5957 end, { desc = "Show Recent Yanks" })
6060-6161- -- TODO: remove
6262- local api = require("yankbank.api")
6363- vim.api.nvim_create_user_command("YankBankApi", function()
6464- print(vim.inspect(api.get_all()))
6565- end, {})
6658end
67596860return M
+52-50
lua/yankbank/menu.lua
···33local data = require("yankbank.data")
44local helpers = require("yankbank.helpers")
5566+--- Container class for YankBank buffer related variables
77+---@class YankBankBufData
88+---@field bufnr integer
99+---@field display_lines table
1010+---@field line_yank_map table
1111+---@field win_id integer
1212+613---create new buffer and reformat yank table for ui
77----@param opts table
88----@return integer?
99----@return table?
1010----@return table?
1111-function M.create_and_fill_buffer(opts)
1414+---@return YankBankBufData?
1515+function M.create_and_fill_buffer()
1216 -- stop if yanks or register types table is empty
1317 if #YANKS == 0 or #REG_TYPES == 0 then
1418 print("No yanks to show.")
1515- return nil, nil, nil
1919+ return nil
1620 end
17211822 -- create new buffer
···2226 local current_filetype = vim.bo.filetype
2327 vim.api.nvim_set_option_value("filetype", current_filetype, { buf = bufnr })
24282525- local display_lines, line_yank_map = data.get_display_lines(opts)
2929+ local display_lines, line_yank_map = data.get_display_lines()
26302731 -- replace current buffer contents with updated table
2832 vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, display_lines)
29333030- return bufnr, display_lines, line_yank_map
3434+ ---@type YankBankBufData
3535+ return {
3636+ bufnr = bufnr,
3737+ display_lines = display_lines,
3838+ line_yank_map = line_yank_map,
3939+ win_id = -1,
4040+ }
3141end
32423343---Calculate size and create popup window from bufnr
3434----@param bufnr integer
3535----@param display_lines table
4444+---@param b YankBankBufData
3645---@return integer
3737-function M.open_window(bufnr, display_lines)
4646+function M.open_window(b)
3847 -- set maximum window width based on number of lines
3948 local max_width = 0
4040- if display_lines and #display_lines > 0 then
4141- for _, line in ipairs(display_lines) do
4949+ if b.display_lines and #b.display_lines > 0 then
5050+ for _, line in ipairs(b.display_lines) do
4251 max_width = math.max(max_width, #line)
4352 end
4453 else
···5160 local width =
5261 math.min(max_width, vim.api.nvim_get_option_value("columns", {}) - 4)
5362 local height = math.min(
5454- display_lines and #display_lines or 1,
6363+ b.display_lines and #b.display_lines or 1,
5564 vim.api.nvim_get_option_value("lines", {}) - 10
5665 )
57665867 -- open window
5959- local win_id = vim.api.nvim_open_win(bufnr, true, {
6868+ local win_id = vim.api.nvim_open_win(b.bufnr, true, {
6069 relative = "editor",
6170 width = width,
6271 height = height,
···7786end
78877988--- Set key mappings for the popup window
8080----@param win_id integer
8181----@param bufnr integer
8282----@param line_yank_map table
8383----@param opts table
8484-function M.set_keymaps(win_id, bufnr, line_yank_map, opts)
8585- -- Key mappings for selection and closing the popup
8686- local map_opts = { noremap = true, silent = true, buffer = bufnr }
8787-8989+---@param b YankBankBufData
9090+function M.set_keymaps(b)
8891 -- default plugin keymaps
8992 local default_keymaps = {
9093 navigation_next = "j",
···99102 yank_register = "+",
100103 }
101104105105+ -- key mappings for selection and closing the popup
106106+ local map_opts = { noremap = true, silent = true, buffer = b.bufnr }
107107+102108 -- merge default and options keymap tables
103103- local k = vim.tbl_deep_extend("force", default_keymaps, opts.keymaps or {})
109109+ local k = vim.tbl_deep_extend("force", default_keymaps, OPTS.keymaps or {})
104110105111 -- merge default and options keymap tables
106106- opts.registers =
107107- vim.tbl_deep_extend("force", default_registers, opts.registers or {})
112112+ OPTS.registers =
113113+ vim.tbl_deep_extend("force", default_registers, OPTS.registers or {})
108114109115 -- check table for number behavior option (prefix or jump, default to prefix)
110110- opts.num_behavior = opts.num_behavior or "prefix"
116116+ OPTS.num_behavior = OPTS.num_behavior or "prefix"
111117112118 -- popup buffer navigation binds
113113- if opts.num_behavior == "prefix" then
119119+ if OPTS.num_behavior == "prefix" then
114120 vim.keymap.set("n", k.navigation_next, function()
115121 local count = vim.v.count1 > 0 and vim.v.count1 or 1
116122 helpers.next_numbered_item(count)
117123 return ""
118118- end, { noremap = true, silent = true, buffer = bufnr })
124124+ end, { noremap = true, silent = true, buffer = b.bufnr })
119125 vim.keymap.set("n", k.navigation_prev, function()
120126 local count = vim.v.count1 > 0 and vim.v.count1 or 1
121127 helpers.prev_numbered_item(count)
122128 return ""
123123- end, { noremap = true, silent = true, buffer = bufnr })
129129+ end, { noremap = true, silent = true, buffer = b.bufnr })
124130 else
125131 vim.keymap.set(
126132 "n",
127133 k.navigation_next,
128134 helpers.next_numbered_item,
129129- { noremap = true, silent = true, buffer = bufnr }
135135+ { noremap = true, silent = true, buffer = b.bufnr }
130136 )
131137 vim.keymap.set(
132138 "n",
133139 k.navigation_prev,
134140 helpers.prev_numbered_item,
135135- { noremap = true, silent = true, buffer = bufnr }
141141+ { noremap = true, silent = true, buffer = b.bufnr }
136142 )
137143 end
138144139145 -- Map number keys to jump to entry if num_behavior is 'jump'
140140- if opts.num_behavior == "jump" then
141141- -- TODO: deal with delayed trigger upon hitting number that is part of valid sequence
142142- -- i.e. '1' when '10' is a valid entry
143143- for i = 1, opts.max_entries do
146146+ if OPTS.num_behavior == "jump" then
147147+ for i = 1, OPTS.max_entries do
144148 vim.keymap.set("n", tostring(i), function()
145149 local target_line = nil
146146- for line_num, yank_num in pairs(line_yank_map) do
150150+ for line_num, yank_num in pairs(b.line_yank_map) do
147151 if yank_num == i then
148152 target_line = line_num
149153 break
150154 end
151155 end
152156 if target_line then
153153- vim.api.nvim_win_set_cursor(win_id, { target_line, 0 })
157157+ vim.api.nvim_win_set_cursor(b.win_id, { target_line, 0 })
154158 end
155159 end, map_opts)
156160 end
···158162159163 -- bind paste behavior
160164 vim.keymap.set("n", k.paste, function()
161161- local cursor = vim.api.nvim_win_get_cursor(win_id)[1]
165165+ local cursor = vim.api.nvim_win_get_cursor(b.win_id)[1]
162166 -- use the mapping to find the original yank
163163- local yankIndex = line_yank_map[cursor]
167167+ local yankIndex = b.line_yank_map[cursor]
164168 if yankIndex then
165169 -- retrieve the full yank, including all lines
166170 local text = YANKS[yankIndex]
167171168172 -- close window upon selection
169169- vim.api.nvim_win_close(win_id, true)
173173+ vim.api.nvim_win_close(b.win_id, true)
170174 helpers.smart_paste(text, REG_TYPES[yankIndex])
171175 else
172176 print("Error: Invalid selection")
173177 end
174174- end, { buffer = bufnr })
178178+ end, { buffer = b.bufnr })
175179176180 -- bind yank behavior
177181 vim.keymap.set("n", k.yank, function()
178178- local cursor = vim.api.nvim_win_get_cursor(win_id)[1]
179179- local yankIndex = line_yank_map[cursor]
182182+ local cursor = vim.api.nvim_win_get_cursor(b.win_id)[1]
183183+ local yankIndex = b.line_yank_map[cursor]
180184 if yankIndex then
181185 local text = YANKS[yankIndex]
182182- -- NOTE: possibly change this to '"' if not using system clipboard
183183- -- - make this an option
184184- vim.fn.setreg(opts.registers.yank_register, text)
185185- vim.api.nvim_win_close(win_id, true)
186186+ vim.fn.setreg(OPTS.registers.yank_register, text)
187187+ vim.api.nvim_win_close(b.win_id, true)
186188 end
187187- end, { buffer = bufnr })
189189+ end, { buffer = b.bufnr })
188190189191 -- close popup keybinds
190192 for _, map in ipairs(k.close) do
191193 vim.keymap.set("n", map, function()
192192- vim.api.nvim_win_close(win_id, true)
194194+ vim.api.nvim_win_close(b.win_id, true)
193195 end, map_opts)
194196 end
195197end
+9-12
lua/yankbank/persistence.lua
···33local persistence = {}
4455---add entry from bank to
66----@param entry string|table
66+---@param entry string
77---@param reg_type string
88----@param opts table
99-function M.add_entry(entry, reg_type, opts)
1010- if opts.persist_type == "sqlite" then
88+function M.add_entry(entry, reg_type)
99+ if OPTS.persist_type == "sqlite" then
1110 persistence:insert_yank(entry, reg_type)
1211 end
1312end
14131514--- get current state of yanks in persistent storage
1616----@param opts table
1717-function M.get_yanks(opts)
1818- if opts.persist_type == "sqlite" then
1515+function M.get_yanks()
1616+ if OPTS.persist_type == "sqlite" then
1917 return persistence:get_bank()
2018 end
2119end
22202321---initialize bank persistence
2424----@param opts table
2522---@return table
2623---@return table
2727-function M.setup(opts)
2828- if not opts.persist_type then
2424+function M.setup()
2525+ if not OPTS.persist_type then
2926 return {}, {}
3030- elseif opts.persist_type == "sqlite" then
3131- persistence = require("yankbank.persistence.sql").setup(opts)
2727+ elseif OPTS.persist_type == "sqlite" then
2828+ persistence = require("yankbank.persistence.sql").setup()
3229 return persistence:get_bank()
3330 else
3431 return {}, {}
+20-4
lua/yankbank/persistence/sql.lua
···8282 return yanks, reg_types
8383end
84848585+--- remove an entry from the banks table matching input text
8686+---@param text string
8787+function data:remove_match(text)
8888+ db:with_open(function()
8989+ return db:eval(
9090+ "DELETE FROM bank WHERE yank_text = :yank_text",
9191+ { yank_text = text }
9292+ )
9393+ end)
9494+end
9595+9696+--- get data in sqlite_tbl form (for api use only)
9797+---@return sqlite_tbl
9898+function M.data()
9999+ return data
100100+end
101101+85102--- set up database persistence
8686----@param opts table
87103---@return sqlite_tbl data
8888-function M.setup(opts)
8989- max_entries = opts.max_entries
104104+function M.setup()
105105+ max_entries = OPTS.max_entries
9010691107 vim.api.nvim_create_user_command("YankBankClearDB", function()
92108 data:remove()
···94110 REG_TYPES = {}
95111 end, {})
961129797- if opts.debug == true then
113113+ if OPTS.debug == true then
98114 vim.api.nvim_create_user_command("YankBankViewDB", function()
99115 print(vim.inspect(data:get()))
100116 end, {})