feat: allow/ignore dirs for save/load

This addresses #1 and allows the user to specify directories which the plugin will automatically save or load from. Alternatively, specify directories for which this behaviour will be ignored
main
olimorris 2022-03-07 18:58:37 +00:00
parent b2e4162c74
commit 0669d29f22
3 changed files with 124 additions and 36 deletions

View File

@ -7,14 +7,14 @@ The plugin was forked from the fantastic [Persistence.nvim](https://github.com/f
## ✨ Features ## ✨ Features
- Automatically saves the active session under `.local/share/nvim/sessions` on exiting Neovim - Automatically saves the active session under `.local/share/nvim/sessions` on exiting Neovim
- Simple API to restore the current or last session - Supports auto saving and loading of sessions with allowed/ignored directories
- Simple API to save/stop/restore/delete/list the current session(s)
- Support for sessions across git branches - Support for sessions across git branches
- Specify custom directory to save sessions - Specify custom directory to save/load sessions from
- Stop or even delete the current session
## ⚡️ Requirements ## ⚡️ Requirements
- Neovim >= 0.5.0 - Neovim >= 0.6.0
## 📦 Installation ## 📦 Installation
@ -55,9 +55,11 @@ The plugin comes with the following defaults:
{ {
dir = vim.fn.expand(vim.fn.stdpath("data") .. "/sessions/"), -- directory where session files are saved dir = vim.fn.expand(vim.fn.stdpath("data") .. "/sessions/"), -- directory where session files are saved
use_git_branch = false, -- create session files based on the branch of the git enabled repository use_git_branch = false, -- create session files based on the branch of the git enabled repository
autosave = true, -- automatically save session files autosave = true, -- automatically save session files when exiting Neovim
autoload = false, -- automatically load the current session on Neovim startup autoload = false, -- automatically load the session for the cwd on Neovim startup
options = { "buffers", "curdir", "tabpages", "winsize" }, -- session options used for saving options = { "buffers", "curdir", "tabpages", "winsize" }, -- session options used for saving
allowed_dirs = nil, -- table of dirs that the plugin will auto-save and auto-load from
ignored_dirs = nil, -- table of dirs that are ignored when auto-saving and auto-loading
before_save = function() end, -- function to run before the session is saved to disk before_save = function() end, -- function to run before the session is saved to disk
after_save = function() end, -- function to run after the session is saved to disk after_save = function() end, -- function to run after the session is saved to disk
} }
@ -65,13 +67,17 @@ The plugin comes with the following defaults:
These can be overwritten by calling the `setup` method and passing in the appropriate value. These can be overwritten by calling the `setup` method and passing in the appropriate value.
> **Note:** `autosave` and `autoload` may not work if you've lazy loaded the plugin.
## 🚀 Usage ## 🚀 Usage
The plugin works well with others like [vim-startify](https://github.com/mhinz/vim-startify) or [dashboard](https://github.com/glepnir/dashboard-nvim). It will never restore a session automatically but the commands below, or a custom autocmd, may be used. The plugin is designed to work with startup screens like [vim-startify](https://github.com/mhinz/vim-startify) or [dashboard](https://github.com/glepnir/dashboard-nvim) out of the box. It will never load a session automatically by default.
To use the plugin, the commands below may be used:
### Commands ### Commands
- `SessionStart` - Start a session. Useful if `autosave = false` - `SessionStart` - Start recording a session. Useful if `autosave = false`
- `SessionStop` - Stop recording a session - `SessionStop` - Stop recording a session
- `SessionSave` - Save the current session - `SessionSave` - Save the current session
- `SessionLoad` - Load the session for the current directory and current branch if `git_use_branch = true` - `SessionLoad` - Load the session for the current directory and current branch if `git_use_branch = true`
@ -79,6 +85,8 @@ The plugin works well with others like [vim-startify](https://github.com/mhinz/v
- `SessionDelete` - Delete the current session - `SessionDelete` - Delete the current session
- `SessionToggle` - Determines whether to load, start or stop a session - `SessionToggle` - Determines whether to load, start or stop a session
> **Note:** The author only binds `SessionToggle` to a keymap for simplicity.
### Callbacks ### Callbacks
The plugin allows for _before_ and _after_ callbacks to be executed relative to the session. This is achieved via the `before_save` and `after_save` configuration options. The plugin allows for _before_ and _after_ callbacks to be executed relative to the session. This is achieved via the `before_save` and `after_save` configuration options.

View File

@ -4,9 +4,11 @@ local M = {}
local defaults = { local defaults = {
dir = vim.fn.expand(vim.fn.stdpath("data") .. "/sessions/"), -- directory where session files are saved dir = vim.fn.expand(vim.fn.stdpath("data") .. "/sessions/"), -- directory where session files are saved
use_git_branch = false, -- create session files based on the branch of the git enabled repository use_git_branch = false, -- create session files based on the branch of the git enabled repository
autosave = true, -- automatically save session files autosave = true, -- automatically save session files when exiting Neovim
autoload = false, -- automatically load the session in the cwd on Neovim startup autoload = false, -- automatically load the session for the cwd on Neovim startup
options = { "buffers", "curdir", "tabpages", "winsize" }, -- session options used for saving options = { "buffers", "curdir", "tabpages", "winsize" }, -- session options used for saving
allowed_dirs = nil, -- table of dirs that the plugin will auto-save and auto-load from
ignored_dirs = nil, -- table of dirs that are ignored for auto-saving and auto-loading
before_save = function() end, -- function to run before the session is saved to disk before_save = function() end, -- function to run before the session is saved to disk
after_save = function() end, -- function to run after the session is saved to disk after_save = function() end, -- function to run after the session is saved to disk
} }

View File

@ -3,7 +3,18 @@ local config = require("persisted.config")
local M = {} local M = {}
local e = vim.fn.fnameescape local e = vim.fn.fnameescape
local echo = vim.api.nvim_echo
local echoerr = function(msg, error)
echo({
{ "[persisted.nvim]: ", "ErrorMsg" },
{ msg, "WarningMsg" },
{ error, "Normal" },
}, true, {})
end
---Setup the plugin's commands
---@return nil
local function setup_commands() local function setup_commands()
vim.cmd([[ vim.cmd([[
command! SessionStart :lua require("persisted").start() command! SessionStart :lua require("persisted").start()
@ -16,16 +27,55 @@ local function setup_commands()
]]) ]])
end end
function M.get_current() ---Check if a target directory exists in a given table
local pattern = "/" ---@param dir_target string
if vim.fn.has("win32") == 1 then ---@param dir_table table
pattern = "[\\:]" ---@return boolean
local function dirs_match(dir_target, dir_table)
for _, dir in pairs(dir_table) do
dir = string.gsub(vim.fn.expand(dir), "/+$", "")
if dir_target == dir then
return true
end end
local name = vim.fn.getcwd():gsub(pattern, "%%") end
return config.options.dir .. name .. get_branch() .. ".vim" return false
end end
function get_branch() ---Does the current working directory allow for the auto-saving and loading?
---@return boolean
local function allow_dir()
local allowed_dirs = config.options.allowed_dirs
if allowed_dirs == nil then
return true
end
return dirs_match(vim.fn.getcwd(), allowed_dirs)
end
---Is the current working directory ignored for auto-saving and loading?
---@return boolean
local function ignore_dir()
local ignored_dirs = config.options.ignored_dirs
if ignored_dirs == nil then
return false
end
return dirs_match(vim.fn.getcwd(), ignored_dirs)
end
---Get the session that was saved last
---@return string
local function get_last()
local sessions = M.list()
table.sort(sessions, function(a, b)
return vim.loop.fs_stat(a).mtime.sec > vim.loop.fs_stat(b).mtime.sec
end)
return sessions[1]
end
---Get the current Git branch
---@return string
local function get_branch()
local git_enabled = (vim.fn.isdirectory(vim.fn.getcwd() .. "/.git") == 1) local git_enabled = (vim.fn.isdirectory(vim.fn.getcwd() .. "/.git") == 1)
if config.options.use_git_branch and git_enabled then if config.options.use_git_branch and git_enabled then
@ -42,25 +92,52 @@ function get_branch()
return "" return ""
end end
function M.get_last() ---Get the current session for the current working directory and git branch
local sessions = M.list() ---@return string
table.sort(sessions, function(a, b) local function get_current()
return vim.loop.fs_stat(a).mtime.sec > vim.loop.fs_stat(b).mtime.sec local pattern = "/"
end) if vim.fn.has("win32") == 1 then
return sessions[1] pattern = "[\\:]"
end
local name = vim.fn.getcwd():gsub(pattern, "%%")
return config.options.dir .. name .. get_branch() .. ".vim"
end end
---Setup the plugin based on the intersect of the default and the user's config
---@param opts table
---@return nil
function M.setup(opts) function M.setup(opts)
config.setup(opts) config.setup(opts)
setup_commands() setup_commands()
if config.options.autoload then if config.options.autoload and (allow_dir() and not ignore_dir()) then
M.load() M.load()
end end
if config.options.autosave then if config.options.autosave and (allow_dir() and not ignore_dir() and vim.g.persisting == nil) then
M.start() M.start()
end end
end end
---Load a session
---@param opt table
---@return nil
function M.load(opt)
opt = opt or {}
local session = opt.last and get_last() or get_current()
if session and vim.fn.filereadable(session) ~= 0 then
local ok, result = pcall(vim.cmd, "source " .. e(session))
if not ok then
echoerr("Error loading the session! ", result)
end
end
if config.options.autosave and (allow_dir() and not ignore_dir()) then
M.start()
end
end
---Start recording a session and write it to disk when exiting Neovim
---@return nil
function M.start() function M.start()
vim.cmd([[ vim.cmd([[
augroup Persisted augroup Persisted
@ -71,6 +148,8 @@ function M.start()
vim.g.persisting = true vim.g.persisting = true
end end
---Stop recording a session
---@return nil
function M.stop() function M.stop()
vim.cmd([[ vim.cmd([[
autocmd! Persisted autocmd! Persisted
@ -79,39 +158,38 @@ function M.stop()
vim.g.persisting = false vim.g.persisting = false
end end
---Save the session to disk
---@return nil
function M.save() function M.save()
config.options.before_save() config.options.before_save()
local tmp = vim.o.sessionoptions local tmp = vim.o.sessionoptions
vim.o.sessionoptions = table.concat(config.options.options, ",") vim.o.sessionoptions = table.concat(config.options.options, ",")
vim.cmd("mks! " .. e(M.get_current())) vim.cmd("mks! " .. e(get_current()))
vim.o.sessionoptions = tmp vim.o.sessionoptions = tmp
vim.g.persisting = true vim.g.persisting = true
config.options.after_save() config.options.after_save()
end end
---Delete the current session from disk
---@return nil
function M.delete() function M.delete()
local session = M.get_current() local session = get_current()
if session and vim.loop.fs_stat(session) ~= 0 then if session and vim.loop.fs_stat(session) ~= 0 then
M.stop() M.stop()
vim.fn.system("rm " .. e(session)) vim.fn.system("rm " .. e(session))
end end
end end
function M.load(opt) ---List all of the sessions in the session directory
opt = opt or {} ---@return table
local session = opt.last and M.get_last() or M.get_current()
if session and vim.fn.filereadable(session) ~= 0 then
vim.cmd("source " .. e(session))
vim.g.persisting = true
end
end
function M.list() function M.list()
return vim.fn.glob(config.options.dir .. "*.vim", true, true) return vim.fn.glob(config.options.dir .. "*.vim", true, true)
end end
---Determines whether to load, start or stop a session
---@return function
function M.toggle() function M.toggle()
if vim.g.persisting == nil then if vim.g.persisting == nil then
return M.load() return M.load()