diff --git a/README.md b/README.md index 1e5a834..202cea1 100644 --- a/README.md +++ b/README.md @@ -1 +1,75 @@ -remembers where you left off +# nivvie :seedline: + +tiny neovim session keeper, keeping your place safe + +## what it does 🍃 + +nivvie remembers where you left off and restores it when you return (session +handling). it keeps sessions stored safely and lets you call on them whenever +you need, without clutter or extra ritual. + +## why nivvie 🍂 + +there are larger session managers with more features. nivvie is a small and +quiet companion, meant for when you want something clean, simple, and reliable. + +## features 🌸 + +- automatic save and restore (no extra steps) +- manual save, load, and delete commands (direct control) +- minimal configuration (defaults just work) +- lightweight and unobtrusive (stays out of the way) + +## installation 🌿 + +add nivvie with your favourite plugin manager. + +###### `vim.pack` + +```lua +vim.pack.add({ "comfysage/nivvie.nvim" }) +``` + +###### `lazy.nvim` + +```lua +{ + "comfysage/nivvie.nvim", + lazy = false, -- nivvie takes care of its own lazy loading + config = function() + require("nivvie").setup() + end +} +``` + +## usage 🌼 + +sessions are saved automatically when you quit neovim and restored when you open it again. you can also manage sessions yourself: + +``` +:Nivvie save [name] " save the current session for the current directory or with a custom name +:Nivvie load [name] " load session for the current directory or with a custom name +:Nivvie delete [name] " delete session for the current directory or with a custom name +``` + +you may also map keys to these commands: + +```lua +vim.keymap.set("n", "ss", ":NivvieSave") +vim.keymap.set("n", "sl", ":NivvieLoad") +``` + +## configuration 🌾 + +nivvie works without configuration (zero setup). you can still adjust its behavior: + +```lua +require("nivvie").setup({ + -- where sessions are stored + session_dir = vim.fn.stdpath("state") .. "/sessions", + -- save on exit + autosave = true, + -- load on start + autorestore = true, +}) +``` diff --git a/plugin/nivvie.lua b/plugin/nivvie.lua index b52c6dc..54fbbcc 100644 --- a/plugin/nivvie.lua +++ b/plugin/nivvie.lua @@ -1,67 +1,149 @@ if vim.g.loaded_session then - return + return end vim.g.loaded_session = true local session = {} +---@private +session.stdin = false + function session.get_uri() - return string.gsub(vim.fn.getcwd(), "[^a-zA-Z0-9_.-]", function(s) - return "<" .. vim.fn.char2nr(s) - end) + return string.gsub(vim.fn.getcwd(), '[^a-zA-Z0-9_.-]', function(s) + return '<' .. vim.fn.char2nr(s) + end) end -local sessiondir = vim.g.sessiondir or vim.fs.joinpath(vim.fn.stdpath("state"), "sessions") +local sessiondir = vim.g.sessiondir + or vim.fs.joinpath(vim.fn.stdpath 'state', 'sessions') -function session.get_path() - return vim.fs.joinpath(sessiondir, session.get_uri() .. ".vim") +---@param name? string +function session.get_path(name) + return vim.fs.joinpath(sessiondir, (name or session.get_uri()) .. '.vim') end -function session.save() - local session_file = session.get_path() +---@param name? string +function session.save(name) + local session_file = session.get_path(name) - vim.fn.mkdir(sessiondir, "p") + vim.fn.mkdir(sessiondir, 'p') - vim.api.nvim_cmd({ - cmd = "mksession", - bang = true, - args = { session_file }, - }, {}) + vim.api.nvim_cmd({ + cmd = 'mksession', + bang = true, + args = { session_file }, + }, {}) end function session.clean() - vim.iter(ipairs(vim.api.nvim_list_bufs())):each(function(_, bufnr) - if vim.bo[bufnr].buftype ~= "" then - vim.api.nvim_buf_delete(bufnr, { force = true }) - end - end) + vim.iter(ipairs(vim.api.nvim_list_bufs())):each(function(_, bufnr) + if vim.bo[bufnr].buftype ~= '' then + vim.api.nvim_buf_delete(bufnr, { force = true }) + end + end) end -function session.load() - local path = session.get_path() - if vim.uv.fs_stat(path) then - vim.api.nvim_cmd({ - cmd = "source", - args = { path }, - }, {}) - vim.api.nvim_exec_autocmds("SessionLoadPost", {}) - end +---@param name? string +function session.load(name) + local path = session.get_path(name) + if vim.uv.fs_stat(path) then + vim.api.nvim_cmd({ + cmd = 'source', + args = { path }, + }, {}) + vim.api.nvim_exec_autocmds('SessionLoadPost', {}) + end end -local group = vim.api.nvim_create_augroup("nivvie", { clear = true }) +---- -vim.api.nvim_create_autocmd({ "VimLeavePre" }, { - group = group, - callback = function() - session.clean() - session.save() - end, -}) +function session.shouldload() + if session.stdin then + return false + end + + if vim.fn.argc() > 0 then + return false + end -if vim.fn.argc() > 0 then - return + local bufs = vim.api.nvim_list_bufs() + bufs = vim + .iter(bufs) + :filter(function(buf) + return vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buftype == '' + end) + :totable() + + return #bufs == 0 end + +--- only load if necessary +function session.autoload() + if not session.shouldload() then + return + end + session.load() +end + +local group = vim.api.nvim_create_augroup('nivvie', { clear = true }) + +vim.api.nvim_create_autocmd({ 'VimLeavePre' }, { + group = group, + callback = function() + session.clean() + session.save() + end, +}) + +vim.api.nvim_create_autocmd({ 'StdinReadPost' }, { + group = group, + callback = function() + session.stdin = true + end, +}) + vim.schedule(function() - session.load() + vim.api.nvim_create_user_command('Nivvie', function(args) + if args.fargs[1] == 'save' then + session.save(args.fargs[2]) + return + elseif args.fargs[1] == 'load' then + session.load(args.fargs[2]) + return + elseif args.fargs[1] == 'delete' then + local path = session.get_path(args.fargs[2]) + if vim.uv.fs_stat(path) then + vim.uv.fs_unlink(path) + end + end + end, { + complete = function() + return { + 'save', + 'load', + 'delete', + } + end, + }) end) + +---- + +if vim.v.vim_did_enter > 0 then + vim.schedule(function() + session.autoload() + end) + return +end + +vim.api.nvim_create_autocmd({ 'VimEnter' }, { + group = group, + callback = function() + vim.schedule(function() + session.autoload() + end) + end, +}) + +return session