···11+-- persistence.lua
22+33+local M = {}
44+55+-- 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
1111+1212+function M.enable_persistence(yanks, opts)
1313+ if not opts.method then
1414+ return
1515+ elseif opts.method == "file" then
1616+ -- TODO:
1717+ require("persistence.file").setup_persistence(
1818+ yanks, opts.persist_file, opts.max_entries)
1919+ elseif opts.method == "sqlite" then
2020+ -- TODO:
2121+ print("sqlite persistence not yet implemented.")
2222+ end
2323+end
2424+2525+return M
+139
lua/yankbank/persistence/file.lua
···11+-- persistence/file.lua
22+33+local M = {}
44+55+local n_entries = 0
66+77+-- function that checks if a file exists
88+---@param file string: file path
99+---@return boolean
1010+local function file_exists(file)
1111+ local f = io.open(file, "rb")
1212+ if f then f:close() end
1313+ return f ~= nil
1414+end
1515+1616+-- function that reads all lines of file into a table
1717+---@param file string: file path
1818+---@return table
1919+local function read_lines(file)
2020+ if not file_exists(file) then return {} end
2121+ local lines = {}
2222+ for line in io.lines(file) do
2323+ lines[#lines+1] = line
2424+ end
2525+ return lines
2626+end
2727+2828+-- check first line from file for presence of yankbank list header.
2929+-- if it exists, populate current number of entries.
3030+---@param line string
3131+---@return boolean
3232+local function check_for_header(line)
3333+ local n = string.match(line, "<YANKBANK_LIST:(%d+)>")
3434+ if n then
3535+ n_entries = n
3636+ return true
3737+ end
3838+ return false
3939+end
4040+4141+-- function that checks for the presence of a yankbank header on a given line.
4242+-- returns t/f and index, length for entries that exist
4343+---@param line string: line from file being checked
4444+---@return table|nil
4545+local function check_for_entry(line)
4646+ local i, l, ft, rt = string.match(line, "<YANKBANK_ENTRY:(%d+),(%d+),(%a+),(%a+)>")
4747+ if i then
4848+ return {
4949+ index = tonumber(i),
5050+ length = tonumber(l),
5151+ file_type = ft,
5252+ reg_type = rt,
5353+ }
5454+ end
5555+end
5656+5757+-- function that reads a yankbank entry from an index to an offset.
5858+---@param i integer: starting index
5959+---@param offset integer: stopping point = i+offset
6060+---@param lines table: file contents
6161+---@return table: yankbank entry in string table form
6262+local function read_entry(i, offset, lines)
6363+ local entry = {}
6464+ for j = i, i + offset - 1 do
6565+ entry[#entry + 1] = lines[j]
6666+ end
6767+ return entry
6868+end
6969+7070+-- populate yankbank with entries contained in file.
7171+---@param yanks table: table to populate with yanks
7272+---@param file string: yankbank persistence file
7373+---@param max_entries integer: maximum number of yankbank entries
7474+local function populate_yankbank(yanks, file, max_entries)
7575+ -- read lines from file
7676+ local lines = read_lines(file)
7777+ if not check_for_header(lines[1]) then
7878+ print("YankBank list header not found in file...")
7979+ return
8080+ end
8181+8282+ -- iterate through remaining lines in file, adding entries to yankbank
8383+ local entries = {}
8484+ local i = 2
8585+ while i <= #lines do
8686+ local res = check_for_entry(lines[i])
8787+ if res then
8888+ local entry = read_entry(i + 1, res.length, lines)
8989+ if res.index < max_entries then
9090+ -- add to entries
9191+ -- NOTE: might need to sort entries afterwards
9292+ -- TODO: populate yankbank entries
9393+ -- - update yanks table, reg_type, and place at correct spot in list
9494+ entries[#entries + 1] = entry -- TODO: might need to convert to string
9595+ -- NOTE: ^ should I use table.insert instead? (probably)
9696+ end
9797+ -- skip lines that were added to entries
9898+ i = i + res.length
9999+ end
100100+ i = i + 1
101101+ end
102102+103103+ -- TODO: add entries to bank
104104+ print(yanks)
105105+106106+ print(vim.inspect(entries))
107107+end
108108+109109+-- setup function for a persistence file.
110110+-- should be called in plugin setup function
111111+---@param yanks table: table to populate with yanks
112112+---@param file string: file path
113113+---@param max_entries integer: maximum number of yankbank entries
114114+function M.setup_persistence(yanks, file, max_entries)
115115+ -- check if file exists, create it (with header) if it does not
116116+ if not file_exists(file) then
117117+ print("Creating file...")
118118+ local f, err = io.open(file, "w")
119119+ if f then
120120+ f:write("<YANKBANK_LIST:0>")
121121+ f:close()
122122+ else
123123+ print(err)
124124+ end
125125+ return
126126+ end
127127+ populate_yankbank(yanks, file, max_entries)
128128+end
129129+130130+-- local lines = read_lines("test.txt")
131131+-- print(vim.inspect(lines))
132132+-- TEST: remove later
133133+local yanks = {}
134134+print(M.setup_persistence(yanks, "test.txt", 10))
135135+yanks = {}
136136+print(M.setup_persistence(yanks, "test1.txt", 10))
137137+138138+139139+return M