Disposable, per-filetype scratch buffers for Neovim. One Lua scratchpad, one SQL scratchpad, one JSON scratchpad — each a single reusable buffer that opens instantly with the right filetype, syntax highlighting, and LSP attached if your config provides one.
Optionally persistent: scratch content can survive Neovim restarts.
Neovim 0.11+ (uses the current vim.validate signature and nvim_open_win's
split field).
With lazy.nvim:
{
"zaier84/scratch.nvim",
config = function()
require("scratch").setup()
end,
}setup() is optional — the plugin works with defaults if you never call it.
Defaults:
require("scratch").setup({
window = "vsplit", -- "vsplit" | "split" | "float" | "current"
float = {
relative = "editor",
width = 40,
height = 10,
},
persist = {
enable = false,
dir = vim.fs.joinpath(vim.fn.stdpath("data"), "scratch"),
},
templates = {},
})window controls how the scratch buffer is displayed. current reuses the
current window instead of creating a new one.
persist.enable turns on saving to disk. persist.dir is where scratch files
live; the directory is created on first save.
templates maps a filetype to the lines a fresh scratch buffer starts with.
| Command | Description |
|---|---|
:ScratchOpen [filetype] |
Open or focus the scratch buffer for a filetype. With no argument, uses the current buffer's filetype. Tab-completes filetypes. |
:ScratchClose |
Save (if persistence is on) and wipe the current scratch buffer. |
:ScratchCloseAll |
Same, for every open scratch buffer. |
:ScratchList |
List active scratch buffers with visibility and line count. |
Inside a scratch buffer, q dismisses the window without destroying the
buffer — content stays in memory and reopening restores it. If the scratch is
the only window open, q replaces it with an empty buffer instead of closing.
Give a filetype a starting point:
require("scratch").setup({
templates = {
lua = { "-- scratch", "" },
python = { "#!/usr/bin/env python3", "" },
sql = { "-- scratch", "" },
},
})Each value is a list of lines. Templates apply only when a scratch buffer is created fresh — if persisted content exists for that filetype, it wins and the template is skipped. This includes an empty persisted file: if you clear a scratch and save it, it stays cleared rather than having the template come back.
Filetypes with no configured template open empty.
With persist.enable = true, scratch content is written to disk when you leave
the buffer, when Neovim exits, and when you press :w.
:w works because persistent scratch buffers use buftype = "acwrite" with a
BufWriteCmd handler. Without persistence they stay nofile, and :w is not
meaningful.
Files are named after the filetype, sanitised to [A-Za-z0-9_-]. Compound
filetypes collapse (html.eruby becomes html_eruby), which means two
filetypes differing only in punctuation would share a file. In practice this
does not come up.
Memory is the source of truth. Persisted content is read only when a scratch buffer is first created in a session. Reopening an existing buffer never re-reads from disk, so unsaved edits are preserved. If two Neovim instances edit the same filetype's scratch, the last one to save wins.
Scratch buffers are per-filetype singletons. A registry maps filetype to
buffer handle and validates on read, so stale handles from a manual
:bwipeout are evicted rather than returned.
Windows are searched in the current tabpage only. If a scratch buffer is
already visible in another tab, :ScratchOpen opens a second window in the
current tab rather than pulling focus across tabpages. Two windows on one
buffer is a normal Neovim state; teleporting the user is not.
Saving has one gate. Persistence enabled, buffer valid, buffer modified — all three checked in a single place, so no save path can skip one.
- No test suite yet.
- Toggling
persist.enablemid-session does not affect scratch buffers that already exist —buftypeis fixed at creation. - Scratch files are not project-scoped. All projects share one scratchpad per filetype.
- The cursor starts at line 1 on a freshly templated buffer rather than below the template.
MIT