summaryrefslogtreecommitdiffstats
path: root/lua/dotfiles/session.lua
blob: 4333978b07b54db9bc7396ad286621bb112729fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
-- Sidecar specification for :mksession. :mksession can't persist everything we want (tab-local
-- variables, man:// buffers, ...), so we keep a JSON object in a sidecar file alongside each `.vim`
-- session. Features register a `save`/`restore` pair: `save` returns the data to stash, `restore`
-- reapplies it after the session has been sourced. The engine owns reading, writing and dispatch;
-- it does not touch :mksession itself. Providers are wired up in plugin/50-session.lua.
--
-- API:
--   register(key, save, restore) — add a provider (provider contract below)
--   write(path)                  — collect every provider and write `path`'s sidecar
--   read(path)                   — read `path`'s sidecar and run each provider's restore
--   remove(path)                 — delete `path`'s sidecar if it exists
--   providers                    — the ordered registry: a list of { key, save, restore }

local M = {}

-- Ordered registry of sidecar providers (the "global table"):
--   { key = string, save = fun(): table, restore = fun(data: table) }
-- `save` returns a JSON-encodable table stored under `key`; `restore` receives it back (never nil)
-- after the session is sourced. Registration order is the restore order.
M.providers = {}

-- The sidecar JSON path that pairs with a `.vim` session file.
local function sidecar_path(path)
	return (path:gsub("%.vim$", "")) .. ".json"
end

-- Register a sidecar provider. `save` and `restore` are both required (passed together) so a
-- provider can never be half-defined.
function M.register(key, save, restore)
	assert(
		type(save) == "function" and type(restore) == "function",
		"session.register: both save and restore are required"
	)
	M.providers[#M.providers + 1] = { key = key, save = save, restore = restore }
end

-- Collect every provider's data and write the sidecar for `path`.
function M.write(path)
	local data = {}
	for _, p in ipairs(M.providers) do
		data[p.key] = p.save()
	end
	local f = io.open(sidecar_path(path), "w")
	if f then
		f:write(vim.json.encode(data))
		f:close()
	end
end

-- Read `path`'s sidecar and dispatch each provider's restore. A missing or malformed sidecar is
-- silently ignored (sessions predating a provider simply won't have its key).
function M.read(path)
	local f = io.open(sidecar_path(path), "r")
	if not f then
		return
	end
	local content = f:read("*a")
	f:close()
	local ok, data = pcall(vim.json.decode, content)
	if not (ok and type(data) == "table") then
		return
	end
	for _, p in ipairs(M.providers) do
		if data[p.key] ~= nil then
			p.restore(data[p.key])
		end
	end
end

-- Delete the sidecar paired with `path`, if present.
function M.remove(path)
	local sidecar = sidecar_path(path)
	if vim.uv.fs_stat(sidecar) then
		vim.fs.rm(sidecar)
	end
end

return M