348 lines
9.5 KiB
Lua
348 lines
9.5 KiB
Lua
local F = require("core.functions")
|
|
|
|
-- Module for managing buffers, these are used for navigation
|
|
|
|
local M = {}
|
|
|
|
-- Buffers, categorized into groups
|
|
-- {
|
|
-- { group = "Project", buffers = { "buffer1", "buffer2" }, active_index = 1 },
|
|
-- { group = "Other", buffers = { "buffer3", "buffer4" }, active_index = 1 },
|
|
-- }
|
|
M.buffers = {}
|
|
|
|
M.buffer_default_group = "Other"
|
|
|
|
M.buffer_matcher = {
|
|
-- match = truthy, function() -> thruthy, or string matching buffer filename
|
|
-- group = string, function() -> string
|
|
{ match = F.find_project_root, group = F.find_project_root },
|
|
{ match = true, group = "Other" }, -- default
|
|
}
|
|
|
|
--------------------------------------------
|
|
|
|
local get_buffer_name = function()
|
|
local buf = vim.api.nvim_get_current_buf()
|
|
local buffer_name = vim.api.nvim_buf_get_name(buf)
|
|
if not buffer_name or buffer_name == "" then return nil end
|
|
return buffer_name
|
|
end
|
|
|
|
M.add_buffer = function()
|
|
local buffer_name = get_buffer_name()
|
|
if not buffer_name then return end
|
|
|
|
-- Evaluate group
|
|
local eval_group = function(config_group)
|
|
if not config_group then return M.buffer_default_group end
|
|
if type(config_group) == "function" then return config_group() end
|
|
return config_group
|
|
end
|
|
|
|
-- Add if buffer does not exist yet
|
|
local add = function(config_group)
|
|
local group = eval_group(config_group)
|
|
|
|
local index
|
|
for i, buffer_group in ipairs(M.buffers) do
|
|
if buffer_group.group == group then index = i end
|
|
end
|
|
|
|
-- Group is new entirely, so we only have 1 buffer
|
|
if not index then
|
|
table.insert(M.buffers, { group = group, buffers = { buffer_name }, active_index = 1 })
|
|
return #M.buffers, 1 -- group index, buffer index
|
|
end
|
|
|
|
-- Buffer previously added, set active
|
|
for i, buffer in ipairs(M.buffers[index].buffers) do
|
|
if buffer == buffer_name then
|
|
M.buffers[index].active_index = i
|
|
return index, i -- group index, buffer index
|
|
end
|
|
end
|
|
|
|
-- Buffer is new, add it to the list
|
|
table.insert(M.buffers[index].buffers, buffer_name)
|
|
local count = #M.buffers[index].buffers
|
|
M.buffers[index].active_index = count
|
|
|
|
return index, count -- group index, buffer index
|
|
end
|
|
|
|
-- Walk matcher configuration
|
|
local matcher = M.buffer_matcher or {}
|
|
if matcher and type(matcher) == "function" then
|
|
matcher = matcher()
|
|
end
|
|
if #matcher == 0 then add(M.buffer_default_group) end
|
|
for _, config in ipairs(M.buffer_matcher) do
|
|
if type(config.match) == "function" and config.match() then
|
|
return add(config.group)
|
|
end
|
|
|
|
-- Match path's filename
|
|
if type(config.match) == "string" and config.match == buffer_name:match("([^/]+)$") then
|
|
return add(config.group)
|
|
end
|
|
|
|
if type(config.match) == "boolean" and config.match then
|
|
return add(config.group)
|
|
end
|
|
end
|
|
|
|
return add(M.buffer_default_group)
|
|
end
|
|
|
|
local get_group_from_buffer = function(buffer_name)
|
|
for i, buffer_group in ipairs(M.buffers) do
|
|
for j, buffer in ipairs(buffer_group.buffers) do
|
|
if buffer == buffer_name then
|
|
return i, j -- group index, buffer index
|
|
end
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
local focus_buffer = function(new_buffer_name)
|
|
for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
|
|
if vim.api.nvim_buf_get_name(buffer) == new_buffer_name then
|
|
vim.api.nvim_set_current_buf(buffer)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
M.remove_buffer = function(buffer_name)
|
|
if not buffer_name or buffer_name == "" then return end
|
|
|
|
local group_index, buffer_index = get_group_from_buffer(buffer_name)
|
|
if not group_index or not buffer_index then return end
|
|
|
|
local buffer_group = M.buffers[group_index]
|
|
|
|
-- Remove the buffer and decrease active index
|
|
table.remove(buffer_group.buffers, buffer_index)
|
|
buffer_group.active_index = math.max(buffer_group.active_index - 1, 1)
|
|
local new_buffer_name = buffer_group.buffers[buffer_group.active_index]
|
|
|
|
-- If there are now no buffers in the group, delete the group
|
|
if #buffer_group.buffers == 0 then
|
|
table.remove(M.buffers, group_index)
|
|
if #M.buffers == 0 then return end
|
|
if #M.buffers < group_index then group_index = group_index - 1 end
|
|
new_buffer_name = M.buffers[group_index].buffers[M.buffers[group_index].active_index]
|
|
end
|
|
|
|
-- Make the new index the active buffer
|
|
focus_buffer(new_buffer_name)
|
|
end
|
|
|
|
local buffer_action_in_active_group = function(action, direction)
|
|
local buffer_name = get_buffer_name()
|
|
if not buffer_name then return end
|
|
|
|
-- Get active group from the current buffer
|
|
local group_index, buffer_index = get_group_from_buffer(buffer_name)
|
|
if not group_index then group_index, buffer_index = M.add_buffer() end
|
|
|
|
-- Get buffer set
|
|
local buffers = M.buffers[group_index].buffers
|
|
if #buffers < 2 then return end
|
|
|
|
-- Determine the other index
|
|
local other_index = buffer_index + direction
|
|
if buffer_index == 1 and direction == -1 then
|
|
other_index = #buffers
|
|
elseif buffer_index == #buffers and direction == 1 then
|
|
other_index = 1
|
|
end
|
|
|
|
if action == "move" then
|
|
for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
|
|
-- TODO: Probably not needed if the other autocommands are implemented
|
|
-- Remove inactive buffers
|
|
if not vim.api.nvim_buf_is_loaded(buffer) then
|
|
for i, group_buffer in ipairs(buffers) do
|
|
if buffer == group_buffer then
|
|
table.remove(buffers, i)
|
|
if i > 1 and i <= other_index then
|
|
other_index = other_index - 1
|
|
end
|
|
end
|
|
end
|
|
|
|
goto continue
|
|
end
|
|
|
|
-- Make buffer active
|
|
if vim.api.nvim_buf_get_name(buffer) == buffers[other_index] then
|
|
vim.api.nvim_set_current_buf(buffer)
|
|
M.buffers[group_index].active_index = other_index
|
|
break
|
|
end
|
|
|
|
::continue::
|
|
end
|
|
elseif action == "swap" then
|
|
local tmp = buffers[other_index]
|
|
buffers[other_index] = buffers[buffer_index]
|
|
buffers[buffer_index] = tmp
|
|
end
|
|
|
|
M.buffers[group_index].buffers = buffers
|
|
end
|
|
|
|
M.buffer_move_left = function()
|
|
buffer_action_in_active_group("move", -1)
|
|
end
|
|
|
|
M.buffer_move_right = function()
|
|
buffer_action_in_active_group("move", 1)
|
|
end
|
|
|
|
M.buffer_swap_left = function()
|
|
buffer_action_in_active_group("swap", -1)
|
|
end
|
|
|
|
M.buffer_swap_right = function()
|
|
buffer_action_in_active_group("swap", 1)
|
|
end
|
|
|
|
--------------------------------------------
|
|
-- Group move
|
|
|
|
local buffer_group_move = function(direction)
|
|
local buffer_name = get_buffer_name()
|
|
if not buffer_name then return end
|
|
|
|
-- Get active group from the current buffer
|
|
local group_index, _ = get_group_from_buffer(buffer_name)
|
|
if not group_index then group_index, _ = M.add_buffer() end
|
|
|
|
-- Check groups bounds
|
|
if #M.buffers < 2 then return end
|
|
|
|
-- Determine the other index
|
|
local other_index = group_index + direction
|
|
if group_index == 1 and direction == -1 then
|
|
other_index = #M.buffers
|
|
elseif group_index == #M.buffers and direction == 1 then
|
|
other_index = 1
|
|
end
|
|
|
|
-- Get active index from other group
|
|
local other_active_index = M.buffers[other_index].active_index
|
|
|
|
-- Make buffer active
|
|
-- TODO: What do if this buffer no longer exists?
|
|
local other_buffer = M.buffers[other_index].buffers[other_active_index]
|
|
focus_buffer(other_buffer)
|
|
end
|
|
|
|
M.buffer_group_move_up = function()
|
|
buffer_group_move(-1)
|
|
end
|
|
|
|
M.buffer_group_move_down = function()
|
|
buffer_group_move(1)
|
|
end
|
|
|
|
--------------------------------------------
|
|
-- Telescope functionss
|
|
|
|
local pick = function(title, items, entry_maker, action)
|
|
local actions = require("telescope.actions")
|
|
local action_state = require("telescope.actions.state")
|
|
local conf = require("telescope.config").values
|
|
local finders = require("telescope.finders")
|
|
local pickers = require("telescope.pickers")
|
|
|
|
pickers.new({}, {
|
|
prompt_title = title,
|
|
finder = finders.new_table {
|
|
results = items,
|
|
entry_maker = entry_maker,
|
|
},
|
|
previewer = false,
|
|
sorter = conf.generic_sorter({}),
|
|
attach_mappings = function(prompt_bufnr)
|
|
actions.select_default:replace(function()
|
|
actions.close(prompt_bufnr)
|
|
|
|
local selection = action_state.get_selected_entry()
|
|
action(selection)
|
|
end)
|
|
|
|
return true
|
|
end,
|
|
}):find()
|
|
end
|
|
|
|
M.buffer_pick_buffer = function()
|
|
local buffer_name = get_buffer_name()
|
|
if not buffer_name then return end
|
|
|
|
-- Get active group from the current buffer
|
|
local group_index, _ = get_group_from_buffer(buffer_name)
|
|
if not group_index then group_index, _ = M.add_buffer() end
|
|
|
|
-- Get all buffers from the active group
|
|
local buffers = {}
|
|
for i, buffer in ipairs(M.buffers[group_index].buffers) do
|
|
table.insert(buffers, { key = buffer, value = tostring(i) })
|
|
end
|
|
|
|
pick("Group buffers",
|
|
buffers,
|
|
function(buffer)
|
|
-- Only show last part of the path
|
|
local display = buffer.key:match("^.+/(.+)$") or buffer.key
|
|
return {
|
|
display = display, -- shown in the picker
|
|
ordinal = buffer.value, -- used for sorting/filtering
|
|
value = buffer.value, -- actual value
|
|
}
|
|
end,
|
|
function(selection)
|
|
local new_buffer_name = M.buffers[group_index].buffers[tonumber(selection.value)]
|
|
|
|
-- Make new buffer active
|
|
focus_buffer(new_buffer_name)
|
|
end
|
|
)
|
|
end
|
|
|
|
M.buffer_pick_group = function()
|
|
-- Get all groups
|
|
local groups = {}
|
|
for i, buffer_group in ipairs(M.buffers) do
|
|
table.insert(groups, { key = buffer_group.group, value = tostring(i) })
|
|
end
|
|
|
|
pick("Groups",
|
|
groups,
|
|
function(group)
|
|
-- Only show last part of the path
|
|
local display = group.key:match("^.+/(.+)$") or group.key
|
|
return {
|
|
display = display, -- shown in the picker
|
|
ordinal = group.value, -- used for sorting/filtering
|
|
value = group.value, -- actual value
|
|
}
|
|
end,
|
|
function(selection)
|
|
local buffer_group = M.buffers[tonumber(selection.value)]
|
|
local new_buffer_name = buffer_group.buffers[buffer_group.active_index]
|
|
|
|
-- Make new buffer active
|
|
focus_buffer(new_buffer_name)
|
|
end
|
|
)
|
|
end
|
|
|
|
return M
|