234 lines
8.0 KiB
Lua
234 lines
8.0 KiB
Lua
local wezterm = require("wezterm")
|
|
local session_manager = {}
|
|
local os = wezterm.target_triple
|
|
|
|
--- Displays a notification in WezTerm.
|
|
-- @param message string: The notification message to be displayed.
|
|
local function display_notification(message)
|
|
wezterm.log_info(message)
|
|
-- Additional code to display a GUI notification can be added here if needed
|
|
end
|
|
|
|
--- Retrieves the current workspace data from the active window.
|
|
-- @return table or nil: The workspace data table or nil if no active window is found.
|
|
local function retrieve_workspace_data(window)
|
|
local workspace_name = window:active_workspace()
|
|
local workspace_data = {
|
|
name = workspace_name,
|
|
tabs = {}
|
|
}
|
|
|
|
-- Iterate over tabs in the current window
|
|
for _, tab in ipairs(window:mux_window():tabs()) do
|
|
local tab_data = {
|
|
tab_id = tostring(tab:tab_id()),
|
|
panes = {}
|
|
}
|
|
|
|
-- Iterate over panes in the current tab
|
|
for _, pane_info in ipairs(tab:panes_with_info()) do
|
|
-- Collect pane details, including layout and process information
|
|
table.insert(tab_data.panes, {
|
|
pane_id = tostring(pane_info.pane:pane_id()),
|
|
index = pane_info.index,
|
|
is_active = pane_info.is_active,
|
|
is_zoomed = pane_info.is_zoomed,
|
|
left = pane_info.left,
|
|
top = pane_info.top,
|
|
width = pane_info.width,
|
|
height = pane_info.height,
|
|
pixel_width = pane_info.pixel_width,
|
|
pixel_height = pane_info.pixel_height,
|
|
cwd = tostring(pane_info.pane:get_current_working_dir()),
|
|
tty = tostring(pane_info.pane:get_foreground_process_name())
|
|
})
|
|
end
|
|
|
|
table.insert(workspace_data.tabs, tab_data)
|
|
end
|
|
|
|
return workspace_data
|
|
end
|
|
|
|
--- Saves data to a JSON file.
|
|
-- @param data table: The workspace data to be saved.
|
|
-- @param file_path string: The file path where the JSON file will be saved.
|
|
-- @return boolean: true if saving was successful, false otherwise.
|
|
local function save_to_json_file(data, file_path)
|
|
if not data then
|
|
wezterm.log_info("No workspace data to log.")
|
|
return false
|
|
end
|
|
|
|
local file = io.open(file_path, "w")
|
|
if file then
|
|
file:write(wezterm.json_encode(data))
|
|
file:close()
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
--- Recreates the workspace based on the provided data.
|
|
-- @param workspace_data table: The data structure containing the saved workspace state.
|
|
local function recreate_workspace(window, workspace_data)
|
|
local function extract_path_from_dir(working_directory)
|
|
if os == "x86_64-pc-windows-msvc" then
|
|
-- On Windows, transform 'file:///C:/path/to/dir' to 'C:/path/to/dir'
|
|
return working_directory:gsub("file:///", "")
|
|
elseif os == "x86_64-unknown-linux-gnu" then
|
|
-- On Linux, transform 'file://{computer-name}/home/{user}/path/to/dir' to '/home/{user}/path/to/dir'
|
|
return working_directory:gsub("^.*(/home/)", "/home/")
|
|
else
|
|
return working_directory:gsub("^.*(/Users/)", "/Users/")
|
|
end
|
|
end
|
|
|
|
if not workspace_data or not workspace_data.tabs then
|
|
wezterm.log_info("Invalid or empty workspace data provided.")
|
|
return
|
|
end
|
|
|
|
local tabs = window:mux_window():tabs()
|
|
|
|
if #tabs ~= 1 or #tabs[1]:panes() ~= 1 then
|
|
wezterm.log_info(
|
|
"Restoration can only be performed in a window with a single tab and a single pane, to prevent accidental data loss.")
|
|
return
|
|
end
|
|
|
|
local initial_pane = window:active_pane()
|
|
local foreground_process = initial_pane:get_foreground_process_name()
|
|
|
|
-- Check if the foreground process is a shell
|
|
if foreground_process:find("sh") or foreground_process:find("cmd.exe") or foreground_process:find("powershell.exe") or foreground_process:find("pwsh.exe") or foreground_process:find("nu") then
|
|
-- Safe to close
|
|
initial_pane:send_text("exit\r")
|
|
else
|
|
wezterm.log_info("Active program detected. Skipping exit command for initial pane.")
|
|
end
|
|
|
|
-- Recreate tabs and panes from the saved state
|
|
for _, tab_data in ipairs(workspace_data.tabs) do
|
|
local cwd_uri = tab_data.panes[1].cwd
|
|
local cwd_path = extract_path_from_dir(cwd_uri)
|
|
|
|
local new_tab = window:mux_window():spawn_tab({ cwd = cwd_path })
|
|
if not new_tab then
|
|
wezterm.log_info("Failed to create a new tab.")
|
|
break
|
|
end
|
|
|
|
-- Activate the new tab before creating panes
|
|
new_tab:activate()
|
|
|
|
-- Recreate panes within this tab
|
|
for j, pane_data in ipairs(tab_data.panes) do
|
|
local new_pane
|
|
if j == 1 then
|
|
new_pane = new_tab:active_pane()
|
|
else
|
|
local direction = 'Right'
|
|
if pane_data.left == tab_data.panes[j - 1].left then
|
|
direction = 'Bottom'
|
|
end
|
|
|
|
new_pane = new_tab:active_pane():split({
|
|
direction = direction,
|
|
cwd = extract_path_from_dir(pane_data.cwd)
|
|
})
|
|
end
|
|
|
|
if not new_pane then
|
|
wezterm.log_info("Failed to create a new pane.")
|
|
break
|
|
end
|
|
|
|
-- Restore TTY for Neovim on Linux
|
|
-- NOTE: cwd is handled differently on windows. maybe extend functionality for windows later
|
|
-- This could probably be handled better in general
|
|
if not (os == "x86_64-pc-windows-msvc") then
|
|
if not (os == "x86_64-pc-windows-msvc") and pane_data.tty:sub(- #"/bin/nvim") == "/bin/nvim" then
|
|
new_pane:send_text(pane_data.tty .. " ." .. "\n")
|
|
else
|
|
-- TODO - With running npm commands (e.g a running web client) this seems to execute Node, without the arguments
|
|
new_pane:send_text(pane_data.tty .. "\n")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
wezterm.log_info("Workspace recreated with new tabs and panes based on saved state.")
|
|
return true
|
|
end
|
|
|
|
--- Loads data from a JSON file.
|
|
-- @param file_path string: The file path from which the JSON data will be loaded.
|
|
-- @return table or nil: The loaded data as a Lua table, or nil if loading failed.
|
|
local function load_from_json_file(file_path)
|
|
local file = io.open(file_path, "r")
|
|
if not file then
|
|
wezterm.log_info("Failed to open file: " .. file_path)
|
|
return nil
|
|
end
|
|
|
|
local file_content = file:read("*a")
|
|
file:close()
|
|
|
|
local data = wezterm.json_parse(file_content)
|
|
if not data then
|
|
wezterm.log_info("Failed to parse JSON data from file: " .. file_path)
|
|
end
|
|
return data
|
|
end
|
|
|
|
--- Loads the saved json file matching the current workspace.
|
|
function session_manager.restore_state(window)
|
|
local workspace_name = window:active_workspace()
|
|
local file_path = wezterm.home_dir ..
|
|
"/.config/wezterm/wezterm-session-manager/wezterm_state_" .. workspace_name .. ".json"
|
|
|
|
local workspace_data = load_from_json_file(file_path)
|
|
if not workspace_data then
|
|
window:toast_notification('WezTerm',
|
|
'Workspace state file not found for workspace: ' .. workspace_name, nil, 4000)
|
|
return
|
|
end
|
|
|
|
if recreate_workspace(window, workspace_data) then
|
|
window:toast_notification('WezTerm', 'Workspace state loaded for workspace: ' .. workspace_name,
|
|
nil, 4000)
|
|
else
|
|
window:toast_notification('WezTerm', 'Workspace state loading failed for workspace: ' .. workspace_name,
|
|
nil, 4000)
|
|
end
|
|
end
|
|
|
|
--- Allows to select which workspace to load
|
|
function session_manager.load_state(window)
|
|
-- TODO: Implement
|
|
-- Placeholder for user selection logic
|
|
-- ...
|
|
-- TODO: Call the function recreate_workspace(workspace_data) to recreate the workspace
|
|
-- Placeholder for recreation logic...
|
|
end
|
|
|
|
--- Orchestrator function to save the current workspace state.
|
|
-- Collects workspace data, saves it to a JSON file, and displays a notification.
|
|
function session_manager.save_state(window)
|
|
local data = retrieve_workspace_data(window)
|
|
|
|
-- Construct the file path based on the workspace name
|
|
local file_path = wezterm.home_dir .. "/.config/wezterm/wezterm-session-manager/wezterm_state_" .. data.name .. ".json"
|
|
|
|
-- Save the workspace data to a JSON file and display the appropriate notification
|
|
if save_to_json_file(data, file_path) then
|
|
window:toast_notification('WezTerm Session Manager', 'Workspace state saved successfully', nil, 4000)
|
|
else
|
|
window:toast_notification('WezTerm Session Manager', 'Failed to save workspace state', nil, 4000)
|
|
end
|
|
end
|
|
|
|
return session_manager
|