wezterm icon indicating copy to clipboard operation
wezterm copied to clipboard

macOS: "New wezterm Tab/Window Here" missing for Files and Folders Services Shortcuts

Open dev-zero opened this issue 2 years ago • 6 comments

Describe the solution you'd like

macOS offers a Services menu in Finder. kitty and iTerm2 register themselves to enable a "New iTerm2/kitty Tab/Window Here" link. it would be nice to also have wezterm there.

The settings window:

Screenshot 2023-07-07 at 09 45 48

The services context menu: Screenshot 2023-07-07 at 09 49 52

dev-zero avatar Jul 07 '23 07:07 dev-zero

I plan to work on this FYI. Some references until then:

  • A helpful gist with comments: https://gist.github.com/tonysneed/f9f09bfa28bcf98e8d8306f9b21f99e2

  • I started by making a mac "quick action" with Automator and verified it shows up in the services list for keyboard shortcuts:

  • This adds the item to the "quick actions" menu when right clicking on files/folders, but not the "services" menu:

  • The suggested method of using open -n -b "com.github.wez.wezterm" --args "$*" doesn't work as expected:

    ❯ open -n -b "com.github.wez.wezterm" --args "~/Git/some_project" # Nothing happens
    
  • WezTerm itself seems to not support passing a path to its CLI:

    ❯ wezterm ~/Git/some_project
    error: unrecognized subcommand '~/Git/some_project'
    
    Usage: wezterm [OPTIONS] [COMMAND]
    
    For more information, try '--help'.
    

Nezteb avatar Nov 20 '23 03:11 Nezteb

You need the start subcommand:

https://wezfurlong.org/wezterm/cli/start.html

wez avatar Nov 20 '23 19:11 wez

@wez I tried both wezterm start ~/Git/elixir and wezterm start -- ~/Git/elixir and get a crash each time:

screenshot_2023-11-20_at_20 06 20@2x

😅

Nezteb avatar Nov 20 '23 20:11 Nezteb

Take a look at the --cwd parameter

wez avatar Nov 20 '23 20:11 wez

Ah thanks!

I've got it working now with /opt/homebrew/bin/wezterm start --cwd "$*":

screenshot_2023-11-20_at_20 20 48@2x

The actual .workflow Automator file: Open in WezTerm.workflow.zip

The next step is to figure out how to add this as an actual service plist file, which is beyond me at the moment. 😄

Nezteb avatar Nov 20 '23 20:11 Nezteb

I've created a Shortcut for this: https://www.icloud.com/shortcuts/db66b71a7628475a8f7d115ec89ae916

On installation you will have to set the absolute path of the wezterm executable (preset is the Homebrew version). It will launch WezTerm if it's not running, and it will cd into the right-clicked folder. If you right-click a file, it will cd into the containing folder. It will intelligently use a fresh window.

Image

mjsarfatti avatar Jun 05 '25 16:06 mjsarfatti

Alternatively, I created an Automator Service script that works like a charm (it uses open -a WezTerm when wezterm is closed or wezterm cli spawn --new-window when there is a live socket in $HOME/.local/share/wezterm (i.e., when there is at least one WezTerm window open)

#!/usr/bin/env bash
set -euo pipefail

# Directory where wezterm's gui-sock files are usually created
SOCK_DIR="$HOME/.local/share/wezterm"
WEZTERM_BIN="/Applications/WezTerm.app/Contents/MacOS/wezterm"
WEZTERM_APP="/Applications/WezTerm.app"

find_live_socket() {
  for sock in $(ls -1t "$SOCK_DIR"/gui-sock-* 2>/dev/null || true); do
    if WEZTERM_UNIX_SOCKET="$sock" "$WEZTERM_BIN" cli list-clients >/dev/null 2>&1; then
      echo "$sock"
      return 0
    else
      # cleanup stale socket
      rm -f "$sock"
    fi
  done
  return 1
}

for f in "$@"; do
  # resolve symlinks
  if [[ -L "$f" ]]; then
    f=$(readlink -f "$f")
  fi

  # find live socket (if any)
  if live_socket=$(find_live_socket); then
    export WEZTERM_UNIX_SOCKET="$live_socket"

    if [[ -d "$f" ]]; then
      "$WEZTERM_BIN" cli spawn --new-window --cwd "$f"
    else
      "$WEZTERM_BIN" cli spawn --new-window --cwd "$(dirname "$f")"
    fi
  else
    if [[ -d "$f" ]]; then
      open -a "$WEZTERM_APP" --args start --cwd "$f"
    else
      open -a "$WEZTERM_APP" --args start --cwd "$(dirname "$f")"
    fi
  fi
done

victorgveloso avatar Sep 03 '25 07:09 victorgveloso

I have something similar as @victorgveloso though I never thought of using sockets, nor do I understand why (if) it is better to use them, but this works perfectly and fast for me:

#!/bin/zsh
set -euo pipefail

WEZTERM_APP="/Applications/WezTerm.app"
WEZTERM="$WEZTERM_APP/Contents/MacOS/wezterm"

dir="$1"
[[ -d "$dir" ]] || dir="$(dirname "$dir")"

if "$WEZTERM" cli list >/dev/null 2>&1; then
	"$WEZTERM" cli spawn --cwd "$dir" >/dev/null 2>&1 &
	open -a "$WEZTERM_APP"
else
	open -a "$WEZTERM_APP" --args start --cwd "$dir"
fi

mathmul avatar Dec 17 '25 11:12 mathmul

Why do you call "$WEZTERM" cli spawn --cwd "$dir" >/dev/null 2>&1 & followed by open -a "$WEZTERM_APP"?

That seems to have the same effect as my socket based solution.

I used to use a minimalist script like yours (except I would only call open -a) but I noticed I couldn't alternate between different instances of wezterm with command+~. I assumed MacOS was failing to identify them as instances of the same "app".

The socket was necessary to make that feature work for me. But it's been awhile since I made that script, wezterm might have fixed that issue by now.

Besides, if I called open -a with the socket (instead of cli spawn --new-window) my existing wezterm window would focus and no extra window would be spawned.

victorgveloso avatar Dec 17 '25 12:12 victorgveloso

I haven't refreshed the page before posting, so I deleted my post and am reposting again, and would first like to reply.


The only reason, I call open -a after cli spawn is to focus the window and not have to manually Alt+Tab.

The rest I understand why you have the need for. I just don't use WezTerm in the same way as you do.

Below is my original comment:


OK, I did some testing... Here are my conclusions.

S1 = @victorgveloso 's script S2 = my script

  1. S1 always opens a new WezTerm window, while S2 adds a new tab to an existing window (if one is running).
  2. These scripts are intended for Automator on macOS, so zsh is always available. Using bash if fine too; there is no technical limitation either way.
  3. Correct me if I am wrong, because I used ChatGPT to better understand this. S1 needs to handle multiple GUI instances (opens new windows), so inspecting sockets using cli list-clients makes it more robust, albeit a bit slower (no benchmarks. I eyeballed it, so bias is likely). S2 assumes a single GUI instance (always only one window and adds tabs to it), so discovery using cli list is sufficient. Both approaches are valid for their use case.
  4. If WezTerm is already opened, and one selects multiple folders, the S1 action then opens multiple new windows at their respective dir as CWD. If it is closed however, it only opens one window at the first dir as CWD. S2 does not support that (I personally don't see a good use case for it, except perhaps in combination with symlinks, ie if you have "homepage" dir full of shortcuts to different locations)
  5. S2 already opens at the symlinked directory, but S1 also resolves a symlinked file. Though it only resolves it once - if there is a double link, it gives the second link's parent dir. Addressed below.

Here is my (so far) final script:

#!/bin/zsh
set -euo pipefail

WEZTERM_APP="/Applications/WezTerm.app"
WEZTERM="$WEZTERM_APP/Contents/MacOS/wezterm"

dir="$1"
[[ -L "$dir" ]] && dir="$(realpath "$dir" 2>/dev/null || printf '%s\n' "$dir")"
[[ ! -d "$dir" ]] && dir="$(dirname "$dir")"

if "$WEZTERM" cli list >/dev/null 2>&1; then
	"$WEZTERM" cli spawn --cwd "$dir" >/dev/null 2>&1 &
	open -a "$WEZTERM_APP"
else
	open -a "$WEZTERM_APP" --args start --cwd "$dir"
fi

mathmul avatar Dec 17 '25 14:12 mathmul

That's an impressive analysis. I like the simplicity of your approach but I really need command+~ to work

victorgveloso avatar Dec 17 '25 14:12 victorgveloso