Skip to content

Commit

Permalink
Add arg handling support
Browse files Browse the repository at this point in the history
Introduces two new arguments:

args_allow_single_directory (default: true)
Allows launching nvim with single a argument that's a directory.
auto-session will try to load a session from that directory if possible

args_files_auto_save (default false)
Allow saving a session even when launched with a file argument (or
multiple files/dirs). It does not load any existing session first.
That's not super useful on it's own by args_files_auto_save can be a
callback function that conditionally returns true or false
  • Loading branch information
cameronr committed Jul 8, 2024
1 parent 24c44a8 commit 5df2255
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 53 deletions.
82 changes: 77 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ Auto Session takes advantage of Neovim's existing session management capabilitie
# 💡 Behaviour

1. When starting `nvim` with no arguments, auto-session will try to restore an existing session for the current `cwd` if one exists.
2. When starting `nvim .` with some argument, auto-session will do nothing.
3. Even after starting `nvim` with an argument, a session can still be manually restored by running `:SessionRestore`.
4. Any session saving and restoration takes into consideration the current working directory `cwd`.
5. When piping to `nvim`, e.g: `cat myfile | nvim`, auto-session behaves like #2.
2. When starting `nvim .` (or another directory), auto-session will try to restore the session for that directory.
3. When starting `nvim some_file.txt` (or multiple files), by default, auto-session won't do anything. See [argument handling](#argument-handling) for more details.
4. Even after starting `nvim` with a file argument, a session can still be manually restored by running `:SessionRestore`.
5. Any session saving and restoration takes into consideration the current working directory `cwd`.
6. When piping to `nvim`, e.g: `cat myfile | nvim`, auto-session won't do anything.

:warning: Please note that if there are errors in your config, restoring the session might fail, if that happens, auto session will then disable auto saving for the current session.
Manually saving a session can still be done by calling `:SessionSave`.
Expand All @@ -30,6 +31,7 @@ By default, `cwd` handling is disabled but when enabled, it works as follows:
Now when the user changes the cwd with `:cd some/new/dir` auto-session handles it gracefully, saving the current session so there aren't losses and loading the session for the upcoming cwd if it exists.

Hooks are available for custom actions _before_ and _after_ the `cwd` is changed. These hooks can be configured through the `cwd_change_handling` key as follows:

```lua
require("auto-session").setup {
log_level = "error",
Expand Down Expand Up @@ -141,6 +143,8 @@ require("auto-session").setup {
pre_cwd_changed_hook = nil, -- function: This is called after auto_session code runs for the `DirChangedPre` autocmd
post_cwd_changed_hook = nil, -- function: This is called after auto_session code runs for the `DirChanged` autocmd
},
args_allow_single_directory = true, -- boolean Follow normal sesion save/load logic if launched with a single directory as the only argument
args_allow_files_auto_save = false, -- boolean|function Allow saving a session even when launched with a file argument (or multiple files/dirs). It does not load any existing session first. While you can just set this to true, you probably want to set it to a function that decides when to save a session when launched with file args. See documentation for more detail
}
```

Expand Down Expand Up @@ -262,6 +266,74 @@ require('auto-session').setup {
}
```

## Argument Handling

By default, when `nvim` is run with a single directory argument, auto-session will try to restore the session for that directory. If `nvim` is run with multiple directories or any file arguments, auto-session won't try to restore a session and won't auto-save a session on exit (if enabled). Those behaviors can be changed with these config parameters:

```lua
args_allow_single_directory = true, -- boolean Follow normal sesion save/load logic if launched with a single directory as the only argument
args_allow_files_auto_save = false, -- boolean|function Allow saving a session even when launched with a file argument (or multiple files/dirs). It does not load any existing session first. While you can just set this to true, you probably want to set it to a function that decides when to save a session when launched with file args. See documentation for more detail
```

For `args_allow_single_directory`, if you frequently use `netrw` to look at directories, you might want to add it to `bypass_session_save_file_types` if you don't want to create a session for each directory you look at:

```lua
bypass_session_save_file_types = { 'netrw' }
```

If `args_allow_files_auto_save` is true, auto-session won't load any session when `nvim` is launched with file argument(s) but it will save on exit. What's probably more useful is to set `args_allow_files_auto_save` to a function that returns true if a session should be saved and false otherwise. auto-session will call that function on auto save when run with arguments. Here's one example config where it will save the session if at least two buffers are open after being launched with arguments:

```lua
return {
'rmagatti/auto-session',
config = function()
require('auto-session').setup({
auto_restore_enabled = true,
auto_save_enabled = true,

args_allow_files_auto_save = function()
local supported = 0

local buffers = vim.api.nvim_list_bufs()
for _, buf in ipairs(buffers) do
-- Check if the buffer is valid and loaded
if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_is_loaded(buf) then
local path = vim.api.nvim_buf_get_name(buf)
if vim.fn.filereadable(path) == 1 then supported = supported + 1 end
end
end

-- If we have more 2 or more supported buffers, save the session
return supported >= 2
end,
})
end,
}

```

Another possibility is to only save the session if there are at least two windows with buffers backed by normal files:

```lua
args_allow_files_auto_save = function()
local supported = 0

local tabpages = vim.api.nvim_list_tabpages()
for _, tabpage in ipairs(tabpages) do
local windows = vim.api.nvim_tabpage_list_wins(tabpage)
for _, window in ipairs(windows) do
local buffer = vim.api.nvim_win_get_buf(window)
local file_name = vim.api.nvim_buf_get_name(buffer)
if vim.fn.filereadable(file_name) then supported = supported + 1 end
end
end

-- If we have 2 or more windows with supported buffers, save the session
return supported >= 2
end,

```

## Disabling the plugin

One might run into issues with Firenvim or another plugin and want to disable `auto_session` altogether based on some condition.
Expand All @@ -286,7 +358,7 @@ For troubleshooting refer to the [wiki page](https://github.com/rmagatti/auto-se
## 🔭 Session Lens

Session Lens has been merged into Auto Session so now you can see, load, and delete your sessions using Telescope! It's enabled by
default if you have Telescope, but here's the Lazy config that shows the configuration options:
default if you have Telescope, but here's the Lazy config that shows the configuration options:

```lua

Expand Down
85 changes: 37 additions & 48 deletions lua/auto-session/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local AutoSession = {
conf = {},
}

-- Run comand hooks
-- Run command hooks
local function run_hook_cmds(cmds, hook_name)
local results = {}
if not Lib.is_empty_table(cmds) then
Expand Down Expand Up @@ -71,14 +71,13 @@ local defaultConf = {
---@field log_level? string|integer "debug", "info", "warn", "error" or vim.log.levels.DEBUG, vim.log.levels.INFO, vim.log.levels.WARN, vim.log.levels.ERROR
---Argv Handling
---@field args_allow_single_directory? boolean Follow normal sesion save/load logic if launched with a single directory as the only argument
---@field args_handling? string How to handle sessions when nvim is launched with arguments. Must be one of
---'replace_session': don't load existing session but save on exit
---'replace_session_only_if_multiple_buffers': don't load existing session and save session on exit if there's more than one buffer that would be saved
---'new_session_named_with_args': add arguments to session name for loading/saving (not implemented)
---@field args_allow_files_auto_save? boolean|function Allow saving a session even when launched with a file argument (or multiple files/dirs). It does not load any existing session first. While you can just set this to true, you probably want to set it to a function that decides when to save a session when launched with file args. See documentation for more detail

local luaOnlyConf = {
bypass_session_save_file_types = nil, -- Bypass auto save when only buffer open is one of these file types
close_unsupported_windows = true, -- Close windows that aren't backed by normal file
close_unsupported_windows = true, -- Close windows that aren't backed by normal file
args_allow_single_directory = true, -- Allow single directory arguments by default
args_allow_files_auto_save = false, -- Don't save session for file args by default
---CWD Change Handling Config
---@class CwdChangeHandling
---@field restore_upcoming_session boolean {true} restore session for upcoming cwd on cwd change
Expand Down Expand Up @@ -205,16 +204,19 @@ end

-- Returns whether Auto restoring / saving is enabled for the args nvim was launched with
local launch_argv = nil
local enabled_for_command_line_argv = function(is_save)
local function enabled_for_command_line_argv(is_save)
is_save = is_save or false

-- When a session is loaded, it will also load the global argument list so
-- save the argv we were actually launched with so we can always access it
-- If no args (or launch_argv has been unset, allow restoring/saving)
if not launch_argv then
launch_argv = vim.fn.argv()
Lib.logger.debug "No arguments, restoring/saving enabled"
return true
end

local argc = #launch_argv

Lib.logger.debug("enabled_for_command_line_argv, launch_argv: " .. vim.inspect(launch_argv))

if argc == 0 then
-- Launched with no args, saving is enabled
Lib.logger.debug "No arguments, restoring/saving enabled"
Expand All @@ -232,42 +234,23 @@ local enabled_for_command_line_argv = function(is_save)
return true
end

local args_handling = AutoSession.conf.args_handling

if not args_handling then
if not AutoSession.conf.args_allow_files_auto_save then
return false
end

if args_handling == "replace_session" then
-- Don't load, but do save
if not is_save then
Lib.logger.debug "[replace_session] Not allowing restore when launched with argument"
else
Lib.logger.debug "[replace_session] Allowing save when launched with argument argument"
end

return is_save
elseif args_handling == "replace_session_only_if_multiple_buffers" then
-- Don't restore
if not is_save then
Lib.logger.debug "[replace_session_only_if_multiple] Not allowing restore when launched with argument"
return false
end
-- Check close_unsupported_windows
if Lib.count_supported_buffers() > 1 then
Lib.logger.debug "[replace_session_only_if_multiple_buffers] multiple buffers, allow save"
return true
end
Lib.logger.debug "[replace_session_only_if_multiple_buffers] single buffer, disallow save"
if not is_save then
Lib.logger.debug "Not allowing restore when launched with argument"
return false
elseif args_handling == "new_session_named_with_args" then
-- TODO: implement me or maybe not worth it
return false
else
Lib.logger.warn("Invalid value for args_handling: " .. args_handling)
end

return false
if type(AutoSession.conf.args_allow_files_auto_save) == "function" then
local ret = AutoSession.conf.args_allow_files_auto_save()
Lib.logger.debug("conf.args_allow_files_auto_save() returned: " .. vim.inspect(ret))
return ret
end

Lib.logger.debug "Allowing possible save when launched with argument"
return true
end

local in_headless_mode = function()
Expand All @@ -276,6 +259,7 @@ end

local auto_save = function()
if in_pager_mode() or in_headless_mode() or not enabled_for_command_line_argv(true) then
Lib.logger.debug "auto_save, pager, headless, or enabled_for_command_line_argv returned false"
return false
end

Expand Down Expand Up @@ -732,11 +716,6 @@ end
function AutoSession.SaveSession(sessions_dir, auto)
Lib.logger.debug { sessions_dir = sessions_dir, auto = auto }

-- Delete global arguments since the buffers are what we want to
-- save the state of. i.e. we don't want to reopen the arguments
-- that were passed to nvim at launch time
vim.cmd "%argdel"

local session_file_name = get_session_file_name(sessions_dir)

Lib.logger.debug { session_file_name = session_file_name }
Expand Down Expand Up @@ -775,13 +754,20 @@ end
local function auto_restore_session_at_vim_enter()
local session_dir = nil

local argv = vim.fn.argv()
-- Save the launch args here as restoring a session will replace vim.fn.argv. We clear
-- launch_argv in restore session so it's only used for the session launched from the command
-- line
launch_argv = vim.fn.argv()

-- Is there exactly one argument and is it a directory?
if AutoSession.conf.args_allow_single_directory and #argv == 1 and vim.fn.isdirectory(argv[1]) == Lib._VIM_TRUE then
if
AutoSession.conf.args_allow_single_directory
and #launch_argv == 1
and vim.fn.isdirectory(launch_argv[1]) == Lib._VIM_TRUE
then
-- Get the full path of the directory and make sure it doesn't have a trailing path_separator
-- to make sure we find the session
session_dir = vim.fn.fnamemodify(argv[1], ":p"):gsub("[" .. Lib.get_path_separator() .. "]$", "")
session_dir = vim.fn.fnamemodify(launch_argv[1], ":p"):gsub("[" .. Lib.get_path_separator() .. "]$", "")
Lib.logger.debug("Launched with single directory, using as session_dir: " .. session_dir)
end

Expand Down Expand Up @@ -843,6 +829,9 @@ function AutoSession.RestoreSession(sessions_dir_or_file)
local cmd = AutoSession.conf.silent_restore and "silent source " .. file_path or "source " .. file_path
local success, result = pcall(vim.cmd, cmd)

-- Clear any saved command line args since we don't need them anymore
launch_argv = nil

if not success then
Lib.logger.error([[
Error restoring session! The session might be corrupted.
Expand Down

0 comments on commit 5df2255

Please sign in to comment.