Cavediver
A novel approach on file navigation context management in Neovim buffers.
Install / Use
/learn @kampanaut/CavediverREADME
Cavediver
Introduction
This is a navigation context manager system. Let me explain what that is: have you ever felt lost after unconsciously jumping to files trying to get around the codebase just because you forgot to be conscious about it? Like some jumps earlier you should have remembered your current filename, but you were too busy thinking about the problem at hand not the filename itself. And also sometimes you don't want to mess up your current jumping setup, like, at some point you have decided to just swap between files A and B, with A being your current file, and now you have to go to C. In traditional neovim, B would have been forgotten, and now you can only jump between A and C. It's fine if you remember the full filename of B, what if you forgot? And now it gets annoying to try remember it and then it just interrupts your flow, trying to go back to only swap between A and B.
This is the kind of problem this plugin solves for you. We introduce mainly Triquetra buffer system. This is the novel part of the project. In a way because of how the triquetra buffers are presented in the UI, this gives you at least a semblance of your current jumping setup. And I have designed this in a way, that you can always restore the secondary buffer and the ternary buffer so you can always get back to what once was. There are other neat features as well, just read the How to Use section below.
Functions
- Triquetra Buffer System: Each window maintains current/secondary/ternary buffer relationships with a primary buffer
- Session Persistence: Buffer relationships survive restarts through hash-based file identification
- Cycling Mode: Explore buffers without losing your working context
- Context Preservation: Remembers where buffers came from for restoration
- Buffer Lifecycle: Closed buffers reopen when accessed through relationships
- Visual Feedback: Color-coded bufferline and winbar show buffer relationships
- Per-Window Tracking: Independent buffer relationships for each window
New Feature
- Multi-version primary buffer
You can backtrack now your previous primary buffer. Every time you set a new buffer as a primary, it is put in the first of a queue (primary_buffers). The first one is always the primary, the others are the "previous".
- You can now then manage it with a window pop-up, it is editable like that in harpoon window.
- Delete-yank and then paste it in another place to reorder...
- Or just delete, to really remove it.
- Type up a filereadable filepath and just save.
- The system validates if it is readable. If it is readable, it registers it.
- If not, then vim.notify() an error, nothing is saved.
- If you press enter while under a line (in normal mode), that line will be put on top which will be promoted as the current primary buffer.
- The default keybind
<m-;><m-f>will now just always select the first elementprimary_buffers[1] - If you disable primary buffer, you can still use the pop-up window to set a primary buffer from the queue, but
<m-;><m-f>won't do anything at all, until you set it to active again.. - You can open the popup floating window with
<m-;>F
- You can now then manage it with a window pop-up, it is editable like that in harpoon window.
Demo
This is a short demo. It just covers how the triquetra buffers update for all sorts of jumps. The system automatically handles all cases, to make jumps and backtracking consistent. This buffers update only updates at BufEnter and non-cycling mode.
You can also see that the two windows have their own history. You can turn this off.
Requirements
- resession.nvim
- nvim-cokeline
- harpoon (harpoon feature still coupled with the plugin, working on togglable option)
- openssl (system installed, used for hashing file names and directories)
Installation
This works for all plugin managers.
lazy.nvim (An example)
{
"kampanaut/cavediver",
-- dir = "~/Projects/nvim/cavediver",
config = true
dependencies = {
"ThePrimeagen/harpoon",
-- resession.nvim and nvim-cokeline, requires this plugin.
}
}
Resession.nvim setup
You have to add a hook for the session manager, to allow this plugin to have persistence.
This cavediver plugin saves the session state in your neovim's data directory by default.
{
"stevearc/resession.nvim",
lazy = false,
config = function()
local resession = require("resession")
resession.setup( {
buf_filter = function(bufnr)
local buftype = vim.bo[bufnr].buftype
if vim.bo[bufnr].filetype == "image_nvim" or vim.bo[bufnr].filetype == "oil" then -- if you incorporated oil.nvim for example.
return true
elseif buftype ~= "" then
return false
elseif vim.api.nvim_get_option_value("buflisted", { buf = bufnr }) == false then
return false
else
return resession.default_buf_filter(bufnr)
end
end,
-- your configurations....
})
resession.add_hook("pre_save", function()
require('cavediver').save_session(vim.loop.cwd())
end)
resession.add_hook("post_load", function()
require('cavediver').load_session(vim.loop.cwd())
end)
end,
dependencies = {
"kampanaut/cavediver"
}
},
nvim-cokeline setup
The cavediver plugin can work without the bufferline, but it would be nice to visualise the visit history of all your browsers in a bufferline, so that you can now how you can end up to your current buffer.
{
"willothy/nvim-cokeline",
config = function()
-- update_bufferline_state()
require('cokeline').setup({
show_if_buffers_are_at_least = 2,
fill_hl = 'Normal',
buffers = {
-- A function to filter out unwanted buffers. Takes a buffer table as a
-- parameter (see the following section for more infos) and has to return
-- either `true` or `false`.
-- default: `false`.
---@type false | fun(buf: Buffer):boolean
filter_valid = function(buffer)
return require('cavediver').bufferline.bufnr_is_displayed(buffer.number)
end,
-- A looser version of `filter_valid`, use this function if you still
-- want the `cokeline-{switch,focus}-{prev,next}` mappings to work for
-- these buffers without displaying them in your bufferline.
-- default: `false`.
---@type false | fun(buf: Buffer):boolean
filter_visible = false,
-- Which buffer to focus when a buffer is deleted, `prev` focuses the
-- buffer to the left of the deleted one while `next` focuses the one the
-- right.
-- default: 'next'.
focus_on_delete = 'prev',
-- If set to `last` new buffers are added to the end of the bufferline,
-- if `next` they are added next to the current buffer.
-- if set to `directory` buffers are sorted by their full path.
-- if set to `number` buffers are sorted by bufnr, as in default Neovim
-- default: 'last'.
---@type 'last' | 'next' | 'directory' | 'number' | fun(a: Buffer, b: Buffer):boolean
new_buffers_position = function(buffer_a, buffer_b)
local compare = require('cavediver').bufferline.compare_buffers(buffer_a.number, buffer_b.number)
return compare
end,
-- If true, right clicking a buffer will close it
-- The close button will still work normally
-- Default: true
---@type boolean
delete_on_right_click = true,
},
mappings = {
disable_mouse = false,
cycle_prev_next = true
},
pick = {
use_filename = false,
letters = "jfkdlsa;bvncmurieowpqyt"
},
default_hl = {
bg = function(buffer)
return require('cavediver').bufferline.get_theme_bg_color(buffer.is_focused)
end,
fg = function(buffer)
return require('cavediver').bufferline.get_theme_fg_color(buffer.number, buffer.is_focused)
end,
bold = function(buffer)
return require('cavediver').bufferline.get_buffer_bold(buffer.number)
end,
},
history = {
enabled = false,
},
tabs = {
placement = "right",
components = require('cavediver').bufferline.cokeline.create_tab_components()
},
components = require('cavediver').bufferline.cokeline.create_buffer_components()
})
end
dependencies = {
"nvim-lua/plenary.nvim", -- Required for v0.4.0+
"nvim-tree/nvim-web-devicons", -- If you want devicons
"stevearc/resession.nvim", -- Optional, for persistent history
"kampanaut/cavediver"
},
}
Configuration Defaults
You can make your own theme as well, make your own color markers for each buffer type.
You can start by just modifying the base colors
local defaults = {
session_dir = vim.fn.stdpath("data") .. "/cavediver/sessions/",
bufferline = {
history_view = "global" -- "global" | "window"
},
colors = {
base = {
focused = {
fg = "#D5C4A1",
Related Skills
node-connect
341.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
341.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.6kCommit, push, and open a PR
