Skip to content

Commit

Permalink
refactor: update logic for autoload or starting sessions (#104)
Browse files Browse the repository at this point in the history
* Update logic for autoload or starting sessions.

The logic to prevent autoloading/starting sessions when any arguments
are supplied to neovim is to prevent session management from kicking in
when editing a single file.

This updates the logic to allow a single argument passed to neovim as
long as the argument is an existing directory. When neovim is launched
in this way it behaves the same as opening neovim with no arguments but
has changed the working directory.

This results in consistent behavior of the autoloading/starting of
sessions when passing a directory argument to start neovim.

See: #93

* Fix comment, make comparisons more direct

* Update functions to be directory-aware

The main functionality in `init.lua` assumes using current working
directory in most cases. This refactors these functions to allow passing
in a directory instead.

The default behavior is to now use the current directory unless neovim
was started with a single directory argument, using that instead.

This also special-cases `.` as `vim.fn.expand()` does not resolve that
to the current working directory.
  • Loading branch information
neandrake authored Dec 21, 2023
1 parent 66d540f commit 7944b9a
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ require("persisted").setup({

Autoloading can be further controlled for certain directories by specifying `allowed_dirs` and `ignored_dirs`.

> **Note**: Autoloading will not occur if the plugin is lazy loaded or a user opens Neovim with arguments. For example: `nvim some_file.rb`
> **Note**: Autoloading will not occur if the plugin is lazy loaded or a user opens Neovim with arguments other than a single directory argument. For example: `nvim some_file.rb` will not not result in autoloading but `nvim some/existing/path` or `nvim .` will.
### Following current working directory

Expand Down
12 changes: 7 additions & 5 deletions doc/persisted.nvim.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Install the plugin with your preferred package manager:
>vim
" Vim Script
Plug 'olimorris/persisted.nvim'

lua << EOF
require("persisted").setup {
-- your configuration comes here
Expand Down Expand Up @@ -274,7 +274,9 @@ Autoloading can be further controlled for certain directories by specifying


**Note**Autoloading will not occur if the plugin is lazy loaded or a user opens
Neovim with arguments. For example: `nvim some_file.rb`
Neovim with arguments other than a single directory argument. For example:
`nvim some_file.rb` will not result in autoloading but
`nvim some/existing/path` or `nvim .` will.

FOLLOWING CURRENT WORKING DIRECTORY ~

Expand Down Expand Up @@ -378,7 +380,7 @@ autocmd can be created to hook into the `PersistedSavePre` event:

>lua
local group = vim.api.nvim_create_augroup("PersistedHooks", {})

vim.api.nvim_create_autocmd({ "User" }, {
pattern = "PersistedSavePre",
group = group,
Expand All @@ -395,14 +397,14 @@ made available to the callbacks:

>lua
local group = vim.api.nvim_create_augroup("PersistedHooks", {})

vim.api.nvim_create_autocmd({ "User" }, {
pattern = "PersistedTelescopeLoadPre",
group = group,
callback = function(session)
-- Save the currently loaded session
require("persisted").save({ session = vim.g.persisted_loaded_session })

-- Delete all of the open buffers
vim.api.nvim_input("<ESC>:%bd!<CR>")
end,
Expand Down
100 changes: 71 additions & 29 deletions lua/persisted/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,61 @@ local function escape_pattern(str, pattern, replace, n)
return string.gsub(str, pattern, replace, n)
end

---Checks if vim was started with either zero arguments or a single argument
---which is a drectory.
---@return boolean
local function is_neovim_start_ok()
if vim.fn.argc() == 1 then
return vim.fn.isdirectory(vim.fn.argv(0)) ~= 0
end
return vim.fn.argc() == 0
end

---Gets the directory to be used for sessions.
---@return string
local function get_start_dir()
if vim.fn.argc() == 1 then
local dir = vim.fn.expand(vim.fn.argv(0))
if dir == '.' then
return vim.fn.getcwd()
end
if vim.fn.isdirectory(dir) ~= 0 then
return dir
end
end
return vim.fn.getcwd()
end

---Does the current working directory allow for the auto-saving and loading?
---@param dir string
---@return boolean
local function allow_dir()
local function allow_dir(dir)
local allowed_dirs = config.options.allowed_dirs

if allowed_dirs == nil then
return true
end

return utils.dirs_match(vim.fn.getcwd(), allowed_dirs)
return utils.dirs_match(dir, allowed_dirs)
end

---Is the current working directory ignored for auto-saving and loading?
---@param dir string
---@return boolean
local function ignore_dir()
local function ignore_dir(dir)
local ignored_dirs = config.options.ignored_dirs

if ignored_dirs == nil then
return false
end

return utils.dirs_match(vim.fn.getcwd(), ignored_dirs)
return utils.dirs_match(dir, ignored_dirs)
end

---Get the session that was saved last
---@param dir string The directory whose last session to load.
---@return string
local function get_last()
local function get_last(dir)
local sessions = vim.fn.glob(config.options.save_dir .. "*.vim", true, true)

table.sort(sessions, function(a, b)
Expand All @@ -55,20 +83,22 @@ local function get_last()
end

---Get the current Git branch
---@param dir? string The directory to inspect for a Git branch. If not set then the current working directory is used.
---@return string|nil
function M.get_branch()
function M.get_branch(dir)
dir = dir or get_start_dir()
if config.options.use_git_branch then
vim.fn.system([[git rev-parse 2> /dev/null]])
vim.fn.system("git -C " .. dir .. " rev-parse 2>/dev/null")

local git_enabled = (vim.v.shell_error == 0)

if git_enabled then
local git_branch = vim.fn.systemlist([[git rev-parse --abbrev-ref HEAD 2>/dev/null]])
local git_branch = vim.fn.systemlist("git -C " .. dir .. " rev-parse --abbrev-ref HEAD 2>/dev/null")

if vim.v.shell_error == 0 then
local branch = config.options.branch_separator .. git_branch[1]:gsub("/", "%%")
local branch_session = config.options.save_dir
.. vim.fn.getcwd():gsub(utils.get_dir_pattern(), "%%")
.. dir:gsub(utils.get_dir_pattern(), "%%")
.. branch
.. ".vim"

Expand Down Expand Up @@ -100,18 +130,21 @@ function M.get_branch()
end

---Get the current session for the current working directory and git branch
---@param dir string The directory whose session file to get.
---@return string
local function get_current()
local name = vim.fn.getcwd():gsub(utils.get_dir_pattern(), "%%")
local branch = M.get_branch()
local function get_current(dir)
local name = dir:gsub(utils.get_dir_pattern(), "%%")
local branch = M.get_branch(dir)

return config.options.save_dir .. name .. (branch or "") .. ".vim"
end

---Determine if a session for the current wording directory, exists
---@param dir? string The directory whose associated session to check if exists. If not set, current working directory is used.
---@return boolean
function M.session_exists()
return vim.fn.filereadable(get_current()) ~= 0
function M.session_exists(dir)
dir = dir or get_start_dir()
return vim.fn.filereadable(get_current(dir)) ~= 0
end

---Setup the plugin
Expand All @@ -120,21 +153,24 @@ end
function M.setup(opts)
config.setup(opts)

local dir = get_start_dir()
if
config.options.autosave
and (allow_dir() and not ignore_dir() and vim.g.persisting == nil)
and vim.fn.argc() == 0
and (allow_dir(dir) and not ignore_dir(dir) and vim.g.persisting == nil)
and is_neovim_start_ok()
then
M.start()
end
end

---Load a session
---@param opt? table
---@param dir? string
---@return nil
function M.load(opt)
function M.load(opt, dir)
opt = opt or {}
local session = opt.session or (opt.last and get_last() or get_current())
dir = dir or get_start_dir()
local session = opt.session or (opt.last and get_last(dir) or get_current(dir))

local session_exists = vim.fn.filereadable(session) ~= 0

Expand All @@ -158,18 +194,18 @@ function M.load(opt)
}, true, {})
end

if config.options.autosave and (allow_dir() and not ignore_dir()) then
if config.options.autosave and (allow_dir(dir) and not ignore_dir(dir)) then
M.start()
end
end

---Automatically load the session for the current dir
---@return nil
function M.autoload()
-- Ensure that no arguments have been passed to Neovim
if config.options.autoload and vim.fn.argc() == 0 then
if allow_dir() and not ignore_dir() then
M.load()
local dir = get_start_dir()
if config.options.autoload and is_neovim_start_ok() then
if allow_dir(dir) and not ignore_dir(dir) then
M.load({}, dir)
end
end
end
Expand Down Expand Up @@ -201,9 +237,11 @@ end

---Save the session
---@param opt? table
---@param dir? string
---@return nil
function M.save(opt)
function M.save(opt, dir)
opt = opt or {}
dir = dir or get_start_dir()

if not opt.session then
-- Do not save the session if the user has manually stopped it...unless it's forced
Expand All @@ -222,14 +260,16 @@ function M.save(opt)
end
end

local session = opt.session or (vim.g.persisted_branch_session or vim.g.persisting_session or get_current())
local session = opt.session or (vim.g.persisted_branch_session or vim.g.persisting_session or get_current(dir))
write(session)
end

---Delete the current session
---@param dir? string The directory whose associated session to delete. If not set, the current working directory is used.
---@return nil
function M.delete()
local session = get_current()
function M.delete(dir)
dir = dir or get_start_dir()
local session = get_current(dir)
if session and vim.loop.fs_stat(session) ~= 0 then
vim.api.nvim_exec_autocmds("User", { pattern = "PersistedDeletePre", data = { name = session } })

Expand All @@ -243,12 +283,14 @@ function M.delete()
end

---Determines whether to load, start or stop a session
---@param dir? string The directory whose associated session saving should be toggled. If not set, the current working directory is used.
---@return nil
function M.toggle()
function M.toggle(dir)
vim.api.nvim_exec_autocmds("User", { pattern = "PersistedToggled" })
dir = dir or get_start_dir()

if vim.g.persisting == nil then
return M.load()
return M.load({}, dir)
end
if vim.g.persisting then
return M.stop()
Expand Down

0 comments on commit 7944b9a

Please sign in to comment.