From ca7c3f2d259b5ea6ac60d594a826354b16097dd5 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Wed, 3 Jul 2024 00:34:05 -0700 Subject: [PATCH 1/4] Initial exploration on how to support launch args Add args_handling config option to control how args are handled: replace_session: don't load existing session but save on exit replace_session_only_if_multiple_buffers: don't load existing session but if there is more than one buffer that would be saved, then save on exit new_session_named_with_args: not implemented, may create too many sessions and may not be worth it --- lua/auto-session/init.lua | 118 +++++++++++++++++++++++++++++++------- lua/auto-session/lib.lua | 22 +++++++ 2 files changed, 119 insertions(+), 21 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index ddbdbb4..7b25462 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -69,6 +69,13 @@ local defaultConf = { ---@field close_unsupported_windows? boolean Whether to close windows that aren't backed by a real file ---@field silent_restore boolean Whether to restore sessions silently or not ---@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_dot? boolean Follow normal sesion save/load logic if launched as 'nvim .' +---@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) + 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 @@ -192,23 +199,70 @@ local function get_branch_name() return "" end -local pager_mode = nil local in_pager_mode = function() - if pager_mode ~= nil then - return pager_mode - end -- Only evaluate this once - - local opened_with_args = next(vim.fn.argv()) ~= nil -- Neovim was opened with args - local reading_from_stdin = vim.g.in_pager_mode == Lib._VIM_TRUE -- Set from StdinReadPre - - pager_mode = opened_with_args or reading_from_stdin - Lib.logger.debug("in pager mode", pager_mode) - if pager_mode then - local no_restore_cmds = AutoSession.get_cmds "no_restore" - Lib.logger.debug("In pager mode, skipping auto restore and unning no-restore hook cmds", no_restore_cmds) - run_hook_cmds(no_restore_cmds, "no-restore") + return vim.g.in_pager_mode == Lib._VIM_TRUE +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) + 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 not launch_argv then + launch_argv = vim.fn.argv() + end + local argc = #launch_argv + + if argc == 0 then + -- Launched with no args, saving is enabled + Lib.logger.debug "No arguments, restoring/saving enabled" + return true + end + + -- if conf.args_allow_dot is true, support session loading/saving with nvim . + if argc == 1 and launch_argv[1] == "." and AutoSession.conf.args_allow_dot then + Lib.logger.debug "Allowing restore when launched with . argument" + return true + end + + local args_handling = AutoSession.conf.args_handling + + if not args_handling 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" + return false + elseif args_handling == "new_session_named_with_args" then + -- TODO: implement me + return false + else + Lib.logger.warn("Invalid value for args_handling: " .. args_handling) end - return pager_mode + + return false end local in_headless_mode = function() @@ -216,7 +270,7 @@ local in_headless_mode = function() end local auto_save = function() - if in_pager_mode() or in_headless_mode() then + if in_pager_mode() or in_headless_mode() or not enabled_for_command_line_argv(true) then return false end @@ -230,7 +284,7 @@ local auto_save = function() end local auto_restore = function() - if in_pager_mode() or in_headless_mode() then + if in_pager_mode() or in_headless_mode() or not enabled_for_command_line_argv(false) then return false end @@ -665,6 +719,12 @@ end ---@param auto boolean 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 } @@ -695,6 +755,22 @@ function AutoSession.AutoRestoreSession(session_dir) return false end +---Function called by AutoSession at VimEnter when automatically restoring a session. +---This function exists just to make sure we dispatch the no_restore hook +local function auto_restore_session_at_vim_enter() + -- If it succeeded, we're done + if AutoSession.AutoRestoreSession() then + return true + end + + -- Dispatch the no_restore hooks + local no_restore_cmds = AutoSession.get_cmds "no_restore" + Lib.logger.debug("No session restored, call no_restore hooks", no_restore_cmds) + run_hook_cmds(no_restore_cmds, "no-restore") + + return false +end + local function extract_dir_or_file(session_dir_or_file) local session_dir = nil local session_file = nil @@ -1020,7 +1096,7 @@ function SetupAutocmds() if not AutoSession.conf.auto_restore_lazy_delay_enabled then -- If auto_restore_lazy_delay_enabled is false, just restore the session as normal - AutoSession.AutoRestoreSession() + auto_restore_session_at_vim_enter() return end @@ -1028,14 +1104,14 @@ function SetupAutocmds() local ok, lazy_view = pcall(require, "lazy.view") if not ok then -- No Lazy, load as usual - AutoSession.AutoRestoreSession() + auto_restore_session_at_vim_enter() return end if not lazy_view.visible() then -- Lazy isn't visible, load as usual Lib.logger.debug "Lazy is loaded, but not visible, restore session!" - AutoSession.AutoRestoreSession() + auto_restore_session_at_vim_enter() return end @@ -1080,7 +1156,7 @@ function SetupAutocmds() -- Schedule restoration for the next pass in the event loop to time for the window to close -- Not doing this could create a blank buffer in the restored session vim.schedule(function() - AutoSession.AutoRestoreSession() + auto_restore_session_at_vim_enter() end) end, }) diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index df9a2f0..c0dd811 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -185,6 +185,8 @@ function Lib.has_open_buffers() return result end +-- Iterate over the tabpages and then the windows and close any window that has a buffer that isn't backed by +-- a real file function Lib.close_unsupported_windows() local tabpages = vim.api.nvim_list_tabpages() for _, tabpage in ipairs(tabpages) do @@ -203,6 +205,26 @@ function Lib.close_unsupported_windows() end end +-- Count the number of supported buffers +function Lib.count_supported_buffers() + 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 file_name = vim.api.nvim_buf_get_name(buf) + if Lib.is_readable(file_name) then + supported = supported + 1 + Lib.logger.debug("is supported: " .. file_name .. " count: " .. vim.inspect(supported)) + end + end + end + + return supported +end + function Lib.get_path_separator() -- Get cross platform path separator return package.config:sub(1, 1) From f79c94808af65c9eba6ea878f36683118f092685 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Fri, 5 Jul 2024 00:15:40 -0700 Subject: [PATCH 2/4] Support single, directory launch argument If nvim is launched with a single, directory then try to load a session from that directory (factoring in all of the other rules). We make sure to temporarily disable cwd_change_handling if enabled as restoring the session will change the cwd in this case:x --- lua/auto-session/init.lua | 51 ++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index 7b25462..b932c8b 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -70,7 +70,7 @@ local defaultConf = { ---@field silent_restore boolean Whether to restore sessions silently or not ---@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_dot? boolean Follow normal sesion save/load logic if launched as 'nvim .' +---@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 @@ -221,9 +221,10 @@ local enabled_for_command_line_argv = function(is_save) return true end - -- if conf.args_allow_dot is true, support session loading/saving with nvim . - if argc == 1 and launch_argv[1] == "." and AutoSession.conf.args_allow_dot then - Lib.logger.debug "Allowing restore when launched with . argument" + -- if conf.args_allow_single_directory = true, then enable session handling if only param is a directory + + if argc == 1 and vim.fn.isdirectory(launch_argv[1]) and AutoSession.conf.args_allow_single_directory then + Lib.logger.debug "Allowing restore when launched with a single directory argument" return true end @@ -323,10 +324,13 @@ local function bypass_save_by_filetype() return true end -local function suppress_session() +local function suppress_session(session_dir) local dirs = vim.g.auto_session_suppress_dirs or AutoSession.conf.auto_session_suppress_dirs or {} - local cwd = vim.fn.getcwd() + -- If session_dir is set, use that otherwise use cwd + -- session_dir will be set when loading a session from a directory at lauch (i.e. from argv) + local cwd = session_dir or vim.fn.getcwd() + for _, s in pairs(dirs) do if s ~= "/" then s = string.gsub(vim.fn.simplify(Lib.expand(s)), "/+$", "") @@ -720,7 +724,7 @@ 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 + -- 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" @@ -744,26 +748,45 @@ function AutoSession.SaveSession(sessions_dir, auto) end ---Function called by AutoSession when automatically restoring a session. ----This function avoids calling RestoreSession automatically when argv is not nil. ---@param session_dir any ---@return boolean boolean returns whether restoring the session was successful or not. function AutoSession.AutoRestoreSession(session_dir) - if is_enabled() and auto_restore() and not suppress_session() then + -- WARN: should this be checking is_allowed_dir as well? + if is_enabled() and auto_restore() and not suppress_session(session_dir) then return AutoSession.RestoreSession(session_dir) end return false end ----Function called by AutoSession at VimEnter when automatically restoring a session. ----This function exists just to make sure we dispatch the no_restore hook +---Function called by AutoSession at VimEnter to automatically restore a session. +---If launched with a single directory parameter and conf.args_allow_single_directory is true, pass +---that in as the session_dir. Handles both 'nvim .' and 'nvim some/dir' +--- +---Also make sure to call no_restore if no session was restored local function auto_restore_session_at_vim_enter() - -- If it succeeded, we're done - if AutoSession.AutoRestoreSession() then + local session_dir = nil + + local 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]) 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() .. "]$", "") + Lib.logger.debug("Launched with single directory, using as session_dir: " .. session_dir) + end + + -- Restoring here may change the cwd so disable cwd processing while restoring + AutoSession.restore_in_progress = true + local success, result = pcall(AutoSession.AutoRestoreSession, session_dir) + AutoSession.restore_in_progress = false + + if success and result then return true end - -- Dispatch the no_restore hooks + -- No session was restored, dispatch no-restore hook local no_restore_cmds = AutoSession.get_cmds "no_restore" Lib.logger.debug("No session restored, call no_restore hooks", no_restore_cmds) run_hook_cmds(no_restore_cmds, "no-restore") From acc12999b21be46fe796230feaa385718a4287fd Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Fri, 5 Jul 2024 22:42:06 -0700 Subject: [PATCH 3/4] Fix bug detecting single directory Got tripped up by 0 being true in Lua. Would cause any single argument to be treated as a directory to load a session from Also annoated another suspected bug on line 384 but not traced through at this time --- lua/auto-session/init.lua | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index b932c8b..09f8bb3 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -222,9 +222,13 @@ local enabled_for_command_line_argv = function(is_save) end -- if conf.args_allow_single_directory = true, then enable session handling if only param is a directory - - if argc == 1 and vim.fn.isdirectory(launch_argv[1]) and AutoSession.conf.args_allow_single_directory then - Lib.logger.debug "Allowing restore when launched with a single directory argument" + if + argc == 1 + and vim.fn.isdirectory(launch_argv[1]) == Lib._VIM_TRUE + and AutoSession.conf.args_allow_single_directory + then + -- Actual session will be loaded in auto_restore_session_at_vim_enter + Lib.logger.debug("Allowing restore when launched with a single directory argument: " .. launch_argv[1]) return true end @@ -257,7 +261,7 @@ local enabled_for_command_line_argv = function(is_save) Lib.logger.debug "[replace_session_only_if_multiple_buffers] single buffer, disallow save" return false elseif args_handling == "new_session_named_with_args" then - -- TODO: implement me + -- TODO: implement me or maybe not worth it return false else Lib.logger.warn("Invalid value for args_handling: " .. args_handling) @@ -377,6 +381,10 @@ local function get_session_file_name(upcoming_session_dir) Lib.logger.debug("get_session_file_name", { session = session, upcoming_session_dir = upcoming_session_dir }) + -- BUG: The then case below will never be entered becuase vim.fn.isdirectory will return 0 or 1, both of which + -- are true in Lua. However, changing it to compare against Lib._VIM_FALSE (and removing the not) generates + -- an error on autosave that would need to be traced down. Since I don't understand the purpose of this code + -- right now, I'm leaving as is. if not vim.fn.isdirectory(Lib.expand(session or upcoming_session_dir)) then Lib.logger.debug( "Session and sessions_dir either both point to a file or do not exist", @@ -533,7 +541,7 @@ function AutoSession.get_session_files() local files = {} local sessions_dir = AutoSession.get_root_dir() - if not vim.fn.isdirectory(sessions_dir) then + if vim.fn.isdirectory(sessions_dir) == Lib._VIM_FALSE then return files end @@ -770,7 +778,7 @@ local function auto_restore_session_at_vim_enter() local 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]) then + if AutoSession.conf.args_allow_single_directory and #argv == 1 and vim.fn.isdirectory(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() .. "]$", "") From 5df2255e1d9a76771c75c5419a1294ed3b97c55d Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Sun, 7 Jul 2024 19:59:52 -0700 Subject: [PATCH 4/4] Add arg handling support 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 --- README.md | 82 ++++++++++++++++++++++++++++++++++--- lua/auto-session/init.lua | 85 +++++++++++++++++---------------------- 2 files changed, 114 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 73624c5..b5e54a6 100644 --- a/README.md +++ b/README.md @@ -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`. @@ -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", @@ -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 } ``` @@ -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. @@ -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 diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index 09f8bb3..0c73935 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -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 @@ -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 @@ -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" @@ -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() @@ -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 @@ -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 } @@ -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 @@ -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.