-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathsession-manager.lua
233 lines (200 loc) · 8.01 KB
/
session-manager.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
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