diff options
Diffstat (limited to '')
-rw-r--r-- | README.md | 39 | ||||
-rw-r--r-- | lua/buffer-browser.lua | 94 | ||||
-rw-r--r-- | plugin/buffer-browser.vim | 13 |
3 files changed, 146 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..70dcc7f --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# NVIM Buffer Browser Navigation + +`:b#` on steroids. Browse your buffers like you browse history in a browser. + +## Motivation + +While `:bnext` and `:bprev` allows you to browse between buffers, it is not +very intuitive. Oftentimes I would jump to definitions, a different file +through netrw, an org file and then when using bprev I would end up in a +completely different file, because buffers are ordered by when they are opened. +`:b#`, <Ctrl-I> and <Ctrl-O> works only assuming you didn't navigate one step +further in the documentation. + +I wanted to be able to browse buffers in a way that is similar to how you +browse tabs in a browser. + +## Usage + +Install through any of your favorite plugin managers. For example, with +[lazy](https://www.lazyvim.org). + +This plugin implements two functions: `require('buffer-browser').next()` and +`require('buffer-browser').prev()`. + +You can easily map these to whatever you want. Here is an example `init.lua`: +```lua +vim.api.nvim_set_keymap('n', '<leader>b[', require("buffer-browser").next(), {desc = "Next [B]uffer [[]"}) +vim.api.nvim_set_keymap('n', '<leader>b]', require("buffer-browser").prev(), {desc = "Previous [B]uffer []]"}) +``` + +## Splits + +This plugin works with splits. If you have multiple splits open, the plugin +will fork the split history and create a different "buffer history" for that +particular split. + +## Credits + +The plugin is mostly based on [ton/vim-bufsurf](https://github.com/ton/vim-bufsurf), but rewritten in Lua. diff --git a/lua/buffer-browser.lua b/lua/buffer-browser.lua new file mode 100644 index 0000000..c6a41a8 --- /dev/null +++ b/lua/buffer-browser.lua @@ -0,0 +1,94 @@ +-- BUFFER BROWSER +-- Author: Marc Coquand +-- See readme for explanation on what it does. +-- This code contains examples that can be used to test the code. +-- Run them in `lua %` +-- or with a code runner, like sniprun. +local api = vim.api + +local function StateAppend(bufName, state, filters) + -- State has three fields, current = current buffer, previous = previous buffer, and future = future buffers + -- This function clears the future, and appends the current to the previous, and sets the current to the next + + -- If filters matches the bufName, skip the buffer + if filters ~= nil then + for _, filter in ipairs(filters) do + if string.match(bufName, filter) then + return state + end + end + end + + -- Clear the future + state.future = {} + -- Append the current to the previous + table.insert(state.previous, state.current) + -- Set the current to the next + state.current = bufName + + return state +end +-- Test StateAppend +-- local state = { current = 1, previous = { 2, 3 }, future = { 4, 5 } } +-- print(StateAppend(6, state, {})['current']) +-- -- > 6 +-- state = { current = 1, previous = { 2, 3 }, future = { 4, 5 } } +-- print(StateAppend(6, state, {})['previous'][1]) +-- -- > 2 +-- state = { current = 1, previous = { 2, 3 }, future = { 4, 5 } } +-- print(StateAppend(6, state, { 6 })['current']) +-- -- > 1 + +local function StateGoBack(state) + -- Go back in the state by setting current to the first element of previous, and appending the current to the future + -- Check if past is empty, if so return state as is + if #state.previous == 0 then + return state + end + + table.insert(state.future, state.current) + state.current = table.remove(state.previous, 1) + return state +end +-- Test StateGoBack +-- local state = { current = 1, previous = { 2, 3 }, future = { 4, 5 } } +-- print(StateGoBack(StateGoBack(StateGoBack(state)))['current']) +-- > 3 + +local function StateGoForward(state) + -- Go forward in the state by setting current to the first element of future, and appending the current to the previous + + -- Check if future is empty, if so return state as is + if #state.future == 0 then + return state + end + + table.insert(state.previous, state.current) + state.current = table.remove(state.future, 1) + + return state +end +-- Test StateGoForward +-- local state = { current = 1, previous = { 2, 3 }, future = { 4, 5 } } +-- print(StateGoForward(StateGoForward(StateGoForward(state)))['current']) +-- > 5 + +function BufferEnter() + local bufName = api.nvim_buf_get_name(0) + local state = vim.g.buffer_browser_state + local filters = vim.g.buffer_browser_filters + vim.g.buffer_browser_state = StateAppend(bufName, state, filters) +end + +local BufferBrowserGroup = api.nvim_create_augroup('BufferBrowser') + +api.nvim_create_autocmd('WinEnter', { + '*', + 'lua BufferEnter()', + { group = BufferBrowserGroup } +}) +api.nvim_create_autocmd('BufEnter', { + '*', + 'lua BufferEnter()', + { group = BufferBrowserGroup } +}) diff --git a/plugin/buffer-browser.vim b/plugin/buffer-browser.vim new file mode 100644 index 0000000..dfdb366 --- /dev/null +++ b/plugin/buffer-browser.vim @@ -0,0 +1,13 @@ +if exists('g:loaded_buffer_browser') | finish | endif " prevent loading file twice + +let s:save_cpo = &cpo " save user coptions +set cpo&vim " reset them to defaults + +" command to run our plugin +command! BufferBrowserNext lua require'buffer_browser'.next() +command! BufferBrowserPrevious lua require'buffer_browser'.prev() + +let &cpo = s:save_cpo " and restore after +unlet s:save_cpo + +let g:loaded_whid = 1 |