diff --git a/README.md b/README.md index d3b7ad4..a4ffff4 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ Here are the default settings: -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode delete_session = { "i", "" }, alternate_session = { "i", "" }, + copy_session = { "i", "" }, }, session_control = { diff --git a/lua/auto-session/config.lua b/lua/auto-session/config.lua index 3973609..604ee84 100644 --- a/lua/auto-session/config.lua +++ b/lua/auto-session/config.lua @@ -57,6 +57,7 @@ local M = {} ---@class SessionLensMappings ---@field delete_session table mode and key for deleting a session from the picker ---@field alternate_session table mode and key for swapping to alertnate session from the picker +---@field copy_session table mode and key for copying a session from the picker ---@type AutoSession.Config local defaults = { @@ -94,6 +95,7 @@ local defaults = { -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode delete_session = { "i", "" }, alternate_session = { "i", "" }, + copy_session = { "i", "" }, }, ---@type SessionControl diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index a792235..b7402be 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -321,7 +321,7 @@ end ---@private ---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) (Defaults to true) +---@param with_trailing_separator? boolean whether to incude the trailing separator. A few places (e.g. telescope picker) don't expect a trailing separator (Defaults to true) ---@return string function AutoSession.get_root_dir(with_trailing_separator) if with_trailing_separator == nil then diff --git a/lua/auto-session/session-lens/actions.lua b/lua/auto-session/session-lens/actions.lua index cb3094b..6043887 100644 --- a/lua/auto-session/session-lens/actions.lua +++ b/lua/auto-session/session-lens/actions.lua @@ -1,6 +1,7 @@ local AutoSession = require "auto-session" local Config = require "auto-session.config" local Lib = require "auto-session.lib" +local transform_mod = require("telescope.actions.mt").transform_mod local M = {} @@ -92,4 +93,16 @@ M.alternate_session = function(prompt_bufnr) source_session(session_name, prompt_bufnr) end -return M +---@private +---Copy session action +---Ask user for the new name and then copy the session to that name +M.copy_session = function(_) + local action_state = require "telescope.actions.state" + local selection = action_state.get_selected_entry() + + local new_name = vim.fn.input("New session name: ", selection.display) + local content = vim.fn.readfile(selection.path) + vim.fn.writefile(content, AutoSession.get_root_dir() .. Lib.escape_session_name(new_name) .. ".vim") +end + +return transform_mod(M) diff --git a/lua/auto-session/session-lens/init.lua b/lua/auto-session/session-lens/init.lua index 3e69ace..ce169f4 100644 --- a/lua/auto-session/session-lens/init.lua +++ b/lua/auto-session/session-lens/init.lua @@ -69,8 +69,10 @@ end ---Triggers the customized telescope picker for switching sessions ---@param custom_opts any SessionLens.search_session = function(custom_opts) - local themes = require "telescope.themes" + local telescope_themes = require "telescope.themes" local telescope_actions = require "telescope.actions" + local telescope_finders = require "telescope.finders" + local telescope_conf = require("telescope.config").values custom_opts = (vim.tbl_isempty(custom_opts or {}) or custom_opts == nil) and Config.session_lens or custom_opts @@ -88,7 +90,7 @@ SessionLens.search_session = function(custom_opts) custom_opts.shorten_path = nil end - local theme_opts = themes.get_dropdown(custom_opts.theme_conf) + local theme_opts = telescope_themes.get_dropdown(custom_opts.theme_conf) -- Use default previewer config by setting the value to nil if some sets previewer to true in the custom config. -- Passing in the boolean value errors out in the telescope code with the picker trying to index a boolean instead of a table. @@ -97,45 +99,50 @@ SessionLens.search_session = function(custom_opts) custom_opts["previewer"] = nil end - local opts = { - prompt_title = "Sessions", + local finder_opts = { entry_maker = SessionLens.make_telescope_callback(custom_opts), cwd = session_root_dir, - attach_mappings = function(_, map) + } + + local find_command + if 1 == vim.fn.executable "rg" then + find_command = { "rg", "--files", "--color", "never", "--sortr", "modified" } + elseif 1 == vim.fn.executable "ls" then + find_command = { "ls", "-t" } + elseif 1 == vim.fn.executable "cmd" and vim.fn.has "win32" == 1 then + find_command = { "cmd", "/C", "dir", "/b", "/o-d" } + end + + local opts = { + prompt_title = "Sessions", + attach_mappings = function(prompt_bufnr, map) telescope_actions.select_default:replace(Actions.source_session) local mappings = Config.session_lens.mappings if mappings then map(mappings.delete_session[1], mappings.delete_session[2], Actions.delete_session) map(mappings.alternate_session[1], mappings.alternate_session[2], Actions.alternate_session) + + Actions.copy_session:enhance { + post = function() + local action_state = require "telescope.actions.state" + local picker = action_state.get_current_picker(prompt_bufnr) + picker:refresh(telescope_finders.new_oneshot_job(find_command, finder_opts), { reset_prompt = true }) + end, + } + + map(mappings.copy_session[1], mappings.copy_session[2], Actions.copy_session) end return true end, } opts = vim.tbl_deep_extend("force", opts, theme_opts, custom_opts or {}) - local find_command = (function() - if opts.find_command then - if type(opts.find_command) == "function" then - return opts.find_command(opts) - end - return opts.find_command - elseif 1 == vim.fn.executable "rg" then - return { "rg", "--files", "--color", "never", "--sortr", "modified" } - elseif 1 == vim.fn.executable "ls" then - return { "ls", "-t" } - elseif 1 == vim.fn.executable "cmd" and vim.fn.has "win32" == 1 then - return { "cmd", "/C", "dir", "/b", "/o-d" } - end - end)() - - 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), + finder = telescope_finders.new_oneshot_job(find_command, finder_opts), + previewer = telescope_conf.file_previewer(opts), + sorter = telescope_conf.file_sorter(opts), }) :find() end diff --git a/tests/mini-tests/test_ui.lua b/tests/mini-tests/test_ui.lua index 4fe69a4..622a082 100644 --- a/tests/mini-tests/test_ui.lua +++ b/tests/mini-tests/test_ui.lua @@ -63,6 +63,25 @@ T["session lens"]["can load a session"] = function() expect.equality(1, child.fn.bufexists(TL.other_file)) end +T["session lens"]["can copy a session"] = function() + expect.equality(0, child.fn.bufexists(TL.test_file)) + child.cmd "SessionSearch" + -- give the UI time to come up + local session_name = "project_x" + vim.loop.sleep(250) + child.type_keys(session_name) + vim.loop.sleep(20) + child.type_keys "" + vim.loop.sleep(20) + + -- will append to session_name + local copy_name = "copy" + child.type_keys(copy_name .. "") + -- give the session time to load + vim.loop.sleep(500) + expect.equality(1, vim.fn.filereadable(TL.makeSessionPath(session_name .. copy_name))) +end + T["session lens"]["can delete a session"] = function() expect.equality(1, vim.fn.filereadable(TL.named_session_path)) child.cmd "SessionSearch"