From 775946e2160ffe290477a3f328e0668411e94099 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Sun, 30 Jun 2024 21:38:48 -0700 Subject: [PATCH 1/4] Unify session selection logic, Fixes #287 Unify the session loading logic between Telesecop session-lens and AutoSession search so that we always use the session file to load the session (vs relying on changing directory). Set a flag to make sure cwd_change_handling (if enabled) doesn't also try to restore the session This also fixes a session load failure when a session with a git branch name is selected from Telescope session-lens or Autosession search. Removed the non-functional (as far as I can see) code for buftypes_to_ignore. That code would not bwipeout a buffer if it matched but the buffers get wiped out by the sourcing the session file anyway and having that code generates an error when the buffer is opened in another process which interrupts the session swap. Made the option deprecated and asked anyone using it to report it on GH. --- lua/auto-session/autocmds.lua | 15 ++++++- lua/auto-session/init.lua | 55 ++++++++++++++++++++--- lua/auto-session/session-lens/actions.lua | 26 +---------- lua/auto-session/session-lens/init.lua | 6 ++- 4 files changed, 70 insertions(+), 32 deletions(-) diff --git a/lua/auto-session/autocmds.lua b/lua/auto-session/autocmds.lua index 1a656cd..5355769 100644 --- a/lua/auto-session/autocmds.lua +++ b/lua/auto-session/autocmds.lua @@ -6,7 +6,7 @@ local M = {} ---@param config table auto session config ---@param AutoSession table auto session instance M.setup_autocmds = function(config, AutoSession) - if not config.cwd_change_handling or vim.tbl_isempty(config.cwd_change_handling or {}) then + if not config.cwd_change_handling or not config.cwd_change_handling.restore_upcoming_session then Lib.logger.debug "cwd_change_handling is disabled, skipping setting DirChangedPre and DirChanged autocmd handling" return end @@ -30,10 +30,18 @@ M.setup_autocmds = function(config, AutoSession) return end + if AutoSession.restore_in_progress then + Lib.logger.debug "DirChangedPre: restore_in_progress is true, ignoring this event" + return + end + AutoSession.AutoSaveSession() -- Clear all buffers and jumps after session save so session doesn't blead over to next session. + -- NOTE: If the code in restore_selected_session that tries to keep matching buftypes open across + -- sessions actually works, we should also have that logic here. vim.cmd "%bd!" + vim.cmd "clearjumps" if type(conf.pre_cwd_changed_hook) == "function" then @@ -56,6 +64,11 @@ M.setup_autocmds = function(config, AutoSession) return end + if AutoSession.restore_in_progress then + Lib.logger.debug "DirChanged: restore_in_progress is true, ignoring this event" + return + end + -- all buffers should've been deleted in `DirChangedPre`, something probably went wrong if Lib.has_open_buffers() then Lib.logger.debug "Cancelling session restore" diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index a081c57..3b75b6d 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -180,6 +180,7 @@ end -- get the current git branch name, if any, and only if configured to do so local function get_branch_name() if AutoSession.conf.auto_session_use_git_branch then + -- WARN: this assumes you want the branch of the cwd local out = vim.fn.systemlist "git rev-parse --abbrev-ref HEAD" if vim.v.shell_error ~= 0 then Lib.logger.debug(string.format("git failed with: %s", table.concat(out, "\n"))) @@ -483,7 +484,7 @@ function AutoSession.get_session_files() end) return vim.tbl_map(function(entry) - return { display_name = AutoSession.format_file_name(entry), path = entry } + return { display_name = AutoSession.format_file_name(entry), path = sessions_dir .. "/" .. entry } end, entries) end @@ -509,10 +510,7 @@ local function handle_autosession_command(data) local files = AutoSession.get_session_files() if data.args:match "search" then open_picker(files, "Select a session:", function(choice) - -- Change dir to selected session path, the DirChangePre and DirChange events will take care of the rest - -- BUG: The above is only true if cwd_change_handling is true which means sessions - -- won't be restored if cwd_change_handling is false - vim.fn.chdir(choice.display_name) + AutoSession.restore_selected_session(choice.path) end) elseif data.args:match "delete" then open_picker(files, "Delete a session:", function(choice) @@ -521,6 +519,52 @@ local function handle_autosession_command(data) end end +-- Handler for when a session is picked from the UI, either via Telescope or via AutoSession.select_session +-- We'll load the selected session file, setting restore_in_progress so DirChangedPre/DirChanged won't +-- also try to load the session when the directory is changed +function AutoSession.restore_selected_session(session_filename) + Lib.logger.debug("[restore_selected_session]: filename: " .. session_filename) + + AutoSession.AutoSaveSession() + + -- NOTE: + -- In theory, this is supposed to keep open buffers that are in buftypes_to_ignore. However, even if + -- we keep them open here, they'll be cleared when we source the session file sp I don't think + -- this code does anything. It also interrupts session loading if the buffer replaced is loaded + -- by another process. So, I've replaced it with %bd! which is what cwd_change_handling does. + -- This code and block should be removed when it's confirmed that no users are using it effectively + -- + -- local buffers = vim.api.nvim_list_bufs() + -- for _, bufn in pairs(buffers) do + -- if + -- not vim.tbl_contains( + -- AutoSession.conf.session_lens.buftypes_to_ignore, + -- vim.api.nvim_get_option_value("buftype", { buf = bufn }) + -- ) + -- then + -- vim.cmd("silent bwipeout!" .. bufn) + -- else + -- Lib.logger.debug "[restore_selected_session] Not closing buffer because it matches buftypes_to_ignore" + -- end + -- end + + vim.cmd "%bd!" + + -- Would it be better to always clear jumps in RestoreSession? + vim.cmd "clearjumps" + + -- Set restore_in_progress so cwd_change_handling won't also try to load the session when the directory is changed + -- And use a pcall to make sure we unset the flag whether loading was successful or not + AutoSession.restore_in_progress = true + local success, result = pcall(AutoSession.RestoreSession, session_filename) + AutoSession.restore_in_progress = false + + if not success or not result then + Lib.logger.info("Could not load session for filename: " .. session_filename) + return + end +end + vim.api.nvim_create_user_command("Autosession", handle_autosession_command, { nargs = 1 }) -- local function write_to_session_control(session_file_name) @@ -767,6 +811,7 @@ Disabling auto save. Please check for errors in your config. Error: elseif session_file then Lib.logger.debug "Using session FILE" local escaped_file = session_file:gsub("%%", "\\%%") + Lib.logger.debug("Using session FILE: " .. escaped_file) if Lib.is_readable(escaped_file) then Lib.logger.debug "isReadable, calling restore" RESTORED_WITH = restore(escaped_file) diff --git a/lua/auto-session/session-lens/actions.lua b/lua/auto-session/session-lens/actions.lua index 225e856..f3d02b4 100644 --- a/lua/auto-session/session-lens/actions.lua +++ b/lua/auto-session/session-lens/actions.lua @@ -39,31 +39,7 @@ local function source_session(selection, prompt_bufnr) end vim.defer_fn(function() - local cwd_change_handling_conf = M.functions.conf.cwd_change_handling - - -- If cwd_change_handling is true, the current session will be saved in the DirChangedPre AutoCmd - -- and the new session will be restored in DirChanged - if type(cwd_change_handling_conf) == "table" and cwd_change_handling_conf.restore_upcoming_session then - -- Take advatage of cwd_change_handling behaviour for switching sessions - Lib.logger.debug "Triggering vim.fn.chdir since cwd_change_handling feature is enabled" - vim.fn.chdir(M.functions.format_file_name(type(selection) == "table" and selection.filename or selection)) - else - -- TODO: Since cwd_change_handling is disabled, we save and restore here. This would probably be better - -- handled in AutoSession itself since the same case comes up if the built in picker is used - -- (e.g. :Autosession search). - Lib.logger.debug "Triggering session-lens behaviour since cwd_change_handling feature is disabled" - M.functions.AutoSaveSession() - - local buffers = vim.api.nvim_list_bufs() - for _, bufn in pairs(buffers) do - if not vim.tbl_contains(M.conf.buftypes_to_ignore, vim.api.nvim_buf_get_option(bufn, "buftype")) then - vim.cmd("silent bwipeout!" .. bufn) - end - end - - vim.cmd "clearjumps" - M.functions.RestoreSession(type(selection) == "table" and selection.path or selection) - end + M.functions.restore_selected_session(type(selection) == "table" and selection.path) end, 50) end diff --git a/lua/auto-session/session-lens/init.lua b/lua/auto-session/session-lens/init.lua index 37c473b..f2aebc2 100644 --- a/lua/auto-session/session-lens/init.lua +++ b/lua/auto-session/session-lens/init.lua @@ -15,7 +15,7 @@ local SessionLens = { ---@field shorten_path boolean Deprecated, pass { 'shorten' } to path_display ---@field path_display table An array that specifies how to handle paths. Read :h telescope.defaults.path_display ---@field theme_conf table ----@field buftypes_to_ignore table +---@field buftypes_to_ignore table Deprecated, if you're using this please report your usage on github ---@field previewer boolean ---@field session_control session_control ---@field load_on_setup boolean @@ -37,6 +37,10 @@ function SessionLens.setup(auto_session) Lib.setup(SessionLens.conf, auto_session) Actions.setup(SessionLens.conf, auto_session) logger.log_level = auto_session.conf.log_level + + if SessionLens.conf.buftypes_to_ignore ~= nil and not vim.tbl_isempty(SessionLens.conf.buftypes_to_ignore) then + logger.warn('buftypes_to_ignore is deprecated. If you think you need this option, please file a bug on GitHub. If not, please remove it from your config') + end end ---Search session From 92e7239febef0d1e7eebfaa3d55dacab443aba92 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Mon, 1 Jul 2024 20:22:50 -0700 Subject: [PATCH 2/4] Fix #295 by detecting if *x.vim is a session file The session check works as follows: For each session file, first check that it's not a directory. Then check if it ends in x.vim. If it doesn't, then return true. If it does, if the first line contains the word "SessionLoad" then return true and false otherwise. This will include valid session files that happen to end in x and not include the *x.vim session files neovim creates for custom user commands saved with the session. --- lua/auto-session/init.lua | 2 +- lua/auto-session/lib.lua | 31 +++++++++++++++++++++++ lua/auto-session/session-lens/library.lua | 6 +++++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index 3b75b6d..29e27a1 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -480,7 +480,7 @@ function AutoSession.get_session_files() end local entries = vim.fn.readdir(sessions_dir, function(item) - return vim.fn.isdirectory(item) == 0 and not string.find(item, "x.vim$") + return Lib.is_session_file(sessions_dir, item) end) return vim.tbl_map(function(entry) diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index c2d7c2c..d0c4696 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -203,4 +203,35 @@ function Lib.close_unsupported_windows() end end +-- Get cross platform path separator +local path_separator = package.config:sub(1, 1) + +-- When Neovim makes a session file, it may save an additional x.vim file +-- with custom user commands. This function returns false if it's one of those files +function Lib.is_session_file(session_dir, file_path) + -- if it's a directory, don't include + if vim.fn.isdirectory(file_path) ~= 0 then + return false + end + + -- if it's a file that doesn't end in x.vim, include + if not string.find(file_path, "x.vim$") then + return true + end + + -- the file ends in x.vim, make sure it has SessionLoad on the first line + local file = io.open(session_dir .. path_separator .. file_path, "r") + if not file then + Lib.logger.debug("Could not open file: " .. session_dir .. path_separator .. file_path) + return false + end + + local first_line = file:read "*line" + file:close() + + Lib.logger.debug("file_path" .. file_path .. " first line: " .. first_line) + + return first_line and string.find(first_line, "SessionLoad") ~= nil +end + return Lib diff --git a/lua/auto-session/session-lens/library.lua b/lua/auto-session/session-lens/library.lua index bdaa5ed..b628103 100644 --- a/lua/auto-session/session-lens/library.lua +++ b/lua/auto-session/session-lens/library.lua @@ -36,6 +36,12 @@ end function Lib.make_entry.gen_from_file(opts) local root = Lib.functions.get_root_dir() return function(line) + -- Don't include x.vim files that nvim makes for custom user + -- commands + if not AutoSessionLib.is_session_file(root, line) then + return nil + end + return { ordinal = line, value = line, From 948e151580b7501726eac366b17e301dd20aa9a0 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 2 Jul 2024 22:13:31 -0700 Subject: [PATCH 3/4] Remove logging --- lua/auto-session/lib.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index d0c4696..7a56307 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -229,8 +229,6 @@ function Lib.is_session_file(session_dir, file_path) local first_line = file:read "*line" file:close() - Lib.logger.debug("file_path" .. file_path .. " first line: " .. first_line) - return first_line and string.find(first_line, "SessionLoad") ~= nil end From 943e6995cf008914cdd72d6aceb5baf2708889c0 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Thu, 4 Jul 2024 21:29:32 -0700 Subject: [PATCH 4/4] Use cross platform separator for new code Will have to look at other uses of '/' at a later time --- lua/auto-session/init.lua | 5 ++++- lua/auto-session/lib.lua | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index 29e27a1..ddbdbb4 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -483,8 +483,11 @@ function AutoSession.get_session_files() return Lib.is_session_file(sessions_dir, item) end) + -- Get cross platform path separator + local path_separator = Lib.get_path_separator() + return vim.tbl_map(function(entry) - return { display_name = AutoSession.format_file_name(entry), path = sessions_dir .. "/" .. entry } + return { display_name = AutoSession.format_file_name(entry), path = sessions_dir .. path_separator .. entry } end, entries) end diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index 7a56307..df9a2f0 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -203,8 +203,10 @@ function Lib.close_unsupported_windows() end end --- Get cross platform path separator -local path_separator = package.config:sub(1, 1) +function Lib.get_path_separator() + -- Get cross platform path separator + return package.config:sub(1, 1) +end -- When Neovim makes a session file, it may save an additional x.vim file -- with custom user commands. This function returns false if it's one of those files @@ -219,6 +221,8 @@ function Lib.is_session_file(session_dir, file_path) return true end + local path_separator = Lib.get_path_separator() + -- the file ends in x.vim, make sure it has SessionLoad on the first line local file = io.open(session_dir .. path_separator .. file_path, "r") if not file then