Skip to content

Commit

Permalink
Merge pull request #400 from cameronr/main
Browse files Browse the repository at this point in the history
feat: support for custom Snacks picker
  • Loading branch information
cameronr authored Jan 27, 2025
2 parents 021b64e + cc4ab06 commit 16016db
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 46 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ AutoSession exposes the following commands that can be used or mapped to any key
:SessionPurgeOrphaned " removes all orphaned sessions with no working directory left.
:SessionSearch " open a session picker, uses Telescope if installed, vim.ui.select otherwise
:SessionSearch " open a session picker, uses Telescope or Snacks if installed, vim.ui.select otherwise
: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.
Expand All @@ -153,7 +153,7 @@ If you create a manually named session via `SessionSave my_session` or you resto

## 🔭 Session Lens

You can use Telescope to see, load, and delete your sessions. It's enabled by default if you have Telescope, but here's the Lazy config that shows the configuration options:
You can use Telescope or [snacks.nvim](https://github.com/folke/snacks.nvim) to see, load, and delete your sessions. It's enabled by default if you have Telescope, but here's the Lazy config that shows the configuration options:

```lua

Expand Down Expand Up @@ -198,7 +198,7 @@ You can use Telescope to see, load, and delete your sessions. It's enabled by de
```

You can use `:SessionSearch` to launch the session picker. If `load_on_setup = false`, `:SessionSearch` will initialize the Telescope extension when called. You can also use
`:Telescope session-lens` to launch the session picker but only if `load_on_setup = true` or you've previously called `SessionSearch`.
`:Telescope session-lens` to launch the session picker but only if `load_on_setup = true` or you've previously called `SessionSearch`. If you don't have Telescope installed but do have Snacks installed (and the picker enabled), AutoSession will use Snacks as the session picker. No change in configuration is needed (e.g. it will use the same keymap config).

The following default keymaps are available when the session-lens picker is open:

Expand Down
2 changes: 1 addition & 1 deletion doc/auto-session.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ This plugin provides the following commands:

`:SessionPurgeOrphaned` - removes all orphaned sessions with no working directory left.

`:SessionSearch` - open a session picker, uses Telescope if installed, vim.ui.select otherwise
`:SessionSearch` - open a session picker, uses Telescope or Snacks if installed, vim.ui.select otherwise

==============================================================================
API *auto-session.api*
Expand Down
82 changes: 80 additions & 2 deletions lua/auto-session/autocmds.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ local SessionLens -- will be initialized later
---
--- `:SessionPurgeOrphaned` - removes all orphaned sessions with no working directory left.
---
--- `:SessionSearch` - open a session picker, uses Telescope if installed, vim.ui.select otherwise
--- `:SessionSearch` - open a session picker, uses Telescope or Snacks if installed, vim.ui.select otherwise
---@brief ]]

local M = {}
Expand Down Expand Up @@ -122,6 +122,79 @@ local function setup_session_lens()
return true
end

local function has_snacks()
local success, snacks_picker_enabled = pcall(function()
---@diagnostic disable-next-line: undefined-field
return Snacks.config.picker.enabled
end)
return success and snacks_picker_enabled
end

local function snacks_session_search()
local mappings = Config.session_lens.mappings or {}
Snacks.picker.pick {
title = "Sessions",
finder = function()
return Lib.get_session_list(M.AutoSession.get_root_dir())
end,
format = "text",
transform = function(item)
item.text = item.display_name
end,
layout = {
preview = Config.session_lens.theme_conf.preview,
},
win = {
input = {
keys = {
["dd"] = "session_delete",
[mappings.delete_session[2]] = { "session_delete", mode = mappings.delete_session[1] },
[mappings.alternate_session[2]] = { "session_alternate", mode = mappings.alternate_session[1] },
[mappings.copy_session[2]] = { "session_copy", mode = mappings.copy_session[1] },
},
},
list = { keys = { ["dd"] = "session_delete" } },
},
actions = {
confirm = function(picker, item)
picker:close()
vim.schedule(function()
M.AutoSession.autosave_and_restore(item.session_name)
end)
end,
session_delete = function(picker, item)
vim.schedule(function()
M.AutoSession.DeleteSessionFile(item.path, item.display_name)
picker:find() -- refresh picker
end)
end,
session_alternate = function(picker, _)
vim.schedule(function()
local altername_session_name = Lib.get_alternate_session_name(Config.session_lens.session_control)
if not altername_session_name then
return
end
picker:close()
vim.defer_fn(function()
M.AutoSession.autosave_and_restore(altername_session_name)
end, 50)
end)
end,
session_copy = function(picker, item)
vim.schedule(function()
local new_name = vim.fn.input("New session name: ", item.text)
if not new_name or new_name == "" or new_name == item.text then
return
end
local content = vim.fn.readfile(item.path)
vim.fn.writefile(content, M.AutoSession.get_root_dir() .. Lib.escape_session_name(new_name) .. ".vim")
picker:find() -- refresh picker
end)
end,
},
}
end

local function setup_dirchanged_autocmds(AutoSession)
if not Config.cwd_change_handling then
Lib.logger.debug "cwd_change_handling is disabled, skipping setting DirChangedPre and DirChanged autocmd handling"
Expand Down Expand Up @@ -256,12 +329,17 @@ function M.setup_autocmds(AutoSession)
})

vim.api.nvim_create_user_command("SessionSearch", function()
-- If Telescope is installed, use that otherwise use vim.ui.select
-- Use telescope if installed, otherwise snacks, otherwise vim.ui.select
if setup_session_lens() and SessionLens then
vim.cmd "Telescope session-lens"
return
end

if has_snacks() then
snacks_session_search()
return
end

handle_autosession_command { args = "search" }
end, {
desc = "Open a session picker",
Expand Down
34 changes: 34 additions & 0 deletions lua/auto-session/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -681,4 +681,38 @@ function Lib.get_session_list(sessions_dir)
end, entries)
end

---Get the name of the altnernate session stored in the session control file
---@return string|nil name of the alternate session, suitable for calls to LoadSession
function Lib.get_alternate_session_name(session_control_conf)
if not session_control_conf then
Lib.logger.error "No session_control in config!"
return nil
end

local filepath = vim.fn.expand(session_control_conf.control_dir) .. session_control_conf.control_filename

if vim.fn.filereadable(filepath) == 0 then
return nil
end

local json = Lib.load_session_control_file(filepath)

local sessions = {
current = json.current,
alternate = json.alternate,
}

Lib.logger.debug("get_alternate_session_name", { sessions = sessions, json = json })

if sessions.current == sessions.alternate then
Lib.logger.info "Current session is the same as alternate, returning nil"
return nil
end
local file_name = vim.fn.fnamemodify(sessions.alternate, ":t")
if Lib.is_legacy_file_name(file_name) then
return (Lib.legacy_unescape_session_name(file_name):gsub("%.vim$", ""))
end
return Lib.escaped_session_name_to_session_name(file_name)
end

return Lib
43 changes: 3 additions & 40 deletions lua/auto-session/session-lens/actions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,6 @@ local transform_mod = require("telescope.actions.mt").transform_mod
local M = {}

---@private
local function get_alternate_session()
---@diagnostic disable-next-line: undefined-field
local session_control_conf = Config.session_lens.session_control

if not session_control_conf then
Lib.logger.error "No session_control in config!"
return
end

local filepath = vim.fn.expand(session_control_conf.control_dir) .. session_control_conf.control_filename

if vim.fn.filereadable(filepath) == 1 then
local json = Lib.load_session_control_file(filepath)

local sessions = {
current = json.current,
alternate = json.alternate,
}

Lib.logger.debug("get_alternate_session", { sessions = sessions, json = json })

if sessions.current ~= sessions.alternate then
return sessions.alternate
end

Lib.logger.info "Current session is the same as alternate!"
end
end

local function source_session(session_name, prompt_bufnr)
if prompt_bufnr then
Expand Down Expand Up @@ -74,23 +46,14 @@ end

---@private
M.alternate_session = function(prompt_bufnr)
local alternate_session = get_alternate_session()

if not alternate_session then
local alternate_session_name = Lib.get_alternate_session_name(Config.session_lens.session_control)
if not alternate_session_name then
vim.notify "There is no alternate session"
-- Keep the picker open in case they want to select a session to load
return
end

local file_name = vim.fn.fnamemodify(alternate_session, ":t")
local session_name
if Lib.is_legacy_file_name(file_name) then
session_name = (Lib.legacy_unescape_session_name(file_name):gsub("%.vim$", ""))
else
session_name = Lib.escaped_session_name_to_session_name(file_name)
end

source_session(session_name, prompt_bufnr)
source_session(alternate_session_name, prompt_bufnr)
end

---@private
Expand Down

0 comments on commit 16016db

Please sign in to comment.