Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stevearc/resession.nvim
A replacement for mksession with a better API
https://github.com/stevearc/resession.nvim
neovim neovim-plugin nvim nvim-plugin
Last synced: 3 days ago
JSON representation
A replacement for mksession with a better API
- Host: GitHub
- URL: https://github.com/stevearc/resession.nvim
- Owner: stevearc
- License: mit
- Created: 2022-09-09T05:31:03.000Z (about 2 years ago)
- Default Branch: master
- Last Pushed: 2024-08-16T22:22:27.000Z (3 months ago)
- Last Synced: 2024-08-16T23:29:48.663Z (3 months ago)
- Topics: neovim, neovim-plugin, nvim, nvim-plugin
- Language: Lua
- Homepage:
- Size: 113 KB
- Stars: 201
- Watchers: 3
- Forks: 13
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# resession.nvim
A replacement for `:mksession` with a better API
- **No magic behavior**. Only does what you tell it.
- Supports **tab-scoped sessions**.
- Extensive **customizability** in what gets saved/restored.
- Easy to write **extensions** for other plugins.---
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Guides](#guides)
- [Automatically save a session when you exit Neovim](#automatically-save-a-session-when-you-exit-neovim)
- [Periodically save the current session](#periodically-save-the-current-session)
- [Create one session per directory](#create-one-session-per-directory)
- [Create one session per git branch](#create-one-session-per-git-branch)
- [Use tab-scoped sessions](#use-tab-scoped-sessions)
- [Saving custom data with an extension](#saving-custom-data-with-an-extension)
- [Setup options](#setup-options)
- [API](#api)
- [setup(config)](#setupconfig)
- [load_extension(name, opts)](#load_extensionname-opts)
- [get_current()](#get_current)
- [get_current_session_info()](#get_current_session_info)
- [detach()](#detach)
- [list(opts)](#listopts)
- [delete(name, opts)](#deletename-opts)
- [save(name, opts)](#savename-opts)
- [save_tab(name, opts)](#save_tabname-opts)
- [save_all(opts)](#save_allopts)
- [load(name, opts)](#loadname-opts)
- [add_hook(name, callback)](#add_hookname-callback)
- [remove_hook(name, callback)](#remove_hookname-callback)
- [default_buf_filter(bufnr)](#default_buf_filterbufnr)
- [is_loading()](#is_loading)
- [Extensions](#extensions)
- [FAQ](#faq)## Requirements
- Neovim 0.8+
## Installation
resession supports all the usual plugin managers
lazy.nvim
```lua
{
'stevearc/resession.nvim',
opts = {},
}
```Packer
```lua
require("packer").startup(function()
use({
"stevearc/resession.nvim",
config = function()
require("resession").setup()
end,
})
end)
```Paq
```lua
require("paq")({
{ "stevearc/resession.nvim" },
})
```Neovim native package
```sh
git clone --depth=1 https://github.com/stevearc/resession.nvim.git \
"${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/pack/resession/start/resession.nvim
```## Quick start
```lua
local resession = require("resession")
resession.setup()
-- Resession does NOTHING automagically, so we have to set up some keymaps
vim.keymap.set("n", "ss", resession.save)
vim.keymap.set("n", "sl", resession.load)
vim.keymap.set("n", "sd", resession.delete)
```Now you can use `ss` to save a session. When you want to load a session, use `sl`.
## Guides
### Automatically save a session when you exit Neovim
```lua
vim.api.nvim_create_autocmd("VimLeavePre", {
callback = function()
-- Always save a special session named "last"
resession.save("last")
end,
})
```### Periodically save the current session
When you are attached to a session (have saved or loaded a session), use this config to periodically re-save that session in the background.
```lua
require("resession").setup({
autosave = {
enabled = true,
interval = 60,
notify = true,
},
})
```### Create one session per directory
Load a dir-specific session when you open Neovim, save it when you exit.
```lua
vim.api.nvim_create_autocmd("VimEnter", {
callback = function()
-- Only load the session if nvim was started with no args
if vim.fn.argc(-1) == 0 then
-- Save these to a different directory, so our manual sessions don't get polluted
resession.load(vim.fn.getcwd(), { dir = "dirsession", silence_errors = true })
end
end,
nested = true,
})
vim.api.nvim_create_autocmd("VimLeavePre", {
callback = function()
resession.save(vim.fn.getcwd(), { dir = "dirsession", notify = false })
end,
})
```### Create one session per git branch
Same as above, but have a separate session for each git branch in a directory.
```lua
local function get_session_name()
local name = vim.fn.getcwd()
local branch = vim.trim(vim.fn.system("git branch --show-current"))
if vim.v.shell_error == 0 then
return name .. branch
else
return name
end
end
vim.api.nvim_create_autocmd("VimEnter", {
callback = function()
-- Only load the session if nvim was started with no args
if vim.fn.argc(-1) == 0 then
resession.load(get_session_name(), { dir = "dirsession", silence_errors = true })
end
end,
})
vim.api.nvim_create_autocmd("VimLeavePre", {
callback = function()
resession.save(get_session_name(), { dir = "dirsession", notify = false })
end,
})
```### Use tab-scoped sessions
When saving a session, only save the current tab
```lua
-- Bind `save_tab` instead of `save`
vim.keymap.set("n", "ss", resession.save_tab)
vim.keymap.set("n", "sl", resession.load)
vim.keymap.set("n", "sd", resession.delete)
```This will save only the current tabpage layout, but will save _all_ of the open buffers. You can provide a filter to exclude buffers. For example, if you are using `:tcd` to have tabs open for different directories, this will only save buffers in the current tabpage directory:
```lua
require("resession").setup({
tab_buf_filter = function(tabpage, bufnr)
local dir = vim.fn.getcwd(-1, vim.api.nvim_tabpage_get_number(tabpage))
-- ensure dir has trailing /
dir = dir:sub(-1) ~= "/" and dir .. "/" or dir
return vim.startswith(vim.api.nvim_buf_get_name(bufnr), dir)
end,
})
```### Saving custom data with an extension
To create an extension, create a file in your runtimepath at `lua/resession/extensions/myplugin.lua`. Add the following contents:
```lua
local M = {}---Get the saved data for this extension
---@param opts resession.Extension.OnSaveOpts Information about the session being saved
---@return any
M.on_save = function(opts)
return {}
end---Restore the extension state
---@param data The value returned from on_save
M.on_pre_load = function(data)
-- This is run before the buffers, windows, and tabs are restored
end---Restore the extension state
---@param data The value returned from on_save
M.on_post_load = function(data)
-- This is run after the buffers, windows, and tabs are restored
end---Called when resession gets configured
---This function is optional
---@param data table The configuration data passed in the config
M.config = function(data)
--
end---Check if a window is supported by this extension
---This function is optional, but if provided save_win and load_win must
---also be present.
---@param winid integer
---@param bufnr integer
---@return boolean
M.is_win_supported = function(winid, bufnr)
return true
end---Save data for a window
---@param winid integer
---@return any
M.save_win = function(winid)
-- This is used to save the data for a specific window that contains a non-file buffer (e.g. a filetree).
return {}
end---Called with the data from save_win
---@param winid integer
---@param config any
---@return integer|nil If the original window has been replaced, return the new ID that should replace it
M.load_win = function(winid, config)
-- Restore the window from the config
endreturn M
```Then to activate it, users can add the extension to their call to `setup`:
```lua
require("resession").setup({
extensions = {
myplugin = {
-- these args will get passed in to M.config()
},
},
})
```For tab-scoped sessions, the `on_save` and `on_load` methods of extensions will be **disabled by default**. There is a special config argument always available that can override this:
```lua
require("resession").setup({
extensions = {
myplugin = {
enable_in_tab = true,
},
},
})
```Refer to [the quickfix extension](lua/resession/extensions/quickfix.lua) for a complete example.
## Setup options
```lua
require("resession").setup({
-- Options for automatically saving sessions on a timer
autosave = {
enabled = false,
-- How often to save (in seconds)
interval = 60,
-- Notify when autosaved
notify = true,
},
-- Save and restore these options
options = {
"binary",
"bufhidden",
"buflisted",
"cmdheight",
"diff",
"filetype",
"modifiable",
"previewwindow",
"readonly",
"scrollbind",
"winfixheight",
"winfixwidth",
},
-- Custom logic for determining if the buffer should be included
buf_filter = require("resession").default_buf_filter,
-- Custom logic for determining if a buffer should be included in a tab-scoped session
tab_buf_filter = function(tabpage, bufnr)
return true
end,
-- The name of the directory to store sessions in
dir = "session",
-- Show more detail about the sessions when selecting one to load.
-- Disable if it causes lag.
load_detail = true,
-- List order ["modification_time", "creation_time", "filename"]
load_order = "modification_time",
-- Configuration for extensions
extensions = {
quickfix = {},
},
})
```## API
### setup(config)
`setup(config)` \
Initialize resession with configuration options| Param | Type | Desc |
| ------ | ------- | ---- |
| config | `table` | |### load_extension(name, opts)
`load_extension(name, opts)` \
Load an extension some time after calling setup()| Param | Type | Desc |
| ----- | -------- | ----------------------------------- |
| name | `string` | Name of the extension |
| opts | `table` | Configuration options for extension |### get_current()
`get_current(): string` \
Get the name of the current sessionReturns:
| Type | Desc |
| ------ | ---- |
| string | ? |### get_current_session_info()
`get_current_session_info(): nil|resession.SessionInfo` \
Get information about the current session### detach()
`detach()` \
Detach from the current session### list(opts)
`list(opts): string[]` \
List all available saved sessions| Param | Type | Desc | |
| ----- | ------------------------- | ------------- | ------------------------------------------------ |
| opts | `nil\|resession.ListOpts` | | |
| | dir | `nil\|string` | Name of directory to list (overrides config.dir) |### delete(name, opts)
`delete(name, opts)` \
Delete a saved session| Param | Type | Desc | |
| ----- | --------------------------- | --------------------------------------------- | ------------------------------------------------------- |
| name | `nil\|string` | If not provided, prompt for session to delete | |
| opts | `nil\|resession.DeleteOpts` | | |
| | dir | `nil\|string` | Name of directory to delete from (overrides config.dir) |### save(name, opts)
`save(name, opts)` \
Save a session to disk| Param | Type | Desc | |
| ----- | ------------------------- | -------------- | ---------------------------------------------------- |
| name | `nil\|string` | | |
| opts | `nil\|resession.SaveOpts` | | |
| | attach | `nil\|boolean` | Stay attached to session after saving (default true) |
| | notify | `nil\|boolean` | Notify on success |
| | dir | `nil\|string` | Name of directory to save to (overrides config.dir) |### save_tab(name, opts)
`save_tab(name, opts)` \
Save a tab-scoped session| Param | Type | Desc | |
| ----- | ------------------------- | -------------------------------------------------- | ---------------------------------------------------- |
| name | `nil\|string` | If not provided, will prompt user for session name | |
| opts | `nil\|resession.SaveOpts` | | |
| | attach | `nil\|boolean` | Stay attached to session after saving (default true) |
| | notify | `nil\|boolean` | Notify on success |
| | dir | `nil\|string` | Name of directory to save to (overrides config.dir) |### save_all(opts)
`save_all(opts)` \
Save all current sessions to disk| Param | Type | Desc | |
| ----- | ---------------------------- | -------------- | ----------------- |
| opts | `nil\|resession.SaveAllOpts` | | |
| | notify | `nil\|boolean` | Notify on success |### load(name, opts)
`load(name, opts)` \
Load a session| Param | Type | Desc | |
| ----- | ------------------------- | ---------------------- | ------------------------------------------------------------ |
| name | `nil\|string` | | |
| opts | `nil\|resession.LoadOpts` | | |
| | attach | `nil\|boolean` | Stay attached to session after loading (default true) |
| | reset | `nil\|boolean\|"auto"` | Close everything before loading the session (default "auto") |
| | silence_errors | `nil\|boolean` | Don't error when trying to load a missing session |
| | dir | `nil\|string` | Name of directory to load from (overrides config.dir) |**Note:**
The default value of `reset = "auto"` will reset when loading a normal session, but _not_ when
loading a tab-scoped session.### add_hook(name, callback)
`add_hook(name, callback)` \
Add a callback that runs at a specific time| Param | Type | Desc |
| -------- | -------------------------------------------------- | ---- |
| name | `"pre_save"\|"post_save"\|"pre_load"\|"post_load"` | |
| callback | `fun(...: any)` | |### remove_hook(name, callback)
`remove_hook(name, callback)` \
Remove a hook callback| Param | Type | Desc |
| -------- | -------------------------------------------------- | ---- |
| name | `"pre_save"\|"post_save"\|"pre_load"\|"post_load"` | |
| callback | `fun(...: any)` | |### default_buf_filter(bufnr)
`default_buf_filter(bufnr): boolean` \
The default config.buf_filter (takes all buflisted files with "", "acwrite", or "help" buftype)| Param | Type | Desc |
| ----- | --------- | ---- |
| bufnr | `integer` | |### is_loading()
`is_loading(): boolean` \
Returns true if a session is currently being loaded## Extensions
- [quickfix](lua/resession/extensions/quickfix.lua) (built-in)
- [aerial.nvim](https://github.com/stevearc/aerial.nvim)
- [overseer.nvim](https://github.com/stevearc/overseer.nvim)
- [telescope-resession.nvim](https://github.com/scottmckendry/telescope-resession.nvim) - alternative save/load UI## FAQ
**Q: Why another session plugin?**
A: All the other plugins use `:mksession` under the hood
**Q: Why don't you want to use `:mksession`?**
A: While it's amazing that this feature is built-in to vim, and it does an impressively good job for most situations, it is very difficult to customize. If `:help sessionoptions` covers your use case, then you're golden. If you want anything else, you're out of luck.