···4747---
4848---@param i integer index to pin
4949function M.pin_entry(i)
5050- -- TODO: check persistence mode, max_entries
5151- -- - add third table YB_PINS to keep track of pins
5252- -- TODO: show pins differently in popup
5050+ if i > #YB_PINS then
5151+ return
5252+ end
5353+5454+ -- TODO: show pins differently in popup (could use different hl_groups for pinned entries?)
5555+ YB_PINS[i] = 1
5656+5357 if YB_OPTS.persist_type == "sqlite" then
5458 return require("yankbank.persistence.sql")
5559 .data()
···6165---
6266---@param i integer index to unpin
6367function M.unpin_entry(i)
6464- -- TODO: check persistence mode, max_entries
6565- -- - in sql.lua, add 3rd field (bool) pinned
6868+ if i > #YB_PINS then
6969+ return
7070+ end
7171+7272+ -- TODO: update popup pin highlight
7373+ YB_PINS[i] = 0
7474+6675 if YB_OPTS.persist_type == "sqlite" then
6776 return require("yankbank.persistence.sql")
6877 .data()
···7180end
72817382-- TODO: individual popup keymap setting functions
7474--- - could just update opts table that is passed into set_keymaps
75837684return M
+23-5
lua/yankbank/clipboard.lua
···2233-- import persistence module
44local persistence = require("yankbank.persistence")
55+local utils = require("yankbank.utils")
5667--- Function to add yanked text to table
78---@param text string
···1314 return
1415 end
15161717+ local is_pinned = 0
1818+1619 -- check for duplicate values already inserted
1720 for i, entry in ipairs(YB_YANKS) do
1821 if entry == text then
1922 -- remove matched entry so it can be inserted at 1st position
2020- -- TODO: pin handling in global tables
2123 table.remove(YB_YANKS, i)
2224 table.remove(YB_REG_TYPES, i)
2525+ is_pinned = table.remove(YB_PINS, i)
2326 break
2427 end
2528 end
26293030+ -- override is_pinned if pin is set
3131+ is_pinned = (pin == 1 or pin == true) and 1
3232+ or (pin == 0 or pin == false) and 0
3333+ or is_pinned
3434+2735 -- add entry to bank
2828- -- TODO: pin handling in global tables
2936 table.insert(YB_YANKS, 1, text)
3037 table.insert(YB_REG_TYPES, 1, reg_type)
3838+ table.insert(YB_PINS, 1, is_pinned)
31393240 -- trim table size if necessary
3341 if #YB_YANKS > YB_OPTS.max_entries then
3434- -- TODO: pin handling in global tables
3535- table.remove(YB_YANKS)
3636- table.remove(YB_REG_TYPES)
4242+ local i = utils.last_zero_entry(YB_PINS)
4343+4444+ if not i or i == 1 then
4545+ -- WARN: undefined behavior
4646+ print(
4747+ "Warning: all YankBank entries are pinned, insertion behavior is undefined when all entries are pinned."
4848+ )
4949+ else
5050+ -- remove last non-pinned entry
5151+ table.remove(YB_YANKS, i)
5252+ table.remove(YB_REG_TYPES, i)
5353+ table.remove(YB_PINS, i)
5454+ end
3755 end
38563957 -- add entry to persistent store
+2-1
lua/yankbank/init.lua
···33-- define global variables
44YB_YANKS = {}
55YB_REG_TYPES = {}
66+YB_PINS = {}
67YB_OPTS = {}
7889-- local imports
···4748 YB_OPTS = vim.tbl_deep_extend("keep", opts or {}, default_opts)
48494950 -- enable persistence based on opts (needs to be called before autocmd setup)
5050- YB_YANKS, YB_REG_TYPES = persistence.setup()
5151+ YB_YANKS, YB_REG_TYPES, YB_PINS = persistence.setup()
51525253 -- create clipboard autocmds
5354 clipboard.setup_yank_autocmd()
+3-2
lua/yankbank/persistence.lua
···2222---initialize bank persistence
2323---@return table
2424---@return table
2525+---@return table
2526function M.setup()
2627 if not YB_OPTS.persist_type then
2727- return {}, {}
2828+ return {}, {}, {}
2829 elseif YB_OPTS.persist_type == "sqlite" then
2930 persistence = require("yankbank.persistence.sql").setup()
3031 return persistence:get_bank()
3132 else
3232- return {}, {}
3333+ return {}, {}, {}
3334 end
3435end
3536
+11-8
lua/yankbank/persistence/sql.lua
···11local M = {}
2233-local sqlite = require("sqlite.db")
33+local sqlite = require("sqlite")
4455-- local dbdir = vim.fn.stdpath("data") .. "/databases"
66local dbdir = debug.getinfo(1).source:sub(2):match("(.*/).*/.*/.*/") or "./"
···7575function data:trim_size()
7676 if self:count() > max_entries then
7777 -- remove the oldest entry
7878- local oldest_entry = db:with_open(function()
7878+ local e = db:with_open(function()
7979+ -- TODO: figure out what to do if all entries are pinned
7980 return db:select("bank", {
8081 where = { pinned = 0 },
8182 order_by = { asc = "rowid" },
8282- limit = { 1 },
8383+ limit = 1,
8384 })[1]
8485 end)
85868686- if oldest_entry then
8787+ if e then
8788 db:with_open(function()
8889 db:eval(
8990 "DELETE FROM bank WHERE yank_text = :yank_text",
9090- { yank_text = oldest_entry.yank_text }
9191+ { yank_text = e.yank_text }
9192 )
9293 end)
9394 end
···9596end
96979798--- get sqlite bank contents
9898----@return table yanks, table reg_types
9999+---@return table yanks, table reg_types, table pins
99100function data:get_bank()
100100- local yanks, reg_types = {}, {}
101101+ local yanks, reg_types, pins = {}, {}, {}
101102102103 local bank = self:get()
103104 for _, entry in ipairs(bank) do
104105 table.insert(yanks, 1, entry.yank_text)
105106 table.insert(reg_types, 1, entry.reg_type)
107107+ table.insert(pins, 1, entry.pinned)
106108 end
107109108108- return yanks, reg_types
110110+ return yanks, reg_types, pins
109111end
110112111113--- remove an entry from the banks table matching input text
···143145function data.unpin(text, reg_type)
144146 return db:with_open(function()
145147 -- TODO: always returns true or nothing
148148+ -- - figure out how to return if updated or remove return
146149 return db:eval(
147150 "UPDATE bank SET pinned = 0 WHERE yank_text = :yank_text and reg_type = :reg_type",
148151 { yank_text = text, reg_type = reg_type }
+16
lua/yankbank/utils.lua
···11+local M = {}
22+33+--- DOC:
44+---
55+---@param t table
66+---@return integer?
77+function M.last_zero_entry(t)
88+ for i = #t, 1, -1 do
99+ if t[i] == 0 then
1010+ return i
1111+ end
1212+ end
1313+ return nil
1414+end
1515+1616+return M