From e3e9da737d64a7699d5768073e32d13a9fe88cc0 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 26 Nov 2024 13:32:23 -0500 Subject: [PATCH 1/3] fix: #208 stop LSs when restoring session But don't do this on startup as calling vim.lsp.get_clients() causes a small but noticeable delay on startup. --- lua/auto-session/config.lua | 2 + lua/auto-session/init.lua | 65 +++++++++++++++++++++++-------- tests/ls_stop_on_restore_spec.lua | 35 +++++++++++++++++ tests/test_lib.lua | 1 + 4 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 tests/ls_stop_on_restore_spec.lua diff --git a/lua/auto-session/config.lua b/lua/auto-session/config.lua index 175d50b..2c4dbdb 100644 --- a/lua/auto-session/config.lua +++ b/lua/auto-session/config.lua @@ -26,6 +26,7 @@ local M = {} ---@field show_auto_restore_notif? boolean Whether to show a notification when auto-restoring ---@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 ---@field cwd_change_handling? boolean Follow cwd changes, saving a session before change and restoring after +---@field lsp_stop_on_restore? boolean|function Should language servers be stopped when restoring a session. Can also be a function that will be called if set. Not called on autorestore from startup ---@field session_lens? SessionLens Session lens configuration options --- ---Hooks @@ -79,6 +80,7 @@ local defaults = { continue_restore_on_error = true, -- Keep loading the session even if there's an error show_auto_restore_notif = false, -- Whether to show a notification when auto-restoring cwd_change_handling = false, -- Follow cwd changes, saving a session before change and restoring after + lsp_stop_on_restore = false, -- Should language servers be stopped when restoring a session. Can also be a function that will be called if set. Not called on autorestore from startup log_level = "error", -- Sets the log level of the plugin (debug, info, warn, error). ---@type SessionLens diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index baeec0f..cc73590 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -438,14 +438,19 @@ end ---Function called by AutoSession when automatically restoring a session. ---@param session_name? string An optional session to load +---@param is_startup? boolean|nil Is this autorestore happening on startup ---@return boolean boolean returns whether restoring the session was successful or not. -function AutoSession.AutoRestoreSession(session_name) +function AutoSession.AutoRestoreSession(session_name, is_startup) -- WARN: should this be checking is_allowed_dir as well? if not is_enabled() or not auto_restore() or suppress_session(session_name) then return false end - return AutoSession.RestoreSession(session_name, Config.show_auto_restore_notif) + local opts = { + show_message = Config.show_auto_restore_notif, + is_startup_autorestore = is_startup, + } + return AutoSession.RestoreSession(session_name, opts) end ---@private @@ -471,7 +476,7 @@ function AutoSession.auto_restore_session_at_vim_enter() local session_name = Lib.remove_trailing_separator(vim.fn.fnamemodify(launch_argv[1], ":p")) Lib.logger.debug("Launched with single directory, using as session_dir: " .. session_name) - if AutoSession.AutoRestoreSession(session_name) then + if AutoSession.AutoRestoreSession(session_name, true) then return true end @@ -482,7 +487,7 @@ function AutoSession.auto_restore_session_at_vim_enter() Config.auto_save = false end else - if AutoSession.AutoRestoreSession() then + if AutoSession.AutoRestoreSession(nil, true) then return true end @@ -493,7 +498,12 @@ function AutoSession.auto_restore_session_at_vim_enter() local last_session_name = Lib.get_latest_session(AutoSession.get_root_dir()) if last_session_name then Lib.logger.debug("Found last session: " .. last_session_name) - if AutoSession.RestoreSession(last_session_name, Config.show_auto_restore_notif) then + if + AutoSession.RestoreSession( + last_session_name, + { show_message = Config.show_auto_restore_notif, is_startup_autorestore = true } + ) + then return true end end @@ -576,21 +586,26 @@ function AutoSession.SaveSessionToDir(session_dir, session_name, show_message) return true end +---@class RestoreOpts +---@field show_message boolean|nil Should messages be shown +---@field is_startup_autorestore boolean|nil True if this is the the startup autorestore + ---Restores a session from the passed in directory. If no optional session name ---is passed in, it uses the cwd as the session name ---@param session_name? string|nil Optional session name ----@param show_message? boolean Optional, whether to show a message on restore (true by default) -function AutoSession.RestoreSession(session_name, show_message) - return AutoSession.RestoreSessionFromDir(AutoSession.get_root_dir(), session_name, show_message) +---@param opts? RestoreOpts|nil restore options +function AutoSession.RestoreSession(session_name, opts) + return AutoSession.RestoreSessionFromDir(AutoSession.get_root_dir(), session_name, opts) end ---Restores a session from the passed in directory. If no optional session name ---is passed in, it uses the cwd as the session name ---@param session_dir string Directory to write the session file to ---@param session_name? string|nil Optional session name ----@param show_message? boolean Optional, whether to show a message on restore (true by default) -function AutoSession.RestoreSessionFromDir(session_dir, session_name, show_message) +---@param opts? RestoreOpts|nil restore options +function AutoSession.RestoreSessionFromDir(session_dir, session_name, opts) Lib.logger.debug("RestoreSessionFromDir start", { session_dir, session_name }) + opts = opts or {} -- Canonicalize and create session_dir if needed session_dir = Lib.validate_root_dir(session_dir) Lib.logger.debug("RestoreSessionFromDir validated session_dir: ", session_dir) @@ -623,7 +638,7 @@ function AutoSession.RestoreSessionFromDir(session_dir, session_name, show_messa local legacy_session_path = session_dir .. legacy_escaped_session_name if vim.fn.filereadable(legacy_session_path) ~= 1 then - if show_message == nil or show_message then + if opts.show_message == nil or opts.show_message then vim.notify("Could not restore session: " .. Lib.get_session_display_name(escaped_session_name)) end return false @@ -653,18 +668,34 @@ function AutoSession.RestoreSessionFromDir(session_dir, session_name, show_messa end end - return AutoSession.RestoreSessionFile(session_path, show_message) + return AutoSession.RestoreSessionFile(session_path, opts) end ---Restores a session from a specific file ---@param session_path string The session file to load ----@param show_message? boolean Optional, whether to show a message on restore (true by default) +---@param opts? RestoreOpts|nil restore options ---@return boolean Was a session restored -function AutoSession.RestoreSessionFile(session_path, show_message) - AutoSession.run_cmds "pre_restore" - +function AutoSession.RestoreSessionFile(session_path, opts) Lib.logger.debug("RestoreSessionFile restoring session from: " .. session_path) + opts = opts or {} + AutoSession.run_cmds "pre_restore" + + -- Stop any language servers if config is set but don't do + -- this on startup as it causes a perceptible delay (and we + -- know there aren't any language servers anyway) + if not opts.is_startup_autorestore then + if Config.lsp_stop_on_restore then + if type(Config.lsp_stop_on_restore) == "function" then + Config.lsp_stop_on_restore() + else + local clients = vim.lsp.get_clients() + if #clients > 0 then + vim.lsp.stop_client(clients) + end + end + end + end -- Vim cmds require escaping any % with a \ but we don't want to do that -- for direct filesystem operations (like in save_extra_cmds_new) so we -- that here, as late as possible and only for this operation @@ -709,7 +740,7 @@ Error: ]] .. result) local session_name = Lib.escaped_session_name_to_session_name(vim.fn.fnamemodify(session_path, ":t")) Lib.logger.debug("Restored session: " .. session_name) - if show_message == nil or show_message then + if opts.show_message == nil or opts.show_message then vim.notify("Restored session: " .. session_name) end diff --git a/tests/ls_stop_on_restore_spec.lua b/tests/ls_stop_on_restore_spec.lua new file mode 100644 index 0000000..a8fa11b --- /dev/null +++ b/tests/ls_stop_on_restore_spec.lua @@ -0,0 +1,35 @@ +local TL = require "tests/test_lib" + +describe("lsp_stop_on_restore", function() + local as = require "auto-session" + as.setup {} + TL.clearSessionFilesAndBuffers() + vim.cmd("e " .. TL.test_file) + as.SaveSession() + + it("calls user function on restore", function() + local stop_called = false + as.setup { + lsp_stop_on_restore = function() + stop_called = true + end, + } + + as.RestoreSession() + + assert.True(stop_called) + end) + + it("doesn't try to stop ls on initial autorestore", function() + local stop_called = false + as.setup { + lsp_stop_on_restore = function() + stop_called = true + end, + } + + as.auto_restore_session_at_vim_enter() + + assert.False(stop_called) + end) +end) diff --git a/tests/test_lib.lua b/tests/test_lib.lua index 4d2ec1e..fa7efba 100644 --- a/tests/test_lib.lua +++ b/tests/test_lib.lua @@ -1,3 +1,4 @@ +require "plenary" local asLib = require "auto-session.lib" local M = {} From 3513582b304b6e20347cfc2506ce88276d7cc947 Mon Sep 17 00:00:00 2001 From: cameronr Date: Tue, 26 Nov 2024 18:43:23 +0000 Subject: [PATCH 2/3] chore(docs): auto-generate vimdoc --- doc/auto-session.txt | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/doc/auto-session.txt b/doc/auto-session.txt index beb506b..68a4d93 100644 --- a/doc/auto-session.txt +++ b/doc/auto-session.txt @@ -30,6 +30,7 @@ AutoSession.Config *AutoSession.Config* {show_auto_restore_notif?} (boolean) Whether to show a notification when auto-restoring {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 {cwd_change_handling?} (boolean) Follow cwd changes, saving a session before change and restoring after + {lsp_stop_on_restore?} (boolean|function) Should language servers be stopped when restoring a session. Can also be a function that will be called if set. Not called on autorestore from startup {session_lens?} (SessionLens) Session lens configuration options {pre_save_cmds?} (table) executes before a session is saved @@ -124,11 +125,12 @@ AutoSession.AutoSaveSession() *AutoSession.AutoSaveSession* *AutoSession.AutoRestoreSession* -AutoSession.AutoRestoreSession({session_name?}) +AutoSession.AutoRestoreSession({session_name?}, {is_startup?}) Function called by AutoSession when automatically restoring a session. Parameters: ~ - {session_name?} (string) An optional session to load + {session_name?} (string) An optional session to load + {is_startup?} (boolean|nil) Is this autorestore happening on startup Returns: ~ (boolean) returns whether restoring the session was successful or not. @@ -161,34 +163,41 @@ AutoSession.SaveSessionToDir({session_dir}, {session_name?}, {show_message?}) (boolean) +RestoreOpts *RestoreOpts* + + Fields: ~ + {show_message} (boolean|nil) Should messages be shown + {is_startup_autorestore} (boolean|nil) True if this is the the startup autorestore + + *AutoSession.RestoreSession* -AutoSession.RestoreSession({session_name?}, {show_message?}) +AutoSession.RestoreSession({session_name?}, {opts?}) Restores a session from the passed in directory. If no optional session name is passed in, it uses the cwd as the session name Parameters: ~ - {session_name?} (string|nil) Optional session name - {show_message?} (boolean) Optional, whether to show a message on restore (true by default) + {session_name?} (string|nil) Optional session name + {opts?} (RestoreOpts|nil) restore options *AutoSession.RestoreSessionFromDir* -AutoSession.RestoreSessionFromDir({session_dir}, {session_name?}, {show_message?}) +AutoSession.RestoreSessionFromDir({session_dir}, {session_name?}, {opts?}) Restores a session from the passed in directory. If no optional session name is passed in, it uses the cwd as the session name Parameters: ~ - {session_dir} (string) Directory to write the session file to - {session_name?} (string|nil) Optional session name - {show_message?} (boolean) Optional, whether to show a message on restore (true by default) + {session_dir} (string) Directory to write the session file to + {session_name?} (string|nil) Optional session name + {opts?} (RestoreOpts|nil) restore options *AutoSession.RestoreSessionFile* -AutoSession.RestoreSessionFile({session_path}, {show_message?}) +AutoSession.RestoreSessionFile({session_path}, {opts?}) Restores a session from a specific file Parameters: ~ - {session_path} (string) The session file to load - {show_message?} (boolean) Optional, whether to show a message on restore (true by default) + {session_path} (string) The session file to load + {opts?} (RestoreOpts|nil) restore options Returns: ~ (boolean) a session restored From 1ba7a78bf0fe2f782e0d3321ddcb02f803e61e27 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 26 Nov 2024 13:47:23 -0500 Subject: [PATCH 3/3] chore(README): update docs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d9d982c..646a486 100644 --- a/README.md +++ b/README.md @@ -66,13 +66,14 @@ Here are the default settings: auto_restore_last_session = false, -- On startup, loads the last saved session if session for cwd does not exist use_git_branch = false, -- Include git branch name in session name lazy_support = true, -- Automatically detect if Lazy.nvim is being used and wait until Lazy is done to make sure session is restored correctly. Does nothing if Lazy isn't being used. Can be disabled if a problem is suspected or for debugging - bypass_save_filetypes = nil, -- List of file types to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards + bypass_save_filetypes = nil, -- List of filetypes to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards close_unsupported_windows = true, -- Close windows that aren't backed by normal file before autosaving a session args_allow_single_directory = true, -- Follow normal sesion save/load logic if launched with a single directory as the only argument args_allow_files_auto_save = false, -- 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 continue_restore_on_error = true, -- Keep loading the session even if there's an error show_auto_restore_notif = false, -- Whether to show a notification when auto-restoring cwd_change_handling = false, -- Follow cwd changes, saving a session before change and restoring after + lsp_stop_on_restore = false, -- Should language servers be stopped when restoring a session. Can also be a function that will be called if set. Not called on autorestore from startup log_level = "error", -- Sets the log level of the plugin (debug, info, warn, error). session_lens = {