diff --git a/.github/workflows/docgen.yml b/.github/workflows/docgen.yml index dcdb6a9..64981bf 100644 --- a/.github/workflows/docgen.yml +++ b/.github/workflows/docgen.yml @@ -15,7 +15,7 @@ jobs: - name: Generating help run: | curl -Lq https://github.com/numToStr/lemmy-help/releases/latest/download/lemmy-help-x86_64-unknown-linux-gnu.tar.gz | tar xz - ./lemmy-help ./lua/auto-session/init.lua ./lua/auto-session/autocmds.lua ./lua/auto-session/session-lens/init.lua ./lua/auto-session/session-lens/actions.lua > doc/${{env.PLUGIN_NAME}}.txt + ./lemmy-help ./lua/auto-session/config.lua ./lua/auto-session/autocmds.lua ./lua/auto-session/init.lua ./lua/auto-session/session-lens/init.lua ./lua/auto-session/session-lens/actions.lua > doc/${{env.PLUGIN_NAME}}.txt - name: Commit uses: stefanzweifel/git-auto-commit-action@v5 diff --git a/.gitignore b/.gitignore index 77ddff8..50e4407 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ doc/tags tests/test_sessions tests/custom_sessions tests/test_git +tests/symlink-test diff --git a/README.md b/README.md index 72c7bc0..61aebd5 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,12 @@ AutoSession takes advantage of Neovim's existing session management capabilities dependencies = { 'nvim-telescope/telescope.nvim', -- Only needed if you want to use session lens }, + + ---enables autocomplete for opts + ---@module "auto-session" + ---@type AutoSession.Config opts = { - auto_session_suppress_dirs = { '~/', '~/Projects', '~/Downloads', '/' }, + suppressed_dirs = { '~/', '~/Projects', '~/Downloads', '/' }, -- log_level = 'debug', } } @@ -31,7 +35,7 @@ use { 'rmagatti/auto-session', config = function() require("auto-session").setup { - auto_session_suppress_dirs = { "~/", "~/Projects", "~/Downloads", "/"}, + suppressed_dirs = { "~/", "~/Projects", "~/Downloads", "/"}, } end } @@ -51,73 +55,57 @@ Manually saving a session can still be done by calling `:SessionSave`. # โš™๏ธ Configuration -### Configuration - -You can set the auto_session root dir that will be used for auto session saving and restoring. - -```viml -let g:auto_session_root_dir = path/to/my/custom/dir - -" or use Lua -lua << EOF -local opts = { - auto_session_enabled = true, - auto_session_root_dir = vim.fn.stdpath('data') .. "/sessions/", - auto_save_enabled = true, - auto_restore_enabled = true, - auto_session_suppress_dirs = nil, - auto_session_allowed_dirs = nil, - auto_session_create_enabled = true, - auto_session_enable_last_session = false, - auto_session_use_git_branch = false, - auto_restore_lazy_delay_enabled = true, - log_level = 'error', -} - -require('auto-session').setup(opts) -EOF -``` - -### Options - -| Config | Options | Default | Description | -| -------------------------------- | ------------------------ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| auto_session_enabled | false, true | true | Enables/disables the plugin's auto save _and_ restore features | -| auto_session_root_dir | "/some/path/you/want" | vim.fn.stdpath('data').."/sessions/" | Changes the root dir for sessions | -| auto_save_enabled | false, true | true | Enables/disables auto saving | -| auto_restore_enabled | false, true | true | Enables/disables auto restoring | -| auto_session_suppress_dirs | ["list", "of paths"] | nil | Suppress session create/restore if in one of the list of dirs | -| auto_session_allowed_dirs | ["list", "of paths"] | nil | Allow session create/restore if in one of the list of dirs | -| auto_session_create_enabled | false, true, function | true | Enables/disables the plugin's session auto creation. Can also be a Lua function that returns true if a session should be created and false otherwise | -| auto_session_enable_last_session | false, true | false | On startup, loads the last loaded session if session for cwd does not exist | -| auto_session_use_git_branch | false, true | false | Use the git branch to differentiate the session name | -| auto_restore_lazy_delay_enabled | false, true | true | Enables/disables delaying auto-restore if Lazy.nvim is used | -| log_level | 'debug', 'info', 'error' | 'error' | Sets the log level of the plugin. Set to info for more feedback on what's happening | - -#### Notes - -`auto_session_suppress_dirs` and `auto_session_allowed_dirs` support base paths with `*` wildcard (e.g.: `/my/base/path/*`) - -### Lua Only Options +Here are the default settings: ```lua -require("auto-session").setup { - bypass_session_save_file_types = nil, -- table: Bypass auto save when only buffer open is one of these file types, useful to ignore dashboards - close_unsupported_windows = true, -- boolean: Close windows that aren't backed by normal file - cwd_change_handling = { -- table: Config for handling the DirChangePre and DirChanged autocmds, can be set to nil to disable altogether - restore_upcoming_session = false, -- boolean: restore session for upcoming cwd on cwd change - pre_cwd_changed_hook = nil, -- function: This is called after auto_session code runs for the `DirChangedPre` autocmd - post_cwd_changed_hook = nil, -- function: This is called after auto_session code runs for the `DirChanged` autocmd +{ + enabled = true, -- Enables/disables auto creating, saving and restoring + root_dir = vim.fn.stdpath "data" .. "/sessions/", -- Root dir where sessions will be stored + auto_save = true, -- Enables/disables auto saving session on exit + auto_restore = true, -- Enables/disables auto restoring session on start + auto_create = true, -- Enables/disables auto creating new session files. Can take a function that should return true/false if a new session file should be created or not + suppressed_dirs = nil, -- Suppress session restore/create in certain directories + alloweded_dirs = nil, -- Allow session restore/create in certain directories + auto_restore_last_session = false, -- On startup, loads the last saved session if session for cwd does not exist + use_git_branch = false, -- Include git branch name in session name + lazy_support = true, -- Automatically detect if Lazy.nvim is being used and wait until Lazy is done to make sure session is restored correctly. Does nothing if Lazy isn't being used. Can be disabled if a problem is suspected or for debugging + bypass_save_filetypes = nil, -- List of file types to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards + close_unsupported_windows = true, -- Close windows that aren't backed by normal file before autosaving a session + args_allow_single_directory = true, -- Follow normal sesion save/load logic if launched with a single directory as the only argument + args_allow_files_auto_save = false, -- Allow saving a session even when launched with a file argument (or multiple files/dirs). It does not load any existing session first. While you can just set this to true, you probably want to set it to a function that decides when to save a session when launched with file args. See documentation for more detail + continue_restore_on_error = true, -- Keep loading the session even if there's an error + cwd_change_handling = false, -- Follow cwd changes, saving a session before change and restoring after + log_level = "error", -- Sets the log level of the plugin (debug, info, warn, error). + + session_lens = { + load_on_setup = true, -- Initialize on startup (requires Telescope) + theme_conf = { -- Pass through for Telescope theme options + -- layout_config = { -- As one example, can change width/height of picker + -- width = 0.8, -- percent of window + -- height = 0.5, + -- }, + }, + previewer = false, -- File preview for session picker + + mappings = { + -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode + delete_session = { "i", "" }, + alternate_session = { "i", "" }, + }, + + session_control = { + control_dir = vim.fn.stdpath "data" .. "/auto_session/", -- Auto session control dir, for control files, like alternating between two sessions with session-lens + control_filename = "session_control.json", -- File name of the session control file + }, }, - args_allow_single_directory = true, -- boolean Follow normal sesion save/load logic if launched with a single directory as the only argument - args_allow_files_auto_save = false, -- 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 - silent_restore = true, -- Suppress extraneous messages and source the whole session, even if there's an error. Set to false to get the line number a restore error } ``` +NOTE: Older configuration names are still currently supported and will be automatically translated to the names above. If you want to update your config to the new names, `:checkhealth auto-session` will show you your config using the new names. + #### Recommended sessionoptions config -For a better experience with the plugin overall using this config for `sessionoptions` is recommended. +For a better experience with the plugin overall using this config for `sessionoptions` is recommended: **Lua** @@ -133,78 +121,19 @@ set sessionoptions+=winpos,terminal,folds :warning: if you use [packer.nvim](https://github.com/wbthomason/packer.nvim)'s lazy loading feature, and you have the `options` value in your `sessionoptions` beware it might lead to weird behaviour with the lazy loading, especially around key-based lazy loading where keymaps are kept and thus the lazy loading mapping packer creates never gets set again. -### Current Working Directory - -AutoSession can track `cwd` changes! - -It's disabled by default, 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`/ -- DirChanged (after the cwd has changed): - - Restore session using new cwd - - Run the `post_cwd_changed_hook` - -Now when you 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. Here's the config for tracking cwd and a hook example: - -```lua -require('auto-session').setup({ - auto_session_suppress_dirs = { '~/', '~/Projects', '~/Downloads', '/' }, - - cwd_change_handling = { - restore_upcoming_session = true, -- Disabled by default, set to true to enable - pre_cwd_changed_hook = nil, -- already the default, no need to specify like this, only here as an example - post_cwd_changed_hook = function() -- example refreshing the lualine status line _after_ the cwd changes - --require("lualine").refresh() -- refresh lualine so the new session name is displayed in the status bar - end, - }, -}) -``` - -### Last Session - -This optional feature enables the keeping track and loading of the last session. -The last session is only loaded at startup if there isn't already a session for the current working directory. -This feature can come in handy when starting Neovim from a GUI for example. - -:warning: If the directory does not exist, default directory will be used and an error message will be printed. -:warning: This feature is still experimental and as of right now it interferes with the plugin's ability to auto create new sessions when opening Neovim in a new directory. - -```lua -require('auto-session').setup { - auto_session_enable_last_session = true, -} -``` - -A quick workaround for inability to auto create new sessions is to conditionally enable last session. - -```lua -require('auto-session').setup { - auto_session_enable_last_session = vim.loop.cwd() == vim.loop.os_homedir(), -} -``` - -Now last session will be restored only when Neovim is launched in the home directory, which is usually right after launching the terminal or Neovim GUI clients. - # ๐Ÿ“ข Commands AutoSession exposes the following commands that can be used or mapped to any keybindings for manually saving and restoring sessions. ```viml -:SessionSave " saves a session based on the `cwd` in `auto_session_root_dir` -:SessionSave my_session " saves a session called `my_session` in `auto_session_root_dir` +:SessionSave " saves a session based on the `cwd` in `root_dir` +:SessionSave my_session " saves a session called `my_session` in `root_dir` -:SessionRestore " restores a session based on the `cwd` from `auto_session_root_dir` -:SessionRestore my_session " restores `my_session` from `auto_session_root_dir` +:SessionRestore " restores a session based on the `cwd` from `root_dir` +:SessionRestore my_session " restores `my_session` from `root_dir` -:SessionDelete " deletes a session based on the `cwd` from `auto_session_root_dir` -:SessionDelete my_session " deletes `my_sesion` from `auto_session_root_dir` +:SessionDelete " deletes a session based on the `cwd` from `root_dir` +:SessionDelete my_session " deletes `my_sesion` from `root_dir` :SessionDisableAutoSave " disables autosave :SessionDisableAutoSave! " enables autosave (still does all checks in the config) @@ -218,204 +147,180 @@ AutoSession exposes the following commands that can be used or mapped to any key :Autosession delete " open a vim.ui.select picker to choose a session to delete. ``` -## ๐Ÿช Command Hooks - -#### Command hooks are a list of commands that get executed at different stages of the session management lifecycle. +# ๐Ÿ“– More Configuration Details -Command hooks exist in the format: {hook_name} +## ๐Ÿ”ญ Session Lens -- `{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 +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: -Hooks are configured by setting +```lua -```viml -let g:auto_session_{hook_name}_cmds = ["{hook_command1}", "{hook_command2}"] +{ + 'rmagatti/auto-session', + lazy = false, + dependencies = { + 'nvim-telescope/telescope.nvim', + }, + keys = { + -- Will use Telescope if installed or a vim.ui.select picker otherwise + { 'wr', 'SessionSearch', desc = 'Session search' }, + { 'ws', 'SessionSave', desc = 'Save session' }, + { 'wa', 'SessionToggleAutoSave', desc = 'Toggle autosave' }, + }, -" or use Lua -lua << EOF -require('auto-session').setup { - {hook_name}_cmds = {"{hook_command1}", "{hook_command2}"} - save_extra_cmds = { - function() - return [[echo "hello world"]] - end - } + ---enables autocomplete for opts + ---@module "auto-session" + ---@type AutoSession.Config + opts = { + -- โš ๏ธ This will only work if Telescope.nvim is installed + -- The following are already the default values, no need to provide them if these are already the settings you want. + session_lens = { + -- If load_on_setup is false, make sure you use `:SessionSearch` to open the picker as it will initialize everything first + load_on_setup = true, + previewer = false, + mappings = { + -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode + delete_session = { "i", "" }, + alternate_session = { "i", "" }, + }, + -- Can also set some Telescope picker options + theme_conf = { + border = true, + -- layout_config = { + -- width = 0.8, -- Can set width and height as percent of window + -- height = 0.5, + -- }, + }, + }, + } } -EOF ``` -`hook_command` is a valid command mode command. -e.g. to close NERDTree before saving the session. +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`. -```viml -let g:auto_session_pre_save_cmds = ["tabdo NERDTreeClose"] -``` +The following default keymaps are available when the session-lens picker is open: -Hooks can also be lua functions -For example to update the directory of the session in nvim-tree: +- `` loads the currently highlighted session. +- `` swaps to 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. -```lua -local function restore_nvim_tree() - local nvim_tree_api = require('nvim-tree.api') - nvim_tree_api.tree.open() - nvim_tree_api.tree.change_root(vim.fn.getcwd()) - nvim_tree_api.tree.reload() -end +NOTE: If you previously installed `rmagatti/session-lens`, you should remove it from your config as it is no longer necessary. -require('auto-session').setup { - post_restore_cmds = {"{vim_cmd_1}", restore_nvim_tree, "{vim_cmd_2}"} -} -``` +### Preview -## Conditionally creating a session + -`auto_session_create_enabled` can take a function that returns if a session should be created or not as part of auto saving. As one example, you could -use this to only create sessions for git projects: +## ๐Ÿ“ Allowed / Suppressed directories -```lua +There are two config options, `allowed_dirs` and `suppressed_dirs`, that control which directories AutoSession will auto-save a session for. If `allowed_dirs` is set, sessions will only be auto-saved in matching directories. If `suppressed_dirs` is set, then a session won't be auto-saved for a matching directory. If both are set, a session will only be auto-saved if it matches an allowed dir and does not match a suppressed dir. - config = function() - require('auto-session').setup({ - auto_save_enabled = true, - auto_restore_enabled = true, - - auto_session_create_enabled = function() - local cmd = 'git rev-parse --is-inside-work-tree' - return vim.fn.system(cmd) == 'true\n' - end, - }) - end +Both options are a table of directories, with support for globs: +```lua + alloweded_dirs = { '/some/dir/', '/projects/*' } + suppressed_dirs = { '/projects/secret' } ``` -## Argument Handling +With those options, sessions would only be auto-saved for `/some/dir` and any direct child of `/projects` (e.g. `/projects/myproject` but not `/projects/myproject/submodule`) except `/projects/secret` -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: +## ๐Ÿšถ Current Working Directory -```lua - args_allow_single_directory = true, -- boolean Follow normal sesion save/load logic if launched with a single directory as the only argument - args_allow_files_auto_save = false, -- 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 -``` +AutoSession can track `cwd` changes! -For `args_allow_single_directory`, if you frequently use `netrw` to look at directories, you might want to add it to `bypass_session_save_file_types` if you don't want to create a session for each directory you look at: +It's disabled by default, but when enabled it works as follows: -```lua - bypass_session_save_file_types = { 'netrw' } -``` +- 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 +- DirChanged (after the cwd has changed): + - Restore session using new cwd + - Run the `post_cwd_changed` hook -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: +Now when you 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. Here's the config for tracking cwd and a hook example: ```lua -return { - 'rmagatti/auto-session', - config = function() - require('auto-session').setup({ - auto_restore_enabled = true, - auto_save_enabled = true, - - args_allow_files_auto_save = function() - local supported = 0 - - local buffers = vim.api.nvim_list_bufs() - for _, buf in ipairs(buffers) do - -- Check if the buffer is valid and loaded - if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_is_loaded(buf) then - local path = vim.api.nvim_buf_get_name(buf) - if vim.fn.filereadable(path) ~= 0 then supported = supported + 1 end - end - end - - -- If we have more 2 or more supported buffers, save the session - return supported >= 2 - end, - }) - end, -} +require('auto-session').setup({ + suppressed_dirs = { '~/', '~/Projects', '~/Downloads', '/' }, -``` + cwd_change_handling = true -Another possibility is to only save the session if there are at least two windows with buffers backed by normal files: + pre_cwd_changed_cmds = { + "tabdo NERDTreeClose" -- Close NERDTree before saving session + } -```lua - args_allow_files_auto_save = function() - local supported = 0 - - local tabpages = vim.api.nvim_list_tabpages() - for _, tabpage in ipairs(tabpages) do - local windows = vim.api.nvim_tabpage_list_wins(tabpage) - for _, window in ipairs(windows) do - local buffer = vim.api.nvim_win_get_buf(window) - local file_name = vim.api.nvim_buf_get_name(buffer) - if vim.fn.filereadable(file_name) ~= 0 then supported = supported + 1 end - end - end - - -- If we have 2 or more windows with supported buffers, save the session - return supported >= 2 - end, + post_cwd_changed_cmds = { + function() + require("lualine").refresh() -- example refreshing the lualine status line _after_ the cwd changes + end + } +}) ``` -## ๐Ÿ”ญ Session Lens +## ๐Ÿ–ฅ๏ธ Dashboards -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: +If you use a dashboard, you probably don't want to try and save a session when just the dashboard is open. To avoid that, add your dashboard filetype to the bypass list as follows: ```lua +require('auto-session').setup({ + bypass_save_filetypes = { 'alpha', 'dashboard' } -- or whatever dashboard you use +}) -{ - 'rmagatti/auto-session', - lazy = false, - dependencies = { - 'nvim-telescope/telescope.nvim', - }, - keys = { - -- Will use Telescope if installed or a vim.ui.select picker otherwise - { 'wr', 'SessionSearch', desc = 'Session search' }, - { 'ws', 'SessionSave', desc = 'Save session' }, - { 'wa', 'SessionToggleAutoSave', desc = 'Toggle autosave' }, - }, - config = function() - require('auto-session').setup({ - -- โš ๏ธ This will only work if Telescope.nvim is installed - -- The following are already the default values, no need to provide them if these are already the settings you want. - session_lens = { - -- If load_on_setup is false, make sure you use `:SessionSearch` to open the picker as it will initialize everything first - load_on_setup = true, - theme_conf = { border = true }, - previewer = false, - mappings = { - -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode - delete_session = { "i", "" }, - alternate_session = { "i", "" }, - }, - }, - }) - end, -} ``` -You can use `:Telescope session-lens` to launch the session picker but if you set `load_on_setup = false`, you'll need to call `require("auto-session").setup_session_lens()` first. Or you can just use `:SessionSearch` and it'll make sure everything is initialized. +## ๐Ÿช Command Hooks -The following shortcuts are available when the session-lens picker is open +#### Command hooks are a list of commands that get executed at different stages of the session management lifecycle. -- `` loads the currently highlighted session. -- `` swaps to 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. +Command hooks exist in the format: {hook_name} -NOTE: If you previously installed `rmagatti/session-lens`, you should remove it from your config as it is no longer necessary. +- `{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_cwd_changed}`: executes _before_ a directory is changed (if `cwd_change_handling` is enabled) +- `{post_cwd_changed}`: executes _after_ a directory is changed (if `cwd_change_handling` is enabled) -### Preview +Each hook is a table of vim commands or lua functions (or a mix of both): - +```lua +require('auto-session').setup { + -- {hook_name}_cmds = {"{hook_command1}", "{hook_command2}"} + + pre_save_cmds = { + "tabdo NERDTreeClose" -- Close NERDTree before saving session + }, -## Statusline + post_restore_cmds = { + "someOtherVimCommand", + function() + -- Restore nvim-tree after a session is restored + local nvim_tree_api = require('nvim-tree.api') + nvim_tree_api.tree.open() + nvim_tree_api.tree.change_root(vim.fn.getcwd()) + nvim_tree_api.tree.reload() + end + }, + + save_extra_cmds = { + function() + return [[echo "hello world"]] + end + } +} +``` + +## โž– Statusline You can show the current session name in the statusline by using the function `current_session_name()`. With no arguments, it will return the full session name. For automatically created sessions that will be the path where the session was saved. If you only want the last directory in the path, you can call `current_session_name(true)`. @@ -438,18 +343,107 @@ require('lualine').setup{ Screen Shot 2021-10-30 at 3 58 57 PM -## Dashboards +## โฎ๏ธ Last Session -If you use a dashboard, you probably don't want to try and save a session when just the dashboard is open. To avoid that, add your dashboard filetype to the bypass list as follows: +This optional feature enables the keeping track and loading of the last session. +The last session is only loaded at startup if there isn't already a session for the current working directory. +This feature can come in handy when starting Neovim from a GUI for example. + +:warning: If the directory does not exist, default directory will be used and an error message will be printed. +:warning: This feature is still experimental and as of right now it interferes with the plugin's ability to auto create new sessions when opening Neovim in a new directory. + +```lua +require('auto-session').setup { + auto_restore_last_session = true, +} +``` + +A quick workaround for inability to auto create new sessions is to conditionally enable last session. + +```lua +require('auto-session').setup { + auto_restore_last_session = vim.loop.cwd() == vim.loop.os_homedir(), +} +``` + +Now last session will be restored only when Neovim is launched in the home directory, which is usually right after launching the terminal or Neovim GUI clients. + +## Conditionally creating a session + +`auto_create` doesn't just have to be a boolean, it can also take a function that returns if a session should be created or not as part of auto saving. As one example, you could use this to only create new session files for git projects: + +```lua + +require('auto-session').setup({ + auto_create = function() + local cmd = 'git rev-parse --is-inside-work-tree' + return vim.fn.system(cmd) == 'true\n' + end, +}) + +``` + +## ๐Ÿ—ƒ๏ธ Argument Handling + +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 + args_allow_files_auto_save = false, -- 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 +``` + +For `args_allow_single_directory`, if you frequently use `netrw` to look at directories, you might want to add it to `bypass_save_filetypes` if you don't want to create a session for each directory you look at: + +```lua + bypass_save_filetypes = { 'netrw' } +``` + +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 require('auto-session').setup({ - bypass_session_save_file_types = { 'alpha', 'dashboard' } -- or whatever dashboard you use + args_allow_files_auto_save = function() + local supported = 0 + + local buffers = vim.api.nvim_list_bufs() + for _, buf in ipairs(buffers) do + -- Check if the buffer is valid and loaded + if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_is_loaded(buf) then + local path = vim.api.nvim_buf_get_name(buf) + if vim.fn.filereadable(path) ~= 0 then supported = supported + 1 end + end + end + + -- If we have more 2 or more supported buffers, save the session + return supported >= 2 + end, }) +``` +Another possibility is to only save the session if there are at least two windows with buffers backed by normal files: + +```lua +require('auto-session').setup({ + args_allow_files_auto_save = function() + local supported = 0 + + local tabpages = vim.api.nvim_list_tabpages() + for _, tabpage in ipairs(tabpages) do + local windows = vim.api.nvim_tabpage_list_wins(tabpage) + for _, window in ipairs(windows) do + local buffer = vim.api.nvim_win_get_buf(window) + local file_name = vim.api.nvim_buf_get_name(buffer) + if vim.fn.filereadable(file_name) ~= 0 then supported = supported + 1 end + end + end + + -- If we have 2 or more windows with supported buffers, save the session + return supported >= 2 + end, +}) ``` -## Disabling the plugin +## ๐Ÿšซ Disabling the plugin You might run into issues with Firenvim or another plugin and want to disable `auto_session` altogether based on some condition. For this example, as to not try and save sessions for Firenvim, we disable the plugin if the `started_by_firenvim` variable is set. @@ -463,7 +457,7 @@ endif One can also disable the plugin by setting the `auto_session_enabled` option to false at startup. ```sh -nvim "+let g:auto_session_enabled = v:false" +nvim --cmd "let g:auto_session_enabled = v:false" ``` ## ๐Ÿšง Troubleshooting diff --git a/doc/auto-session.txt b/doc/auto-session.txt index 26dda7a..73a1ff8 100644 --- a/doc/auto-session.txt +++ b/doc/auto-session.txt @@ -1,67 +1,70 @@ -defaultConf *defaultConf* - table default config for auto session +============================================================================== +Table of Contents *toc* - Fields: ~ - {auto_session_enabled?} (boolean) Enables/disables auto saving and restoring - {auto_session_root_dir?} (string) root directory for session files, by default is `vim.fn.stdpath('data') .. '/sessions/'` - {auto_save_enabled?} (boolean) Enables/disables auto saving session on exit - {auto_restore_enabled?} (boolean) Enables/disables auto restoring session on start - {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_create_enabled?} (boolean|function) Enables/disables auto creating new sessions. Can take a function that should return true/false if a session should be created or not - {auto_session_enable_last_session?} (boolean) On startup, loads the last saved session if session for cwd does not exist - {auto_session_use_git_branch?} (boolean) Include git branch name in session name to differentiate between sessions for different git branches - {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 - {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 - - -luaOnlyConf *luaOnlyConf* - Lua Only Configs for Auto Session - - Fields: ~ - {cwd_change_handling?} (boolean|CwdChangeHandling) - {bypass_session_save_file_types?} (table) List of file types to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards - {close_unsupported_windows?} (boolean) Whether to close windows that aren't backed by a real file - {silent_restore?} (boolean) Suppress extraneous messages and source the whole session, even if there's an error. Set to false to get the line number of a restore 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 - {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 - {session_lens?} (session_lens_config) Session lens configuration options +Config ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท |auto-session.config| +Commands ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท |auto-session.commands| +API ยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท |auto-session.api| +============================================================================== +Config *auto-session.config* -CwdChangeHandling *CwdChangeHandling* - CWD Change Handling Config +AutoSession.Config *AutoSession.Config* Fields: ~ - {restore_upcoming_session} (boolean) {true} restore session for upcoming cwd on cwd change - {pre_cwd_changed_hook?} (boolean) {true} This is called after auto_session code runs for the DirChangedPre autocmd - {post_cwd_changed_hook?} (boolean) {true} This is called after auto_session code runs for the DirChanged autocmd - - -session_lens_config *session_lens_config* - Session Lens Config + {enabled?} (boolean) Enables/disables auto saving and restoring + {root_dir?} (string) root directory for session files, by default is `vim.fn.stdpath('data') .. '/sessions/'` + {auto_save?} (boolean) Enables/disables auto saving session on exit + {auto_restore?} (boolean) Enables/disables auto restoring session on start + {auto_create?} (boolean|function) Enables/disables auto creating new session files. Can take a function that should return true/false if a new session file should be created or not + {suppressed_dirs?} (table) Suppress auto session for directories + {allowed_dirs?} (table) Allow auto session for directories, if empty then all directories are allowed except for suppressed ones + {auto_restore_last_lession?} (boolean) On startup, loads the last saved session if session for cwd does not exist + {use_git_branch?} (boolean) Include git branch name in session name to differentiate between sessions for different git branches + {lazy_support?} (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 + {bypass_save_filetypes?} (table) List of file types to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards + {close_unsupported_windows?} (boolean) Whether to close windows that aren't backed by a real file + {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 + {continue_restore_on_error?} (boolean) Keep loading the session even if there's an error. Set to false to get the line number of an error when loading a session + {log_level?} (string|integer) "debug", "info", "warn", "error" or vim.log.levels.DEBUG, vim.log.levels.INFO, vim.log.levels.WARN, vim.log.levels.ERROR + {cwd_change_handling?} (boolean) Follow cwd changes, saving a session before change and restoring after + {session_lens?} (SessionLens) Session lens configuration options + {pre_save_cmds?} (table) executes before a session is saved + + Hooks + {save_extra_cmds?} (table) executes before a session is saved + {post_save_cmds?} (table) executes after a session is saved + {pre_restore_cmds?} (table) executes before a session is restored + {post_restore_cmds?} (table) executes after a session is restored + {pre_delete_cmds?} (table) executes before a session is deleted + {post_delete_cmds?} (table) executes after a session is deleted + {no_restore_cmds?} (table) executes at VimEnter when no session is restored + {pre_cwd_changed_cmds?} (table) executes before cwd is changed if cwd_change_handling is true + {post_cwd_changed_cmds?} (table) executes after cwd is changed if cwd_change_handling is true + + +SessionLens *SessionLens* + Sessien Lens Cenfig Fields: ~ - {load_on_setup?} (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) Deprecated, if you're using this please report your usage on github - {previewer?} (boolean) Whether to show a preview of the session file (not very useful to most people) - {session_control?} (session_control) - {mappings?} (session_lens_mapping) + {load_on_setup?} (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) Telescope theme options + {previewer?} (boolean) Whether to show a preview of the session file (not very useful to most people) + {session_control?} (SessionControl) + {mappings?} (SessionLensMappings) -session_control *session_control* - Session Control Config +SessionControl *SessionControl* Fields: ~ {control_dir} (string) {control_filename} (string) -session_lens_mapping *session_lens_mapping* +SessionLensMappings *SessionLensMappings* Session Lens Mapping Fields: ~ @@ -69,11 +72,36 @@ session_lens_mapping *session_lens_mapping* {alternate_session} (table) mode and key for swapping to alertnate session from the picker +============================================================================== +Commands *auto-session.commands* + +This plugin provides the following commands: + + `:SessionSave` - saves a session based on the `cwd` in `root_dir` + `:SessionSave my_session` - saves a session called `my_session` in `root_dir` + + `:SessionRestore` - restores a session based on the `cwd` from `root_dir` + `:SessionRestore my_session` - restores `my_session` from `root_dir` + + `:SessionDelete` - deletes a session based on the `cwd` from `root_dir` + `:SessionDelete my_session` - deletes `my_sesion` from `root_dir` + + `:SessionDisableAutoSave` - disables autosave + `:SessionDisableAutoSave!` - enables autosave (still does all checks in the config) + `:SessionToggleAutoSave` - toggles autosave + + `:SessionPurgeOrphaned` - removes all orphaned sessions with no working directory left. + + `:SessionSearch` - open a session picker, uses Telescope if installed, vim.ui.select otherwise + +============================================================================== +API *auto-session.api* + AutoSession.setup({config}) *AutoSession.setup* Setup function for AutoSession Parameters: ~ - {config} (defaultConf|nil) Config for auto session + {config} (AutoSession.Config|nil) Config for auto session AutoSession.session_exists_for_cwd() *AutoSession.session_exists_for_cwd* @@ -104,10 +132,6 @@ AutoSession.AutoRestoreSession({session_name?}) (boolean) returns whether restoring the session was successful or not. -AutoSession.PurgeOrphanedSessions() *AutoSession.PurgeOrphanedSessions* - Deletes sessions where the original directory no longer exists - - *AutoSession.SaveSession* AutoSession.SaveSession({session_name?}, {show_message?}) Saves a session to the dir specified in the config. If no optional @@ -209,16 +233,4 @@ AutoSession.DisableAutoSave({enable?}) *AutoSession.DisableAutoSave* (boolean) autosaving is enabled or not -SessionLens.setup() *SessionLens.setup* - - - *SessionLens.search_session* -SessionLens.search_session({custom_opts}) - Search session - Triggers the customized telescope picker for switching sessions - - Parameters: ~ - {custom_opts} (any) - - vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/lua/auto-session/autocmds.lua b/lua/auto-session/autocmds.lua index 327c0a2..80f22b2 100644 --- a/lua/auto-session/autocmds.lua +++ b/lua/auto-session/autocmds.lua @@ -1,18 +1,158 @@ local Lib = require "auto-session.lib" +local Config = require "auto-session.config" +local SessionLens -- will be initialized later + +---@mod auto-session.commands Commands +---@brief [[ +---This plugin provides the following commands: +--- +--- `:SessionSave` - saves a session based on the `cwd` in `root_dir` +--- `:SessionSave my_session` - saves a session called `my_session` in `root_dir` +--- +--- `:SessionRestore` - restores a session based on the `cwd` from `root_dir` +--- `:SessionRestore my_session` - restores `my_session` from `root_dir` +--- +--- `:SessionDelete` - deletes a session based on the `cwd` from `root_dir` +--- `:SessionDelete my_session` - deletes `my_sesion` from `root_dir` +--- +--- `:SessionDisableAutoSave` - disables autosave +--- `:SessionDisableAutoSave!` - enables autosave (still does all checks in the config) +--- `:SessionToggleAutoSave` - toggles autosave +--- +--- `:SessionPurgeOrphaned` - removes all orphaned sessions with no working directory left. +--- +--- `:SessionSearch` - open a session picker, uses Telescope if installed, vim.ui.select otherwise +---@brief ]] local M = {} +---Calls lib function for completeing session names with session dir +local function complete_session(ArgLead, CmdLine, CursorPos) + return Lib.complete_session_for_dir(M.AutoSession.get_root_dir(), ArgLead, CmdLine, CursorPos) +end + ---@private ----Setup autocmds for DirChangedPre and DirChanged ----@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 not config.cwd_change_handling.restore_upcoming_session then - Lib.logger.debug "cwd_change_handling is disabled, skipping setting DirChangedPre and DirChanged autocmd handling" +---@class PickerItem +---@field session_name string +---@field display_name string +---@field path string + +---@return PickerItem[] +local function get_session_files() + local files = {} + local sessions_dir = M.AutoSession.get_root_dir() + + if vim.fn.isdirectory(sessions_dir) == Lib._VIM_FALSE then + return files + end + + local entries = vim.fn.readdir(sessions_dir, function(item) + return Lib.is_session_file(sessions_dir .. item) + end) + + return vim.tbl_map(function(file_name) + -- sessions_dir is guaranteed to have a trailing separator so don't need to add another one here + local session_name + local display_name + if Lib.is_legacy_file_name(file_name) then + session_name = (Lib.legacy_unescape_session_name(file_name):gsub("%.vim$", "")) + display_name = session_name .. " (legacy)" + else + session_name = Lib.escaped_session_name_to_session_name(file_name) + display_name = Lib.get_session_display_name(file_name) + end + + return { + session_name = session_name, + display_name = display_name, + path = sessions_dir .. file_name, + } + end, entries) +end + +---@param files string[] +---@param prompt string +---@param callback fun(choice: PickerItem) +local function open_picker(files, prompt, callback) + vim.ui.select(files, { + prompt = prompt, + kind = "auto-session", + format_item = function(item) + return item.display_name + end, + }, function(choice) + if choice then + callback(choice) + end + end) +end + +---@param data table +local function handle_autosession_command(data) + local files = get_session_files() + if data.args:match "search" then + open_picker(files, "Select a session:", function(choice) + M.AutoSession.autosave_and_restore(choice.session_name) + end) + elseif data.args:match "delete" then + open_picker(files, "Delete a session:", function(choice) + M.AutoSession.DeleteSessionFile(choice.path, choice.display_name) + end) + end +end + +--- Deletes sessions where the original directory no longer exists +local function purge_orphaned_sessions() + local orphaned_sessions = {} + + for _, session in ipairs(get_session_files()) do + if + not Lib.is_named_session(session.session_name) and vim.fn.isdirectory(session.session_name) == Lib._VIM_FALSE + then + Lib.logger.debug("purge: " .. session.session_name) + table.insert(orphaned_sessions, session.session_name) + end + end + + if Lib.is_empty_table(orphaned_sessions) then + Lib.logger.info "Nothing to purge" return end - local conf = config.cwd_change_handling + for _, session_name in ipairs(orphaned_sessions) do + Lib.logger.info("Purging: ", session_name) + local escaped_session = Lib.escape_session_name(session_name) + local session_path = string.format("%s/%s.vim", M.AutoSession.get_root_dir(), escaped_session) + Lib.logger.debug("purging: " .. session_path) + vim.fn.delete(Lib.expand(session_path)) + end +end + +---@private +---Make sure session_lens is setup. Ok to call multiple times +local function setup_session_lens() + if SessionLens then + return true + end + + local has_telescope, telescope = pcall(require, "telescope") + + if not has_telescope then + Lib.logger.info "Telescope.nvim is not installed. Session Lens cannot be setup!" + return false + end + + SessionLens = require "auto-session.session-lens" + -- Register session-lens as an extension so :Telescope will complete on session-lens + telescope.load_extension "session-lens" + return true +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" + return + end vim.api.nvim_create_autocmd("DirChangedPre", { callback = function() @@ -41,56 +181,229 @@ M.setup_autocmds = function(config, AutoSession) end AutoSession.AutoSaveSession() + AutoSession.run_cmds "pre_cwd_changed" + end, + pattern = "global", + }) + + vim.api.nvim_create_autocmd("DirChanged", { + callback = function() + Lib.logger.debug "DirChanged" + Lib.logger.debug(" cwd: " .. vim.fn.getcwd()) + Lib.logger.debug(" changed window: " .. tostring(vim.v.event.changed_window)) + Lib.logger.debug(" scope: " .. vim.v.event.scope) - if type(conf.pre_cwd_changed_hook) == "function" then - conf.pre_cwd_changed_hook() + -- see above + if vim.v.event.changed_window then + return end + + if AutoSession.restore_in_progress or vim.g.SessionLoad then + -- NOTE: We don't call the cwd_changed_hook here (or in the other case below) + -- I think that's probably the right choice because I assume that event is mostly + -- for preparing sessions for save/restoring but we don't want to do that when we're + -- already restoring a session + Lib.logger.debug "DirChangedPre: restore_in_progress/vim.g.SessionLoad 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" + return + end + + local success = AutoSession.AutoRestoreSession() + + if not success then + Lib.logger.info("Could not load session for: " .. vim.fn.getcwd()) + -- Don't return, still dispatch the hook below + end + + AutoSession.run_cmds "post_cwd_changed" end, pattern = "global", }) +end - if conf.restore_upcoming_session then - vim.api.nvim_create_autocmd("DirChanged", { - callback = function() - Lib.logger.debug "DirChanged" - Lib.logger.debug(" cwd: " .. vim.fn.getcwd()) - Lib.logger.debug(" changed window: " .. tostring(vim.v.event.changed_window)) - Lib.logger.debug(" scope: " .. vim.v.event.scope) +---@private +---Setup autocmds for DirChangedPre and DirChanged +---@param AutoSession table auto session instance +function M.setup_autocmds(AutoSession) + -- Check if the auto-session plugin has already been loaded to prevent loading it twice + if vim.g.loaded_auto_session ~= nil then + return + end - -- see above - if vim.v.event.changed_window then - return - end + -- Set here to avoid req + M.AutoSession = AutoSession + + -- Initialize variables + vim.g.in_pager_mode = false + + vim.api.nvim_create_user_command("SessionSave", function(args) + return AutoSession.SaveSession(args.args) + end, { + bang = true, + nargs = "?", + desc = "Save session using current working directory as the session name or an optional session name", + }) + + vim.api.nvim_create_user_command("SessionRestore", function(args) + return AutoSession.RestoreSession(args.args) + end, { + complete = complete_session, + bang = true, + nargs = "?", + desc = "Restore session using current working directory as the session name or an optional session name", + }) + + vim.api.nvim_create_user_command("SessionDelete", function(args) + return AutoSession.DeleteSession(args.args) + end, { + complete = complete_session, + bang = true, + nargs = "*", + desc = "Delete session using the current working directory as the session name or an optional session name", + }) - if AutoSession.restore_in_progress or vim.g.SessionLoad then - -- NOTE: We don't call the cwd_changed_hook here (or in the other case below) - -- I think that's probably the right choice because I assume that event is mostly - -- for preparing sessions for save/restoring but we don't want to do that when we're - -- already restoring a session - Lib.logger.debug "DirChangedPre: restore_in_progress/vim.g.SessionLoad is true, ignoring this event" + vim.api.nvim_create_user_command("SessionDisableAutoSave", function(args) + return AutoSession.DisableAutoSave(args.bang) + end, { + bang = true, + desc = "Disable autosave. Enable with a !", + }) + + vim.api.nvim_create_user_command("SessionToggleAutoSave", function() + return AutoSession.DisableAutoSave(not Config.auto_save) + end, { + bang = true, + desc = "Toggle autosave", + }) + + vim.api.nvim_create_user_command("SessionSearch", function() + -- If Telescope is installed, use that otherwise use vim.ui.select + if setup_session_lens() and SessionLens then + vim.cmd "Telescope session-lens" + return + end + + handle_autosession_command { "search" } + end, { + desc = "Open a session picker", + }) + + vim.api.nvim_create_user_command("Autosession", handle_autosession_command, { + complete = function(_, _, _) + return { "search", "delete" } + end, + nargs = 1, + }) + + vim.api.nvim_create_user_command( + "SessionPurgeOrphaned", + purge_orphaned_sessions, + { desc = "Remove all orphaned sessions with no directory left" } + ) + + local group = vim.api.nvim_create_augroup("auto_session_group", {}) + + vim.api.nvim_create_autocmd({ "StdinReadPre" }, { + group = group, + pattern = "*", + callback = function() + vim.g.in_pager_mode = true + end, + }) + + -- Used to track the Lazy window if we're delaying loading until it's dismissed + local lazy_view_win = nil + vim.api.nvim_create_autocmd({ "VimEnter" }, { + group = group, + pattern = "*", + nested = true, + callback = function() + if vim.g.in_pager_mode then + -- Don't auto restore session in pager mode + Lib.logger.debug "In pager mode, skipping auto restore" + AutoSession.run_cmds "no_restore" + return + end + + if not Config.lazy_support then + -- If auto_restore_lazy_delay_enabled is false, just restore the session as normal + AutoSession.auto_restore_session_at_vim_enter() + return + end + + -- Not in pager mode, auto_restore_lazy_delay_enabled is true, check for Lazy + local ok, lazy_view = pcall(require, "lazy.view") + if not ok then + -- No Lazy, load as usual + AutoSession.auto_restore_session_at_vim_enter() + return + end + + if not lazy_view.visible() then + -- Lazy isn't visible, load as usual + Lib.logger.debug "Lazy is loaded, but not visible, will try to restore session" + AutoSession.auto_restore_session_at_vim_enter() + return + end + + -- If the Lazy window is visibile, hold onto it for later + lazy_view_win = lazy_view.view.win + Lib.logger.debug "Lazy window is still visible, waiting for it to close" + end, + }) + + vim.api.nvim_create_autocmd({ "VimLeavePre" }, { + group = group, + pattern = "*", + callback = function() + if not vim.g.in_pager_mode then + AutoSession.AutoSaveSession() + end + end, + }) + + -- Set a flag to indicate that the plugin has been loaded + vim.g.loaded_auto_session = true + + if Config.lazy_support then + -- Helper to delay loading the session if the Lazy.nvim window is open + vim.api.nvim_create_autocmd("WinClosed", { + callback = function(event) + -- If we we're in pager mode or we have no Lazy window, bail out + if vim.g.in_pager_mode or not lazy_view_win then 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" + if event.match ~= tostring(lazy_view_win) then + -- A window was closed, but it wasn't Lazy's window so keep waiting + Lib.logger.debug "A window was closed but it was not Lazy, keep waiting" return end - local success = AutoSession.AutoRestoreSession() - - if not success then - Lib.logger.info("Could not load session for: " .. vim.fn.getcwd()) - -- Don't return, still dispatch the hook below - end + Lib.logger.debug "Lazy window was closed, restore the session!" - if type(conf.post_cwd_changed_hook) == "function" then - conf.post_cwd_changed_hook() - end + -- Clear lazy_view_win so we stop processing future WinClosed events + lazy_view_win = nil + -- Schedule restoration for the next pass in the event loop to time for the window to close + -- Not doing this could create a blank buffer in the restored session + vim.schedule(function() + AutoSession.auto_restore_session_at_vim_enter() + end) end, - pattern = "global", }) end + + setup_dirchanged_autocmds(AutoSession) + + if Config.session_lens.load_on_setup then + Lib.logger.debug "Loading session lens" + setup_session_lens() + end end return M diff --git a/lua/auto-session/config.lua b/lua/auto-session/config.lua new file mode 100644 index 0000000..4c51d8d --- /dev/null +++ b/lua/auto-session/config.lua @@ -0,0 +1,232 @@ +---@diagnostic disable: inject-field +---@type AutoSession.Config +local M = {} + +---@toc toc + +---@mod auto-session.config Config + +---@class AutoSession.Config +---@field enabled? boolean Enables/disables auto saving and restoring +---@field root_dir? string root directory for session files, by default is `vim.fn.stdpath('data') .. '/sessions/'` +---@field auto_save? boolean Enables/disables auto saving session on exit +---@field auto_restore? boolean Enables/disables auto restoring session on start +---@field auto_create? boolean|function Enables/disables auto creating new session files. Can take a function that should return true/false if a new session file should be created or not +---@field suppressed_dirs? table Suppress auto session for directories +---@field allowed_dirs? table Allow auto session for directories, if empty then all directories are allowed except for suppressed ones +---@field auto_restore_last_lession? boolean On startup, loads the last saved session if session for cwd does not exist +---@field use_git_branch? boolean Include git branch name in session name to differentiate between sessions for different git branches +---@field lazy_support? 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 +---@field bypass_save_filetypes? table List of file types to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards +---@field close_unsupported_windows? boolean Whether to close windows that aren't backed by a real file +---Argv Handling +---@field args_allow_single_directory? boolean Follow normal sesion save/load logic if launched with a single directory as the only argument +---@field 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 +---@field continue_restore_on_error? boolean Keep loading the session even if there's an error. Set to false to get the line number of an error when loading a session +---@field log_level? string|integer "debug", "info", "warn", "error" or vim.log.levels.DEBUG, vim.log.levels.INFO, vim.log.levels.WARN, vim.log.levels.ERROR +---@field cwd_change_handling? boolean Follow cwd changes, saving a session before change and restoring after +---@field session_lens? SessionLens Session lens configuration options +--- +---Hooks +---@field pre_save_cmds? table executes before a session is saved +---@field save_extra_cmds? table executes before a session is saved +---@field post_save_cmds? table executes after a session is saved +---@field pre_restore_cmds? table executes before a session is restored +---@field post_restore_cmds? table executes after a session is restored +---@field pre_delete_cmds? table executes before a session is deleted +---@field post_delete_cmds? table executes after a session is deleted +---@field no_restore_cmds? table executes at VimEnter when no session is restored +---@field pre_cwd_changed_cmds? table executes before cwd is changed if cwd_change_handling is true +---@field post_cwd_changed_cmds? table executes after cwd is changed if cwd_change_handling is true + +---Sessien Lens Cenfig +---@class SessionLens +---@field load_on_setup? boolean +---@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 Telescope theme options +---@field previewer? boolean Whether to show a preview of the session file (not very useful to most people) +---@field session_control? SessionControl +---@field mappings? SessionLensMappings + +---@class SessionControl +---@field control_dir string +---@field control_filename string + +---Session Lens Mapping +---@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 + +---@type AutoSession.Config +local defaults = { + enabled = true, -- Enables/disables auto creating, saving and restoring + root_dir = vim.fn.stdpath "data" .. "/sessions/", -- Root dir where sessions will be stored + auto_save = true, -- Enables/disables auto saving session on exit + auto_restore = true, -- Enables/disables auto restoring session on start + auto_create = true, -- Enables/disables auto creating new session files. Can take a function that should return true/false if a new session file should be created or not + suppressed_dirs = nil, -- Suppress session restore/create in certain directories + alloweded_dirs = nil, -- Allow session restore/create in certain directories + auto_restore_last_session = false, -- On startup, loads the last saved session if session for cwd does not exist + use_git_branch = false, -- Include git branch name in session name + lazy_support = true, -- Automatically detect if Lazy.nvim is being used and wait until Lazy is done to make sure session is restored correctly. Does nothing if Lazy isn't being used. Can be disabled if a problem is suspected or for debugging + bypass_save_filetypes = nil, -- List of filetypes to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards + close_unsupported_windows = true, -- Close windows that aren't backed by normal file before autosaving a session + args_allow_single_directory = true, -- Follow normal sesion save/load logic if launched with a single directory as the only argument + args_allow_files_auto_save = false, -- Allow saving a session even when launched with a file argument (or multiple files/dirs). It does not load any existing session first. While you can just set this to true, you probably want to set it to a function that decides when to save a session when launched with file args. See documentation for more detail + continue_restore_on_error = true, -- Keep loading the session even if there's an error + cwd_change_handling = false, -- Follow cwd changes, saving a session before change and restoring after + log_level = "error", -- Sets the log level of the plugin (debug, info, warn, error). + + ---@type SessionLens + session_lens = { + load_on_setup = true, -- Initialize on startup (requires Telescope) + theme_conf = { -- Pass through for Telescope theme options + -- layout_config = { -- As one example, can change width/height of picker + -- width = 0.8, -- percent of window + -- height = 0.5, + -- }, + }, + previewer = false, -- File preview for session picker + + ---@type SessionLensMappings + mappings = { + -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode + delete_session = { "i", "" }, + alternate_session = { "i", "" }, + }, + + ---@type SessionControl + session_control = { + control_dir = vim.fn.stdpath "data" .. "/auto_session/", -- Auto session control dir, for control files, like alternating between two sessions with session-lens + control_filename = "session_control.json", -- File name of the session control file + }, + }, +} + +---@type AutoSession.Config +M.options = {} + +---@type AutoSession.Config +---Used to show the user their config using the new names without the defaults +M.options_without_defaults = {} + +---Does the config have old names. Used to show a warning in the health check +M.has_old_config = true + +---Set config options based on vim globals +---@param config AutoSession.Config +local function check_for_vim_globals(config) + local vim_globals_mapping = { + auto_session_enabled = "enabled", + auto_session_root_dir = "root_dir", + auto_save_enabled = "auto_save", + auto_restore_enabled = "auto_restore", + auto_session_allowed_dirs = "allowed_dirs", + auto_session_suppress_dirs = "suppressed_dirs", + auto_session_create_enabled = "auto_create", + auto_session_enable_last_session = "auto_restore_last_session", + auto_session_use_git_branch = "use_git_branch", + pre_save_cmds = "pre_save_cmds", + save_extra_cmds = "save_extra_cmds", + post_save_cmds = "post_save_cmds", + pre_restore_cmds = "pre_restore_cmds", + post_restore_cmds = "post_restore_cmds", + pre_delete_cmds = "pre_delete_cmds", + post_delete_cmds = "post_delete_cmds", + no_restore_cmds = "no_restore_cmds", + } + + for global_name, config_name in pairs(vim_globals_mapping) do + -- if the global is set and the config isn't set, set the config + if vim.g[global_name] ~= nil then + M.has_old_config = true + if config[config_name] == nil then + config[config_name] = vim.g[global_name] + end + end + end +end + +---Look for old config names, and set them with the new names +---@param config AutoSession.Config +local function check_old_config_names(config) + local old_config_names = { + auto_session_enabled = "enabled", + auto_session_root_dir = "root_dir", + auto_save_enabled = "auto_save", + auto_restore_enabled = "auto_restore", + auto_session_allowed_dirs = "allowed_dirs", + auto_session_suppress_dirs = "suppressed_dirs", + auto_session_create_enabled = "auto_create", + auto_session_enable_last_session = "auto_restore_last_lession", + auto_session_use_git_branch = "use_git_branch", + auto_restore_lazy_delay_enabled = "lazy_support", + bypass_session_save_file_types = "bypass_save_filetypes", + silent_restore = "continue_restore_on_error", + } + + for old_name, new_name in pairs(old_config_names) do + -- if old name is set and new name isn't set, then copy over the value to the new name + -- and clear the old name + if config[old_name] ~= nil then + M.has_old_config = true + if config[new_name] == nil then + config[new_name] = config[old_name] + end + config[old_name] = nil + end + end + + if + config["cwd_change_handling"] + and type(config["cwd_change_handling"]) == "table" + and config.cwd_change_handling["restore_upcoming_session"] + then + local old_cwd_change_handling = config.cwd_change_handling or {} -- shouldn't be nil but placate LS + config["cwd_change_handling"] = old_cwd_change_handling.restore_upcoming_session + if old_cwd_change_handling["pre_cwd_changed_hook"] then + config.pre_cwd_changed_cmds = { old_cwd_change_handling.pre_cwd_changed_hook } + end + if old_cwd_change_handling["post_cwd_changed_hook"] then + config.post_cwd_changed_cmds = { old_cwd_change_handling.post_cwd_changed_hook } + end + end +end + +---@param config? AutoSession.Config +function M.setup(config) + ---@diagnostic disable-next-line: param-type-mismatch + M.options_without_defaults = vim.deepcopy(config) or {} + + -- capture any old vim global config options + check_for_vim_globals(M.options_without_defaults) + + -- capture any old config names + check_old_config_names(M.options_without_defaults) + + M.options = vim.tbl_deep_extend("force", defaults, M.options_without_defaults) +end + +function M.check(logger) + if not vim.tbl_contains(vim.split(vim.o.sessionoptions, ","), "localoptions") then + logger.warn "vim.o.sessionoptions is missing localoptions. \nUse `:checkhealth autosession` for more info." + end + + -- TODO: At some point, we should pop up a warning about old config if + -- M.has_old_config but let's make sure everything is working well before doing that +end + +---@export Config +return setmetatable(M, { + __index = function(_, key) + if M.options == nil then + M.setup() + end + ---@diagnostic disable-next-line: need-check-nil + return M.options[key] + end, + __tostring = function(_) + return vim.inspect(M.options) + end, +}) diff --git a/lua/auto-session/health.lua b/lua/auto-session/health.lua index f7813cb..e62a400 100644 --- a/lua/auto-session/health.lua +++ b/lua/auto-session/health.lua @@ -1,4 +1,6 @@ local AutoSession = require "auto-session" +local Lib = require "auto-session.lib" +local Config = require "auto-session.config" local M = {} @@ -13,7 +15,7 @@ local error = vim.health.error or vim.health.report_error ---@diagnostic disable-next-line: deprecated local info = vim.health.info or vim.health.report_info -local function check_sesssion_options() +local function check_session_options() if not vim.tbl_contains(vim.split(vim.o.sessionoptions, ","), "localoptions") then warn( "`vim.o.sessionoptions` should contain 'localoptions' to make sure\nfiletype and highlighting work correctly after a session is restored.\n\n" @@ -26,12 +28,24 @@ local function check_sesssion_options() end function M.check() - start "auto-session" + start "vim options" + check_session_options() + start "Config" + if Config.has_old_config then + info( + "You have old config names. You could update your config to:\n" + .. vim.inspect(Config.options_without_defaults) + .. "\n\nYou could also need to remove any vim global config settings" + ) + else + ok("\n" .. vim.inspect(Config.options_without_defaults)) + end + + start "General Info" info("Session directory: " .. AutoSession.get_root_dir()) - info("Current session: " .. AutoSession.Lib.current_session_name()) - info("Current sesssion file: " .. vim.v.this_session) - check_sesssion_options() + info("Current session: " .. Lib.current_session_name()) + info("Current session file: " .. vim.v.this_session) end return M diff --git a/lua/auto-session/init.lua b/lua/auto-session/init.lua index e3b480e..2fc68de 100644 --- a/lua/auto-session/init.lua +++ b/lua/auto-session/init.lua @@ -1,272 +1,58 @@ local Lib = require "auto-session.lib" +local Config = require "auto-session.config" local AutoCmds = require "auto-session.autocmds" ----------- Setup ---------- -local AutoSession = { - ---@type luaOnlyConf - conf = {}, - - -- Hold on to the lib object here, useful to have the same Lib object for unit - -- testing, especially since the logger needs the config to be functional - Lib = Lib, - - -- Hold onto session_lens object for popping search on :SessionSearch - session_lens = nil, -} - --- Run command hooks -local function run_hook_cmds(cmds, hook_name) - local results = {} - if not Lib.is_empty_table(cmds) then - for _, cmd in ipairs(cmds) do - Lib.logger.debug(string.format("Running %s command: %s", hook_name, cmd)) - local success, result - - if type(cmd) == "function" then - success, result = pcall(cmd) - else - ---@diagnostic disable-next-line: param-type-mismatch - success, result = pcall(vim.cmd, cmd) - end - if not success then - Lib.logger.error(string.format("Error running %s. error: %s", cmd, result)) - else - table.insert(results, result) - end - end - end - return results -end - ----table default config for auto session ----@class defaultConf ----@field auto_session_enabled? boolean Enables/disables auto saving and restoring ----@field auto_session_root_dir? string root directory for session files, by default is `vim.fn.stdpath('data') .. '/sessions/'` ----@field auto_save_enabled? boolean Enables/disables auto saving session on exit ----@field auto_restore_enabled? boolean Enables/disables auto restoring session on start ----@field auto_session_suppress_dirs? table Suppress auto session for directories ----@field auto_session_allowed_dirs? table Allow auto session for directories, if empty then all directories are allowed except for suppressed ones ----@field auto_session_create_enabled? boolean|function Enables/disables auto creating new sessions. Can take a function that should return true/false if a session should be created or not ----@field auto_session_enable_last_session? boolean On startup, loads the last saved session if session for cwd does not exist ----@field auto_session_use_git_branch? boolean Include git branch name in session name to differentiate between sessions for different git branches ----@field 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 ----@field log_level? string|integer "debug", "info", "warn", "error" or vim.log.levels.DEBUG, vim.log.levels.INFO, vim.log.levels.WARN, vim.log.levels.ERROR - ----Default config for auto session ----@type defaultConf -local defaultConf = { - auto_session_enabled = true, -- Enables/disables auto creating, saving and restoring - auto_session_root_dir = vim.fn.stdpath "data" .. "/sessions/", -- Root dir where sessions will be stored - auto_save_enabled = true, -- Enables/disables auto save feature - auto_restore_enabled = true, -- Enables/disables auto restore feature - auto_session_suppress_dirs = nil, -- Suppress session restore/create in certain directories - auto_session_allowed_dirs = nil, -- Allow session restore/create in certain directories - auto_session_create_enabled = true, -- Enables/disables auto creating new sessions. Can take a function that should return true/false if a session should be created or not - auto_session_enable_last_session = vim.g.auto_session_enable_last_session or false, -- Enables/disables the "last session" feature - auto_session_use_git_branch = vim.g.auto_session_use_git_branch or false, -- Include git branch name in session name - auto_restore_lazy_delay_enabled = true, -- Enables/disables Lazy delay feature - log_level = vim.g.auto_session_log_level or AutoSession.conf.log_level or AutoSession.conf.log_level or "error", -- Sets the log level of the plugin (debug, info, error). camelCase logLevel for compatibility. -} - ----Lua Only Configs for Auto Session ----@class luaOnlyConf ----@field cwd_change_handling? boolean|CwdChangeHandling ----@field bypass_session_save_file_types? table List of file types to bypass auto save when the only buffer open is one of the file types listed, useful to ignore dashboards ----@field close_unsupported_windows? boolean Whether to close windows that aren't backed by a real file ----@field silent_restore? boolean Suppress extraneous messages and source the whole session, even if there's an error. Set to false to get the line number of a restore error ----@field log_level? string|integer "debug", "info", "warn", "error" or vim.log.levels.DEBUG, vim.log.levels.INFO, vim.log.levels.WARN, vim.log.levels.ERROR ----Argv Handling ----@field args_allow_single_directory? boolean Follow normal sesion save/load logic if launched with a single directory as the only argument ----@field 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 ----@field session_lens? session_lens_config Session lens configuration options - -local luaOnlyConf = { - bypass_session_save_file_types = nil, -- Bypass auto save when only buffer open is one of these file types, useful to ignore dashboards - close_unsupported_windows = true, -- Close windows that aren't backed by normal file - args_allow_single_directory = true, -- Allow single directory arguments by default - args_allow_files_auto_save = false, -- Don't save session for file args by default - ---CWD Change Handling Config - ---@class CwdChangeHandling - ---@field restore_upcoming_session boolean {true} restore session for upcoming cwd on cwd change - ---@field pre_cwd_changed_hook? boolean {true} This is called after auto_session code runs for the DirChangedPre autocmd - ---@field post_cwd_changed_hook? boolean {true} This is called after auto_session code runs for the DirChanged autocmd - - ---@type boolean|CwdChangeHandling this config can also be set to `false` to disable cwd change handling altogether. - ---Can also be set to a table with any of the following keys: - --- { - --- restore_upcoming_session = true, - --- pre_cwd_changed_hook = nil, -- lua function hook. This is called after auto_session code runs for the `DirChangedPre` autocmd - --- post_cwd_changed_hook = nil, -- lua function hook. This is called after auto_session code runs for the `DirChanged` autocmd - --- } - cwd_change_handling = false, - - ---Session Lens Config - ---@class session_lens_config - ---@field load_on_setup? boolean - ---@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 Deprecated, if you're using this please report your usage on github - ---@field previewer? boolean Whether to show a preview of the session file (not very useful to most people) - ---@field session_control? session_control - ---@field mappings? session_lens_mapping - - ---Session Control Config - ---@class session_control - ---@field control_dir string - ---@field control_filename string - - ---Session Lens Mapping - ---@class session_lens_mapping - ---@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 - - ---@type session_lens_config - session_lens = { - load_on_setup = true, - previewer = false, - theme_conf = {}, - buftypes_to_ignore = {}, - session_control = { - control_dir = vim.fn.stdpath "data" .. "/auto_session/", -- Auto session control dir, for control files, like alternating between two sessions with session-lens - control_filename = "session_control.json", -- File name of the session control file - }, - mappings = { - -- Mode can be a string or a table, e.g. {"i", "n"} for both insert and normal mode - delete_session = { "i", "" }, - alternate_session = { "i", "" }, - }, - }, - silent_restore = true, -- Suppress extraneous messages and source the whole session, even if there's an error. Set to false to get the line number of a restore error -} - --- Set default config on plugin load -AutoSession.conf = vim.tbl_deep_extend("force", defaultConf, luaOnlyConf) - --- Pass configs to Lib -Lib.conf = { - log_level = AutoSession.conf.log_level, -} - -local function check_config() - if not vim.tbl_contains(vim.split(vim.o.sessionoptions, ","), "localoptions") then - Lib.logger.warn "vim.o.sessionoptions is missing localoptions. \nUse `:checkhealth autosession` for more info." - end -end +---@mod auto-session.api API +local AutoSession = {} ---Setup function for AutoSession ----@param config defaultConf|nil Config for auto session +---@param config AutoSession.Config|nil Config for auto session function AutoSession.setup(config) - AutoSession.conf = vim.tbl_deep_extend("force", AutoSession.conf, config or {}) - Lib.setup(AutoSession.conf) - Lib.logger.debug("Config at start of setup", { conf = AutoSession.conf }) + Config.setup(config) + Lib.setup(Config.log_level) + Lib.logger.debug("Config at start of setup", tostring(Config)) + Config.check(Lib.logger) - -- Validate the root dir here so AutoSession.conf.auto_session_root_dir is set - -- correctly in all cases + -- Validate the root dir here so it's always set up correctly AutoSession.get_root_dir() - check_config() - - if AutoSession.conf.session_lens.load_on_setup then - Lib.logger.debug "Loading session lens on setup" - AutoSession.setup_session_lens() - end - - AutoCmds.setup_autocmds(AutoSession.conf, AutoSession) - - SetupAutocmds() -end - ----@private ----Make sure session_lens is setup. Ok to call multiple times -function AutoSession.setup_session_lens() - if AutoSession.session_lens then - return true - end - - local has_telescope, telescope = pcall(require, "telescope") - - if not has_telescope then - Lib.logger.info "Telescope.nvim is not installed. Session Lens cannot be setup!" - return false - end - - AutoSession.session_lens = require "auto-session.session-lens" - AutoSession.session_lens.setup() - -- Register session-lens as an extension so :Telescope will complete on session-lens - telescope.load_extension "session-lens" - return true + -- Will also setup session lens + AutoCmds.setup_autocmds(AutoSession) end local function is_enabled() - if vim.g.auto_session_enabled ~= nil then - return vim.g.auto_session_enabled == Lib._VIM_TRUE - elseif AutoSession.conf.auto_session_enabled ~= nil then - return AutoSession.conf.auto_session_enabled - end - - return true + return Config.enabled end local function is_allowed_dirs_enabled() - local enabled = false - - if vim.g.auto_session_allowed_dirs ~= nil then - enabled = not vim.tbl_isempty(vim.g.auto_session_allowed_dirs) - else - enabled = not vim.tbl_isempty(AutoSession.conf.auto_session_allowed_dirs or {}) - end - - Lib.logger.debug("is_allowed_dirs_enabled", enabled) - return enabled + return not vim.tbl_isempty(Config.allowed_dirs or {}) end local function is_auto_create_enabled() - if vim.g.auto_session_create_enabled ~= nil then - if type(vim.g.auto_session_create_enabled) == "function" then - if vim.g.auto_session_create_enabled() then - Lib.logger.debug "vim.g.auto_session_create_enabled returned true, allowing creation" - return true - else - Lib.logger.debug "vim.g.auto_session_create_enabled returned false, not allowing creation" - return false - end - else - return vim.g.auto_session_create_enabled == Lib._VIM_TRUE - end + if type(Config.auto_create) ~= "function" then + return Config.auto_create end - if AutoSession.conf.auto_session_create_enabled ~= nil then - if type(AutoSession.conf.auto_session_create_enabled) == "function" then - if AutoSession.conf.auto_session_create_enabled() then - Lib.logger.debug "AutoSession.conf.auto_session_create_enabled returned true, allowing creation" - return true - else - Lib.logger.debug "AutoSession.conf.auto_session_create_enabled returned false, not allowing creation" - return false - end - else - return AutoSession.conf.auto_session_create_enabled - end - end - - return true + local result = Config.auto_create() + Lib.logger.debug("auto_create() returned: ", result) + return result end -- get the current git branch name, if any, and only if configured to do so local function get_git_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"))) - return "" - end - return out[1] + if not Config.use_git_branch then + return "" end - return "" + -- 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"))) + return "" + end + return out[1] end local in_pager_mode = function() @@ -298,18 +84,14 @@ local function enabled_for_command_line_argv(is_save) return true end - -- if conf.args_allow_single_directory = true, then enable session handling if only param is a directory - if - argc == 1 - and vim.fn.isdirectory(launch_argv[1]) == Lib._VIM_TRUE - and AutoSession.conf.args_allow_single_directory - then + -- if Config.args_allow_single_directory = true, then enable session handling if only param is a directory + if argc == 1 and vim.fn.isdirectory(launch_argv[1]) == Lib._VIM_TRUE and Config.args_allow_single_directory then -- Actual session will be loaded in auto_restore_session_at_vim_enter Lib.logger.debug("Allowing restore when launched with a single directory argument: " .. launch_argv[1]) return true end - if not AutoSession.conf.args_allow_files_auto_save then + if not Config.args_allow_files_auto_save then Lib.logger.debug "args_allow_files_auto_save is false, not enabling restoring/saving" return false end @@ -319,9 +101,9 @@ local function enabled_for_command_line_argv(is_save) return false end - if type(AutoSession.conf.args_allow_files_auto_save) == "function" then - local ret = AutoSession.conf.args_allow_files_auto_save() - Lib.logger.debug("conf.args_allow_files_auto_save() returned: " .. vim.inspect(ret)) + if type(Config.args_allow_files_auto_save) == "function" then + local ret = Config.args_allow_files_auto_save() + Lib.logger.debug("args_allow_files_auto_save() returned: " .. vim.inspect(ret)) return ret end @@ -346,11 +128,7 @@ local auto_save = function() return false end - if vim.g.auto_save_enabled ~= nil then - return vim.g.auto_save_enabled == Lib._VIM_TRUE - end - - return AutoSession.conf.auto_save_enabled + return Config.auto_save end local auto_restore = function() @@ -358,15 +136,11 @@ local auto_restore = function() return false end - if vim.g.auto_restore_enabled ~= nil then - return vim.g.auto_restore_enabled == Lib._VIM_TRUE - end - - return AutoSession.conf.auto_restore_enabled + return Config.auto_restore end local function bypass_save_by_filetype() - local file_types_to_bypass = AutoSession.conf.bypass_session_save_file_types or {} + local filetypes_to_bypass = Config.bypass_save_filetypes or {} local windows = vim.api.nvim_list_wins() for _, current_window in ipairs(windows) do @@ -377,7 +151,7 @@ local function bypass_save_by_filetype() local buf_ft = vim.api.nvim_buf_get_option(buf, "filetype") local local_return = false - for _, ft_to_bypass in ipairs(file_types_to_bypass) do + for _, ft_to_bypass in ipairs(filetypes_to_bypass) do if buf_ft == ft_to_bypass then local_return = true break @@ -395,7 +169,7 @@ local function bypass_save_by_filetype() end local function suppress_session(session_dir) - local dirs = vim.g.auto_session_suppress_dirs or AutoSession.conf.auto_session_suppress_dirs or {} + local dirs = Config.suppressed_dirs or {} -- If session_dir is set, use that otherwise use cwd -- session_dir will be set when loading a session from a directory at lauch (i.e. from argv) @@ -415,7 +189,7 @@ local function is_allowed_dir() return true end - local dirs = vim.g.auto_session_allowed_dirs or AutoSession.conf.auto_session_allowed_dirs or {} + local dirs = Config.allowed_dirs or {} local cwd = vim.fn.getcwd() if Lib.find_matching_directory(cwd, dirs) then @@ -532,7 +306,7 @@ function AutoSession.AutoSaveSession() end end - if AutoSession.conf.close_unsupported_windows then + if Config.close_unsupported_windows then -- Wrap in pcall in case there's an error while trying to close windows local success, result = pcall(Lib.close_unsupported_windows) if not success then @@ -555,39 +329,32 @@ function AutoSession.get_root_dir(with_trailing_separator) end 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) + Config.root_dir = Lib.validate_root_dir(Config.root_dir) + Lib.logger.debug("Root dir set to: " .. Config.root_dir) AutoSession.validated = true end if with_trailing_separator then - return AutoSession.conf.auto_session_root_dir + return Config.root_dir end - return Lib.remove_trailing_separator(AutoSession.conf.auto_session_root_dir) + return Lib.remove_trailing_separator(Config.root_dir) end ---@private ----Get the hook commands to run ----This function gets cmds from both lua and vimscript configs ----@param typ string ----@return function[]|string[] -function AutoSession.get_cmds(typ) - return AutoSession.conf[typ .. "_cmds"] or vim.g["auto_session_" .. typ .. "_cmds"] +---Get the hook commands from the config and run them +---@param hook_name string +---@return table Results of the commands +function AutoSession.run_cmds(hook_name) + local cmds = Config[hook_name .. "_cmds"] + return Lib.run_hook_cmds(cmds, hook_name) end ---Calls a hook to get any user/extra commands and if any, saves them to *x.vim ---@param session_path string The path of the session file to save the extra params for ---@return boolean Returns whether extra commands were saved local function save_extra_cmds_new(session_path) - local extra_cmds = AutoSession.get_cmds "save_extra" - if not extra_cmds then - return false - end - - local data = run_hook_cmds(extra_cmds, "save-extra") + local data = AutoSession.run_cmds "save_extra" if not data then return false end @@ -600,76 +367,6 @@ local function save_extra_cmds_new(session_path) return true end ----@private ----@class PickerItem ----@field session_name string ----@field display_name string ----@field path string - ----@return PickerItem[] -local function get_session_files() - local files = {} - local sessions_dir = AutoSession.get_root_dir() - - if vim.fn.isdirectory(sessions_dir) == Lib._VIM_FALSE then - return files - end - - local entries = vim.fn.readdir(sessions_dir, function(item) - return Lib.is_session_file(sessions_dir .. item) - end) - - return vim.tbl_map(function(file_name) - -- sessions_dir is guaranteed to have a trailing separator so don't need to add another one here - local session_name - local display_name - if Lib.is_legacy_file_name(file_name) then - session_name = (Lib.legacy_unescape_session_name(file_name):gsub("%.vim$", "")) - display_name = session_name .. " (legacy)" - else - session_name = Lib.escaped_session_name_to_session_name(file_name) - display_name = Lib.get_session_display_name(file_name) - end - - return { - session_name = session_name, - display_name = display_name, - path = sessions_dir .. file_name, - } - end, entries) -end - ----@param files string[] ----@param prompt string ----@param callback fun(choice: PickerItem) -local function open_picker(files, prompt, callback) - vim.ui.select(files, { - prompt = prompt, - kind = "auto-session", - format_item = function(item) - return item.display_name - end, - }, function(choice) - if choice then - callback(choice) - end - end) -end - ----@param data table -local function handle_autosession_command(data) - local files = get_session_files() - if data.args:match "search" then - open_picker(files, "Select a session:", function(choice) - AutoSession.autosave_and_restore(choice.session_name) - end) - elseif data.args:match "delete" then - open_picker(files, "Delete a session:", function(choice) - AutoSession.DeleteSessionFile(choice.path, choice.display_name) - end) - end -end - ---@private ---Handler for when a session is picked from the UI, either via Telescope or via AutoSession.select_session ---Save the current session if the session we're loading isn't also for the cwd (if autosave allows) @@ -689,8 +386,8 @@ function AutoSession.autosave_and_restore(session_name) 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 + local control_dir = Config.session_lens.session_control.control_dir + local control_file = Config.session_lens.session_control.control_filename session_file_name = Lib.expand(session_file_name) -- expand the path @@ -736,12 +433,13 @@ function AutoSession.AutoRestoreSession(session_name) return AutoSession.RestoreSession(session_name, false) end +---@private ---Called at VimEnter (after Lazy is done) to see if we should automatically restore a session ----If launched with a single directory parameter and conf.args_allow_single_directory is true, pass +---If launched with a single directory parameter and Config.args_allow_single_directory is true, pass ---that in as the session_dir. Handles both 'nvim .' and 'nvim some/dir' ---Also make sure to call no_restore if no session was restored ---@return boolean Was a session restored -local function auto_restore_session_at_vim_enter() +function AutoSession.auto_restore_session_at_vim_enter() -- Save the launch args here as restoring a session will replace vim.fn.argv. We clear -- launch_argv in restore session so it's only used for the session launched from the command -- line @@ -749,7 +447,7 @@ local function auto_restore_session_at_vim_enter() -- Is there exactly one argument and is it a directory? if - AutoSession.conf.args_allow_single_directory + Config.args_allow_single_directory and #launch_argv == 1 and vim.fn.isdirectory(launch_argv[1]) == Lib._VIM_TRUE then @@ -766,7 +464,7 @@ local function auto_restore_session_at_vim_enter() -- want to enable autosaving since it might replace the session for the cwd if vim.fn.getcwd() ~= session_name then Lib.logger.debug "Not enabling autosave because launch argument didn't load session and doesn't match cwd" - AutoSession.conf.auto_save_enabled = false + Config.auto_save = false end else if AutoSession.AutoRestoreSession() then @@ -774,7 +472,7 @@ local function auto_restore_session_at_vim_enter() end -- Check to see if the last session feature is on - if AutoSession.conf.auto_session_enable_last_session then + if Config.auto_restore_last_lession then Lib.logger.debug "Last session is enabled, checking for session" local last_session_name = Lib.get_latest_session(AutoSession.get_root_dir()) @@ -789,51 +487,12 @@ local function auto_restore_session_at_vim_enter() end -- No session was restored, dispatch no-restore hook - local no_restore_cmds = AutoSession.get_cmds "no_restore" Lib.logger.debug "No session restored, call no_restore hooks" - run_hook_cmds(no_restore_cmds, "no-restore") + AutoSession.run_cmds "no_restore" return false end --- If we're unit testing, we need this entry point since the test harness loads our tests after --- VimEnter has been called -if vim.env.AUTOSESSION_UNIT_TESTING then - AutoSession.auto_restore_session_at_vim_enter = auto_restore_session_at_vim_enter -end - ----Calls lib function for completeing session names with session dir -local function complete_session(ArgLead, CmdLine, CursorPos) - return Lib.complete_session_for_dir(AutoSession.get_root_dir(), ArgLead, CmdLine, CursorPos) -end - ---- Deletes sessions where the original directory no longer exists -function AutoSession.PurgeOrphanedSessions() - local orphaned_sessions = {} - - for _, session in ipairs(get_session_files()) do - if - not Lib.is_named_session(session.session_name) and vim.fn.isdirectory(session.session_name) == Lib._VIM_FALSE - then - Lib.logger.debug("purge: " .. session.session_name) - table.insert(orphaned_sessions, session.session_name) - end - end - - if Lib.is_empty_table(orphaned_sessions) then - Lib.logger.info "Nothing to purge" - return - end - - for _, session_name in ipairs(orphaned_sessions) do - Lib.logger.info("Purging: ", session_name) - local escaped_session = Lib.escape_session_name(session_name) - local session_path = string.format("%s/%s.vim", AutoSession.get_root_dir(), escaped_session) - Lib.logger.debug("purging: " .. session_path) - vim.fn.delete(Lib.expand(session_path)) - end -end - ---Saves a session to the dir specified in the config. If no optional ---session name is passed in, it uses the cwd as the session name ---@param session_name? string|nil Optional session name @@ -862,8 +521,7 @@ function AutoSession.SaveSessionToDir(session_dir, session_name, show_message) local session_path = session_dir .. escaped_session_name - local pre_cmds = AutoSession.get_cmds "pre_save" - run_hook_cmds(pre_cmds, "pre-save") + AutoSession.run_cmds "pre_save" -- We don't want to save arguments to the session as that can cause issues -- with buffers that can't be removed from the session as they keep being @@ -880,8 +538,7 @@ function AutoSession.SaveSessionToDir(session_dir, session_name, show_message) save_extra_cmds_new(session_path) - local post_cmds = AutoSession.get_cmds "post_save" - run_hook_cmds(post_cmds, "post-save") + AutoSession.run_cmds "post_save" -- session_name might be nil (e.g. when using cwd), unescape escaped_session_name instead Lib.logger.debug("Saved session: " .. Lib.unescape_session_name(escaped_session_name)) @@ -965,8 +622,7 @@ end ---@param show_message? boolean Optional, whether to show a message on restore (true by default) ---@return boolean Was a session restored function AutoSession.RestoreSessionFile(session_path, show_message) - local pre_cmds = AutoSession.get_cmds "pre_restore" - run_hook_cmds(pre_cmds, "pre-restore") + AutoSession.run_cmds "pre_restore" Lib.logger.debug("RestoreSessionFile restoring session from: " .. session_path) @@ -976,12 +632,6 @@ function AutoSession.RestoreSessionFile(session_path, show_message) local vim_session_path = Lib.escape_string_for_vim(session_path) local cmd = "source " .. vim_session_path - if AutoSession.conf.silent_restore then - cmd = "silent! " .. cmd - -- clear errors here so we can - vim.v.errmsg = "" - end - -- Set restore_in_progress here so we won't also try to save/load the session if -- cwd_change_handling = true and the session contains a cd command -- The session file will also set SessionLoad so we'll check that too but feels @@ -993,24 +643,28 @@ function AutoSession.RestoreSessionFile(session_path, show_message) vim.cmd "clearjumps" ---@diagnostic disable-next-line: param-type-mismatch - local success, result = pcall(vim.cmd, cmd) + local success, result = pcall(vim.cmd, "silent " .. cmd) + + -- normal restore failed, source again but with silent! to restore as much as possible + if not success and Config.continue_restore_on_error then + vim.cmd "%bw!" + vim.cmd "clearjumps" + + -- don't capture return values as we'll use success and result from the first call + ---@diagnostic disable-next-line: param-type-mismatch + pcall(vim.cmd, "silent! " .. cmd) + end + AutoSession.restore_in_progress = false -- Clear any saved command line args since we don't need them anymore launch_argv = nil - if AutoSession.conf.silent_restore and vim.v.errmsg and vim.v.errmsg ~= "" then - -- we had an error while sourcing silently so surface it - success = false - result = vim.v.errmsg - end - if not success then Lib.logger.error([[ Error restoring session, disabling auto save. -Set silent_restore = false in the config for a more detailed error message. Error: ]] .. result) - AutoSession.conf.auto_save_enabled = false + Config.auto_save = false return false end @@ -1020,8 +674,7 @@ Error: ]] .. result) vim.notify("Restored session: " .. session_name) end - local post_cmds = AutoSession.get_cmds "post_restore" - run_hook_cmds(post_cmds, "post-restore") + AutoSession.run_cmds "post_restore" write_to_session_control_json(session_path) return true @@ -1075,8 +728,7 @@ end ---@param session_name string Session name being deleted, just use to display messages ---@return boolean Was the session file delted function AutoSession.DeleteSessionFile(session_path, session_name) - local pre_cmds = AutoSession.get_cmds "pre_delete" - run_hook_cmds(pre_cmds, "pre-delete") + AutoSession.run_cmds "pre_delete" Lib.logger.debug("DeleteSessionFile deleting: " .. session_path) @@ -1089,7 +741,7 @@ function AutoSession.DeleteSessionFile(session_path, session_name) -- session_name might be nil (e.g. when using cwd), unescape escaped_session_name instead Lib.logger.info("Auto saving disabled because the current session was deleted: " .. session_name) vim.v.this_session = "" - AutoSession.conf.auto_save_enabled = false + Config.auto_save = false else Lib.logger.debug("DeleteSessionFile Session deleted: " .. session_name) vim.notify("Session deleted: " .. session_name) @@ -1103,8 +755,7 @@ function AutoSession.DeleteSessionFile(session_path, session_name) Lib.logger.debug("DeleteSessionFile deleting extra user commands: " .. extra_commands_path) end - local post_cmds = AutoSession.get_cmds "post_delete" - run_hook_cmds(post_cmds, "post-delete") + AutoSession.run_cmds "post_delete" return result end @@ -1112,185 +763,13 @@ end ---@param enable? boolean Optional paramter to enable autosaving ---@return boolean Whether autosaving is enabled or not function AutoSession.DisableAutoSave(enable) - AutoSession.conf.auto_save_enabled = enable or false - if AutoSession.conf.auto_save_enabled then + Config.auto_save = enable or false + if Config.auto_save then vim.notify "Session auto-save enabled" else vim.notify "Session auto-save disabled" end - return AutoSession.conf.auto_save_enabled -end - -function SetupAutocmds() - -- Check if the auto-session plugin has already been loaded to prevent loading it twice - if vim.g.loaded_auto_session ~= nil then - return - end - - -- Initialize variables - vim.g.in_pager_mode = false - - local function SessionPurgeOrphaned() - return AutoSession.PurgeOrphanedSessions() - end - - vim.api.nvim_create_user_command("SessionSave", function(args) - return AutoSession.SaveSession(args.args) - end, { - bang = true, - nargs = "?", - desc = "Save session using current working directory as the session name or an optional session name", - }) - - vim.api.nvim_create_user_command("SessionRestore", function(args) - return AutoSession.RestoreSession(args.args) - end, { - complete = complete_session, - bang = true, - nargs = "?", - desc = "Restore session using current working directory as the session name or an optional session name", - }) - - vim.api.nvim_create_user_command("SessionDelete", function(args) - return AutoSession.DeleteSession(args.args) - end, { - complete = complete_session, - bang = true, - nargs = "*", - desc = "Delete session using the current working directory as the session name or an optional session name", - }) - - vim.api.nvim_create_user_command("SessionDisableAutoSave", function(args) - return AutoSession.DisableAutoSave(args.bang) - end, { - bang = true, - desc = "Disable autosave. Enable with a !", - }) - - vim.api.nvim_create_user_command("SessionToggleAutoSave", function() - return AutoSession.DisableAutoSave(not AutoSession.conf.auto_save_enabled) - end, { - bang = true, - desc = "Toggle autosave", - }) - - vim.api.nvim_create_user_command("SessionSearch", function() - -- If Telescope is installed, use that otherwise use vim.ui.select - if AutoSession.setup_session_lens() and AutoSession.session_lens then - vim.cmd "Telescope session-lens" - return - end - - handle_autosession_command { "search" } - end, { - desc = "Open a session picker", - }) - - vim.api.nvim_create_user_command("Autosession", handle_autosession_command, { - complete = function(_, _, _) - return { "search", "delete" } - end, - nargs = 1, - }) - - vim.api.nvim_create_user_command( - "SessionPurgeOrphaned", - SessionPurgeOrphaned, - { desc = "Remove all orphaned sessions with no directory left" } - ) - - local group = vim.api.nvim_create_augroup("auto_session_group", {}) - - vim.api.nvim_create_autocmd({ "StdinReadPre" }, { - group = group, - pattern = "*", - callback = function() - vim.g.in_pager_mode = true - end, - }) - - -- Used to track the Lazy window if we're delaying loading until it's dismissed - local lazy_view_win = nil - vim.api.nvim_create_autocmd({ "VimEnter" }, { - group = group, - pattern = "*", - nested = true, - callback = function() - if vim.g.in_pager_mode then - -- Don't auto restore session in pager mode - local no_restore_cmds = AutoSession.get_cmds "no_restore" - Lib.logger.debug("In pager mode, skipping auto restore", no_restore_cmds) - run_hook_cmds(no_restore_cmds, "no-restore") - return - end - - if not AutoSession.conf.auto_restore_lazy_delay_enabled then - -- If auto_restore_lazy_delay_enabled is false, just restore the session as normal - auto_restore_session_at_vim_enter() - return - end - - -- Not in pager mode, auto_restore_lazy_delay_enabled is true, check for Lazy - local ok, lazy_view = pcall(require, "lazy.view") - if not ok then - -- No Lazy, load as usual - auto_restore_session_at_vim_enter() - return - end - - if not lazy_view.visible() then - -- Lazy isn't visible, load as usual - Lib.logger.debug "Lazy is loaded, but not visible, will try to restore session" - auto_restore_session_at_vim_enter() - return - end - - -- If the Lazy window is visibile, hold onto it for later - lazy_view_win = lazy_view.view.win - Lib.logger.debug "Lazy window is still visible, waiting for it to close" - end, - }) - - vim.api.nvim_create_autocmd({ "VimLeavePre" }, { - group = group, - pattern = "*", - callback = function() - if not vim.g.in_pager_mode then - AutoSession.AutoSaveSession() - end - end, - }) - - -- Set a flag to indicate that the plugin has been loaded - vim.g.loaded_auto_session = true - - if AutoSession.conf.auto_restore_lazy_delay_enabled then - -- Helper to delay loading the session if the Lazy.nvim window is open - vim.api.nvim_create_autocmd("WinClosed", { - callback = function(event) - -- If we we're in pager mode or we have no Lazy window, bail out - if vim.g.in_pager_mode or not lazy_view_win then - return - end - - if event.match ~= tostring(lazy_view_win) then - -- A window was closed, but it wasn't Lazy's window so keep waiting - Lib.logger.debug "A window was closed but it was not Lazy, keep waiting" - return - end - - Lib.logger.debug "Lazy window was closed, restore the session!" - - -- Clear lazy_view_win so we stop processing future WinClosed events - lazy_view_win = nil - -- Schedule restoration for the next pass in the event loop to time for the window to close - -- Not doing this could create a blank buffer in the restored session - vim.schedule(function() - auto_restore_session_at_vim_enter() - end) - end, - }) - end + return Config.auto_save end return AutoSession diff --git a/lua/auto-session/lib.lua b/lua/auto-session/lib.lua index a7b0ef5..643b2d4 100644 --- a/lua/auto-session/lib.lua +++ b/lua/auto-session/lib.lua @@ -1,20 +1,14 @@ local Logger = require "auto-session.logger" -local Config = {} local Lib = { logger = {}, - conf = { - log_level = false, - }, - Config = Config, _VIM_FALSE = 0, _VIM_TRUE = 1, } -function Lib.setup(config) - Lib.conf = vim.tbl_deep_extend("force", Lib.conf, config or {}) +function Lib.setup(log_level) Lib.logger = Logger:new { - log_level = Lib.conf.log_level, + log_level = log_level, } end @@ -349,7 +343,7 @@ end ---@param escaped_session_name string The session file name. It should not have a path component ---@return table The session name components function Lib.get_session_display_name_as_table(escaped_session_name) - -- sesssion name contains a |, split on that and get git branch + -- session name contains a |, split on that and get git branch local session_name = Lib.escaped_session_name_to_session_name(escaped_session_name) local splits = vim.split(session_name, "|") @@ -497,12 +491,34 @@ end ---@param dirs table ---@param dirToFind string function Lib.find_matching_directory(dirToFind, dirs) - Lib.logger.debug("find_matching_directory", { dirToFind = dirToFind, dirs = dirs }) - for _, s in pairs(dirs) do - local expanded = Lib.expand(s) - -- Lib.logger.debug("find_matching_directory expanded: " .. s) + local dirsToCheck = {} + + -- resolve any symlinks and also check those + for _, dir in pairs(dirs) do + -- first expand it + local expanded_dir = Lib.expand(dir) + + -- resolve symlinks + local resolved_dir = vim.fn.resolve(expanded_dir) + + -- Lib.logger.debug("dir: " .. dir .. " expanded_dir: " .. expanded_dir .. " resolved_dir: " .. resolved_dir) + + -- add the base expanded dir first. in theory, we should only need + -- the resolved directory but other systems might behave differently so + -- safer to check both + table.insert(dirsToCheck, expanded_dir) + + -- add the resolved dir if it's different (e.g. a symlink) + if resolved_dir ~= expanded_dir then + table.insert(dirsToCheck, resolved_dir) + end + end + + Lib.logger.debug("find_matching_directory", { dirToFind = dirToFind, dirsToCheck = dirsToCheck }) + + for _, dir in pairs(dirsToCheck) do ---@diagnostic disable-next-line: param-type-mismatch - for path in string.gmatch(expanded, "[^\r\n]+") do + for path in string.gmatch(dir, "[^\r\n]+") do local simplified_path = vim.fn.simplify(path) local path_without_trailing_slashes = string.gsub(simplified_path, "/+$", "") @@ -518,4 +534,33 @@ function Lib.find_matching_directory(dirToFind, dirs) return false end +---@param cmds table Cmds to run +---@param hook_name string Name of the hook being run +---@return table Results of the cmds +function Lib.run_hook_cmds(cmds, hook_name) + local results = {} + if Lib.is_empty_table(cmds) then + return results + end + + for _, cmd in ipairs(cmds) do + Lib.logger.debug(string.format("Running %s command: %s", hook_name, cmd)) + local success, result + + if type(cmd) == "function" then + success, result = pcall(cmd) + else + ---@diagnostic disable-next-line: param-type-mismatch + success, result = pcall(vim.cmd, cmd) + end + + if not success then + Lib.logger.error(string.format("Error running %s. error: %s", cmd, result)) + else + table.insert(results, result) + end + end + return results +end + return Lib diff --git a/lua/auto-session/session-lens/actions.lua b/lua/auto-session/session-lens/actions.lua index 751495b..cb3094b 100644 --- a/lua/auto-session/session-lens/actions.lua +++ b/lua/auto-session/session-lens/actions.lua @@ -1,12 +1,19 @@ local AutoSession = require "auto-session" -local Lib = AutoSession.Lib +local Config = require "auto-session.config" +local Lib = require "auto-session.lib" local M = {} ---@private local function get_alternate_session() ---@diagnostic disable-next-line: undefined-field - local session_control_conf = AutoSession.conf.session_lens.session_control + 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 diff --git a/lua/auto-session/session-lens/init.lua b/lua/auto-session/session-lens/init.lua index 96c4865..d8bc0d6 100644 --- a/lua/auto-session/session-lens/init.lua +++ b/lua/auto-session/session-lens/init.lua @@ -1,19 +1,10 @@ +local Config = require "auto-session.config" +local Lib = require "auto-session.lib" local Actions = require "auto-session.session-lens.actions" local AutoSession = require "auto-session" -local Lib = AutoSession.Lib ----------- Setup ---------- -local SessionLens = { - conf = {}, -} - -function SessionLens.setup() - SessionLens.conf = AutoSession.conf.session_lens - - if SessionLens.conf.buftypes_to_ignore ~= nil and not vim.tbl_isempty(SessionLens.conf.buftypes_to_ignore) then - Lib.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 +local SessionLens = {} ---@private ---Function generator that returns the function for generating telescope file entries. Only exported @@ -29,7 +20,11 @@ function SessionLens.make_telescope_callback(opts) -- Don't include x.vim files that nvim makes for custom user -- commands if not Lib.is_session_file(session_root_dir .. file_name) then - return nil + -- FIXME: Returning nil would be better here since otherwise the result count + -- will be off. However, returning nil can prevent delete from working so return {} + -- until this is fixed: + -- https://github.com/nvim-telescope/telescope.nvim/issues/3265 + return {} end -- the name of the session, to be used for restoring/deleting @@ -38,7 +33,7 @@ function SessionLens.make_telescope_callback(opts) -- the name to display, possibly with a shortened path local display_name - -- an annotation about the sesssion, added to display_name after any path processing + -- an annotation about the session, added to display_name after any path processing local annotation = "" if Lib.is_legacy_file_name(file_name) then session_name = (Lib.legacy_unescape_session_name(file_name):gsub("%.vim$", "")) @@ -73,6 +68,7 @@ function SessionLens.make_telescope_callback(opts) end end +---@private ---Search session ---Triggers the customized telescope picker for switching sessions ---@param custom_opts any @@ -80,7 +76,7 @@ SessionLens.search_session = function(custom_opts) local themes = require "telescope.themes" local telescope_actions = require "telescope.actions" - custom_opts = (vim.tbl_isempty(custom_opts or {}) or custom_opts == nil) and SessionLens.conf or custom_opts + custom_opts = (vim.tbl_isempty(custom_opts or {}) or custom_opts == nil) and Config.session_lens or custom_opts -- Use auto_session_root_dir from the Auto Session plugin local session_root_dir = AutoSession.get_root_dir() @@ -112,7 +108,7 @@ SessionLens.search_session = function(custom_opts) attach_mappings = function(_, map) telescope_actions.select_default:replace(Actions.source_session) - local mappings = AutoSession.conf.session_lens.mappings + 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) diff --git a/tests/allowed_dirs_spec.lua b/tests/allowed_dirs_spec.lua index d0d2ca3..293239e 100644 --- a/tests/allowed_dirs_spec.lua +++ b/tests/allowed_dirs_spec.lua @@ -4,12 +4,15 @@ TL.clearSessionFilesAndBuffers() describe("The allowed dirs config", function() local as = require "auto-session" + local c = require "auto-session.config" as.setup { auto_session_allowed_dirs = { "/dummy" }, + -- log_level = "debug", } TL.clearSessionFilesAndBuffers() vim.cmd("e " .. TL.test_file) + local cwd = vim.fn.getcwd() it("doesn't save a session for a non-allowed dir", function() as.AutoSaveSession() @@ -19,7 +22,7 @@ describe("The allowed dirs config", function() end) it("saves a session for an allowed dir", function() - as.conf.auto_session_allowed_dirs = { vim.fn.getcwd() } + c.allowed_dirs = { vim.fn.getcwd() } as.AutoSaveSession() -- Make sure the session was created @@ -32,7 +35,7 @@ describe("The allowed dirs config", function() it("saves a session for an allowed dir with a glob", function() TL.clearSessionFilesAndBuffers() vim.cmd("e " .. TL.test_file) - as.conf.auto_session_allowed_dirs = { vim.fn.getcwd() .. "/tests/*" } + c.allowed_dirs = { vim.fn.getcwd() .. "/tests/*" } -- Change to a sub directory to see if it's allowed vim.cmd "cd tests/test_files" @@ -45,4 +48,25 @@ describe("The allowed dirs config", function() -- Make sure the session was created assert.equals(1, vim.fn.filereadable(session_path)) end) + + if vim.fn.has "win32" == 0 then + it("saves a session for an allowed dir with a symlink", function() + TL.clearSessionFilesAndBuffers() + vim.cmd("cd " .. cwd) + + vim.cmd("e " .. TL.test_file) + c.allowed_dirs = { vim.fn.getcwd() .. "/tests/symlink-test" } + + vim.fn.system "ln -snf test_files tests/symlink-test" + vim.cmd "cd tests/symlink-test" + + local session_path = TL.makeSessionPath(vim.fn.getcwd()) + assert.equals(0, vim.fn.filereadable(session_path)) + + assert.True(as.AutoSaveSession()) + + -- Make sure the session was created + assert.equals(1, vim.fn.filereadable(session_path)) + end) + end end) diff --git a/tests/args_files_enabled_spec.lua b/tests/args_files_enabled_spec.lua index 7a29389..a985b66 100644 --- a/tests/args_files_enabled_spec.lua +++ b/tests/args_files_enabled_spec.lua @@ -17,6 +17,8 @@ describe("The args files enabled config", function() }, } + local c = require "auto-session.config" + TL.clearSessionFilesAndBuffers() it("can save a session", function() @@ -76,11 +78,11 @@ describe("The args files enabled config", function() local as = require "auto-session" - as.conf.auto_save_enabled = true + c.auto_save = true assert.equals(true, as.AutoSaveSession()) - as.conf.auto_save_enabled = false + c.auto_save = false -- Session should have new file TL.assertSessionHasFile(TL.default_session_path, TL.other_file) @@ -90,42 +92,42 @@ describe("The args files enabled config", function() end) it("doesn't autosave when args_allow_files_auto_save returns false", function() - M.clearSessionFilesAndBuffers() + TL.clearSessionFilesAndBuffers() vim.cmd("e " .. TL.other_file) assert.equals(1, vim.fn.bufexists(TL.other_file)) local as = require "auto-session" - as.conf.auto_save_enabled = true - as.conf.args_allow_files_auto_save = function() + c.auto_save = true + c.args_allow_files_auto_save = function() return false end assert.equals(false, as.AutoSaveSession()) - as.conf.auto_save_enabled = false + c.auto_save = false assert.equals(false, TL.sessionHasFile(TL.default_session_path, TL.other_file)) assert.equals(false, TL.sessionHasFile(TL.default_session_path, TL.test_file)) end) it("does autosave a session when args_allow_files_auto_save returns true", function() - M.clearSessionFilesAndBuffers() + TL.clearSessionFilesAndBuffers() vim.cmd("e " .. TL.other_file) assert.equals(1, vim.fn.bufexists(TL.other_file)) local as = require "auto-session" - as.conf.auto_save_enabled = true - as.conf.args_allow_files_auto_save = function() + c.auto_save = true + c.args_allow_files_auto_save = function() return true end assert.equals(true, as.AutoSaveSession()) - as.conf.auto_save_enabled = false + c.auto_save = false -- Session should have new file TL.assertSessionHasFile(TL.default_session_path, TL.other_file) diff --git a/tests/args_single_dir_enabled_spec.lua b/tests/args_single_dir_enabled_spec.lua index e062041..8f7242f 100644 --- a/tests/args_single_dir_enabled_spec.lua +++ b/tests/args_single_dir_enabled_spec.lua @@ -5,6 +5,8 @@ local stub = require "luassert.stub" describe("The args single dir enabled config", function() local no_restore_hook_called = false local as = require "auto-session" + local c = require "auto-session.config" + as.setup { args_allow_single_directory = true, args_allow_files_auto_save = false, @@ -38,7 +40,7 @@ describe("The args single dir enabled config", function() it("does not autosave for cwd if single directory arg does not have a session", function() no_restore_hook_called = false --enable autosave for this test - as.conf.auto_save_enabled = true + c.auto_save = true local s = stub(vim.fn, "argv") s.returns { "tests" } @@ -52,7 +54,7 @@ describe("The args single dir enabled config", function() -- Revert the stub vim.fn.argv:revert() - as.conf.auto_save_enabled = false + c.auto_save = false end) it("does restore a session when run with a single directory", function() diff --git a/tests/cmds_custom_dir_spec.lua b/tests/cmds_custom_dir_spec.lua index 8af6818..2dfdf59 100644 --- a/tests/cmds_custom_dir_spec.lua +++ b/tests/cmds_custom_dir_spec.lua @@ -8,7 +8,7 @@ describe("The default config", function() } local custom_sessions_dir = vim.fn.getcwd() .. "/tests/custom_sessions/" - local cwd_session_name = M.escapeSessionName(vim.fn.getcwd()) + local cwd_session_name = TL.escapeSessionName(vim.fn.getcwd()) local cwd_session_path = custom_sessions_dir .. cwd_session_name .. ".vim" local named_session_path = custom_sessions_dir .. TL.named_session_name .. ".vim" diff --git a/tests/cmds_enable_toggle_spec.lua b/tests/cmds_enable_toggle_spec.lua index 93fe002..53d46dc 100644 --- a/tests/cmds_enable_toggle_spec.lua +++ b/tests/cmds_enable_toggle_spec.lua @@ -1,28 +1,29 @@ describe("The default config", function() local as = require "auto-session" + local c = require "auto-session.config" as.setup {} it("can disable autosave", function() - as.conf.auto_save_enabled = true + c.auto_save = true vim.cmd "SessionDisableAutoSave" - assert.False(as.conf.auto_save_enabled) + assert.False(c.auto_save) end) it("can enable autosave", function() - as.conf.auto_save_enabled = false + c.auto_save = false vim.cmd "SessionDisableAutoSave!" - assert.True(as.conf.auto_save_enabled) + assert.True(c.auto_save) end) it("can toggle autosave", function() - assert.True(as.conf.auto_save_enabled) + assert.True(c.auto_save) vim.cmd "SessionToggleAutoSave" - assert.False(as.conf.auto_save_enabled) + assert.False(c.auto_save) vim.cmd "SessionToggleAutoSave" - assert.True(as.conf.auto_save_enabled) + assert.True(c.auto_save) end) end) diff --git a/tests/cmds_spec.lua b/tests/cmds_spec.lua index 052cedd..cda4f8f 100644 --- a/tests/cmds_spec.lua +++ b/tests/cmds_spec.lua @@ -3,6 +3,8 @@ local TL = require "tests/test_lib" describe("The default config", function() local as = require "auto-session" + local Lib = require "auto-session.lib" + local c = require "auto-session.config" as.setup { -- log_level = "debug", } @@ -80,12 +82,12 @@ describe("The default config", function() assert.equals(1, vim.fn.bufexists(TL.test_file)) - assert.equals(TL.named_session_name, require("auto-session").Lib.current_session_name()) - assert.equals(TL.named_session_name, require("auto-session").Lib.current_session_name(true)) + assert.equals(TL.named_session_name, require("auto-session.lib").current_session_name()) + assert.equals(TL.named_session_name, require("auto-session.lib").current_session_name(true)) end) it("can complete session names", function() - local sessions = as.Lib.complete_session_for_dir(TL.session_dir, "") + local sessions = Lib.complete_session_for_dir(TL.session_dir, "") -- print(vim.inspect(sessions)) assert.True(vim.tbl_contains(sessions, TL.default_session_name)) @@ -93,7 +95,7 @@ describe("The default config", function() print(vim.inspect(sessions)) -- With my prefix, only named session should be present - sessions = as.Lib.complete_session_for_dir(TL.session_dir, "my") + sessions = Lib.complete_session_for_dir(TL.session_dir, "my") assert.False(vim.tbl_contains(sessions, TL.default_session_name)) assert.True(vim.tbl_contains(sessions, TL.named_session_name)) end) @@ -115,7 +117,7 @@ describe("The default config", function() vim.cmd("SessionDelete " .. TL.named_session_name) -- Auto save should be disabled when deleting the current session - assert.False(as.conf.auto_save_enabled) + assert.False(c.auto_save) -- Deleting current session should set vim.v.this_session = "" assert.True(vim.v.this_session == "") @@ -131,10 +133,10 @@ describe("The default config", function() assert.equals(1, vim.fn.bufexists(TL.test_file)) -- auto_save_enabled will be disabled by delete above - assert.False(as.conf.auto_save_enabled) + assert.False(c.auto_save) -- enable it - as.conf.auto_save_enabled = true + c.auto_save = true as.AutoSaveSession() diff --git a/tests/extra_sesssion_commands_spec.lua b/tests/extra_sesssion_commands_spec.lua index 2f1a262..46cf933 100644 --- a/tests/extra_sesssion_commands_spec.lua +++ b/tests/extra_sesssion_commands_spec.lua @@ -5,6 +5,7 @@ TL.clearSessionFilesAndBuffers() describe("Config with extra session commands", function() local save_extra_cmds_called = false local as = require "auto-session" + local Lib = require "auto-session.lib" as.setup { save_extra_cmds = { function() @@ -64,10 +65,10 @@ describe("Config with extra session commands", function() end) it("can correctly differentiate x.vim session and xx.vim custom commands", function() - assert.True(as.Lib.is_session_file(TL.session_dir .. TL.default_session_name .. ".vim")) - assert.False(as.Lib.is_session_file(TL.session_dir .. TL.default_session_name .. "x.vim")) - assert.True(as.Lib.is_session_file(TL.session_dir .. session_name .. ".vim")) - assert.False(as.Lib.is_session_file(TL.session_dir .. session_name .. "x.vim")) + assert.True(Lib.is_session_file(TL.session_dir .. TL.default_session_name .. ".vim")) + assert.False(Lib.is_session_file(TL.session_dir .. TL.default_session_name .. "x.vim")) + assert.True(Lib.is_session_file(TL.session_dir .. session_name .. ".vim")) + assert.False(Lib.is_session_file(TL.session_dir .. session_name .. "x.vim")) end) it("deletes a default session's extra commands when deleting the session", function() diff --git a/tests/git_spec.lua b/tests/git_spec.lua index cf9b851..992b96b 100644 --- a/tests/git_spec.lua +++ b/tests/git_spec.lua @@ -3,6 +3,7 @@ local TL = require "tests/test_lib" describe("The git config", function() local as = require "auto-session" + local Lib = require "auto-session.lib" as.setup { auto_session_use_git_branch = true, -- log_level = "debug", @@ -60,7 +61,7 @@ describe("The git config", function() -- print(session_path) assert.equals(1, vim.fn.filereadable(branch_session_path)) - assert.equals(vim.fn.getcwd() .. " (branch: main)", as.Lib.current_session_name()) + assert.equals(vim.fn.getcwd() .. " (branch: main)", Lib.current_session_name()) end) it("Autorestores a session with the branch name", function() @@ -73,7 +74,7 @@ describe("The git config", function() assert.equals(1, vim.fn.filereadable(branch_session_path)) - assert.equals(vim.fn.getcwd() .. " (branch: main)", as.Lib.current_session_name()) + assert.equals(vim.fn.getcwd() .. " (branch: main)", Lib.current_session_name()) end) it("can migrate an old git session", function() @@ -95,7 +96,7 @@ describe("The git config", function() assert.equals(1, vim.fn.filereadable(branch_session_path)) assert.equals(0, vim.fn.filereadable(legacy_branch_session_path)) - assert.equals(vim.fn.getcwd() .. " (branch: main)", as.Lib.current_session_name()) + assert.equals(vim.fn.getcwd() .. " (branch: main)", Lib.current_session_name()) end) it("can get the session name of a git branch with a slash", function() @@ -105,8 +106,8 @@ describe("The git config", function() local session_path = TL.session_dir .. TL.escapeSessionName(vim.fn.getcwd() .. "|slash/branch") .. ".vim" assert.equals(1, vim.fn.filereadable(session_path)) - assert.equals(vim.fn.getcwd() .. " (branch: slash/branch)", as.Lib.current_session_name()) - assert.equals(git_test_dir .. " (branch: slash/branch)", as.Lib.current_session_name(true)) - print(as.Lib.current_session_name()) + assert.equals(vim.fn.getcwd() .. " (branch: slash/branch)", Lib.current_session_name()) + assert.equals(git_test_dir .. " (branch: slash/branch)", Lib.current_session_name(true)) + print(Lib.current_session_name()) end) end) diff --git a/tests/lib_spec.lua b/tests/lib_spec.lua index f3a0954..fbd790f 100644 --- a/tests/lib_spec.lua +++ b/tests/lib_spec.lua @@ -5,7 +5,7 @@ describe("Lib / Helper functions", function() local as = require "auto-session" as.setup {} - local Lib = as.Lib + local Lib = require "auto-session.lib" TL.clearSessionFilesAndBuffers() @@ -45,8 +45,8 @@ describe("Lib / Helper functions", function() it("get_last_session() returns nil when no session", function() ---@diagnostic disable-next-line: missing-parameter - assert.equals(nil, as.Lib.get_latest_session()) - assert.equals(nil, as.Lib.get_latest_session(TL.session_dir)) + assert.equals(nil, Lib.get_latest_session()) + assert.equals(nil, Lib.get_latest_session(TL.session_dir)) end) it("can percent encode/decode", function() diff --git a/tests/session_control_spec.lua b/tests/session_control_spec.lua index dd0b56f..5615ed4 100644 --- a/tests/session_control_spec.lua +++ b/tests/session_control_spec.lua @@ -2,7 +2,10 @@ local TL = require "tests/test_lib" describe("The default config", function() - require("auto-session").setup { + local as = require "auto-session" + local Lib = require "auto-session.lib" + + as.setup { -- log_level = "debug", } @@ -46,15 +49,13 @@ describe("The default config", function() -- 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) + local session_control = 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.named_session_path), session_control.current) - assert.equals(as.Lib.expand(TL.default_session_path), session_control.alternate) + assert.equals(Lib.expand(TL.named_session_path), session_control.current) + assert.equals(Lib.expand(TL.default_session_path), session_control.alternate) end) it("Saving twice doesn't set alternate", function() @@ -68,28 +69,24 @@ describe("The default config", function() -- 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) + local session_control = 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) + assert.equals(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) + assert.equals(Lib.expand(TL.named_session_path), session_control.alternate) end) it("lib function handles edge cases", function() - local as = require "auto-session" - -- Don't throw an error on nil - local session_control = as.Lib.load_session_control_file(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 = as.Lib.load_session_control_file "tests/session_control_spec.lua" + session_control = Lib.load_session_control_file "tests/session_control_spec.lua" assert.equals("table", type(session_control)) end) end) diff --git a/tests/session_lens_spec.lua b/tests/session_lens_spec.lua index c63f40d..9ecacee 100644 --- a/tests/session_lens_spec.lua +++ b/tests/session_lens_spec.lua @@ -3,6 +3,7 @@ local TL = require "tests/test_lib" describe("Session lens", function() local as = require "auto-session" + local session_lens = require "auto-session.session-lens" as.setup { -- log_level = "debug", } @@ -11,9 +12,7 @@ describe("Session lens", function() as.SaveSession() as.SaveSession "project_x" - -- initialize session_lens - assert.True(as.setup_session_lens()) - local make_telescope_entry = as.session_lens.make_telescope_callback {} + local make_telescope_entry = session_lens.make_telescope_callback {} local data = make_telescope_entry(TL.escapeSessionName(TL.default_session_name) .. ".vim") assert.not_nil(data) diff --git a/tests/suppress_dirs_spec.lua b/tests/suppress_dirs_spec.lua index cee8a37..79a1c26 100644 --- a/tests/suppress_dirs_spec.lua +++ b/tests/suppress_dirs_spec.lua @@ -3,6 +3,7 @@ local TL = require "tests/test_lib" describe("The suppress dirs config", function() local as = require "auto-session" + local c = require "auto-session.config" as.setup { auto_session_root_dir = TL.session_dir, @@ -38,7 +39,7 @@ describe("The suppress dirs config", function() it("doesn't save a session for an allowed dir with a glob", function() TL.clearSessionFilesAndBuffers() vim.cmd("e " .. TL.test_file) - as.conf.auto_session_suppress_dirs = { vim.fn.getcwd() .. "/tests/*" } + c.suppressed_dirs = { vim.fn.getcwd() .. "/tests/*" } -- Change to a sub directory to see if it's allowed vim.cmd "cd tests/test_files" diff --git a/tests/test_lib.lua b/tests/test_lib.lua index fad250f..4d2ec1e 100644 --- a/tests/test_lib.lua +++ b/tests/test_lib.lua @@ -1,5 +1,5 @@ local asLib = require "auto-session.lib" -M = {} +local M = {} -- This disables the headless check inside autosession -- I couldn't find a good way to mock out the calls to make this unnecessary