diff --git a/lua/bufferline.lua b/lua/bufferline.lua index 7bc28950..6e68aa9b 100644 --- a/lua/bufferline.lua +++ b/lua/bufferline.lua @@ -116,7 +116,7 @@ local function setup_autocommands(conf) api.nvim_create_autocmd("SessionLoadPost", { pattern = "*", group = BUFFERLINE_GROUP, - callback = function() state.restore_positions() end, + callback = function() state.custom_sort = utils.restore_positions() end, }) end if not options.always_show_bufferline then diff --git a/lua/bufferline/commands.lua b/lua/bufferline/commands.lua index 7bea9f95..8b8c1283 100644 --- a/lua/bufferline/commands.lua +++ b/lua/bufferline/commands.lua @@ -8,25 +8,13 @@ local utils = lazy.require("bufferline.utils") ---@module "bufferline.utils" local config = lazy.require("bufferline.config") ---@module "bufferline.config" local groups = lazy.require("bufferline.groups") ---@module "bufferline.groups" local sorters = lazy.require("bufferline.sorters") ---@module "bufferline.sorters" -local constants = lazy.require("bufferline.constants") ---@module "bufferline.constants" local pick = lazy.require("bufferline.pick") ---@module "bufferline.pick" local M = {} -local positions_key = constants.positions_key - local fmt = string.format local api = vim.api ----@param ids number[] -local function save_positions(ids) vim.g[positions_key] = table.concat(ids, ",") end - ---- @param elements bufferline.TabElement[] ---- @return number[] -local function get_ids(elements) - return vim.tbl_map(function(item) return item.id end, elements) -end - --- open the current element ---@param id number local function open_element(id) @@ -170,9 +158,9 @@ function M.move_to(to_index, from_index) local destination_buf = state.components[next_index] state.components[next_index] = item state.components[index] = destination_buf - state.custom_sort = get_ids(state.components) + state.custom_sort = utils.get_ids(state.components) local opts = config.options - if opts.persist_buffer_sort then save_positions(state.custom_sort) end + if opts.persist_buffer_sort then utils.save_positions(state.custom_sort) end ui.refresh() end end @@ -269,9 +257,9 @@ end function M.sort_by(sort_by) if next(state.components) == nil then return utils.notify("Unable to find elements to sort, sorry", "warn") end sorters.sort(state.components, { sort_by = sort_by }) - state.custom_sort = get_ids(state.components) + state.custom_sort = utils.get_ids(state.components) local opts = config.options - if opts.persist_buffer_sort then save_positions(state.custom_sort) end + if opts.persist_buffer_sort then utils.save_positions(state.custom_sort) end ui.refresh() end diff --git a/lua/bufferline/state.lua b/lua/bufferline/state.lua index 90f23dbf..c45f91a2 100644 --- a/lua/bufferline/state.lua +++ b/lua/bufferline/state.lua @@ -1,7 +1,6 @@ local M = {} local lazy = require("bufferline.lazy") -local constants = lazy.require("bufferline.constants") ---@module "bufferline.constants" local utils = lazy.require("bufferline.utils") ---@module "bufferline.utils" -----------------------------------------------------------------------------// @@ -21,15 +20,6 @@ local state = { right_offset_size = 0, } -function M.restore_positions() - local str = vim.g[constants.positions_key] - if not str then return str end - -- these are converted to strings when stored - -- so have to be converted back before usage - local ids = vim.split(str, ",") - if ids and #ids > 0 then state.custom_sort = vim.tbl_map(tonumber, ids) end -end - ---@param list bufferline.Component[] ---@return bufferline.Component[] local function filter_invisible(list) diff --git a/lua/bufferline/types.lua b/lua/bufferline/types.lua index f7aeb4eb..0dba6e76 100644 --- a/lua/bufferline/types.lua +++ b/lua/bufferline/types.lua @@ -216,7 +216,7 @@ ---@field is_picking boolean ---@field visible_components bufferline.Component[] ---@field __components bufferline.Component[] ----@field custom_sort number[] +---@field custom_sort number[]? ---@field left_offset_size number ---@field right_offset_size number diff --git a/lua/bufferline/utils/init.lua b/lua/bufferline/utils/init.lua index 4c06c08c..726ba7f2 100644 --- a/lua/bufferline/utils/init.lua +++ b/lua/bufferline/utils/init.lua @@ -154,6 +154,30 @@ function M.notify(msg, level, opts) vim.schedule(function() vim.notify(msg, level, nopts) end) end +---@return number[]? +function M.restore_positions() + local str = vim.g[constants.positions_key] + local ok, paths = pcall(vim.json.decode, str) + if not ok or type(paths) ~= "table" or #paths == 0 then return nil end + local ids = vim.tbl_map(function(path) + local escaped = vim.fn.fnameescape(path) + return vim.fn.bufnr("^" .. escaped .. "$" --[[@as integer]]) + end, paths) + return vim.tbl_filter(function(id) return id ~= -1 end, ids) +end + +---@param ids number[] +function M.save_positions(ids) + local paths = vim.tbl_map(function(id) return vim.api.nvim_buf_get_name(id) end, ids) + vim.g[constants.positions_key] = vim.json.encode(paths) +end + +--- @param elements bufferline.TabElement[] +--- @return number[] +function M.get_ids(elements) + return vim.tbl_map(function(item) return item.id end, elements) +end + ---Get an icon for a filetype using either nvim-web-devicons or vim-devicons ---if using the lua plugin this also returns the icon's highlights ---@param opts bufferline.IconFetcherOpts diff --git a/tests/utils_spec.lua b/tests/utils_spec.lua index ccdf8a48..39923825 100644 --- a/tests/utils_spec.lua +++ b/tests/utils_spec.lua @@ -18,4 +18,51 @@ describe("Utils tests", function() local truncated = utils.truncate_name("filename.md.md", 13) assert.is_equal(truncated, "filename.md" .. constants.ELLIPSIS) end) + + it("should save/restore positions correctly", function() + -- remove existing buffers + vim.cmd("silent %bwipeout!") + + local names = { "c.txt", "a.txt", "d.txt", "e.txt", "b.txt" } + local bufs = {} + for _, name in ipairs(names) do + vim.cmd.edit(name) + bufs[name] = api.nvim_get_current_buf() + end + + local ids = { + bufs["a.txt"], + bufs["b.txt"], + bufs["c.txt"], + bufs["d.txt"], + bufs["e.txt"], + } + + utils.save_positions(ids) + + assert.same(utils.restore_positions(), ids) + + -- restore_positions should not return invalid bufids + + vim.cmd("bwipeout! " .. bufs["c.txt"]) + + ids = { + bufs["a.txt"], + bufs["b.txt"], + bufs["d.txt"], + bufs["e.txt"], + } + assert.same(utils.restore_positions(), ids) + + vim.g[constants.positions_key] = '["INVALID_PATH"]' + assert.same(utils.restore_positions(), {}) + + -- empty or invalid JSON should return nil + + vim.g[constants.positions_key] = "[]" + assert.is_equal(utils.restore_positions(), nil) + + vim.g[constants.positions_key] = "" + assert.is_equal(utils.restore_positions(), nil) + end) end)