From 867c83002b1c0e74edc356dd32ad96036edd8e7f Mon Sep 17 00:00:00 2001 From: Steven Arcangeli Date: Sat, 10 Sep 2022 19:11:30 -0700 Subject: [PATCH] feat: extensions can support special windows --- README.md | 3 +- lua/resession/extensions/example.lua | 44 +++++++++++++++++ lua/resession/layout.lua | 74 ++++++++++++++++++++-------- 3 files changed, 99 insertions(+), 22 deletions(-) create mode 100644 lua/resession/extensions/example.lua diff --git a/README.md b/README.md index 87144aa..beca21c 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,13 @@ A: All the other plugins use `:mksession` under the hood **Q: Why don't you want to use `:mksession`?** -A: While it's amazing that this feature is built-in to vim, and it does an impressively good job for most situations, it's very difficult to customize. If `:help sessionoptions` covers your use case, then you're golden. If you want anything else, you're out of luck. +A: While it's amazing that this feature is built-in to vim, and it does an impressively good job for most situations, it is very difficult to customize. If `:help sessionoptions` covers your use case, then you're golden. If you want anything else, you're out of luck. ## TODO - [ ] tab-scoped sessions - [ ] documentation - [ ] make filepaths relative so sessions are portable -- [ ] extensions can add supported buffers (e.g. nvim-tree, aerial) ## Requirements diff --git a/lua/resession/extensions/example.lua b/lua/resession/extensions/example.lua new file mode 100644 index 0000000..b109818 --- /dev/null +++ b/lua/resession/extensions/example.lua @@ -0,0 +1,44 @@ +local M = {} + +---Get the saved data for this extension +---@return any +M.on_save = function() + return {} +end + +M.on_load = function(data) + -- +end + +---Called when resession gets configured +---This function is optional +---@param data table The configuration data passed in the config +M.config = function(data) + -- +end + +---Check if a window is supported by this extension +---This function is optional for extensions +---@param winid integer +---@param bufnr integer +---@return boolean +M.is_win_supported = function(winid, bufnr) + return true +end + +---Save data for a window +---@param winid integer +---@return any +M.save_win = function(winid) + return {} +end + +---Called with the data from save_win +---@param winid integer +---@param config any +---@return integer|nil If the original window has been replaced, return the new ID that should replace it +M.load_win = function(winid, config) + -- +end + +return M diff --git a/lua/resession/layout.lua b/lua/resession/layout.lua index 7fe932b..fc32fee 100644 --- a/lua/resession/layout.lua +++ b/lua/resession/layout.lua @@ -7,17 +7,36 @@ local M = {} ---@return table|false M.get_win_info = function(tabnr, winid) local bufnr = vim.api.nvim_win_get_buf(winid) - if not config.buffers.filter(bufnr) then + local win = {} + local supported_by_ext = false + for ext_name in pairs(config.extensions) do + local ext = util.get_extension(ext_name) + if ext and ext.is_win_supported and ext.is_win_supported(winid, bufnr) then + local ok, extension_data = pcall(ext.save_win, winid) + if ok then + win.extension_data = extension_data + win.extension = ext_name + supported_by_ext = true + else + vim.notify( + string.format("[resession] Extension %s save_win error: %s", ext_name, extension_data), + vim.log.levels.ERROR + ) + end + break + end + end + if not supported_by_ext and not config.buffers.filter(bufnr) then return false end - local win = { + win = vim.tbl_extend("error", win, { bufname = vim.api.nvim_buf_get_name(bufnr), current = vim.api.nvim_get_current_win() == winid, cursor = vim.api.nvim_win_get_cursor(winid), width = vim.api.nvim_win_get_width(winid), height = vim.api.nvim_win_get_height(winid), options = util.save_win_options(winid), - } + }) local winnr = vim.api.nvim_win_get_number(winid) if vim.fn.haslocaldir(winnr, tabnr) == 1 then win.cwd = vim.fn.getcwd(winnr, tabnr) @@ -56,7 +75,7 @@ M.add_win_info_to_layout = function(tabnr, layout) return layout end -local function set_winlayout(layout, visit_data) +local function set_winlayout(layout) local type = layout[1] if type == "leaf" then local win = layout[2] @@ -64,9 +83,6 @@ local function set_winlayout(layout, visit_data) if win.cwd then vim.cmd(string.format("lcd %s", win.cwd)) end - if win.current then - visit_data.winid = vim.api.nvim_get_current_win() - end else local winids = {} for i, v in ipairs(layout[2]) do @@ -81,7 +97,7 @@ local function set_winlayout(layout, visit_data) end for i, v in ipairs(layout[2]) do vim.api.nvim_set_current_win(winids[i]) - set_winlayout(v, visit_data) + set_winlayout(v) end end end @@ -95,24 +111,42 @@ end ---@param layout table ---@param scale_factor number[] Scaling factor for [width, height] -local function set_winlayout_data(layout, scale_factor) +local function set_winlayout_data(layout, scale_factor, visit_data) local type = layout[1] if type == "leaf" then local win = layout[2] - local bufnr = vim.fn.bufadd(win.bufname) - vim.api.nvim_win_set_buf(win.winid, bufnr) - -- After setting the buffer into the window, manually set the filetype to trigger syntax - -- highlighting - vim.api.nvim_buf_set_option(bufnr, "filetype", vim.api.nvim_buf_get_option(bufnr, "filetype")) - vim.api.nvim_win_set_cursor(win.winid, win.cursor) + if win.extension then + local ext = util.get_extension(win.extension) + if ext then + local ok, new_winid = pcall(ext.load_win, win.winid, win.extension_data) + if ok then + win.winid = new_winid or win.winid + else + vim.notify( + string.format("[resession] Extension %s load_win error: %s", win.extension, new_winid), + vim.log.levels.ERROR + ) + end + end + else + local bufnr = vim.fn.bufadd(win.bufname) + vim.api.nvim_win_set_buf(win.winid, bufnr) + -- After setting the buffer into the window, manually set the filetype to trigger syntax + -- highlighting + vim.api.nvim_buf_set_option(bufnr, "filetype", vim.api.nvim_buf_get_option(bufnr, "filetype")) + end + pcall(vim.api.nvim_win_set_cursor, win.winid, win.cursor) util.restore_win_options(win.winid, win.options) - local width_scale = vim.wo[win.winid].winfixwidth and 1 or scale_factor[1] + local width_scale = vim.wo.winfixwidth and 1 or scale_factor[1] vim.api.nvim_win_set_width(win.winid, scale(win.width, width_scale)) - local height_scale = vim.wo[win.winid].winfixheight and 1 or scale_factor[2] + local height_scale = vim.wo.winfixheight and 1 or scale_factor[2] vim.api.nvim_win_set_height(win.winid, scale(win.height, height_scale)) + if win.current then + visit_data.winid = win.winid + end else for i, v in ipairs(layout[2]) do - set_winlayout_data(v, scale_factor) + set_winlayout_data(v, scale_factor, visit_data) end end end @@ -121,9 +155,9 @@ end ---@param scale_factor number[] Scaling factor for [width, height] ---@return nil|integer The window that should have focus after session load M.set_winlayout = function(layout, scale_factor) + set_winlayout(layout) local ret = {} - set_winlayout(layout, ret) - set_winlayout_data(layout, scale_factor) + set_winlayout_data(layout, scale_factor, ret) return ret.winid end