Merge branch 'main' of ssh://git.cynarski.pl:65522/unixporn/Nabu
This commit is contained in:
commit
ab69b02641
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2023 danielcopper
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,76 +0,0 @@
|
|||||||
# WezTerm Session Manager
|
|
||||||
|
|
||||||
The [WezTerm](https://wezfurlong.org/wezterm/) Session Manager is a Lua script
|
|
||||||
enhancement for WezTerm that provides functionality to save, load, and restore
|
|
||||||
terminal sessions. This tool helps manage terminal sessions, its goal is to save
|
|
||||||
and restore different sessions or better workspaces and later restore them.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- **Save Session State** Captures the current layout of windows, tabs and panes,
|
|
||||||
along with their working directories and foreground processes.
|
|
||||||
- **restore Session** Reopens a previously saved session that matches the
|
|
||||||
current workspace name, restoring its layout and directories.
|
|
||||||
- **Load Session (Not implemented yet)** Allows selecting which saved session to
|
|
||||||
load, regardless of the current workspace name.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. **Clone the Repository** Clone the Repository into your WezTerm configuration
|
|
||||||
directory:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/danielcopper/wezterm-session-manager.git ~/.config/wezterm/wezterm-session-manager
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Configure WezTerm:** Edit your 'wezterm.lua' file to include the Session
|
|
||||||
Manager:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local session_manager = require("wezterm-session-manager/session-manager")
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Setup Event Bindings:** Edit your 'wezterm.lua' to include the event
|
|
||||||
bindings to trigger the functions of the session manager
|
|
||||||
|
|
||||||
```lua
|
|
||||||
wezterm.on("save_session", function(window) session_manager.save_state(window) end)
|
|
||||||
wezterm.on("load_session", function(window) session_manager.load_state(window) end)
|
|
||||||
wezterm.on("restore_session", function(window) session_manager.restore_state(window) end)
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Set Keybindings:** Define Keybindings in your 'wezterm.lua' for saving,
|
|
||||||
restoring and loading sessions:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local wezterm = require 'wezterm';
|
|
||||||
return {
|
|
||||||
keys = {
|
|
||||||
{key = "S", mods = "LEADER", action = wezterm.action{EmitEvent = "save_session"}},
|
|
||||||
{key = "L", mods = "LEADER", action = wezterm.action{EmitEvent = "load_session"}},
|
|
||||||
{key = "R", mods = "LEADER", action = wezterm.action{EmitEvent = "restore_session"}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
5. I also recommend to set up a keybinding for creating **named** workspaces as
|
|
||||||
explained
|
|
||||||
[here](https://wezfurlong.org/wezterm/config/lua/keyassignment/SwitchToWorkspace.html).
|
|
||||||
This helps managing and switching states.
|
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
There are currently some limitations and improvements that need to be
|
|
||||||
implemented:
|
|
||||||
|
|
||||||
- The script does not restore the state of running applications within each pane
|
|
||||||
(except nvim on linux which seems to work fine but the general handling should
|
|
||||||
be improved)
|
|
||||||
- It' primarily tested on Linux and Windows, expect some bugs or adjustements
|
|
||||||
that need to be made
|
|
||||||
- Complex pane layouts won't be correctly restored, the current implementation
|
|
||||||
to determine the pane position is extremely basic
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Feedback, bug reports, and contributions to enhance the script are welcome.
|
|
@ -1,233 +0,0 @@
|
|||||||
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
|
|
@ -1 +0,0 @@
|
|||||||
{"name":"default","tabs":[{"panes":[{"cwd":"file://nabu.local/Users/paramah","height":39,"index":0,"is_active":false,"is_zoomed":false,"left":0,"pane_id":"0","pixel_height":1053,"pixel_width":3552,"top":0,"tty":"/opt/homebrew/Cellar/neovim/0.11.0/bin/nvim","width":296},{"cwd":"file://nabu.local/Users/paramah","height":39,"index":1,"is_active":true,"is_zoomed":false,"left":0,"pane_id":"1","pixel_height":1053,"pixel_width":3552,"top":40,"tty":"/bin/zsh","width":296}],"tab_id":"0"}]}
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit f4ed4460aa7cb2f9247c34265b91c5c6ac081bc2
|
|
Loading…
x
Reference in New Issue
Block a user