Open gegoune opened 3 years ago
I'd love to have both these changes.
All good ideas :) when I get some time I can come back to this. Thanks!
I'm sure there's cleaner way to do this, but if you just want to throw something into your config for now, I was able to make a custom producer that sorts the list. Inspired by how FZF sorts their buffer list.
-- Taken from source
-- https://github.com/camspiers/snap/blob/4ed8f920f437138b7da38d5ad9003a1e2ca2ddb3/lua/snap/producer/vim/buffer.lua
local function get_buffers()
local function _1_(_241)
return vim.fn.bufname(_241)
end
local function _2_(_241)
return ((vim.fn.bufname(_241) ~= "") and (vim.fn.buflisted(_241) == 1) and (vim.fn.bufexists(_241) == 1))
end
return vim.tbl_map(_1_, vim.tbl_filter(_2_, vim.api.nvim_list_bufs()))
end
-- Table of buffers
local snap_buffers = {}
function _G.push_buffer()
local bufname = vim.fn.bufname("")
-- push a key/value of buffer path and time entered
snap_buffers[bufname] = vim.fn.reltimefloat(vim.fn.reltime())
end
function _G.delete_buffer()
local bufname = vim.fn.bufname("")
-- Remove path from table
snap_buffers[bufname] = nil
end
vim.cmd [[
augroup snap_buffers
autocmd!
autocmd BufWinEnter,WinEnter * call v:lua.push_buffer()
autocmd BufDelete * silent! call v:lua.delete_buffer()
augroup END
]]
local function getKeysSortedByValue(tbl)
local keys = {}
for key in pairs(tbl) do
table.insert(keys, key)
end
table.sort(
keys,
function(a, b)
return tbl[a] > tbl[b]
end
)
return keys
end
local function tableHasValue(tbl, val)
for _, value in pairs(tbl) do
if value == val then
return true
end
end
return false
end
local function makeBufferList()
-- Get the active buffers that snap uses
-- (this is a trimmed down list)
local activeBuffers = get_buffers()
-- Get our sorted list of buffers (with some we don't want)
local filePathsSortedByTime = getKeysSortedByValue(snap_buffers)
local result = {}
for _, filepath in pairs(filePathsSortedByTime) do
if (tableHasValue(activeBuffers, filepath)) then
-- filter down our sorted list to the same items that Snap uses
table.insert(result, filepath)
end
end
return result
end
local function bufferProducer()
-- Runs the slow-mode to get the buffers
local result = snap.sync(makeBufferList)
coroutine.yield(result)
end
This is 95% of a solution for me, thank you very much.
Only change I did for myself is to add the newest entry at the bottom:
local function makeBufferList()
-- Get the active buffers that snap uses
-- (this is a trimmed down list)
local activeBuffers = get_buffers()
-- Get our sorted list of buffers (with some we don't want)
local filePathsSortedByTime = getKeysSortedByValue(snap_buffers)
local result = {}
local first = false
for _, filepath in pairs(filePathsSortedByTime) do
if (tableHasValue(activeBuffers, filepath)) then
-- filter down our sorted list to the same items that Snap uses
if first == false then
first = filepath
else
table.insert(result, filepath)
end
end
end
if first ~= false then
table.insert(result, first)
end
return result
end
I find it nice not to have it on the top - I'm unlikely to not switch buffers :).
Almost perfect, it seems to keep one buffer list per cwd :(. I don't get it.
This might be a slightly more elegant way to do it. The :buffers t
command will print the buffer list in order of access for us. Unfortunately I don't think there's a way to get this list programmatically, but you can do some string manipulation to create this list. I think this will be more reliable and accurate than my previous solution.
local function getSortedBufferList()
-- Hacky way to get the list of buffers sorted by recency
-- There's no programmatic way to get this AFAIK
-- But the ":buffers t" command does sort it correctly
-- This redirects the output of the command to a register,
-- then assigns the contents of that register to a global variable
-- we can access
vim.cmd [[
let temp_reg = @"
redir @"
execute "buffers t"
redir END
let output = copy(@")
let g:raw_buffer_list = output
let @" = temp_reg
]]
-- This is now a multiline string of the buffer list
-- We need to trim this down into a table of filepaths
local rawBuffers = vim.g.raw_buffer_list
local splitLines = vim.split(rawBuffers, "\n", false)
local result = {}
-- The filepaths always start at this index
local quoteStart = 11
for _, line in pairs(splitLines) do
-- Identify the index position of the closing quote
local endIndex = string.find(line, '"', quoteStart)
if type(endIndex) == "number" then
-- grab the string between the quotes
local filename = string.sub(line, quoteStart, endIndex - 1)
table.insert(result, filename)
end
end
return result
end
local function bufferProducer(request)
-- Runs the slow-mode to get the buffers
local result = snap.sync(getSortedBufferList)
-- Move the active buffer (first filepath)
-- to the bottom of the list
local currentBuffer = result[1]
table.remove(result, 1)
table.insert(result, currentBuffer)
if request.canceled() then
coroutine.yield(nil)
else
coroutine.yield(result)
end
end
Here's a producer that sorts buffers by lastused
and excludes the current buffer
(fn get-sorted-buffers [request]
(fn []
(let [original-buf (vim.api.nvim_win_get_buf (. request :winnr))
bufs (vim.tbl_filter #(and (not= (vim.fn.bufname $1) "")
(= (vim.fn.buflisted $1) 1)
(= (vim.fn.bufexists $1) 1)
(not= $1 original-buf))
(vim.api.nvim_list_bufs))]
(table.sort bufs
#(> (. (vim.fn.getbufinfo $1) 1 :lastused)
(. (vim.fn.getbufinfo $2) 1 :lastused)))
(vim.tbl_map #(vim.fn.bufname $1) bufs))))
(fn sorted-buffers [request]
(snap.sync (get-sorted-buffers request)))
As a side note, I think the winnr
field in Request
might be misnamed -- it's actually the window ID. (:h winid
)
FZF does sort buffers on buffers selection list by most recently used. This is very helpful and makes switching to most recently used buffers easier as they are closer to the end of the list (I do not mean oldfiles here, which is different).
FZF.vim also does not allow to pick up buffer shown in 'current' window, this is shown as yellow on screenshot below and is not selectable.
After changing buffer to
_neogit.lua
and invoking fzf buffers again it changes to:Do you think this functionality could be implemented in snap's buffer producer?