Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 58 additions & 20 deletions src/scripts/terminal-helper
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
# 3. The terminal emulator with best accessibility comes first.
# 4. No order is guaranteed/desired for the remaining terminal emulators.

set -e
LAUNCHER_CMD=bash

usage() {
Expand All @@ -40,8 +39,11 @@ done
# OPTIND is a global variable
shift $((OPTIND - 1))

file="$(mktemp)"
echo "$1" >"$file"
file="$(mktemp)" || exit 1
echo "$1" >"$file" || {
rm "$file"
exit 1
}
cmd="${LAUNCHER_CMD} \"$file\""
echo "$cmd"

Expand All @@ -52,7 +54,7 @@ declare -A terminals=(
["ghostty"]="ghostty -e $cmd"
["kgx"]="kgx --wait -e $cmd"
["gnome-terminal"]="gnome-terminal --wait -- $cmd"
["kitty"]="kitty $cmd"
["kitty"]="kitty --wait-for-single-instance-window-close $cmd"
["wezterm"]="wezterm start --always-new-process $cmd"
["konsole"]="konsole -e $cmd"
["lxterminal"]="lxterminal -e $cmd"
Expand All @@ -61,7 +63,7 @@ declare -A terminals=(
["terminator"]="terminator -x $cmd"
["xfce4-terminal"]="xfce4-terminal --disable-server --command '$cmd'"
["xterm"]="xterm -e $cmd"
["ptyxis"]="ptyxis -e $cmd"
["ptyxis"]="ptyxis -- $cmd"
)
declare -a term_order=(
"alacritty"
Expand All @@ -82,27 +84,63 @@ declare -a term_order=(

)

if [ -z "$terminal" ] || ! command -v "$terminal" &>/dev/null; then
for entry in "${term_order[@]}"; do
if command -v "$entry" >/dev/null 2>&1; then
# gnome-console does not exit on command completion so we need to kill
# it manually
[[ "$entry" == "kgx" ]] && echo "kill -SIGQUIT \$PPID 2>/dev/null" >> "$file"
terminal="$entry"
break
fi
done
# 1. $TERMINAL must come first (per invariants)
if [ -n "$TERMINAL" ] && [[ -n "${terminals[$TERMINAL]+_}" ]] && command -v "$TERMINAL" &>/dev/null; then
terminal="$TERMINAL"
fi

if [ -z "$terminal" ]; then
# Ordered candidates: $TERMINAL first, then the known terminals that are
# installed. Launch failures fall through to the next candidate.
declare -a candidates=()
if [ -n "$terminal" ]; then
candidates+=("$terminal")
fi
for entry in "${term_order[@]}"; do
[[ "$entry" == "$terminal" ]] && continue
command -v "$entry" >/dev/null 2>&1 && candidates+=("$entry")
done

if [ ${#candidates[@]} -eq 0 ]; then
rm "$file"
notify-send -t 1500 --app-name=CachyOS "No terminal installed" "Could not find a terminal emulator. Please install one."
exit 1
fi

eval "${terminals[${terminal}]}" 2>/dev/null || {
if [[ "$terminal" != "kgx" ]]; then
failed=1
for entry in "${candidates[@]}"; do
# Rewrite the script file so a failed attempt doesn't leave terminal
# specific lines (e.g. the kgx kill) behind for the next candidate.
echo "$1" >"$file" || {
rm "$file"
exit 2
exit 1
}
if [[ "$entry" == "kgx" ]]; then
# gnome-console does not exit on command completion so we need to kill
# it manually
echo '(( PPID > 1 )) && kill -SIGQUIT $PPID 2>/dev/null' >>"$file"
fi
}
# Normalize the shell exit status: some terminals (foot, st) propagate
# it, and a failed command must not be mistaken for a failed launch.
echo 'exit 0' >>"$file"

eval "${terminals[$entry]}" 2>/dev/null
rc=$?
# kgx is killed by the line above after the command completes, which
# shows up as exit status 131; treat that as a successful launch.
if [[ $rc -eq 0 ]] || { [[ "$entry" == "kgx" ]] && [[ $rc -eq 131 ]]; }; then
failed=0
break
fi
# 126/127 mean the command was canceled or not authorized (e.g. the user
# dismissed the pkexec prompt) — retrying would just prompt again.
if [[ $rc -eq 126 ]] || [[ $rc -eq 127 ]]; then
break
fi
done

rm "$file"

if ((failed)); then
notify-send -t 1500 --app-name=CachyOS "Failed to launch terminal" "Could not start a terminal emulator to run the command."
exit 2
fi