resurrect.wezterm

repository·main·Indexed 43 days ago

https://github.com/mlflexer/resurrect.wezterm

A Wezterm plugin for saving and restoring the state of terminal windows, tabs, and panes, including shell output and layouts. Inspired by tmux-resurrect, it features workspace management, encrypted state storage (supporting age, rage, and GPG), periodic auto-saving, and a fuzzy finder for interactive state restoration.

Tokens
4.6K
Snippets
13
Records
16
Agent score
5%

What's inside resurrect.wezterm

  1. Listen to resurrect events

    main

    The plugin emits various events that you can hook into using wezterm.on(event_name, callback). This is useful for triggering UI notifications or logging.

    Commonly used events:

    • resurrect.error(err)
    • resurrect.state_manager.load_state.start(name, type) / .finished(name, type)
    • resurrect.state_manager.save_state.start(file_path, event_type) / .finished(file_path, event_type)
    • resurrect.periodic_save.start(opts) / .finished(opts)
    • resurrect.window_state.restore_window.start / .finished

    Example: Toast notification on error or save completion:

    local resurrect_event_listeners = {
      "resurrect.error",
      "resurrect.state_manager.save_state.finished",
    }
    local is_periodic_save = false
    
    -- Detect if the next save is a periodic one to suppress notifications
    wezterm.on("resurrect.periodic_save", function()
      is_periodic_save = true
    end)
    
    for _, event in ipairs(resurrect_event_listeners) do
      wezterm.on(event, function(...)
        if event == "resurrect.state_manager.save_state.finished" and is_periodic_save then
          is_periodic_save = false
          return
        end
        local args = { ... }
        local msg = event
        for _, v in ipairs(args) do
          msg = msg .. " " .. tostring(v)
        end
        wezterm.gui.gui_windows()[1]:toast_notification("Wezterm - resurrect", msg, nil, 4000)
      end)
    end
    local resurrect_event_listeners = {
      "resurrect.error",
      "resurrect.state_manager.save_state.finished",
    }
    local is_periodic_save = false
    wezterm.on("resurrect.periodic_save", function()
      is_periodic_save = true
    end)
    for _, event in ipairs(resurrect_event_listeners) do
      wezterm.on(event, function(...)
        if event == "resurrect.state_manager.save_state.finished" and is_periodic_save then
          is_periodic_save = false
          return
        end
        local args = { ... }
        local msg = event
        for _, v in ipairs(args) do
          msg = msg .. " " .. tostring(v)
        end
        wezterm.gui.gui_windows()[1]:toast_notification("Wezterm - resurrect", msg, nil, 4000)
      end)
    end
  2. Install resurrect.wezterm

    main

    To use the plugin, require it in your Wezterm configuration using the wezterm.plugin.require method with the repository URL.

    local wezterm = require("wezterm")
    local resurrect = wezterm.plugin.require("https://github.com/MLFlexer/resurrect.wezterm")
  3. Automate state saving and restoration

    main

    You can automate the lifecycle of your terminal state using built-in methods and Wezterm events:

    • Periodic Saving: Use resurrect.state_manager.periodic_save() to automatically save workspaces at regular intervals (e.g., every 15 minutes).
    • Event-based Restoration: You can hook into other plugins or Wezterm events to restore state automatically. For example, when a workspace is created, you can call resurrect.workspace_state.restore_workspace() with the loaded state.
    -- Example: Automatically restore workspace state when a new one is created
    wezterm.on("smart_workspace_switcher.workspace_switcher.created", function(window, path, label)
      local workspace_state = resurrect.workspace_state
    
      workspace_state.restore_workspace(resurrect.state_manager.load_state(label, "workspace"), {
        window = window,
        relative = true,
        restore_text = true,
        on_pane_restore = resurrect.tab_state.default_on_pane_restore,
      })
    end)
  4. Enable resurrecting on startup

    main

    To automatically restore your previous session when Wezterm starts, add the following event handler to your configuration:

    wezterm.on("gui-startup", resurrect.state_manager.resurrect_on_gui_startup)

    Note: For this to work, you must ensure the current state is being written to disk, either via resurrect.state_manager.periodic_save or by manually calling resurrect.state_manager.write_current_state("workspace name", "workspace") when changing workspaces.

  5. Configure state encryption

    main

    To protect saved state files, you can enable encryption using resurrect.state_manager.set_encryption.

    Supported methods:

    • age (Default): Requires age installed on your system.
    • rage: Requires rage installed.
    • gpg: Requires GnuPG installed.

    Configuration Options:

    • enable: Boolean to turn encryption on/off.
    • method: String specifying the provider ("age", "rage", or "gpg").
    • private_key: Path to your private key (required for age and rage). For gpg, this can be omitted if you use your email/key ID.
    • public_key: The public key string (required for age).

    Note for macOS users: If the encryption provider is not in your PATH, provide the absolute path to the executable in the method field (e.g., method = "/opt/homebrew/bin/age").

    local resurrect = wezterm.plugin.require("https://github.com/MLFlexer/resurrect.wezterm")
    
    resurrect.state_manager.set_encryption({
      enable = true,
      method = "age",
      private_key = "/path/to/private/key.txt",
      public_key = "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p",
    })
  6. Secure your terminal state with encryption

    main
    By default, resurrect.wezterm saves the terminal state as plaintext JSON files. This includes the output of your shell, which may contain sensitive information or secrets. To prevent storing vulnerable data in plaintext, you must configure encryption for your state files. Refer to the specific documentation for encrypting state to implement this security measure.
  7. Save workspace, window, or tab state

    main

    You can trigger state saving via manual keybindings. The plugin provides different levels of granularity:

    • Workspace State: Saves the entire workspace (all windows, tabs, and panes) using resurrect.workspace_state.get_workspace_state() and resurrect.state_manager.save_state().
    • Window State: Uses resurrect.window_state.save_window_action() to save the current window.
    • Tab State: Uses resurrect.tab_state.save_tab_action() to save the current tab.

    Example keybindings for config.keys:

    local resurrect = wezterm.plugin.require("https://github.com/MLFlexer/resurrect.wezterm")
    
    config.keys = {
      -- Save entire workspace
      { 
        key = "w", 
        mods = "ALT", 
        action = wezterm.action_callback(function(win, pane) 
          resurrect.state_manager.save_state(resurrect.workspace_state.get_workspace_state()) 
        end) 
      },
      -- Save current window
      { key = "W", mods = "ALT", action = resurrect.window_state.save_window_action() },
      -- Save current tab
      { key = "T", mods = "ALT", action = resurrect.tab_state.save_tab_action() },
      -- Save both workspace and current window
      { 
        key = "s", 
        mods = "ALT", 
        action = wezterm.action_callback(function(win, pane) 
          resurrect.state_manager.save_state(resurrect.workspace_state.get_workspace_state())
          resurrect.window_state.save_window_action()
        end) 
      },
    }
  8. Delete a saved state via fuzzy finder

    main

    You can implement a keybinding to allow users to select and delete saved state files using the fuzzy loader.

    local resurrect = wezterm.plugin.require("https://github.com/MLFlexer/resurrect.wezterm")
    
    config.keys = {
      {
        key = "d",
        mods = "ALT",
        action = wezterm.action_callback(function(win, pane)
          resurrect.fuzzy_loader.fuzzy_load(win, pane, function(id)
              resurrect.state_manager.delete_state(id)
            end,
            {
              title = "Delete State",
              description = "Select State to Delete and press Enter = accept, Esc = cancel, / = filter",
              fuzzy_description = "Search State to Delete: ",
              is_fuzzy = true,
            })
        end),
      },
    }
  9. Load saved state via fuzzy finder

    main

    Use resurrect.fuzzy_loader.fuzzy_load to interactively select and restore a saved state. The callback provides an id (formatted as type/name.ext) and a label. You must parse the id to determine the type (workspace, window, or tab) and then call the appropriate restore method from resurrect.state_manager and the corresponding state module.

    local resurrect = wezterm.plugin.require("https://github.com/MLFlexer/resurrect.wezterm")
    
    config.keys = {
      {
        key = "r",
        mods = "ALT",
        action = wezterm.action_callback(function(win, pane)
          resurrect.fuzzy_loader.fuzzy_load(win, pane, function(id, label)
            local type = string.match(id, "^([^/]+)") -- match before '/'
            id = string.match(id, "([^/]+)$") -- match after '/'
            id = string.match(id, "(.+)%..+") -- remove file extension
            
            local opts = {
              relative = true,
              restore_text = true,
              on_pane_restore = resurrect.tab_state.default_on_pane_restore,
            }
    
            if type == "workspace" then
              local state = resurrect.state_manager.load_state(id, "workspace")
              resurrect.workspace_state.restore_workspace(state, opts)
            elseif type == "window" then
              local state = resurrect.state_manager.load_state(id, "window")
              resurrect.window_state.restore_window(pane:window(), state, opts)
            elseif type == "tab" then
              local state = resurrect.state_manager.load_state(id, "tab")
              resurrect.tab_state.restore_tab(pane:tab(), state, opts)
            end
          end)
        end),
      },
    }
  10. Restore state into the current window

    main

    To replace the contents of your current window with a saved state (closing existing tabs to make room for the restored ones), use resurrect.window_state.restore_window with close_open_tabs = true.

    local opts = {
      close_open_tabs = true,
      window = pane:window(),
      on_pane_restore = resurrect.tab_state.default_on_pane_restore,
      relative = true,
      restore_text = true,
    }
    resurrect.window_state.restore_window(pane:window(), state, opts)
  11. Change the state save directory

    main

    You can change where resurrect stores its JSON state files using resurrect.state_manager.change_state_save_dir(path).

    Windows Users: Ensure the directory has write permissions. It is highly recommended to set an explicit path to a user-accessible directory.

    -- Example for Windows users
    resurrect.state_manager.change_state_save_dir("C:\\Users\\<user>\\Desktop\\state\\")
  12. Implement custom encryption/decryption

    main

    If you have a non-standard encryption workflow, you can provide your own encrypt and decrypt functions via resurrect.state_manager.set_encryption.

    • encrypt(file_path, lines): Should take the destination file path and the content lines, then perform the encryption.
    • decrypt(file_path): Should take the file path and return the decrypted string content.
    resurrect.state_manager.set_encryption({
      enable = true,
      private_key = "/path/to/private/key.txt",
      public_key = "public_key",
      encrypt = function(file_path, lines)
        -- your custom encryption logic here
      end,
      decrypt = function(file_path)
        -- your custom decryption logic here
        -- must return the decrypted string
      end,
    })