wezterm
                                
                                
                                
                                    wezterm copied to clipboard
                            
                            
                            
                        Add `activate-window` command to wezterm cli
Is your feature request related to a problem? Please describe.
It's currently not possible to switch to a different window via wezterm cli. This makes it difficult to switch workspaces via shell scripts. For example, I have a shell script that pipes a few directories into fzf and let's me choose one of them. If I chose one of those directories, I want to create a new workspace for it, set the appropriate working directory and then immediately switch to the new workspace.
Creating a new workspace is already possible via wezterm cli spawn --workspace <WORKSPACE_NAME> ... but wezterm will not switch to the newly created workspace by default, so I have to use SwitchToWorkspace separately.
Describe the solution you'd like
I'd like to be able to call wezterm cli activate-window --window-id <WINDOW_ID> to activate an existing window. If the GUI is already running, then it should immediately switch to the given window.
Additional context
I would probably - my specific workflow - prefer the SwitchToWorkspace action to have some kind of hook or event that allows me to do something before I switch to the new workspace (for example choosing a folder that will be the working-directory and use the name of that folder as workspace name) in one swoop. But since the wezterm cli already provides commands to activate panes and tabs, I'd guess it makes sense to also provide a command to activate windows.
Activating a window with the intent of switching workspace is a bit thorny because you're really wanting to control the GUI (which is what owns the GUI window -> Mux window mapping), but the CLI operates at the Mux level which doesn't have any GUI concepts. There's no established way to achieve this sort of command. The existing activate-pane and activate-tab commands are simpler because the Mux model has a first class parent object (the mux tab and mux window, respectively) which points to the child object. Workspaces are really just labelled windows; there is no parent object, so plumbing this particular thing via the CLI requires a decent amount of design work.
Putting that aside for the moment and focusing on:
would probably - my specific workflow - prefer the
SwitchToWorkspaceaction to have some kind of hook or event that allows me to do something before I switch to the new workspace (for example choosing a folder that will be the working-directory and use the name of that folder as workspace name) in one swoop
Take a look at:
- InputSelector for a way to prompt from a list of existing things
 - PromptInputLine to prompt for input
 
You could use the result of the prompting to initiate a window:perform_action of SwitchToWorkspace with an appropriate name or other parameters.
Sounds very good! Didn't know about the existence of InputSelector, which makes things a lot easier. I guess I'll simpy write a module and handle stuff inside wezterm (which I'd like to do in the first place, anyways).
Thanks a lot! Should I close as not planned, then?
We can keep it open for a bit; I may decide to close it later, or I may figure out a way to make this work nicely.
Just wanted to share this script that does what op is describing, in case anyone stumbles across the same problem:
{
    key = "R",
    mods = "SHIFT|SUPER",
    action = wezterm.action_callback(function(window, pane)
      local cmd = [[
      echo "$({
        echo $HOME;
        echo $HOME/.dotfiles;
        echo $HOME/.config/nvim;
        echo $HOME/Documents/Coding/Notes;
        find $HOME/Documents/Coding -mindepth 2 -maxdepth 2 -type d;
      })"
      ]]
      local file = io.popen(cmd)
      local output = file:read("*a")
      file:close()
      local choices = {}
      for directory in string.gmatch(output, "([^\n]+)") do
        table.insert(choices, { label = directory })
      end
      window:perform_action(
        act.InputSelector {
          title = "Workspaces",
          choices = choices,
          action = wezterm.action_callback(function(window, pane, id, label)
            if label then
              window:perform_action(act.SwitchToWorkspace {
                name = label:match("([^/]+)$"),
                spawn = {
                  cwd = label,
                }
              }, pane)
            end
          end),
        },
        pane
      )
    end),
  }
Change whatever is in the echo to your own liking.
I'd like to voice support for an activate-workspace CLI command because I prefer to use tools like fzf to pick a project to open rather than tying myself to a wezterm specific solution.
As a side question, @wez what does the activate-pane command actually do? If I'm in workspace A and activate a pane in workspace B (not currently visible) then my GUI doesn't automatically switch to workspace B to see the newly activated pane. The same is true for activate-tab. I'm wondering if we could just alter those CLI commands to also change the UI focus and achieve the same result as OP wants?
Here's how I got it working using what is available today and keeping only the minimum amount of code inside of my wezterm config.
Create a select-project.sh script
Assumes you have
fdandfzf
#!/bin/bash
# This script will open a new terminal for the selected project.
# Terminal used: wezterm
# hacky way to switch workspace via the wezterm cli
# source: https://github.com/wez/wezterm/issues/2979#issuecomment-1447519267
# watch discussion: https://github.com/wez/wezterm/discussions/3534
# watch issue: https://github.com/wez/wezterm/issues/3542
wezterm-switch-workspace() {
	args=$(jq -n --arg workspace "$1" --arg cwd "$2" '{"workspace":$workspace,"cwd":$cwd}' | base64)
	printf "\033]1337;SetUserVar=%s=%s\007" switch-workspace $args
}
# List of project roots, all are assumed to be below $HOME
project_roots=(
	"$HOME/Source"
	"$XDG_CONFIG_HOME"
)
# 1. Get all project folders without trailing slash
project_folders=$(fd --min-depth 1 --max-depth 1 -t directory . ${project_roots[@]} | xargs realpath)
# 2. Select a project using fzf (all paths are relative to $HOME)
selected_folder=$(printf '%s\n' "${project_folders[@]}" | sed "s|$HOME/||" | fzf)
# 3. Switch to the workspace by communicating with wezterm
wezterm-switch-workspace $selected_folder $HOME/$selected_folder
Handle the action in wezterm config
local wezterm = require 'wezterm'
local act = wezterm.action
wezterm.on('user-var-changed', function(window, pane, name, value)
  if name == 'switch-workspace' then
    local cmd_context = wezterm.json_parse(value)
    window:perform_action(
      act.SwitchToWorkspace {
        name = cmd_context.workspace,
        spawn = {
          cwd = cmd_context.cwd,
        },
      },
      pane
    )
  end
end)
                                    
                                    
                                    
                                
I also would like a way to switch to an existing workspace from the cli. I ran into this while trying to port one of my tmux scripts to wezterm. It has the same use case of selecting a project with fzf and creating a workspace for it.
I ended up with a similar solution before I found this issue. Here is mine in case it will help anyone:
https://github.com/benelan/git-mux/blob/wezterm/lua/git-mux.lua
I set the user var in the shell script here. It checks if stdin is a tty so I can use InputSelector instead of fzf in keymaps, e.g.
    {
      key = "p",
      mods = "LEADER|CTRL",
      action = wezterm.action_callback(require("git-mux").project),
    },
I was able to do the larger half of the script that handles creating/switching to git worktrees and wezterm tabs via the cli, and it would be nice to get the workspace portion there too!