myypo / windovigation.nvim

A plugin for Neovim that lets you switch buffers based on window unique file history like VScode and Evil Emacs, instead of a global buffer list.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

🏎️ Windovigation.nvim

This enables you to switch buffers based on a buffer history scoped to the window split / pane, like VScode and Evil Emacs, instead of a global buffer list.

This is a replacement for your current keymaps that you use to switch or kill buffers. And complements all the other vim like movement like cursor, definition jumps. πŸ‘Œ

✨ Features

  • 🏎️ Buffers scoped to the window for faster, more reliable and muscle memory friendly switching.
  • πŸš€ Switch to the previous or the next buffer based on an order of which file was written in that window.
  • πŸͺ¦ Kill a buffer to return to the previously entered file in that window.
  • πŸ’Ύ Session Restoration support for any of your session plugins.
  • πŸ“‘ Lua api for all actions performed by the plugin.
  • πŸ“‹ Supports Tabs: windovigation.nvim respects Neovim buffer > window > tab hierarchy.
  • ⌨️ Keymaps to switch or kill buffers on [b, ]b, [B, ]B, <leader>bk that can be adjusted in the options.

πŸ“¦ Installation

  1. Add the plugin to your config with disabled lazy loading, for example LazyVim:
{
  "volskaya/windovigation.nvim",
  lazy = false,
  opts = {},
}
  1. If you use a session restoration plugin that provides something like a pre save hook, you should add our persist_state to its config.
πŸ’‘ For example LazyVim's default folke/persistence.nvim
{
  "folke/persistence.nvim",
  event = "BufReadPre",
  opts = {
    pre_save = function()
      require("windovigation.actions").persist_state()
    end,
  },
}
  1. Add "buffers", "blank", "help", "terminal", "winsize", "tabpages" to your global sessionoptions.

⚠️ For this plugin to restore state properly, your window layout must match between close and restore. πŸ‘†

If your session restoration plugin isn't wrapped around :mksession or ignores sessionoptions, refer to their README on how to handle this properly, if needed.

πŸ’‘ Example (place it together with your other global options)
vim.opt.sessionoptions = {
  -- Windovigation required options.
  "buffers",
  "help",
  "blank",
  "terminal",
  "winsize",
  "tabpages",
  -- Other options.
  "curdir",
  "globals",
  "folds",
}

βš™οΈ Options

{
  -- Auto restore state on SessionLoadPost.
  --
  -- When using plugins with custom session handling,
  -- use require("windovigation.actions").restore_state().
  auto_restore_state = true,

  -- Auto persist state on VimLeavePre.
  --
  -- This only persists it vim global variables and
  -- does not create the session file for you! It's
  -- expected you have something else actually handle
  -- the session file.
  --
  -- When using plugins with custom session handling,
  -- use require("windovigation.actions").persist_state().
  auto_persist_state = true,

  -- When toggled on, closing a file will switch to the most
  -- recent entered file, not the recently written file.
  after_close_file_switch_to_recent = true,

  -- Prevents the move actions from working when the current
  -- buffer type is nofile, that's usually on buffers like
  -- the Neotree or git diffs.
  prevent_switching_nofile = true,

  -- The files, where their path contains one of these values,
  -- won't be scoped in our history
  no_scope_filter = {
    -- This is here to workaround git diff for a split second opening some kind
    -- of a normal looking file in /private that shouldn't be scoped.
    "/private/var/folders*",
  },

  -- Prevents the buffer from closing, when there aren't any
  -- of our tracked windows still scoping their file.
  --
  -- This only respects special buffer types.
  --
  -- For example if you wish to stop terminal buffers from
  -- being closed, set this to {"terminal"}.
  no_close_buftype = {},

  -- Options for the built in keymaps that get
  -- reattached to every buffer on enter, to avoid
  -- lazy loaded packages from stealing them.
  --
  -- Set this to false if you wish to set keymaps by yourself.
  keymaps = {
    bracket_movement_key = "b", -- Like [b, ]b, [B, ]B
    buffer_close_key = "k", -- Like <leader>bk
  },
}

πŸ’Ύ Session Restoration

By default the plugin automatically restores state on SessionLoadPost, that's called by Neovim when restoring a session. But you can handle this manually with lua.

require("windovigation.actions").persist_state()
require("windovigation.actions").restore_state()

⌨️ Default Keymaps

  • [b - Switches to the previous file.
  • ]b - Switches to the next file.
  • [B - Switches to the first file.
  • ]B - Switches to the last file.
  • <leader>bk - Closes the current file and destroys the buffer, if no other window has this file open.

πŸš€ Commands

  • :WindovigationPreviousFile - Switches to the previous file.
  • :WindovigationNextFile - Switches to the next file.
  • :WindovigationFirstFile - Switches to the first file.
  • :WindovigationLastFile - Switches to the last file.
  • :WindovigationCloseFile - Closes the current file and destroys the buffer, if no other window has this file open.

πŸ“‘ Lua Actions

require("windovigation.actions").move_to_previous_file()
require("windovigation.actions").move_to_next_file()
require("windovigation.actions").move_to_first_file()
require("windovigation.actions").move_to_last_file()

require("windovigation.actions").close_current_file()

require("windovigation.actions").restore_state()
require("windovigation.actions").persist_state()

πŸ”Ž Custom File Picker Integration

Integrating with your file picker is optional.

But it's expected that switching to a file through a file picker or a text search, bumps the file to the front of that windows history.

In Neovim there really isn't a consistent "File Picked" event, so this case needs to be handled manually in your config with require("windovigation.handlers").handle_file_picked.

πŸ’‘ Example
require("windovigation.handlers").handle_file_picked({
  buf = vim.api.nvim_get_current_buf(),
  file = file_name, -- A file name that was provided by your file picker.
})

πŸ”­ Telescope Integration Example

I use Telescope, so I've included utilities that you should be able to add out of the box to your config or use it as reference.

πŸ’‘ Telescope bultin picker example by passing attach_mappings to their options
require("telescope.builtin").find_files({
  -- Windovigation mappings that will bump the file in the active history, when selected.
  attach_mappings = require("windovigation.telescope-utils").attach_mappings,
})
πŸ’‘ File browser extension by passing actions to telescope opts
{
  extensions = {
    file_browser = {
      mappings = {
        ["n"] = {
          ["<Enter>"] = require("windovigation.telescope-file-picker-utils").open_dir_or_file_action,
          ["l"] = require("windovigation.telescope-file-picker-utils").open_dir_or_file_action,
        },
      },
    },
  }
}

About

A plugin for Neovim that lets you switch buffers based on window unique file history like VScode and Evil Emacs, instead of a global buffer list.

License:Apache License 2.0


Languages

Language:Lua 100.0%