···11-- clipboard.lua
22local M = {}
3344--- TODO: convert string to table yanks to work better with files
44+-- import persistence module
55+local persistence = require("yankbank.persistence")
5667-- Function to add yanked text to table
78---@param yanks table
89---@param reg_types table
910---@param text string
1011---@param reg_type string
1111----@param max_entries integer
1212-function M.add_yank(yanks, reg_types, text, reg_type, max_entries)
1212+---@param opts table
1313+function M.add_yank(yanks, reg_types, text, reg_type, opts)
1314 -- avoid adding empty strings
1415 -- TODO: could block adding single characters here
1516 if text == "" or text == " " or text == "\n" then
1617 return
1718 end
1818- print(
1919- "yanks: ",
2020- vim.inspect(yanks),
2121- "| reg_types: ",
2222- vim.inspect(reg_types)
2323- )
24192520 -- do not update with duplicate values
2621 for _, entry in ipairs(yanks) do
···3227 -- add entry to bank
3328 table.insert(yanks, 1, text)
3429 table.insert(reg_types, 1, reg_type)
3535- if #yanks > max_entries then
3030+ if #yanks > opts.max_entries then
3631 table.remove(yanks)
3732 table.remove(reg_types)
3833 end
3434+3535+ -- add entry to persistent store
3636+ persistence.add_entry(yanks, reg_types, opts)
3937end
40384139-- autocommand to listen for yank events
4240---@param yanks table
4341---@param reg_types table
4444----@param max_entries integer
4545-function M.setup_yank_autocmd(yanks, reg_types, max_entries)
4242+---@param opts table
4343+function M.setup_yank_autocmd(yanks, reg_types, opts)
4644 vim.api.nvim_create_autocmd("TextYankPost", {
4745 callback = function()
4846 -- get register information
···5553 if #yanked_text <= 1 then
5654 return
5755 end
5858- M.add_yank(yanks, reg_types, yanked_text, reg_type, max_entries)
5656+ M.add_yank(yanks, reg_types, yanked_text, reg_type, opts)
5957 end
6058 end,
6159 })
+19-23
lua/yankbank/init.lua
···88-- initialize yanks tables
99local yanks = {}
1010local reg_types = {}
1111-local max_entries = 10
1212-local sep = "-----"
1313-local persist_type = "file"
1414-local persist_path = "/tmp/yankbank.txt"
1111+1212+local plugin_path = debug.getinfo(1).source:sub(2):match("(.*/).*/.*/") or "./"
1313+1414+-- default plugin options
1515+local default_opts = {
1616+ max_entries = 10,
1717+ sep = "-----",
1818+ persist_type = "memory",
1919+ persist_path = plugin_path .. "bank.txt",
2020+}
15211622-- wrapper function for main plugin functionality
1717----@param opts table|nil
2323+---@param opts table
1824local function show_yank_bank(opts)
1925 -- Parse command arguments directly if args are provided as a string
2020- opts = opts or {}
2121-2222- -- Fallback to defaults if necessary
2323- local max_entries_opt = opts.max_entries or max_entries
2424- local sep_opt = opts.sep or sep
2525-2626- opts.keymaps = opts.keymaps or {}
27262827 local bufnr, display_lines, line_yank_map =
2929- menu.create_and_fill_buffer(yanks, reg_types, max_entries_opt, sep_opt)
2828+ menu.create_and_fill_buffer(yanks, reg_types, opts)
2929+3030 -- handle empty bank case
3131- if not bufnr then
3131+ if not bufnr or not display_lines or not line_yank_map then
3232 return
3333 end
3434+3435 local win_id = menu.open_window(bufnr, display_lines)
3536 menu.set_keymaps(win_id, bufnr, yanks, reg_types, line_yank_map, opts)
3637end
37383839-- plugin setup
3939----@param opts table|nil
4040+---@param opts table?
4041function M.setup(opts)
4141- opts = opts or {}
4242-4343- -- parse opts
4444- max_entries = opts.max_entries or max_entries
4545-4646- persist_type = opts.persist_type or persist_type
4747- persist_path = opts.persist_path or persist_path
4242+ -- merge opts with default options table
4343+ opts = vim.tbl_deep_extend("force", default_opts, opts or {})
48444945 -- create clipboard autocmds
5050- clipboard.setup_yank_autocmd(yanks, reg_types, max_entries)
4646+ clipboard.setup_yank_autocmd(yanks, reg_types, opts)
51475248 -- Create user command
5349 vim.api.nvim_create_user_command("YankBank", function()
+22-7
lua/yankbank/menu.lua
···66local data = require("yankbank.data")
77local helpers = require("yankbank.helpers")
8899--- create new buffer and reformat yank table for ui
1010-function M.create_and_fill_buffer(yanks, reg_types, max_entries, sep)
99+---create new buffer and reformat yank table for ui
1010+---@param yanks table
1111+---@param reg_types table
1212+---@param opts table
1313+---@return integer?
1414+---@return table?
1515+---@return table?
1616+function M.create_and_fill_buffer(yanks, reg_types, opts)
1117 -- check the content of the system clipboard register
1218 -- TODO: this could be replaced with some sort of polling of the + register
1319 local text = vim.fn.getreg("+")
1420 local most_recent_yank = yanks[1] or ""
1521 if text ~= most_recent_yank then
1622 local reg_type = vim.fn.getregtype("+")
1717- clipboard.add_yank(yanks, reg_types, text, reg_type, max_entries)
2323+ clipboard.add_yank(yanks, reg_types, text, reg_type, opts)
1824 end
19252026 -- stop if yank table is empty
2127 if #yanks == 0 then
2228 print("No yanks to show.")
2323- return
2929+ return nil, nil, nil
2430 end
25312632 -- create new buffer
···3036 local current_filetype = vim.bo.filetype
3137 vim.api.nvim_set_option_value("filetype", current_filetype, { buf = bufnr })
32383333- local display_lines, line_yank_map = data.get_display_lines(yanks, sep)
3939+ local display_lines, line_yank_map = data.get_display_lines(yanks, opts.sep)
34403541 -- replace current buffer contents with updated table
3642 vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, display_lines)
···3844 return bufnr, display_lines, line_yank_map
3945end
40464141--- Calculate size and create popup window from bufnr
4747+---Calculate size and create popup window from bufnr
4848+---@param bufnr integer
4949+---@param display_lines table
5050+---@return integer
4251function M.open_window(bufnr, display_lines)
4352 -- set maximum window width based on number of lines
4453 local max_width = 0
···8190 return win_id
8291end
83928484--- Set key mappings for the popup window
9393+---Set key mappings for the popup window
9494+---@param win_id integer
9595+---@param bufnr integer
9696+---@param yanks table
9797+---@param reg_types table
9898+---@param line_yank_map table
9999+---@param opts table
85100function M.set_keymaps(win_id, bufnr, yanks, reg_types, line_yank_map, opts)
86101 -- Key mappings for selection and closing the popup
87102 local map_opts = { noremap = true, silent = true, buffer = bufnr }
+28-12
lua/yankbank/persistence.lua
···11-- persistence.lua
22-32local M = {}
4355--- TODO: for file-based persistence:
66--- - need system for moving entries around in list
77--- - either use tags and search by tag (could be out of order)
88--- - or keep list in sorted order (likely more i/o heavy)
99--- - store local copy of list in memory, to make accesses to popup quick
1010--- - might need plenary for the asynchronous r/w accesses
44+---comment
55+---@param yanks table
66+---@param reg_types table
77+---@param opts table
88+function M.add_entry(yanks, reg_types, opts)
99+ if not opts.persist_type then
1010+ return
1111+ elseif opts.persist_type == "memory" then
1212+ return
1313+ elseif opts.persist_type == "file" then
1414+ -- TODO:
1515+ elseif opts.persist_type == "sqlite" then
1616+ end
1717+end
11181212-function M.enable_persistence(yanks, opts)
1919+---initialize bank persistence
2020+---@param yanks table
2121+---@param reg_types table
2222+---@param opts table
2323+function M.setup(yanks, reg_types, opts)
1324 if not opts.persist_type then
1425 return
1526 elseif opts.persist_type == "file" then
1627 -- TODO:
1717- require("persistence.file").setup_persistence(
1818- yanks,
2828+ require("yankbank.persistence.file").setup_persistence(
1929 opts.persist_path,
2020- opts.max_entries
3030+ opts.max_entries,
3131+ yanks,
3232+ reg_types
2133 )
2234 elseif opts.persist_type == "sqlite" then
2335 -- TODO:
2424- require("persistence.sql").init_db(yanks, opts.persist_path)
3636+ require("yankbank.persistence.sql").init_db(
3737+ yanks,
3838+ reg_types,
3939+ opts.persist_path
4040+ )
2541 end
2642end
2743
+11-23
lua/yankbank/persistence/file.lua
···5050---@param line string: line from file being checked
5151---@return table|nil
5252local function check_for_entry(line)
5353- local i, l, rt =
5454- string.match(line, "<YANKBANK_ENTRY:(%d+),(%d+),(%a+)>")
5353+ local i, l, rt = string.match(line, "<YANKBANK_ENTRY:(%d+),(%d+),(%a+)>")
5554 if i then
5655 return {
5756 index = tonumber(i),
···8786 local lines = {}
8887 for line in f:lines() do
8988 if
9090- string.match(
9191- line,
9292- "<YANKBANK_ENTRY:" .. n_entries .. ",%d+,%a+>"
9393- )
8989+ string.match(line, "<YANKBANK_ENTRY:" .. n_entries .. ",%d+,%a+>")
9490 then
9591 n_entries = n_entries - 1
9692 lines[1] = "<YANKBANK_LIST:" .. n_entries .. ">\n"
···142138143139 -- write entry header
144140 -- FIX: #entry doesn't match number of lines when it is string (number of chars instead of lines)
145145- f:write(
146146- "<YANKBANK_ENTRY:1,"
147147- .. #entry
148148- .. ","
149149- .. reg_type
150150- .. ">\n"
151151- )
141141+ f:write("<YANKBANK_ENTRY:1," .. #entry .. "," .. reg_type .. ">\n")
152142 -- write entry
153143 if type(entry) == "string" then
154144 f:write(entry)
···161151162152 -- write remaining lines
163153 for i = 2, #lines do
164164- local n, l, rt = string.match(
165165- lines[i],
166166- "<YANKBANK_ENTRY:(%d+),(%d+),(%a+)>"
167167- )
154154+ local n, l, rt =
155155+ string.match(lines[i], "<YANKBANK_ENTRY:(%d+),(%d+),(%a+)>")
168156 if n then
169157 lines[i] = "<YANKBANK_ENTRY:"
170170- .. n + 1
171171- .. ","
172172- .. l
173173- .. ","
174174- .. rt
175175- .. ">"
158158+ .. n + 1
159159+ .. ","
160160+ .. l
161161+ .. ","
162162+ .. rt
163163+ .. ">"
176164 end
177165 -- TODO: check headers
178166 f:write(lines[i] .. "\n")