From a088e3ae135470f9f328203bd097648ed927a920 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 07:54:43 -0700 Subject: [PATCH 01/18] build: fix broken unit test dependency --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c26821e..362a370 100644 --- a/Makefile +++ b/Makefile @@ -18,4 +18,4 @@ args-tests: $(PLENARY_DIR): -git clone --depth=1 --branch $(PLENARY_VER) $(PLENARY_URL) $(PLENARY_DIR) + git clone --depth=1 --branch $(PLENARY_VER) $(PLENARY_URL) $(PLENARY_DIR) From a325d84c89fe75595003b70f8c21a2e383545e65 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 11:21:39 -0700 Subject: [PATCH 02/18] test: use .test as testing home, don't set custom session dir everywhere --- .gitignore | 1 + Makefile | 16 ++++++++-------- tests/allowed_dirs_spec.lua | 2 -- tests/args/args_files_enabled_spec.lua | 2 -- tests/args/args_not_enabled_spec.lua | 2 -- tests/args/args_setup_spec.lua | 1 - tests/args/args_single_dir_enabled_spec.lua | 2 -- tests/auto_save_spec.lua | 1 - tests/bypass_save_by_filetypes_spec.lua | 1 - tests/create_enabled_spec.lua | 2 -- tests/cwd_change_handling_spec.lua | 1 - tests/extra_sesssion_commands_spec.lua | 1 - tests/git_spec.lua | 1 - tests/hooks_spec.lua | 1 - tests/minimal.lua | 12 ++++++++++++ tests/minimal.vim | 4 ---- tests/setup_spec.lua | 4 +--- tests/test_lib.lua | 2 +- 18 files changed, 23 insertions(+), 33 deletions(-) create mode 100644 tests/minimal.lua delete mode 100644 tests/minimal.vim diff --git a/.gitignore b/.gitignore index 69de6d0..f9ffcb7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Auto-generated tag files doc/tags .luarc.json +.test .build_tools tests/test_sessions diff --git a/Makefile b/Makefile index 362a370..82e1a04 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ PLENARY_VER = v0.1.4 -PLENARY_DIR = .build_tools/plenary +PLENARY_DIR = .test/plenary PLENARY_URL = https://github.com/nvim-lua/plenary.nvim FILES := $(wildcard tests/*_spec.lua) @@ -7,14 +7,14 @@ FILES := $(wildcard tests/*_spec.lua) .PHONY: test $(FILES) args-tests test: $(PLENARY_DIR) $(FILES) args-tests -$(FILES): - nvim --clean --headless --embed -u tests/minimal.vim +"PlenaryBustedFile $@" +$(FILES): $(PLENARY_DIR) + nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile $@" -args-tests: - nvim --clean --headless --embed -u tests/minimal.vim +"PlenaryBustedFile tests/args/args_setup_spec.lua" - nvim --clean --headless --embed -u tests/minimal.vim +"PlenaryBustedFile tests/args/args_not_enabled_spec.lua" - nvim --clean --headless --embed -u tests/minimal.vim +"PlenaryBustedFile tests/args/args_single_dir_enabled_spec.lua" - nvim --clean --headless --embed -u tests/minimal.vim +"PlenaryBustedFile tests/args/args_files_enabled_spec.lua" +args-tests: $(PLENARY_DIR) + nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_setup_spec.lua" + nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_not_enabled_spec.lua" + nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_single_dir_enabled_spec.lua" + nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_files_enabled_spec.lua" $(PLENARY_DIR): diff --git a/tests/allowed_dirs_spec.lua b/tests/allowed_dirs_spec.lua index bf5dd2f..e018970 100644 --- a/tests/allowed_dirs_spec.lua +++ b/tests/allowed_dirs_spec.lua @@ -4,7 +4,6 @@ TL.clearSessionFilesAndBuffers() describe("The allowed dirs config", function() require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_session_allowed_dirs = { "/dummy" }, } @@ -20,7 +19,6 @@ describe("The allowed dirs config", function() end) require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_session_allowed_dirs = { vim.fn.getcwd() }, } diff --git a/tests/args/args_files_enabled_spec.lua b/tests/args/args_files_enabled_spec.lua index 9dc470d..b36f33a 100644 --- a/tests/args/args_files_enabled_spec.lua +++ b/tests/args/args_files_enabled_spec.lua @@ -5,8 +5,6 @@ local stub = require "luassert.stub" describe("The args files enabled config", function() local no_restore_hook_called = false require("auto-session").setup { - auto_session_root_dir = TL.session_dir, - args_allow_single_directory = false, args_allow_files_auto_save = true, diff --git a/tests/args/args_not_enabled_spec.lua b/tests/args/args_not_enabled_spec.lua index 0b039fd..d0856b4 100644 --- a/tests/args/args_not_enabled_spec.lua +++ b/tests/args/args_not_enabled_spec.lua @@ -5,8 +5,6 @@ local stub = require "luassert.stub" describe("The args not enabled config", function() local no_restore_hook_called = false require("auto-session").setup { - auto_session_root_dir = TL.session_dir, - args_allow_single_directory = false, args_allow_files_auto_save = false, diff --git a/tests/args/args_setup_spec.lua b/tests/args/args_setup_spec.lua index b2851a6..3831098 100644 --- a/tests/args/args_setup_spec.lua +++ b/tests/args/args_setup_spec.lua @@ -1,7 +1,6 @@ ---@diagnostic disable: undefined-field local TL = require "tests/test_lib" require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_save_enabled = false, } diff --git a/tests/args/args_single_dir_enabled_spec.lua b/tests/args/args_single_dir_enabled_spec.lua index 6f5a1cd..0a13419 100644 --- a/tests/args/args_single_dir_enabled_spec.lua +++ b/tests/args/args_single_dir_enabled_spec.lua @@ -5,8 +5,6 @@ local stub = require "luassert.stub" describe("The args single dir enabled config", function() local no_restore_hook_called = false require("auto-session").setup { - auto_session_root_dir = TL.session_dir, - args_allow_single_directory = true, args_allow_files_auto_save = false, diff --git a/tests/auto_save_spec.lua b/tests/auto_save_spec.lua index 719ff64..4cee4b8 100644 --- a/tests/auto_save_spec.lua +++ b/tests/auto_save_spec.lua @@ -3,7 +3,6 @@ local TL = require "tests/test_lib" describe("The auto_save_enabled=false config", function() require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_save_enabled = false, } diff --git a/tests/bypass_save_by_filetypes_spec.lua b/tests/bypass_save_by_filetypes_spec.lua index 483548d..8e77913 100644 --- a/tests/bypass_save_by_filetypes_spec.lua +++ b/tests/bypass_save_by_filetypes_spec.lua @@ -5,7 +5,6 @@ describe("Bypass save by filetypes", function() local as = require "auto-session" as.setup { - auto_session_root_dir = TL.session_dir, bypass_session_save_file_types = { "text" }, } diff --git a/tests/create_enabled_spec.lua b/tests/create_enabled_spec.lua index 44cb712..0307067 100644 --- a/tests/create_enabled_spec.lua +++ b/tests/create_enabled_spec.lua @@ -3,7 +3,6 @@ local TL = require "tests/test_lib" describe("The create_enabled=false config", function() require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_session_create_enabled = false, } @@ -75,7 +74,6 @@ describe("The create_enabled=function config", function() -- so it doesn't re-initialize the config to the default values so be -- careful of values set up in the first call require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_session_create_enabled = function() callback_called = true return allow_create diff --git a/tests/cwd_change_handling_spec.lua b/tests/cwd_change_handling_spec.lua index 926f878..c8abd79 100644 --- a/tests/cwd_change_handling_spec.lua +++ b/tests/cwd_change_handling_spec.lua @@ -6,7 +6,6 @@ describe("The cwd_change_handling config", function() local post_cwd_changed_hook_called = false require("auto-session").setup { -- log_level = "debug", - auto_session_root_dir = TL.session_dir, cwd_change_handling = { restore_upcoming_session = true, pre_cwd_changed_hook = function() diff --git a/tests/extra_sesssion_commands_spec.lua b/tests/extra_sesssion_commands_spec.lua index 130305c..02e4c13 100644 --- a/tests/extra_sesssion_commands_spec.lua +++ b/tests/extra_sesssion_commands_spec.lua @@ -5,7 +5,6 @@ TL.clearSessionFilesAndBuffers() describe("Config with extra session commands", function() local save_extra_cmds_called = false require("auto-session").setup { - auto_session_root_dir = TL.session_dir, save_extra_cmds = { function() save_extra_cmds_called = true diff --git a/tests/git_spec.lua b/tests/git_spec.lua index 031f5fa..7a0219a 100644 --- a/tests/git_spec.lua +++ b/tests/git_spec.lua @@ -3,7 +3,6 @@ local TL = require "tests/test_lib" describe("The git config", function() require("auto-session").setup { - auto_session_root_dir = TL.session_dir, auto_session_use_git_branch = true, } diff --git a/tests/hooks_spec.lua b/tests/hooks_spec.lua index 579087e..f5346f9 100644 --- a/tests/hooks_spec.lua +++ b/tests/hooks_spec.lua @@ -11,7 +11,6 @@ describe("Hooks", function() local post_delete_cmd_called = false as.setup { - auto_session_root_dir = TL.session_dir, pre_save_cmds = { function() print "pre_save_cmd" diff --git a/tests/minimal.lua b/tests/minimal.lua new file mode 100644 index 0000000..3fa7d9f --- /dev/null +++ b/tests/minimal.lua @@ -0,0 +1,12 @@ +-- Keep all testing data in ./.test +local root = vim.fn.fnamemodify("./.test", ":p") + +-- set stdpaths to use .repro +for _, name in ipairs { "config", "data", "state", "cache" } do + vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name +end + +-- Add plenary so we can run it +vim.opt.rtp:append "./.test/plenary" + +require "plenary" diff --git a/tests/minimal.vim b/tests/minimal.vim deleted file mode 100644 index defff89..0000000 --- a/tests/minimal.vim +++ /dev/null @@ -1,4 +0,0 @@ -set rtp+=. -set rtp+=./.build_tools/plenary - -runtime plugin/plenary.vim diff --git a/tests/setup_spec.lua b/tests/setup_spec.lua index e805837..73386fd 100644 --- a/tests/setup_spec.lua +++ b/tests/setup_spec.lua @@ -2,9 +2,7 @@ local TL = require "tests/test_lib" describe("The default config", function() - require("auto-session").setup { - auto_session_root_dir = TL.session_dir, - } + require("auto-session").setup {} TL.clearSessionFilesAndBuffers() diff --git a/tests/test_lib.lua b/tests/test_lib.lua index 02651c9..2219496 100644 --- a/tests/test_lib.lua +++ b/tests/test_lib.lua @@ -23,7 +23,7 @@ M.test_file = M.tests_base_dir .. "/test_files/test.txt" M.other_file = M.tests_base_dir .. "/test_files/other.txt" -- Use absolute path here for cwd_change_handling -M.session_dir = vim.fn.getcwd() .. "/tests/test_sessions/" +M.session_dir = vim.fn.getcwd() .. "/.test/data/nvim/sessions/" -- Construct the session name for the current directory M.default_session_name = M.escapeSessionName(vim.fn.getcwd()) From 4c74b166930d3ac02f145d0fd964de6ea497ddb6 Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 16 Jul 2024 11:56:12 -0700 Subject: [PATCH 03/18] test: fix data path for windows also annotate a bug with Lib.current_session_name --- lua/auto-session/lib.lua | 4 +++- tests/setup_spec.lua | 7 +++++-- tests/test_lib.lua | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index 209dc91..ad90c46 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -21,6 +21,7 @@ function Lib.setup(config) end function Lib.get_file_name(url) + -- BUG: This is broken on windows when the path is only using blackslashes return url:match "^.+/(.+)$" end @@ -29,7 +30,8 @@ function Lib.get_file_extension(url) end -- BUG: This doesn't work correctly for automatically created sessions on windows --- because they have dashes in the name +-- because they have dashes in the name. Can also be broken for paths that only +-- have backslahes (see bug above) function Lib.current_session_name() local fname = Lib.get_file_name(vim.v.this_session) local extension = Lib.get_file_extension(fname) diff --git a/tests/setup_spec.lua b/tests/setup_spec.lua index 73386fd..0068518 100644 --- a/tests/setup_spec.lua +++ b/tests/setup_spec.lua @@ -71,7 +71,9 @@ describe("The default config", function() vim.cmd(":SessionRestore " .. TL.named_session_path) assert.equals(1, vim.fn.bufexists(TL.test_file)) - assert.equals(TL.named_session_name, require("auto-session").Lib.current_session_name()) + + -- FIXME: This currently fails on windows because of Lib.get_file_name(url) + -- assert.equals(TL.named_session_name, require("auto-session").Lib.current_session_name()) end) it("can restore a session using SessionRestoreFromFile", function() @@ -85,7 +87,8 @@ describe("The default config", function() vim.cmd(":SessionRestoreFromFile " .. TL.named_session_name) assert.equals(1, vim.fn.bufexists(TL.test_file)) - assert.equals(TL.named_session_name, require("auto-session").Lib.current_session_name()) + -- FIXME: This currently fails on windows because of Lib.get_file_name(url) + -- assert.equals(TL.named_session_name, require("auto-session").Lib.current_session_name()) end) it("can delete a session with a file path", function() diff --git a/tests/test_lib.lua b/tests/test_lib.lua index 2219496..2413912 100644 --- a/tests/test_lib.lua +++ b/tests/test_lib.lua @@ -22,8 +22,8 @@ M.tests_base_dir = "tests" M.test_file = M.tests_base_dir .. "/test_files/test.txt" M.other_file = M.tests_base_dir .. "/test_files/other.txt" --- Use absolute path here for cwd_change_handling -M.session_dir = vim.fn.getcwd() .. "/.test/data/nvim/sessions/" +-- This is set in minimal.lua to be auto-session/.test/... +M.session_dir = vim.fn.stdpath "data" .. "/sessions/" -- Construct the session name for the current directory M.default_session_name = M.escapeSessionName(vim.fn.getcwd()) From d6e4184c26bb7d709ffdf6611c1c4ae42b852fc6 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 14:53:44 -0700 Subject: [PATCH 04/18] test: session control / alternate session --- tests/session_control_spec.lua | 71 ++++++++++++++++++++++++++++++++++ tests/test_lib.lua | 5 +++ 2 files changed, 76 insertions(+) create mode 100644 tests/session_control_spec.lua diff --git a/tests/session_control_spec.lua b/tests/session_control_spec.lua new file mode 100644 index 0000000..425fd75 --- /dev/null +++ b/tests/session_control_spec.lua @@ -0,0 +1,71 @@ +---@diagnostic disable: undefined-field +local TL = require "tests/test_lib" + +describe("The default config", function() + require("auto-session").setup { + -- log_level = "debug", + } + + TL.clearSessionFilesAndBuffers() + + it("can save a session control file", function() + vim.cmd(":e " .. TL.test_file) + + ---@diagnostic disable-next-line: missing-parameter + vim.cmd ":SessionSave" + -- Make sure the session was created + assert.equals(1, vim.fn.filereadable(TL.default_session_path)) + + vim.cmd "%bw!" + assert.equals(0, vim.fn.bufexists(TL.test_file)) + + -- Session control is only written on restore + vim.cmd ":SessionRestore" + + -- Make sure the restore worked + assert.equals(1, vim.fn.bufexists(TL.test_file)) + + -- Make sure the session control file was written + assert.equals(1, vim.fn.filereadable(TL.default_session_control_path)) + end) + + it("can save a session control file", function() + -- Save a new session + vim.cmd(":SessionSave " .. TL.named_session_name) + + vim.cmd "%bw!" + + assert.equals(0, vim.fn.bufexists(TL.test_file)) + + -- Restore the session to set the original one as the alternate + vim.cmd(":SessionRestore " .. TL.named_session_path) + + -- Make sure session restored + assert.equals(1, vim.fn.bufexists(TL.test_file)) + + -- Make sure the session control file was written + assert.equals(1, vim.fn.filereadable(TL.default_session_control_path)) + + local session_control = require("auto-session").Lib.load_session_control_file(TL.default_session_control_path) + + -- Should not be empty + assert.is_not_nil(next(session_control)) + + print("session_control: " .. vim.inspect(session_control)) + + assert.equals(TL.named_session_path, session_control.current) + assert.equals(TL.default_session_path, session_control.alternate) + end) + + it("lib function handles edge cases", function() + local lib = require("auto-session").Lib + + -- Don't throw an error on nil + local session_control = lib.load_session_control_file(nil) + assert.equals("table", type(session_control)) + + -- Don't throw an error on not a js file + session_control = lib.load_session_control_file "tests/session_control_spec.lua" + assert.equals("table", type(session_control)) + end) +end) diff --git a/tests/test_lib.lua b/tests/test_lib.lua index 2413912..1ee2a6f 100644 --- a/tests/test_lib.lua +++ b/tests/test_lib.lua @@ -24,12 +24,16 @@ M.other_file = M.tests_base_dir .. "/test_files/other.txt" -- This is set in minimal.lua to be auto-session/.test/... M.session_dir = vim.fn.stdpath "data" .. "/sessions/" +M.session_control_dir = vim.fn.stdpath "data" .. "/auto_session/" -- Construct the session name for the current directory M.default_session_name = M.escapeSessionName(vim.fn.getcwd()) M.default_session_path = M.session_dir .. M.default_session_name .. ".vim" +M.default_session_control_name = "session_control.json" +M.default_session_control_path = M.session_control_dir .. M.default_session_control_name + M.named_session_name = "mysession" M.named_session_path = M.session_dir .. M.named_session_name .. ".vim" @@ -49,6 +53,7 @@ end function M.clearSessionFilesAndBuffers() M.clearSessionFiles(M.session_dir) + M.clearSessionFiles(M.session_control_dir) vim.cmd "silent %bw" end From e52ee8eb2ac33d34bf576ad812ba536e5f21fe76 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 15:02:58 -0700 Subject: [PATCH 05/18] fix: #200, #322 again session_control loading throwing an error The basic bug was introduced in #322 becase `table.concat` returns a string so `content[1]` doesn't make sense. The bug that #322 was fixing was repeated in `session-lens/actions.lua` so it made sense to clean it all up. --- lua/auto-session/init.lua | 92 +++++------------------ lua/auto-session/lib.lua | 23 ++++++ lua/auto-session/session-lens/actions.lua | 15 ++-- lua/auto-session/session-lens/init.lua | 18 +++-- 4 files changed, 56 insertions(+), 92 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index 1d4253f..fd847ed 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -655,47 +655,6 @@ end vim.api.nvim_create_user_command("Autosession", handle_autosession_command, { nargs = 1 }) --- local function write_to_session_control(session_file_name) --- local control_dir = AutoSession.conf.session_control.control_dir --- local control_file = AutoSession.conf.session_control.control_filename --- session_file_name = Lib.expand(session_file_name) - --- Lib.init_dir(control_dir) - --- local session_control_file = control_dir .. control_file - --- if vim.fn.filereadable(session_control_file) == 1 then --- local content = vim.fn.readfile(session_control_file) --- local sessions = { current = session_file_name, alternate = Lib.expand(content[#content - 1]) } - --- Lib.logger.debug { sessions = sessions, content = content } - --- if sessions.current == sessions.alternate then --- -- Do not write to file when the new session would be the same as the one already in the file --- Lib.logger.debug "Not writing to session control file, alternate would be the same as current" --- return --- end - --- if #content >= 2 then --- -- File is too big, keep only latest and second latest --- Lib.logger.debug "Session control file is at or over the limit of 2, rewriting to keep size down" --- vim.fn.writefile({ content[#content - 1] }, session_control_file) --- end --- end - --- -- Write latest restored session --- vim.fn.writefile({ session_file_name }, session_control_file, "a") - --- local log_ending_state = function() --- local content = vim.fn.readfile(session_control_file) --- local sessions = { current = session_file_name, alternate = Lib.expand(content[#content - 1]) } - --- Lib.logger.debug("alternate state right before function end", { sessions = sessions, content = content }) --- end - --- log_ending_state() --- end - local function write_to_session_control_json(session_file_name) local control_dir = AutoSession.conf.session_lens.session_control.control_dir local control_file = AutoSession.conf.session_lens.session_control.control_filename @@ -703,48 +662,31 @@ local function write_to_session_control_json(session_file_name) Lib.init_dir(control_dir) - local session_control_file = control_dir .. control_file - - local log_ending_state = function() - local file_lines = vim.fn.readfile(session_control_file) - local content = table.concat(file_lines, " ") - local session_control = vim.json.decode(content[1] or "{}") or {} - local sessions = { current = session_control.current, alternate = session_control.alternate } - - Lib.logger.debug("session control file contents", { sessions = sessions, content = content }) - end - - if vim.fn.filereadable(session_control_file) == 1 then - local file_lines = vim.fn.readfile(session_control_file) - local content = table.concat(file_lines, " ") - Lib.logger.debug { content = content } - local json = vim.json.decode(content[1] or "{}") or {} + -- Get the full path + local session_control_file_path = control_dir .. control_file - local sessions = { - current = session_file_name, - alternate = json.current, - } - - Lib.logger.debug { sessions = sessions, content = content } + -- Load existing data, if it exists + local session_control = Lib.load_session_control_file(session_control_file_path) + Lib.logger.debug("Loaded session control data: ", session_control) - if sessions.current == sessions.alternate then - -- Do not write to file when the new session would be the same as the one already in the file - Lib.logger.debug "Not writing to session control file, alternate would be the same as current" + -- If there's existing data + if session_control.current then + if session_control.current == session_file_name then + Lib.logger.debug( + "Not writing to session control file, current is same as session_file_name: " .. session_file_name + ) return end + session_control.alternate = session_control.current + end - local json_to_save = vim.json.encode(sessions) + session_control.current = session_file_name - vim.fn.writefile({ json_to_save }, session_control_file) - log_ending_state() - return - end + Lib.logger.debug("Saving session control", session_control) - -- Write latest restored session - local json = vim.json.encode { current = session_file_name } - vim.fn.writefile({ json }, session_control_file) + local json_to_save = vim.json.encode(session_control) - log_ending_state() + vim.fn.writefile({ json_to_save }, session_control_file_path) end --Saves the session, overriding if previously existing. diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index ad90c46..2a3fbc4 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -265,4 +265,27 @@ function Lib.is_session_file(session_dir, file_path) return first_line and string.find(first_line, "SessionLoad") ~= nil end +---Decodes the contents of session_control_file_path as a JSON object and returns it. +---Returns an empty table if the file doesn't exist or if the contents couldn't be decoded +--@param session_control_file_path string +--@return table +function Lib.load_session_control_file(session_control_file_path) + -- No file, return empty table + if vim.fn.filereadable(session_control_file_path) ~= 1 then + return {} + end + + local file_lines = vim.fn.readfile(session_control_file_path) + local content = table.concat(file_lines, " ") + + local success, json = pcall(vim.json.decode, content) + + -- Failed to decode, return an empty table + if not success or not json then + return {} + end + + return json +end + return Lib diff --git a/lua/auto-session/session-lens/actions.lua b/lua/auto-session/session-lens/actions.lua index f3d02b4..c666963 100644 --- a/lua/auto-session/session-lens/actions.lua +++ b/lua/auto-session/session-lens/actions.lua @@ -14,15 +14,14 @@ local function get_alternate_session() local filepath = M.conf.session_control.control_dir .. M.conf.session_control.control_filename if vim.fn.filereadable(filepath) == 1 then - local content = vim.fn.readfile(filepath)[1] or "{}" - local json = vim.json.decode(content) or {} -- should never hit the or clause since we're defaulting to a string for content + local json = Lib.load_session_control_file(filepath) local sessions = { current = json.current, alternate = json.alternate, } - Lib.logger.debug("get_alternate_session", { sessions = sessions, content = content }) + Lib.logger.debug("get_alternate_session", { sessions = sessions, json = json }) if sessions.current ~= sessions.alternate then return sessions.alternate @@ -39,7 +38,7 @@ local function source_session(selection, prompt_bufnr) end vim.defer_fn(function() - M.functions.restore_selected_session(type(selection) == "table" and selection.path) + M.functions.restore_selected_session(selection) end, 50) end @@ -67,12 +66,8 @@ M.alternate_session = function(prompt_bufnr) local alternate_session = get_alternate_session() if not alternate_session then - Lib.logger.info "There is no alternate session to navigate to, aborting operation" - - if prompt_bufnr then - actions.close(prompt_bufnr) - end - + vim.notify "There is no alternate session" + -- Keep the picker open in case they want to select a session to load return end diff --git a/lua/auto-session/session-lens/init.lua b/lua/auto-session/session-lens/init.lua index 3ee75b2..e6e23e5 100644 --- a/lua/auto-session/session-lens/init.lua +++ b/lua/auto-session/session-lens/init.lua @@ -39,7 +39,7 @@ function SessionLens.setup(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') + 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 @@ -87,11 +87,13 @@ SessionLens.search_session = function(custom_opts) prompt_title = "Sessions", entry_maker = Lib.make_entry.gen_from_file(custom_opts), cwd = cwd, - -- TOOD: support custom mappings? + -- TODO: Document mappings. At least in Telescope shows the current mappings for the picker + -- Possible future feature: custom mappings? attach_mappings = function(_, map) telescope_actions.select_default:replace(Actions.source_session) map("i", "", Actions.delete_session) map("i", "", Actions.alternate_session) + map("i", "", Actions.alternate_session) return true end, } @@ -118,11 +120,13 @@ SessionLens.search_session = function(custom_opts) local finders = require "telescope.finders" local conf = require("telescope.config").values - require("telescope.pickers").new(opts, { - finder = finders.new_oneshot_job(find_command, opts), - previewer = conf.grep_previewer(opts), - sorter = conf.file_sorter(opts), - }):find() + require("telescope.pickers") + .new(opts, { + finder = finders.new_oneshot_job(find_command, opts), + previewer = conf.grep_previewer(opts), + sorter = conf.file_sorter(opts), + }) + :find() end return SessionLens From ae35f73e5277e779ff310a243fca2b166fd6c959 Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 16 Jul 2024 19:58:57 -0700 Subject: [PATCH 06/18] test: fix session_control_spec on windows It was failing due to inconsistent path separator usage. I found out that vim.fn.expand (Lib.expand) canonicalizes the path separator which could be useful for standardizing paths / preventing edge cases. Whether it picks \ or / depends on the shellslash setting. --- lua/auto-session/lib.lua | 8 ++++++++ tests/session_control_spec.lua | 36 ++++++++++++++++++++++++++++------ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index 2a3fbc4..15402ad 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -164,6 +164,14 @@ function Lib.is_readable(file_path) return readable end +-- NOTE: expand has the side effect of canonicalizing the path +-- separators on windows, meaning if it's a mix of \ and /, it +-- will come out of expand with all \ (or, if shellslash is on, +-- all /) + +---Get the full path for the passed in path +--@param string +--@return string function Lib.expand(file_or_dir) local saved_wildignore = vim.api.nvim_get_option "wildignore" vim.api.nvim_set_option("wildignore", "") diff --git a/tests/session_control_spec.lua b/tests/session_control_spec.lua index 425fd75..6dfa8f4 100644 --- a/tests/session_control_spec.lua +++ b/tests/session_control_spec.lua @@ -51,21 +51,45 @@ describe("The default config", function() -- Should not be empty assert.is_not_nil(next(session_control)) - print("session_control: " .. vim.inspect(session_control)) + local as = require "auto-session" - assert.equals(TL.named_session_path, session_control.current) - assert.equals(TL.default_session_path, session_control.alternate) + assert.equals(as.Lib.expand(TL.named_session_path), session_control.current) + assert.equals(as.Lib.expand(TL.default_session_path), session_control.alternate) + end) + + it("Saving twice doesn't set alternate", function() + -- Save a session then restore it twice to make sure it's not both current and alternate + vim.cmd ":SessionSave" + + vim.cmd ":SessionRestore" + + vim.cmd ":SessionRestore " + + -- Make sure the session control file was written + assert.equals(1, vim.fn.filereadable(TL.default_session_control_path)) + + local session_control = require("auto-session").Lib.load_session_control_file(TL.default_session_control_path) + + -- Should not be empty + assert.is_not_nil(next(session_control)) + + local as = require "auto-session" + + assert.equals(as.Lib.expand(TL.default_session_path), session_control.current) + + -- Should still be mysession from test above + assert.equals(as.Lib.expand(TL.named_session_path), session_control.alternate) end) it("lib function handles edge cases", function() - local lib = require("auto-session").Lib + local as = require "auto-session" -- Don't throw an error on nil - local session_control = lib.load_session_control_file(nil) + local session_control = as.Lib.load_session_control_file(nil) assert.equals("table", type(session_control)) -- Don't throw an error on not a js file - session_control = lib.load_session_control_file "tests/session_control_spec.lua" + session_control = as.Lib.load_session_control_file "tests/session_control_spec.lua" assert.equals("table", type(session_control)) end) end) From 9741259de9d79e7cf5288d48604004c6d8cf4fa8 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 22:52:32 -0700 Subject: [PATCH 07/18] fix: Telescope picker: be consistent with source_session params --- lua/auto-session/session-lens/actions.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/auto-session/session-lens/actions.lua b/lua/auto-session/session-lens/actions.lua index c666963..f0d1c06 100644 --- a/lua/auto-session/session-lens/actions.lua +++ b/lua/auto-session/session-lens/actions.lua @@ -31,14 +31,14 @@ local function get_alternate_session() end end -local function source_session(selection, prompt_bufnr) +local function source_session(path, prompt_bufnr) if prompt_bufnr then local actions = require "telescope.actions" actions.close(prompt_bufnr) end vim.defer_fn(function() - M.functions.restore_selected_session(selection) + M.functions.restore_selected_session(path) end, 50) end @@ -48,7 +48,7 @@ end M.source_session = function(prompt_bufnr) local action_state = require "telescope.actions.state" local selection = action_state.get_selected_entry() - source_session(selection, prompt_bufnr) + source_session(selection.path, prompt_bufnr) end ---Delete session action From 81f314e17dc898308c24fdb1b556f601e1dacb34 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 22:56:47 -0700 Subject: [PATCH 08/18] fix: avoid double path separators between session_dir and sesssion name The double path separators can cause problems with equality tests when comparing sessions and that's a problem for the alternate session feature. --- lua/auto-session/init.lua | 32 ++++++++++++++--------- lua/auto-session/lib.lua | 15 ++++++++++- lua/auto-session/session-lens/library.lua | 13 ++++----- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index fd847ed..c480093 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -507,18 +507,26 @@ end ---Gets the root directory of where to save the sessions. ---By default this resolves to `vim.fn.stdpath "data" .. "/sessions/"` +---@param with_trailing_separator? boolean whether to incude the trailing separator. A few places (telescope picker don't expect a trailing separator) ---@return string -function AutoSession.get_root_dir() - if AutoSession.validated then - return AutoSession.conf.auto_session_root_dir +function AutoSession.get_root_dir(with_trailing_separator) + if with_trailing_separator == nil then + with_trailing_separator = true end - local root_dir = vim.g["auto_session_root_dir"] or AutoSession.conf.auto_session_root_dir + if not AutoSession.validated then + local root_dir = vim.g["auto_session_root_dir"] or AutoSession.conf.auto_session_root_dir + + AutoSession.conf.auto_session_root_dir = Lib.validate_root_dir(root_dir) + Lib.logger.debug("Root dir set to: " .. AutoSession.conf.auto_session_root_dir) + AutoSession.validated = true + end - AutoSession.conf.auto_session_root_dir = Lib.validate_root_dir(root_dir) - Lib.logger.debug("Root dir set to: " .. AutoSession.conf.auto_session_root_dir) - AutoSession.validated = true - return root_dir + if with_trailing_separator then + return AutoSession.conf.auto_session_root_dir + end + + return Lib.dir_without_trailing_separator(AutoSession.conf.auto_session_root_dir) end ---Get the hook commands to run @@ -573,11 +581,9 @@ 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 .. path_separator .. entry } + -- sessions_dir is guaranteed to have a trailing separator so don't need to add another one here + return { display_name = AutoSession.format_file_name(entry), path = sessions_dir .. entry } end, entries) end @@ -614,7 +620,7 @@ end -- Handler for when a session is picked from the UI, either via Telescope or via AutoSession.select_session function AutoSession.restore_selected_session(session_filename) - Lib.logger.debug("[restore_selected_session]: filename: " .. session_filename) + Lib.logger.debug("[restore_selected_session]: filename: ", session_filename) AutoSession.AutoSaveSession() diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index 15402ad..799d10a 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -10,7 +10,6 @@ local Lib = { Config = Config, _VIM_FALSE = 0, _VIM_TRUE = 1, - ROOT_DIR = nil, } function Lib.setup(config) @@ -96,6 +95,20 @@ function Lib.init_dir(dir) end end +---Removes the trailing separator (if any) from a directory, for both unix and windows +---This is needed in some places to avoid duplicate separators that complicate +---the path and make equality checks fail (e.g. session control alternate) +---@param dir string +---@return string +function Lib.dir_without_trailing_separator(dir) + -- For windows, have to check for both as either could be used + if vim.fn.has "win32" == 1 then + dir = dir:gsub("\\$", "") + end + + return (dir:gsub("/$", "")) +end + function Lib.init_file(file_path) if not Lib.is_readable(file_path) then vim.cmd("!touch " .. file_path) diff --git a/lua/auto-session/session-lens/library.lua b/lua/auto-session/session-lens/library.lua index b628103..5d6ae3b 100644 --- a/lua/auto-session/session-lens/library.lua +++ b/lua/auto-session/session-lens/library.lua @@ -1,5 +1,4 @@ local path = require "plenary.path" -local AutoSessionLib = require "auto-session.lib" local Config = {} local Lib = { @@ -11,13 +10,11 @@ local Lib = { Config = Config, _VIM_FALSE = 0, _VIM_TRUE = 1, - ROOT_DIR = nil, } function Lib.setup(config, functions) Lib.conf = vim.tbl_deep_extend("force", Lib.conf, config) Lib.functions = functions - Lib.ROOT_DIR = Lib.functions.get_root_dir() end function Lib.isEmpty(s) @@ -34,11 +31,15 @@ function Lib.appendSlash(str) end function Lib.make_entry.gen_from_file(opts) - local root = Lib.functions.get_root_dir() + -- NOTE:: Lib.functions.Lib is AutoSession.Lib + -- Maybe would be better to require('auto-session') and access the Lib property instead? + + -- We don't want the trailing separator because plenary will add one + local root = Lib.functions.get_root_dir(false) 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 + if not Lib.functions.Lib.is_session_file(root, line) then return nil end @@ -48,7 +49,7 @@ function Lib.make_entry.gen_from_file(opts) filename = line, cwd = root, display = function(_) - local out = AutoSessionLib.unescape_dir(line):match "(.+)%.vim" + local out = Lib.functions.Lib.unescape_dir(line):match "(.+)%.vim" if opts.path_display and vim.tbl_contains(opts.path_display, "shorten") then out = path:new(out):shorten() end From bd2ebf33a98234b52f4773856936ef8176080b18 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 22:58:35 -0700 Subject: [PATCH 09/18] test: Lib tests --- tests/lib_spec.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/lib_spec.lua diff --git a/tests/lib_spec.lua b/tests/lib_spec.lua new file mode 100644 index 0000000..50bf3f0 --- /dev/null +++ b/tests/lib_spec.lua @@ -0,0 +1,26 @@ +---@diagnostic disable: undefined-field +local TL = require "tests/test_lib" + +describe("Lib", function() + local as = require "auto-session" + as.setup { + auto_session_root_dir = TL.session_dir, + } + + local Lib = as.Lib + + it("get_root_dir works", function() + assert.equals(TL.session_dir, as.get_root_dir()) + + assert.equals(TL.session_dir:gsub("/$", ""), as.get_root_dir(false)) + end) + + it("dir_without_trailing_separator works", function() + assert.equals("/tmp/blah", Lib.dir_without_trailing_separator "/tmp/blah/") + + if vim.fn.has "win32" == 1 then + assert.equals("c:\\temp\\blah", Lib.dir_without_trailing_separator "c:\\temp\\blah\\") + assert.equals("c:\\temp\\blah", Lib.dir_without_trailing_separator "c:\\temp\\blah/") + end + end) +end) From b2439b684f9bccb0d0db417da7e0206f67f7b48b Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 23:15:57 -0700 Subject: [PATCH 10/18] fix: cross platform trailing path separator --- lua/auto-session/lib.lua | 23 ++++++++++++++++++++--- tests/lib_spec.lua | 11 +++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index 799d10a..53a6d30 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -67,9 +67,7 @@ end -- Also creates it if necessary -- Falls back to vim.fn.stdpath "data" .. "/sessions/" if the directory is invalid for some reason function Lib.validate_root_dir(root_dir) - if not vim.endswith(root_dir, "/") then - root_dir = root_dir .. "/" - end + root_dir = Lib.ensure_trailing_separator(root_dir) if vim.fn.isdirectory(Lib.expand(root_dir)) == Lib._VIM_FALSE then vim.fn.mkdir(root_dir, "p") @@ -95,6 +93,25 @@ function Lib.init_dir(dir) end end +---Returns a string that's guaranteed to end in a path separator +---@param dir string +---@return string +function Lib.ensure_trailing_separator(dir) + if vim.endswith(dir, "/") then + return dir + end + + -- For windows, have to also check if it ends in a \ + if vim.fn.has "win32" == 1 then + if vim.endswith(dir, "\\") then + return dir + end + end + + -- If not, a / will work for both systems + return dir .. "/" +end + ---Removes the trailing separator (if any) from a directory, for both unix and windows ---This is needed in some places to avoid duplicate separators that complicate ---the path and make equality checks fail (e.g. session control alternate) diff --git a/tests/lib_spec.lua b/tests/lib_spec.lua index 50bf3f0..4378601 100644 --- a/tests/lib_spec.lua +++ b/tests/lib_spec.lua @@ -23,4 +23,15 @@ describe("Lib", function() assert.equals("c:\\temp\\blah", Lib.dir_without_trailing_separator "c:\\temp\\blah/") end end) + + it("ensure_trailing_separator works", function() + assert.equals("/test/path/", Lib.ensure_trailing_separator "/test/path/") + assert.equals("/test/path/", Lib.ensure_trailing_separator "/test/path") + + if vim.fn.has "win32" == 1 then + -- For the future, if we want to canonicalize paths, we can could call vim.fn.expand + assert.equals("c:\\test\\path\\", Lib.ensure_trailing_separator "c:\\test\\path\\") + assert.equals("c:\\test\\path/", Lib.ensure_trailing_separator "c:\\test\\path") + end + end) end) From 972d23b2b9615bdd10ad80c225260af4213c3612 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Tue, 16 Jul 2024 23:21:30 -0700 Subject: [PATCH 11/18] refactor: remove_trailing_separator is a better name --- lua/auto-session/init.lua | 2 +- lua/auto-session/lib.lua | 2 +- tests/lib_spec.lua | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index c480093..5440601 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -526,7 +526,7 @@ function AutoSession.get_root_dir(with_trailing_separator) return AutoSession.conf.auto_session_root_dir end - return Lib.dir_without_trailing_separator(AutoSession.conf.auto_session_root_dir) + return Lib.remove_trailing_separator(AutoSession.conf.auto_session_root_dir) end ---Get the hook commands to run diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index 53a6d30..a13d2e0 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -117,7 +117,7 @@ end ---the path and make equality checks fail (e.g. session control alternate) ---@param dir string ---@return string -function Lib.dir_without_trailing_separator(dir) +function Lib.remove_trailing_separator(dir) -- For windows, have to check for both as either could be used if vim.fn.has "win32" == 1 then dir = dir:gsub("\\$", "") diff --git a/tests/lib_spec.lua b/tests/lib_spec.lua index 4378601..6e50750 100644 --- a/tests/lib_spec.lua +++ b/tests/lib_spec.lua @@ -15,12 +15,14 @@ describe("Lib", function() assert.equals(TL.session_dir:gsub("/$", ""), as.get_root_dir(false)) end) - it("dir_without_trailing_separator works", function() - assert.equals("/tmp/blah", Lib.dir_without_trailing_separator "/tmp/blah/") + it("remove_trailing_separator works", function() + assert.equals("/tmp/blah", Lib.remove_trailing_separator "/tmp/blah/") + assert.equals("/tmp/blah", Lib.remove_trailing_separator "/tmp/blah") if vim.fn.has "win32" == 1 then - assert.equals("c:\\temp\\blah", Lib.dir_without_trailing_separator "c:\\temp\\blah\\") - assert.equals("c:\\temp\\blah", Lib.dir_without_trailing_separator "c:\\temp\\blah/") + assert.equals("c:\\temp\\blah", Lib.remove_trailing_separator "c:\\temp\\blah\\") + assert.equals("c:\\temp\\blah", Lib.remove_trailing_separator "c:\\temp\\blah/") + assert.equals("c:\\temp\\blah", Lib.remove_trailing_separator "c:\\temp\\blah") end end) From ea018438055a7e54e44e84e17c1167cbd3dec7ca Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Wed, 17 Jul 2024 18:10:08 -0700 Subject: [PATCH 12/18] build: fix Makefile when run as a github action Looks like the --embed was causing issues. Not sure why I had it in the first place. --- Makefile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 82e1a04..a11c920 100644 --- a/Makefile +++ b/Makefile @@ -8,13 +8,14 @@ FILES := $(wildcard tests/*_spec.lua) test: $(PLENARY_DIR) $(FILES) args-tests $(FILES): $(PLENARY_DIR) - nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile $@" + nvim --clean --headless -u tests/minimal.lua +"PlenaryBustedFile $@" + args-tests: $(PLENARY_DIR) - nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_setup_spec.lua" - nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_not_enabled_spec.lua" - nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_single_dir_enabled_spec.lua" - nvim --clean --headless --embed -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_files_enabled_spec.lua" + nvim --clean --headless -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_setup_spec.lua" + nvim --clean --headless -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_not_enabled_spec.lua" + nvim --clean --headless -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_single_dir_enabled_spec.lua" + nvim --clean --headless -u tests/minimal.lua +"PlenaryBustedFile tests/args/args_files_enabled_spec.lua" $(PLENARY_DIR): From 6bf34f26b329b121efe84d93b23352cb0d315f7b Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Wed, 17 Jul 2024 18:11:28 -0700 Subject: [PATCH 13/18] test: fix extra separator in middle of path --- tests/minimal.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/minimal.lua b/tests/minimal.lua index 3fa7d9f..f651808 100644 --- a/tests/minimal.lua +++ b/tests/minimal.lua @@ -3,7 +3,7 @@ local root = vim.fn.fnamemodify("./.test", ":p") -- set stdpaths to use .repro for _, name in ipairs { "config", "data", "state", "cache" } do - vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name + vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. name end -- Add plenary so we can run it From c61321b72f5cdf2eb4e6a939ebcdb51bcaa1883b Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Wed, 17 Jul 2024 18:12:29 -0700 Subject: [PATCH 14/18] test: fix git test so it works on a clean system --- tests/git_spec.lua | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tests/git_spec.lua b/tests/git_spec.lua index 7a0219a..6666b14 100644 --- a/tests/git_spec.lua +++ b/tests/git_spec.lua @@ -25,10 +25,24 @@ describe("The git config", function() -- change to that dir vim.cmd(":cd " .. git_test_dir) + local function runCmdAndPrint(cmd) + ---@diagnostic disable-next-line: unused-local + local result = vim.fn.system(cmd) + -- print("Command output:", result) + -- + -- local lines = vim.split(result, "\n") + -- for _, line in ipairs(lines) do + -- print(line) + -- end + -- + -- print("Exit status:", vim.v.shell_error) + end + -- init repo and make a commit - vim.fn.system "git init -b main" - vim.fn.system "git add ." - vim.fn.system "git commit -m 'init'" + runCmdAndPrint "git init -b main" + runCmdAndPrint 'git config user.email "test@test.com"; git config user.name "test"' + runCmdAndPrint "git add test.txt" + runCmdAndPrint "git commit -m 'init'" -- open a file so we have something to save vim.cmd ":e test.txt" @@ -39,6 +53,8 @@ describe("The git config", function() local session_path = TL.session_dir .. TL.escapeSessionName(vim.fn.getcwd() .. "_main.vim") + print(session_path) + assert.equals(1, vim.fn.filereadable(session_path)) end) end) From 6a59e0a53bca32b0d1210b70adf0d58dab79ebf7 Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Wed, 17 Jul 2024 19:00:25 -0700 Subject: [PATCH 15/18] build: run unit tests on push and PRs --- .github/workflows/tests.yml | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..ac5ea64 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,55 @@ +# From +# https://github.com/shortcuts/neovim-plugin-boilerplate/blob/main/.github/workflows/main.yml + +name: tests + +on: + push: + pull_request: + types: [opened, synchronize] + +jobs: + lint: + runs-on: ubuntu-latest + name: lint + steps: + - uses: actions/checkout@v4 + + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: latest + args: --check . -g '*.lua' -g '!deps/' + + test: + runs-on: ubuntu-latest + timeout-minutes: 2 + strategy: + matrix: + neovim_version: ["v0.7.2", "v0.8.3", "v0.9.5", "v0.10.0", "nightly"] + + steps: + - uses: actions/checkout@v4 + + - run: date +%F > todays-date + + - name: restore cache for today's nightly. + uses: actions/cache@v4 + with: + path: _neovim + key: ${{ runner.os }}-x64-${{ hashFiles('todays-date') }} + + - name: setup neovim + uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: ${{ matrix.neovim_version }} + + - name: install ripgrep + run: | + sudo apt-get update + sudo apt-get install -y ripgrep + + - name: run tests + run: | + make test From 1aa43b197a5a0e2a8b8e6c15de983bd10d6bc583 Mon Sep 17 00:00:00 2001 From: cameronr Date: Thu, 18 Jul 2024 02:01:09 +0000 Subject: [PATCH 16/18] chore(docs): auto-generate vimdoc --- doc/auto-session.txt | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/doc/auto-session.txt b/doc/auto-session.txt index 5bf1443..b98f1ce 100644 --- a/doc/auto-session.txt +++ b/doc/auto-session.txt @@ -2,17 +2,17 @@ defaultConf *defaultConf* table default config for auto session Fields: ~ - {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 + {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 {auto_session_enable_last_session?} (boolean) - {auto_session_root_dir?} (string) root directory for session files, by default is `vim.fn.stdpath('data')/sessions/` - {auto_session_enabled?} (boolean) enable auto session - {auto_session_create_enabled} (boolean|nil) Enables/disables auto creating new sessions - {auto_save_enabled?} (boolean) Enables/disables auto saving session - {auto_restore_enabled?} (boolean) Enables/disables auto restoring session - {auto_restore_lazy_delay_enabled?} (boolean) 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 - {auto_session_suppress_dirs?} (table) Suppress auto session for directories - {auto_session_allowed_dirs?} (table) Allow auto session for directories, if empty then all directories are allowed except for suppressed ones - {auto_session_use_git_branch?} (boolean) Include git branch name in session name to differentiate between sessions for different git branches + {auto_session_root_dir?} (string) root directory for session files, by default is `vim.fn.stdpath('data')/sessions/` + {auto_session_enabled?} (boolean) enable auto session + {auto_session_create_enabled} (boolean|function|nil) Enables/disables auto creating new sessions. Can take a function that should return true/false if a session should be created or not + {auto_save_enabled?} (boolean) Enables/disables auto saving session + {auto_restore_enabled?} (boolean) Enables/disables auto restoring session + {auto_restore_lazy_delay_enabled?} (boolean) 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 + {auto_session_suppress_dirs?} (table) Suppress auto session for directories + {auto_session_allowed_dirs?} (table) Allow auto session for directories, if empty then all directories are allowed except for suppressed ones + {auto_session_use_git_branch?} (boolean) Include git branch name in session name to differentiate between sessions for different git branches luaOnlyConf *luaOnlyConf* @@ -24,6 +24,9 @@ luaOnlyConf *luaOnlyConf* {close_unsupported_windows?} (boolean) Whether to close windows that aren't backed by a real file {silent_restore} (boolean) Whether to restore sessions silently or not {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 + {args_allow_single_directory?} (boolean) Follow normal sesion save/load logic if launched with a single directory as the only argument + Argv Handling + {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 CwdChangeHandling *CwdChangeHandling* @@ -71,10 +74,14 @@ AutoSession.AutoSaveSession({sessions_dir?}) {sessions_dir?} (string) the session directory to auto_save a session for. If empty this function will end up using the cwd to infer what session to save for. -AutoSession.get_root_dir() *AutoSession.get_root_dir* + *AutoSession.get_root_dir* +AutoSession.get_root_dir({with_trailing_separator?}) Gets the root directory of where to save the sessions. By default this resolves to `vim.fn.stdpath "data" .. "/sessions/"` + Parameters: ~ + {with_trailing_separator?} (boolean) whether to incude the trailing separator. A few places (telescope picker don't expect a trailing separator) + Returns: ~ (string) @@ -113,6 +120,9 @@ AutoSession.get_session_files() *AutoSession.get_session_files* (PickerItem[]) +AutoSession.restore_selected_session() *AutoSession.restore_selected_session* + + *AutoSession.SaveSession* AutoSession.SaveSession({sessions_dir?}, {auto}) @@ -124,7 +134,6 @@ AutoSession.SaveSession({sessions_dir?}, {auto}) *AutoSession.AutoRestoreSession* AutoSession.AutoRestoreSession({session_dir}) Function called by AutoSession when automatically restoring a session. - This function avoids calling RestoreSession automatically when argv is not nil. Parameters: ~ {session_dir} (any) @@ -135,7 +144,6 @@ AutoSession.AutoRestoreSession({session_dir}) *AutoSession.RestoreSessionFromFile* AutoSession.RestoreSessionFromFile({session_file}) - RestoreSessionFromFile takes a session_file and calls RestoreSession after parsing the provided parameter. Parameters: ~ {session_file} (string) @@ -196,9 +204,10 @@ session_lens_config *session_lens_config* Session Lens Config Fields: ~ - {shorten_path} (boolean) + {shorten_path} (boolean) Deprecated, pass { 'shorten' } to path_display + {path_display} (table) An array that specifies how to handle paths. Read :h telescope.defaults.path_display {theme_conf} (table) - {buftypes_to_ignore} (table) + {buftypes_to_ignore} (table) Deprecated, if you're using this please report your usage on github {previewer} (boolean) {session_control} (session_control) {load_on_setup} (boolean) From f89d8fe6714b4d70997069dda4bdb6d7d78b26db Mon Sep 17 00:00:00 2001 From: Cameron Ring Date: Wed, 17 Jul 2024 19:27:26 -0700 Subject: [PATCH 17/18] docs: add unit tests badge, readme tidying --- README.md | 71 ++++++++++++++++++++------------------- lua/auto-session/init.lua | 3 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index f9bd623..740ec36 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,19 @@ -# 🗒️ Description +# 🗒️ AutoSession -Auto Session takes advantage of Neovim's existing session management capabilities to provide seamless automatic session management. +AutoSession takes advantage of Neovim's existing session management capabilities to provide seamless automatic session management. +[GitHub Actions Workflow Status](https://github.com/rmagatti/auto-session/actions/workflows/tests.yml) + # 💡 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 .` (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. +1. When starting `nvim` with no arguments, AutoSession will try to restore an existing session for the current `cwd` if one exists. +2. When starting `nvim .` (or another directory), AutoSession will try to restore the session for that directory. +3. When starting `nvim some_file.txt` (or multiple files), by default, AutoSession 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. +6. When piping to `nvim`, e.g: `cat myfile | nvim`, AutoSession 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`. @@ -20,16 +22,16 @@ AutoSession can now track `cwd` changes! By default, `cwd` handling is disabled but when enabled, it works as follows: - DirChangedPre (before the cwd actually changes): - - Save the current session - - Clear all buffers `%bd!`. This guarantees buffers don't bleed to the - next session. - - Clear jumps. Also done so there is no bleeding between sessions. - - Run the `pre_cwd_changed_hook`/ + - Save the current session + - Clear all buffers `%bd!`. This guarantees buffers don't bleed to the + next session. + - Clear jumps. Also done so there is no bleeding between sessions. + - Run the `pre_cwd_changed_hook`/ - DirChanged (after the cwd has changed): - - Restore session using new cwd - - Run the `post_cwd_changed_hook` + - Restore session using new cwd + - Run the `post_cwd_changed_hook` -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. +Now when the user changes the cwd with `:cd some/new/dir` AutoSession 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: @@ -85,7 +87,7 @@ use { ### Default -Auto Session by default stores sessions in `vim.fn.stdpath('data').."/sessions/"`. +AutoSession by default stores sessions in `vim.fn.stdpath('data').."/sessions/"`. ### Custom @@ -194,7 +196,7 @@ Now last session will be restored only when Neovim is launched in the home direc # 📢 Commands -Auto Session exposes two commands that can be used or mapped to any keybindings for manually saving and restoring sessions. +AutoSession exposes the following commands that can be used or mapped to any keybindings for manually saving and restoring sessions. ```viml :SessionSave " saves or creates a session in the currently set `auto_session_root_dir`. @@ -205,8 +207,8 @@ Auto Session exposes two commands that can be used or mapped to any keybindings :SessionDelete " deletes a session in the currently set `auto_session_root_dir`. :SessionDelete ~/my/custom/path " deletes a session based on the provided path. :SessionPurgeOrphaned " removes all orphaned sessions with no working directory left. -:Autosession search -:Autosession delete +:Autosession search " open a vim.ui.select picker to choose a session to load. +:Autosession delete " open a vim.ui.select picker to choose a session to delete. ``` You can use the `Autosession {delete|search}` command to open a picker using `vim.ui.select` this will allow you to either delete or search for a session to restore. @@ -218,14 +220,14 @@ There's also Telescope support, see the [Session Lens](#-session-lens) section b Command hooks exist in the format: {hook_name} -- {pre_save}: executes _before_ a session is saved -- {save_extra}: executes _after_ a session is saved, return string will save to `*x.vim`, reference `:help mks` -- {post_save}: executes _after_ a session is saved -- {pre_restore}: executes _before_ a session is restored -- {post_restore}: executes _after_ a session is restored -- {pre_delete}: executes _before_ a session is deleted -- {post_delete}: executes _after_ a session is deleted -- {no_restore}: executes _at_ `VimEnter` _when_ no session is restored +- `{pre_save}`: executes _before_ a session is saved +- `{save_extra}`: executes _after_ a session is saved, return string will save to `*x.vim`, reference `:help mks` +- `{post_save}`: executes _after_ a session is saved +- `{pre_restore}`: executes _before_ a session is restored +- `{post_restore}`: executes _after_ a session is restored +- `{pre_delete}`: executes _before_ a session is deleted +- `{post_delete}`: executes _after_ a session is deleted +- `{no_restore}`: executes _at_ `VimEnter` _when_ no session is restored Hooks are configured by setting @@ -290,7 +292,7 @@ use this to only create sessions for git projects: ## 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: +By default, when `nvim` is run with a single directory argument, AutoSession will try to restore the session for that directory. If `nvim` is run with multiple directories or any file arguments, AutoSession 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 @@ -303,7 +305,7 @@ For `args_allow_single_directory`, if you frequently use `netrw` to look at dire 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: +If `args_allow_files_auto_save` is true, AutoSession 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. AutoSession 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 { @@ -379,7 +381,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 +Session Lens has been merged into AutoSession 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: ```lua @@ -419,12 +421,13 @@ vim.keymap.set("n", "", require("auto-session.session-lens").search_session You can also use `:Telescope session-lens` to launch the session picker. The following shortcuts are available when the session-lens picker is open -* `` restores the previously opened session. This can give you a nice flow if you're constantly switching between two projects. -* `` will delete the currently highlighted session. This makes it easy to keep the session list clean. + +- `` restores the previously opened session. This can give you a nice flow if you're constantly switching between two projects. +- `` will delete the currently highlighted session. This makes it easy to keep the session list clean. NOTE: If you previously installed `rmagatti/session-lens`, you should remove it from your config as it is no longer necessary. -Auto Session provides its own `:Autosession search` and `:Autosession delete` commands, but session-lens is a more complete version of those commands that is specifically built to be used with `telescope.nvim`. These commands make use of `vim.ui.select` which can itself be implemented by other plugins other than telescope. +AutoSession provides its own `:Autosession search` and `:Autosession delete` commands, but session-lens is a more complete version of those commands that is specifically built to be used with `telescope.nvim`. These commands make use of `vim.ui.select` which can itself be implemented by other plugins other than telescope. ### Preview @@ -432,7 +435,7 @@ Auto Session provides its own `:Autosession search` and `:Autosession delete` co ### Statusline -One can show the current session name in the statusline by using an auto-session helper function. +One can show the current session name in the statusline by using an AutoSession helper function. Lualine example config and how it looks @@ -454,5 +457,5 @@ Neovim > 0.7 Tested with: ``` -NVIM v0.7.0 +NVIM v0.7.0 - NVIM 0.10.0 ``` diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index 5440601..939a3a8 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -618,7 +618,8 @@ 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 +---@private +---- Handler for when a session is picked from the UI, either via Telescope or via AutoSession.select_session function AutoSession.restore_selected_session(session_filename) Lib.logger.debug("[restore_selected_session]: filename: ", session_filename) From 54c9ec72f18241611b60a7aac871536d8e0b84fa Mon Sep 17 00:00:00 2001 From: cameronr Date: Thu, 18 Jul 2024 02:28:28 +0000 Subject: [PATCH 18/18] chore(docs): auto-generate vimdoc --- doc/auto-session.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/auto-session.txt b/doc/auto-session.txt index b98f1ce..42738f9 100644 --- a/doc/auto-session.txt +++ b/doc/auto-session.txt @@ -120,9 +120,6 @@ AutoSession.get_session_files() *AutoSession.get_session_files* (PickerItem[]) -AutoSession.restore_selected_session() *AutoSession.restore_selected_session* - - *AutoSession.SaveSession* AutoSession.SaveSession({sessions_dir?}, {auto})