SkillAgentSearch skills...

Cavediver

A novel approach on file navigation context management in Neovim buffers.

Install / Use

/learn @kampanaut/Cavediver
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

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

  1. 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 element primary_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

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.

Image

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

View on GitHub
GitHub Stars5
CategoryDevelopment
Updated24d ago
Forks0

Languages

Lua

Security Score

75/100

Audited on Mar 6, 2026

No findings