Skip to content

Commit

Permalink
feat: extensions can support special windows
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc-stripe committed Sep 11, 2022
1 parent 7446f89 commit 867c830
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 22 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
44 changes: 44 additions & 0 deletions lua/resession/extensions/example.lua
Original file line number Diff line number Diff line change
@@ -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
74 changes: 54 additions & 20 deletions lua/resession/layout.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -56,17 +75,14 @@ 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]
win.winid = vim.api.nvim_get_current_win()
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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down

0 comments on commit 867c830

Please sign in to comment.