Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true

[*.lua]
indent_style = space
indent_size = 2

[*.{md,txt}]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab
58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CI

on:
push:
branches: [main]
pull_request:

jobs:
stylua:
name: stylua
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: JohnnyMorganz/stylua-action@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
version: latest
args: --check .

lint:
name: luacheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: leafo/gh-actions-lua@v10
with:
luaVersion: "5.1"
- uses: leafo/gh-actions-luarocks@v4
- run: luarocks install luacheck
- run: luacheck lua plugin

smoke:
name: load (nvim ${{ matrix.nvim }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
nvim: ["v0.10.4", "stable", "nightly"]
steps:
- uses: actions/checkout@v4
with:
path: persistence-scope.nvim
- uses: rhysd/action-setup-vim@v1
with:
neovim: true
version: ${{ matrix.nvim }}
- name: Clone folke/persistence.nvim
run: git clone --depth=1 https://github.com/folke/persistence.nvim
- name: Headless smoke test
run: |
nvim --headless --noplugin -u NONE \
--cmd "set rtp+=persistence.nvim" \
--cmd "set rtp+=persistence-scope.nvim" \
--cmd "runtime plugin/persistence_scope.lua" \
-c "lua require('persistence_scope').setup({ provider = function() return nil end })" \
-c "lua assert(type(require('persistence_scope').restore) == 'function')" \
-c "checkhealth persistence_scope" \
-c "qa!"
27 changes: 27 additions & 0 deletions .luacheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-- vim: ft=lua tw=80

stds.nvim = {
globals = {
"vim",
},
read_globals = {
"Snacks",
},
}

std = "min+nvim"
cache = true

self = false
codes = true
max_line_length = 120

ignore = {
"212", -- unused argument
"631", -- max_line_length
}

files["lua/persistence_scope/util.lua"] = {
-- shadowing `error` from the global namespace is intentional in some lua helpers
ignore = { "431" },
}
62 changes: 55 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ review. They all collide on the same session file and clobber each other.

`persistence-scope.nvim` fixes that by adding a **scope** to the session path.
By default it uses the current tmux window name; each Neovim instance gets its
own isolated session scoped to it's tmux window name for automatic persistence
own isolated session scoped to its tmux window name for automatic persistence
and restoration.

```text
Expand All @@ -35,6 +35,9 @@ and restoration.
└── %home%me%project.vim
```

> Sessions are still written by `folke/persistence.nvim` β€” this plugin only
> redirects them into a per-scope subdirectory and adds a smarter picker on top.

> Not a tmux user? Bring your own scope β€” any Lua function works (see [Custom providers](#custom-providers)).

## πŸ“š Contents
Expand All @@ -49,6 +52,7 @@ and restoration.
- [Providers](#-providers)
- [Restore Behavior](#-restore-behavior)
- [Examples](#-examples)
- [Troubleshooting](#-troubleshooting)
- [FAQ](#-faq)
- [Acknowledgements](#-acknowledgements)
- [License](#-license)
Expand Down Expand Up @@ -93,10 +97,32 @@ With [`lazy.nvim`](https://github.com/folke/lazy.nvim):
}
```

With Neovim's native package manager (`vim.pack`, Neovim `>= 0.12`):

```lua
vim.pack.add({
{ src = "https://github.com/folke/persistence.nvim" },
{ src = "https://github.com/folke/snacks.nvim" }, -- optional, for the rich picker
{ src = "https://github.com/avgvstvs96/persistence-scope.nvim" },
})

require("persistence_scope").setup({
provider = "tmux_window_name",
})

vim.keymap.set("n", "<leader>qr", function()
require("persistence_scope").restore()
end, { desc = "Restore session" })

vim.keymap.set("n", "<leader>qs", function()
require("persistence_scope").select()
end, { desc = "Select session" })
```

>[!IMPORTANT]
>`persistence-scope.nvim` calls `require("persistence").setup()` for you.
> If you already configure `persistence.nvim` separately, move those options
> into this plugin's `opts` and remove the standalone setup call.
> into this plugin's `opts` / `setup()` call and remove the standalone setup call.

## ⚑ Quick Start

Expand Down Expand Up @@ -145,8 +171,8 @@ Defaults β€” pass any subset to `opts`:

```lua
require("persistence_scope").setup({
-- Scope used to choose the session directory.
-- Built-in providers (see below) or a custom function.
-- Scope used to choose the session directory. Either the name of a
-- built-in provider (see below) or a function returning a scope table.
provider = "tmux_window_name",

-- Picker used by `select()` and ambiguous restores.
Expand All @@ -155,13 +181,18 @@ require("persistence_scope").setup({
-- "vim_ui" β†’ force vim.ui.select
picker = "auto",

-- Base directory for all session files.
-- Base directory for all session files. The current scope's directory
-- is appended to this for the actual save location.
base_dir = vim.fn.stdpath("state") .. "/sessions/",

-- Forwarded to persistence.nvim. When true, non-main branches get
-- their own session files.
branch = true,

-- Forwarded to persistence.nvim. Minimum file buffers required for
-- autosave. `nil` uses the upstream default (1). Set to 0 to always save.
need = nil,

-- If more than one current-scope session was modified within this
-- window of time, restore opens the picker instead of guessing.
recent_seconds = 4 * 60 * 60,
Expand All @@ -171,6 +202,9 @@ require("persistence_scope").setup({
})
```

All options are optional β€” `require("persistence_scope").setup()` with no
arguments works fine and uses the defaults shown above.

## πŸ”Œ Providers

A provider is just a function that returns a **scope table** (or `nil`):
Expand All @@ -193,7 +227,7 @@ no extra scope directory.
| --- | --- | --- |
| `"tmux_window_name"` *(default)* | `#{window_name}` | `tmux-api/` |
| `"tmux_window_index"` | `#{window_index}` | `tmux-window-2/` |
| `"tmux_pane_id"` | `#{pane_id}` | `tmux-pane-%17/` |
| `"tmux_pane_id"` | `#{pane_id}` | `tmux-pane-_17/` *(`%` is sanitized to `_`)* |
| `"tmux_pane_index"` | `#{pane_index}` | `tmux-pane-0/` |
| `"tmux_session_window"` | `#{session_name}:#{window_name}` | `tmux-work_api/` |

Expand Down Expand Up @@ -235,6 +269,20 @@ require("persistence_scope").setup({
If nothing matches at all, you get a friendly `vim.notify` and no session is
sourced.

## 🩺 Troubleshooting

Run `:checkhealth persistence_scope` β€” it reports your Neovim version, whether
`persistence.nvim` / `snacks.nvim` are installed, the resolved scope, where
sessions are being saved, and how many session files already exist.

If scoping doesn't seem to be working:

1. Confirm `:checkhealth` shows a non-`global` scope.
2. Make sure nothing else in your config calls `require("persistence").setup()`
*after* this plugin loads (see the FAQ entry below).
3. Check `:lua = require("persistence_scope").config.base_dir` and inspect the
subdirectories there.

## πŸ§ͺ Examples

### Scope by tmux window name (default)
Expand Down Expand Up @@ -304,7 +352,7 @@ instead:
{
"avgvstvs96/persistence-scope.nvim",
dependencies = { "folke/persistence.nvim" },
opts = { branch = true, need = 1, provider = "tmux_window" },
opts = { branch = true, need = 1, provider = "tmux_window_name" },
}
```

Expand Down
Loading
Loading