-- 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