Files
galaxy/app/assets/bundled/bootstrap/zsh_body.sh
T
rkw6086 75d4965385 Port recent Warp terminal and UI improvements
Improve tab-group search, rename focus, history navigation, shell prompt and
completion handling, emoji width promotion, and macOS clipboard support.
Guard unavailable settings/model-selector/undo-close views and forward the
MCP OAuth callback issuer through the existing authentication flow.

Adapt local changes from 14 upstream Warp commits through f571865ca3f2,
reviewed from the latest 200 commits. Preserve Galaxy provider lifecycle,
permissions, storage, and branding; exclude hosted/cloud infrastructure.

Fix existing boolean-assertion lints and use stronger optimization with four
code-generation units for the app test target to fit macOS unwind offsets.
Production and dependency compilation settings remain unchanged.

Validation: two clean builds and a final build; both prescribed Clippy
commands with -D warnings; formatting, shell syntax and completion cleanup;
167 focused regression tests. Galaxy was not launched.
2026-10-06 14:48:09 -05:00

1523 lines
72 KiB
Bash

# Note that WARP_SESSION_ID is expected to have been set when executing commands to
# emit the InitShell payload, which includes the session ID.
#
# Throughout, command -p is used to call external binaries. command -p resolves the
# given command using the system default $PATH, which ensures the shells can locate
# the corresponding binaries even if the user has a clobbered value of $PATH.
if [[ -z $WARP_BOOTSTRAPPED ]]; then
# Return PS2 to its original value. We set this to an empty string in zsh.sh,
# and want to reset it now that we've received the bootstrap script and started
# to eval it.
if (( ${+ORIGINAL_PS2} )); then
PS2="$ORIGINAL_PS2"
else
unset PS2
fi
# Byte sequence used to signal the start of a DCS. ([0x1b, 0x50, 0x24] which
# maps to <ESC>, P, $ in ASCII.)
DCS_START="$(printf '\eP$')"
# Appended to $DCS_START to signal that the following message is JSON-encoded.
DCS_JSON_MARKER="d"
# Byte sequence used to signal the end of a DCS (7-bit ST: ESC \).
DCS_END="$(printf '\x1b\x5c')"
# OSC used to mark the start of in-band command output.
#
# Printable characters received this OSC and OSC_END_GENERATOR_OUTPUT are parsed and handled as
# output for an in-band command.
OSC_START_GENERATOR_OUTPUT="$(printf '\e]9277;A\a')"
# OSC used to mark the end of in-band command output.
#
# Printable characters received between OSC_START_GENERATOR_OUTPUT and this are parsed and
# handled as output for an in-band command.
OSC_END_GENERATOR_OUTPUT="$(printf '\e]9277;B\a')"
OSC_START="$(printf '\e]9278;')"
OSC_END="$(printf '\a')"
OSC_PARAM_SEPARATOR=";"
OSC_RESET_GRID="$(printf '\e]9279\a')"
# Attempt to cd to the desired initial working directory, swallowing any
# errors. If this fails, the user will end up in their home directory.
if [[ ! -z "$GALAXY_INITIAL_WORKING_DIR" ]]; then
cd "$GALAXY_INITIAL_WORKING_DIR" >/dev/null 2>&1
unset GALAXY_INITIAL_WORKING_DIR
fi
# We configure history to ignore commands starting with space to avoid leaking
# our bootstrap script into the user's history. At this point, we unset this
# option to avoid turning on this behavior and potentially confusing the user.
# If they set it in their config files, their value will be respected.
unsetopt hist_ignore_space
# The temporary files used to track generator PIDs. We'll fill these in later,
# if we execute any generator commands.
_WARP_GENERATOR_PIDS_STARTED_TMP_FILE=""
_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE=""
# Flag to indicate whether the current command is a generator command.
# We use an empty string as the sentinel value (rather than unsetting) for
# compatibility with `setopt nounset`.
_WARP_GENERATOR_COMMAND=""
# Make sure we delete generator PID files when the shell exits, if they exist.
__warp_generator_pid_file_cleanup() {
if [[ -f $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE ]]; then
command -p rm $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE
fi
if [[ -f $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE ]]; then
command -p rm $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE
fi
}
trap __warp_generator_pid_file_cleanup EXIT
# Writes a hex-encoded JSON message to the pty.
warp_send_json_message () {
# Sends a message to the controlling terminal as a DCS control sequence.
# Note that because the JSON string may contain characters that we don't control (including
# unicode), we encode it as hexadecimal string to avoid prematurely calling unhook if
# one of the bytes in JSON is 9c (ST) or other (CAN, SUB, ESC).
local msg=$(warp_hex_encode_string "$1")
# We send the InitShell hook via OSCs when on WSL and via DCSs otherwise.
if [ "$WARP_USING_WINDOWS_CON_PTY" = true ]; then
printf $OSC_START$DCS_JSON_MARKER$OSC_PARAM_SEPARATOR$msg$OSC_END
else
printf "%b%b%s%b" $DCS_START $DCS_JSON_MARKER $msg $DCS_END
fi
}
# Emit the ExitShell hook right before the remote shell exits so the Warp
# client can drop per-session resources (specifically the
# `ssh … remote-server-proxy` child that holds a multiplexed channel on
# the foreground ssh ControlMaster). This avoids a hang where the master
# waits on orphaned slave channels when the user ends their interactive
# session.
#
# Only relevant for remote SSH shells. WARP_IS_SSH is exported to "1"
# by `warp_ssh_helper` on the remote side of a Warp-managed SSH session
# and is unset everywhere else (local shells, subshells, docker
# sandboxes, etc.), so the hook only fires where a remote-server-proxy
# actually needs tearing down.
#
# Installed after warp_send_json_message is defined so the handler is
# callable the moment the hook is registered.
if [[ "$WARP_IS_SSH" == "1" ]]; then
__warp_emit_exit_shell() {
if [[ -n "$WARP_SESSION_ID" ]]; then
warp_send_json_message \
"{\"hook\": \"ExitShell\", \"value\": {\"session_id\": $WARP_SESSION_ID}}"
fi
}
# zshexit_functions is zsh's idiomatic exit-hook mechanism. We prefer
# it over `trap ... EXIT` for a few reasons:
# 1. It is additive: appending to the array composes with the
# existing `trap __warp_generator_pid_file_cleanup EXIT` above.
# Using `trap ... EXIT` here would replace that handler (zsh, like
# bash, only allows one trap per signal) and we would have to
# manually re-invoke the generator cleanup.
# 2. It runs in the main shell's context, unlike `trap ... EXIT`
# which can execute in a subshell under some zsh versions --
# problematic here because we need to write to the parent shell's
# controlling PTY to emit the ExitShell hook.
# 3. It also fires on SIGHUP-triggered exits, so a single
# registration covers both normal exit (exit, logout, Ctrl-D) and
# connection-drop cases.
zshexit_functions+=(__warp_emit_exit_shell)
fi
warp_maybe_send_reset_grid_osc() {
if [ "$WARP_USING_WINDOWS_CON_PTY" = true ]; then
printf $OSC_RESET_GRID
fi
}
# Hex-encodes the given argument and writes it to the PTY, wrapped in the OSC
# sequences for generator output.
#
# Usage:
# warp_send_generator_output_osc $my_output
#
# The payload of the OSC is "<content_length>;<hex-encoded content>".
#
# Note: If we're on windows, we send a reset grid to erase any cursor mutations caused by
# the in-band command.
warp_send_generator_output_osc() {
local hex_encoded_message=$(warp_hex_encode_string "$1")
local byte_count=$(LC_ALL="C"; printf "${#hex_encoded_message}")
printf "%b%i;%s%b" $OSC_START_GENERATOR_OUTPUT $byte_count $hex_encoded_message $OSC_END_GENERATOR_OUTPUT
warp_maybe_send_reset_grid_osc
}
# Executes the given command and writes its output to the pty wrapped in a
# DCS. The written DCS conforms to a basic schema including other metadata:
# "<command_id>;<command_output>;<exit_code>"
# where command_id is the ID given as the first argument to this function,
# exit_code is the exit code of the executed command, and command_output is
# the output itself.
_warp_execute_command() {
local command_id=$1
# This is shorthand to slice the 2nd-nth arguments of this function (i.e.
# the command array) into its own array. The first argument is the
# command_id stored above. Zsh arrays are 1-indexed, hence slicing from
# index 2 rather than index 1.
local -a command
command=("${@:2}")
# Declare raw_output prior to actually assigning it, because `local` is a command itself, which
# interferes with capturing the exit code via $? (it overwrites $? with the 0, because the
# 'local' command always succeeds).
local raw_output
# Command substitution only captures stdout, so redirect stderr to stdout.
# Note that we use `eval` here to actually execute the command, because some shell syntax
# that may be used in the command might not be valid in a command substitution (e.g. the
# '$(<command>)' syntax).
# Also note that zsh variables can contain null characters, so this doesn't require any special
# handling.
raw_output=$(eval "$command" 2>&1)
local exit_code=$?
warp_send_generator_output_osc "$command_id;$raw_output;$exit_code"
}
# Runs the given command in the background, records its PID in
# _WARP_GENERATOR_PIDS_STARTED_TMP_FILE, and adds its PID from the file when
# the job is completed.
_warp_run_generator_command_internal() {
_warp_execute_command "$@" &
# $! contains the PID of the most recently backgrounded command.
local pid=$!
echo $pid >> $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE
wait $pid 2> /dev/null
# If the exit code of the backgrounded _warp_execute_command process is non-zero,
# the call to send the generator output failed (most likely because this is being
# executed in an old zsh version that doesn't support some syntax in
# _warp_execute_command function itself). In this case, send empty output with
# exit code 1 to indicate generator execution failed.
if [[ $? -ne 0 ]]; then
warp_send_generator_output_osc "$1;;1"
fi
# Add the PID to the completed generators PID file.
#
# The completed generator PIDs file may not exist if this generator was (by
# error) left running/not cancelled properly in warp_preexec.
if [[ -f $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE ]]; then
echo $pid >> $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE
fi
}
# Executes a generator command in the background, where the first argument is
# the "command ID" assigned by the Rust app and the second-nth arguments
# specify the command to be run.
#
# Note that the command string should be single-quoted so any variables are
# not substituted until the command string is actually evaluated.
#
# Usage:
# warp_run_generator_command <command_id> '<command> <arg1> ... <argn>'
warp_run_generator_command() {
# Setting this environment variable prevents warp_precmd from emitting the
# 'Block started' hook to the Rust app.
_WARP_GENERATOR_COMMAND=1
# Ensure the started and completed generator PID files exist.
if [[ -z $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE || ! -f $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE ]]; then
_WARP_GENERATOR_PIDS_STARTED_TMP_FILE="$(command -p mktemp)"
fi
if [[ -z $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE || ! -f $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE ]]; then
_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE="$(command -p mktemp)"
fi
# To minimize latency and prevent the user from being blocked from entering a command,
# cache the user's precmd_functions and only register warp_precmd. In the warp_precmd
# execution following this generator command, the user's precmd_functions are restored.
_USER_PRECMD_FUNCTIONS=($precmd_functions)
# Remove all precmd functions other than ones defined by us or p10k. If we remove the
# p10k precmd functions, p10k will see that we started running an in-band command but
# not know when it finishes, which causes a variety of undesirable side-effects.
precmd_functions=(${(M)precmd_functions:#*(warp|p9k)*})
(_warp_run_generator_command_internal "$@" &)
}
# Returns exit code 1 if the given argument starts with 'warp_run_generator_command'.
_is_warp_generator_command() {
[[ "$1" != *"warp_run_generator_command"* ]]
}
# Note that this is very performance sensitive code, so try not to
# invoke any external commands in here.
warp_preexec () {
local warp_escaped_command="$(warp_escape_json $1)"
warp_send_json_message "{\"hook\": \"Preexec\", \"value\": {\"command\": \"$warp_escaped_command\", \"session_id\": $WARP_SESSION_ID}}"
warp_maybe_send_reset_grid_osc
# If this preexec is called for user command, kill ongoing generator command jobs and clean
# up the bookkeeping temp files used to bookkeep.
if _is_warp_generator_command "$1" && [[ -f $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE ]] && [[ -f $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE ]]
then
# Read PIDs from the started generators tmp file that are not present in
# the completed generators tmp file into a zsh array.
#
# The logic used to be the following:
#
# pids=($(command -p comm -23 $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE))
#
# However, that requires that the files are sorted, which we do not enforce (the OS can assign PIDs
# in any order). While we could sort the files and then compare them, the files are expected to be
# small, so we avoid the overhead of spawning multiple processes and instead do the comparison
# manually.
completed_pids=(${(f)"$(<$_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE)"})
spawned_pids=(${(f)"$(<$_WARP_GENERATOR_PIDS_STARTED_TMP_FILE)"})
pids=(${spawned_pids:|completed_pids})
# If the array is not empty, kill the ongoing pids.
if [[ ! -z $pids ]]; then
# Suppress stderr output; kill writes to stderr if any of the given
# PIDS are not running (which might rarely be the case due to race
# conditions in checking which PIDS to cancel and this kill command.
(kill -9 $pids 2>&1) >/dev/null
fi
fi
}
# The git prompt's git commands are read-only and should not interfere with
# other processes. This environment variable is equivalent to running with `git
# --no-optional-locks`, but falls back gracefully for older versions of git.
# See git(1) for and git-status(1) for a description of that flag.
#
# We wrap in a local function instead of exporting the variable directly in
# order to avoid interfering with manually-run git commands by the user.
warp_git () {
GIT_OPTIONAL_LOCKS=0 command git "$@"
}
# Note that this is very performance sensitive code, so try not to
# invoke any external commands in here.
warp_precmd () {
# $? is the exit code of the last command executed in this process, which
# includes commands run within function definitions. So we capture the
# exit code from $? in precmd first, prior to executing any other
# commands so we can be assured that it represents the exit code of the
# previously run user command (as opposed to any of the commands executed
# in this function below).
local exit_code=$?
local next_block_id="precmd-$WARP_SESSION_ID-$((block_id++))"
warp_send_json_message "{\"hook\": \"CommandFinished\", \"value\": {\"exit_code\": $exit_code, \"next_block_id\": \"$next_block_id\", \"session_id\": $WARP_SESSION_ID}}"
warp_maybe_send_reset_grid_osc
# If this is being called for a generator command, short circuit and send an unpopulated
# precmd payload (except for pwd), since we don't re-render the prompt after generator commands
# are run.
if [ -n "$_WARP_GENERATOR_COMMAND" ]; then
# Restore the user's precmd_functions, since they were un-registered prior to executing
# the generator.
precmd_functions=($_USER_PRECMD_FUNCTIONS)
_WARP_GENERATOR_COMMAND=""
warp_send_json_message "{\"hook\": \"Precmd\", \"value\": {
\"exit_code\": $exit_code,
\"next_block_id\": \"$next_block_id\",
\"pwd\": \"\",
\"ps1\": \"\",
\"git_head\": \"\",
\"git_branch\": \"\",
\"virtual_env\": \"\",
\"conda_env\": \"\",
\"node_version\": \"\",
\"session_id\": $WARP_SESSION_ID,
\"is_after_in_band_command\": true
}}"
return 0
fi
# If the files for tracking generator PIDs exist, clear them.
if [[ -n $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE && -f $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE ]]; then
echo "" > $_WARP_GENERATOR_PIDS_STARTED_TMP_FILE
fi
if [[ -n $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE && -f $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE ]]; then
echo "" > $_WARP_GENERATOR_PIDS_COMPLETED_TMP_FILE
fi
# Reset the custom kill-buffer binding as the user's zshrc (which is sourced after zshrc_warp)
# could have added a bindkey. This won't have any user-impact because these shortcuts are only run
# in the context of the zsh line editor, which isn't displayed in Warp.
bindkey -r '^P'
bindkey '^P' kill-buffer
# Reset the custom input-reporting binding as well, in case it was overridden
# by the user's zshrc.
# This is arbitrarily bound to ESC-i in all supported shells ("i" for input).
# Binding to ESC-1 caused bootstrap failures with vi keybindings.
bindkey -r '\ei'
bindkey '\ei' warp_report_input
# Introduce keybinding to switch prompt modes (PS1 vs built-in Warp prompt).
# This is arbitrarily bound to ESC-p in all supported shells ("p" for PS1),
# and we can change it to any other keybinding if needed.
bindkey -r '\ep'
bindkey '\ep' warp_change_prompt_modes_to_ps1
# Introduce keybinding to switch prompt modes (PS1 vs built-in Warp prompt).
# This is arbitrarily bound to ESC-w in all supported shells ("w" for Warp prompt),
# and we can change it to any other keybinding if needed.
bindkey -r '\ew'
bindkey '\ew' warp_change_prompt_modes_to_warp_prompt
local escaped_pwd
if [ -n "${WSL_DISTRO_NAME:-}" ]; then
# In WSL, avoid symlinks b/c on Windows `std::fs` is unable to resolve symlink inside WSL containers.
escaped_pwd=$(warp_escape_json "$(pwd -P)")
else
escaped_pwd=$(warp_escape_json "$PWD")
fi
local escaped_virtual_env=""
local escaped_conda_env=""
local escaped_node_version=""
local escaped_git_head=""
local escaped_git_branch=""
local escaped_kube_config=""
# Only fill these fields once we've finished bootstrapping, as the
# blocks created during the bootstrap process don't have visible
# prompts, and we don't want to invoke `git` before we've sourced the
# user's rcfiles and have a fully-populated PATH.
if [[ -n $WARP_BOOTSTRAPPED ]]; then
if [[ -n ${VIRTUAL_ENV:-} ]]; then
escaped_virtual_env=$(warp_escape_json $VIRTUAL_ENV)
fi
if [[ -n ${CONDA_DEFAULT_ENV:-} ]]; then
escaped_conda_env=$(warp_escape_json $CONDA_DEFAULT_ENV)
fi
# Get the Node.js version, but only when the Node.js Version chip is enabled.
# Warp sets WARP_PROMPT_NODE_VERSION_ENABLED to "0" when the chip is not in the
# prompt (defaulting to enabled when unset), so we avoid spawning `node` on
# every prompt when the chip is not shown.
if [[ "$WARP_PROMPT_NODE_VERSION_ENABLED" != "0" ]] && command -v node > /dev/null 2>&1; then
# Check for package.json in current directory and parent directories
local current_dir="$PWD"
local found_package_json=false
local package_json_dir=""
while [[ -n "$current_dir" ]]; do
if [[ -f "$current_dir/package.json" ]]; then
found_package_json=true
package_json_dir="$current_dir"
break
fi
[[ "$current_dir" == "/" ]] && break
# Strip the last path segment without spawning `dirname`.
current_dir="${current_dir%/*}"
[[ -z "$current_dir" ]] && current_dir="/"
done
# Only show node version if package.json is within a git repository
if [[ "$found_package_json" = true ]]; then
local git_dir="$package_json_dir"
local in_git_repo=false
while [[ -n "$git_dir" ]]; do
if [[ -d "$git_dir/.git" ]]; then
in_git_repo=true
break
fi
[[ "$git_dir" == "/" ]] && break
git_dir="${git_dir%/*}"
[[ -z "$git_dir" ]] && git_dir="/"
done
if [[ "$in_git_repo" = true ]]; then
# Cache the resolved version keyed on PWD + PATH so we only spawn
# `node --version` when the directory or PATH changes (PATH changes
# on `nvm use`). The cache vars are global (no `local`) so they
# persist across precmd invocations.
local node_cache_key="$PWD:$PATH"
if [[ "$node_cache_key" == "$_WARP_NODE_VERSION_CACHE_KEY" ]]; then
escaped_node_version="$_WARP_NODE_VERSION_CACHE_VALUE"
else
local node_version=$(node --version 2>/dev/null)
if [[ -n "$node_version" ]]; then
escaped_node_version=$(warp_escape_json "$node_version")
fi
_WARP_NODE_VERSION_CACHE_KEY="$node_cache_key"
_WARP_NODE_VERSION_CACHE_VALUE="$escaped_node_version"
fi
fi
fi
fi
if [[ -n ${KUBECONFIG:-} ]]; then
escaped_kube_config=$(warp_escape_json $KUBECONFIG)
fi
# Note: We explicitly do _not_ use command -p here, as `git` is a command that can be
# installed in non-standard locations and so is not always available on the shell's
# default PATH. Instead, we rely on the active PATH, as if the user doesn't have git
# available to their session, it is unlikely they will be looking for git branch
# information from the prompt.
local git_branch=""
local git_head=""
if command -v git >/dev/null 2>&1; then
git_branch=$(warp_git symbolic-ref --short HEAD 2> /dev/null)
# The git branch the user is on, or the git commit hash if they're not on a branch.
git_head="${git_branch:-$(warp_git rev-parse --short HEAD 2> /dev/null)}"
fi
escaped_git_head=$(warp_escape_json "$git_head")
escaped_git_branch=$(warp_escape_json "$git_branch")
fi
# We also pass the shell's notion of `honor_ps1` to ensure it's synced correctly on the Warp-side for prompt handling.
# This is passed as a "real boolean" via the JSON payload (string interpolated into JSON string below).
local honor_ps1
if [[ "$WARP_HONOR_PS1" == "1" ]]; then
honor_ps1="true"
else
honor_ps1="false"
fi
local escaped_json="{\"hook\": \"Precmd\", \"value\": {
\"exit_code\": $exit_code,
\"next_block_id\": \"$next_block_id\",
\"pwd\": \"$escaped_pwd\",
\"ps1\": \"\",
\"honor_ps1\": $honor_ps1,
\"rprompt\": \"\",
\"git_head\": \"$escaped_git_head\",
\"git_branch\": \"$escaped_git_branch\",
\"virtual_env\": \"$escaped_virtual_env\",
\"conda_env\": \"$escaped_conda_env\",
\"node_version\": \"$escaped_node_version\",
\"kube_config\": \"$escaped_kube_config\",
\"session_id\": $WARP_SESSION_ID
}}"
warp_send_json_message "$escaped_json"
}
warp_clear_on_next_block () {
warp_send_json_message '{"hook": "ClearOnNextBlock"}'
}
# Format a string value according to JSON syntax.
warp_escape_json () {
# Explanation of the sed replacements (each command is separated by a `;`):
# s/(["\\])/\\\1/g - Replace all double-quote (") and backslash (\) characters with the escaped versions (\" and \\)
# s/\b/\\b/g - Replace all backspace characters with \b
# s/\t/\\t/g - Replace all tab characters with \t
# s/\f/\\f/g - Replace all form feed characters with \f
# s/\r/\\r/g - Replace all carriage return characters with \r
# $!s/$/\\n/ - On every line except the last, insert the \n escape at the end of the line
# Note: sed acts line-by-line, so it doesn't see the literal newline characters to replace
#
# tr -d '\n' - Remove the literal newlines from the final output
#
# Additional note: In a shell script between single quotes ('), no escape sequences are interpreted.
# To work around that and insert the literal values into the regular expressions, we stop the single-quote,
# then add the literal using ANSI-C syntax ($'\t'), then start a new single-quote. That is the meaning
# behind the various `'$'\b''` blocks in the command. All of these separate strings are then concatenated
# together to form the full argument to send to sed.
#
# We also use 'command sed' to ensure that we aren't accidentally executing an alias or function named 'sed'
command -p sed -E 's/(["\\])/\\\1/g; s/'$'\b''/\\b/g; s/'$'\t''/\\t/g; s/'$'\f''/\\f/g; s/'$'\r''/\\r/g; $!s/$/\\n/' <<<"$*" | command -p tr -d '\n'
}
warp_escape_ps1 () {
# Turns out that the processed prompt is a complicated data structure that includes lots of
# information that's passed to the shell (including the actual shell, version, working directory
# and, well, the prompt itself). What is more, prompt can also include emojis - unicode characters
# that sometimes contain special bytes (ie. ST, CAN or SUB) that are otherwise used as unhook
# triggers for the precmd. Instead of escaping those and extracting the value of the prompt itself,
# we simply convert the entire data structure into a single line hex string, which Warp
# later decodes and sends to the grid to show the prompt.
# Note: before converting the prompt to a hex string, we remove the multi-line newlines and replace
# them with a single space (to avoid prompts that span multiple empty lines).
command -p tr '\n\n' ' ' <<< "$*" | command -p od -An -v -tx1 | command -p tr -d ' \n'
}
# warp_hex_encode_string encodes the entire DCS string (JSON) with od making it essentially
# a very long hexadecimal string.
# Afterwards it's decoded in rust and parsed as usual.
# Accepts one argument: DCS JSON string
warp_hex_encode_string () {
printf '%s' "$1" | command -p od -An -v -tx1 | command -p tr -d ' \n'
}
# We set precmd and preexec hooks in order to set the title for the idle
# terminal and the terminal running a command respectively. This is so we
# provide a reasonable default behavior in the case where the user doesn't
# have any shell scripts to set titles.
#
# If another shell script also has precmd/preexec hooks to set the title,
# we won't be clobbering them because our hooks will run first.
# If the WARP_DISABLE_AUTO_TITLE variable is set, we won't set the title at all.
# This way, setting the terminal title in a echo command and escape
# sequences will work (a single command to set the title normally will get
# clobbered by a precmd hook)."
function warp_title {
# Disable oh-my-zsh default title otherwise.
DISABLE_AUTO_TITLE="true"
setopt localoptions nopromptsubst
# Don't set the title if inside emacs, unless using vterm
[[ -n "${INSIDE_EMACS:-}" && "${INSIDE_EMACS:-}" != vterm ]] && return
title="%25<..<$1" # shorten the tab_title to 25 characters
print -Pn "\e]0;${title:q}\a" # set tab & window name (they're the same in Warp)
}
ZSH_THEME_TERM_TITLE_IDLE="%~"
ZSH_THEME_TERM_TAB_TITLE_IDLE_REMOTE="%m:%~"
# Runs before showing the prompt
function warp_set_title_idle_on_precmd {
# If the user wants to set the title using oh-my-zsh, they can
# set the WARP_DISABLE_AUTO_TITLE flag.
[[ "${WARP_DISABLE_AUTO_TITLE:-}" != true ]] || return
if [[ $GALAXY_IS_LOCAL_SHELL_SESSION == "1" ]]; then
warp_title "$ZSH_THEME_TERM_TITLE_IDLE"
else
warp_title "$ZSH_THEME_TERM_TAB_TITLE_IDLE_REMOTE"
fi
}
# Runs before executing the command
function warp_set_title_active_on_preexec {
# If the user wants to set the title using oh-my-zsh, they can
# set the WARP_DISABLE_AUTO_TITLE flag.
[[ "${WARP_DISABLE_AUTO_TITLE:-}" != true ]] || return
emulate -L zsh
setopt extended_glob
# split command into array of arguments
local -a cmdargs
cmdargs=("${(z)2}")
# if running fg, extract the command from the job description
if [[ "${cmdargs[1]}" = fg ]]; then
# get the job id from the first argument passed to the fg command
local job_id jobspec="${cmdargs[2]#%}"
# logic based on jobs arguments:
# http://zsh.sourceforge.net/Doc/Release/Jobs-_0026-Signals.html#Jobs
# https://www.zsh.org/mla/users/2007/msg00704.html
case "$jobspec" in
<->) # %number argument:
# use the same <number> passed as an argument
job_id=${jobspec} ;;
""|%|+) # empty, %% or %+ argument:
# use the current job, which appears with a + in $jobstates:
# suspended:+:5071=suspended (tty output)
job_id=${(k)jobstates[(r)*:+:*]} ;;
-) # %- argument:
# use the previous job, which appears with a - in $jobstates:
# suspended:-:6493=suspended (signal)
job_id=${(k)jobstates[(r)*:-:*]} ;;
[?]*) # %?string argument:
# use $jobtexts to match for a job whose command *contains* <string>
job_id=${(k)jobtexts[(r)*${(Q)jobspec}*]} ;;
*) # %string argument:
# use $jobtexts to match for a job whose command *starts with* <string>
job_id=${(k)jobtexts[(r)${(Q)jobspec}*]} ;;
esac
# override preexec function arguments with job command
if [[ -n "${jobtexts[$job_id]}" ]]; then
1="${jobtexts[$job_id]}"
2="${jobtexts[$job_id]}"
fi
fi
# cmd name only, or if this is sudo or ssh, the next cmd
local CMD="${1[(wr)^(*=*|sudo|ssh|mosh|rake|-*)]:gs/%/%%}"
local LINE="${2:gs/%/%%}"
warp_title "$CMD"
}
function warp_report_input {
local escaped_input="$(warp_escape_json "$BUFFER")"
warp_send_json_message "{ \"hook\": \"InputBuffer\", \"value\": { \"buffer\": \"$escaped_input\", \"session_id\": $WARP_SESSION_ID } }"
# This prevents zsh from printing typeahead as background output after we've fetched it.
BUFFER=""
}
zle -N warp_report_input
function clear() {
warp_send_json_message "{\"hook\": \"Clear\", \"value\": {\"session_id\": $WARP_SESSION_ID}}"
}
function warp_finish_update {
local update_id="$1"
warp_send_json_message "{ \"hook\": \"FinishUpdate\", \"value\": { \"update_id\": \"$update_id\", \"session_id\": $WARP_SESSION_ID} }"
}
# Check if the warp apt source file has been renamed to `warpdotdev.list.distUpgrade` due to an ubuntu version update.
# If this occurred, we want to rename the source file back to `warpdotdev.list` to ensure updates can proceed.
# We purposefully skip this if either the `warpdotdev.list` file already exists (indicating that the user has already
# done this themselves) _or_ if a `warpdotdev.sources` file exists (which is the new Deb822 format for source files).
# The `.sources` file could only exist if a user manually created it; Ubuntu doesn't create one automatically for the
# warp source file due to a bug in its update flow where it considers our source file to be "invalid" because it
# contains a `signed-by` key.
function warp_handle_dist_upgrade {
local source_file_name="$1"
eval "$(command apt-config shell APT_SOURCESDIR 'Dir::Etc::sourceparts/d')"
if [[ ! -e $APT_SOURCESDIR$source_file_name.list && \
! -e $APT_SOURCESDIR$source_file_name.sources && \
-e $APT_SOURCESDIR$source_file_name.list.distUpgrade ]]; then
# DO NOT DO THIS. We should never run a command for user with `sudo`. The only reason this is safe here is because
# we insert this function into the input for the user to determine if they want to execute (we never run it on
# their behalf without their permission). To be transparent about what is being executed with sudo, we echo out the
# command we're about to run.
echo "Executing: sudo cp \"$APT_SOURCESDIR$source_file_name.list.distUpgrade\" \"$APT_SOURCESDIR$source_file_name.list\""
sudo cp "$APT_SOURCESDIR$source_file_name.list.distUpgrade" "$APT_SOURCESDIR$source_file_name.list"
fi
}
# Strips prompt constructs that zsh counts as visible "glitch" columns even
# when they appear inside a %{...%} zero-width region, returning the result
# in $REPLY. The explicit-width form %n{ is rewritten to %{ (preserving the
# brace pairing), and the %G, %nG, and %-nG forms are removed entirely.
# Neither change affects the rendered prompt bytes, only zsh's internal
# width accounting. Literal %% escapes are matched first so that they cannot
# form false positives (e.g. %%1{ renders as literal text and must be left
# alone).
function warp_strip_glitch_width_constructs() {
setopt localoptions extendedglob
local match mbegin mend
REPLY=${1:-}
REPLY=${REPLY//(#b)(%%|%<->\{|%(-|)(<->|)G)/${${match[1]:#%(-|)(<->|)G}/(#s)%<->\{(#e)/%\{}}
}
# Check whether the prompt-related variables have OSC prompt marker sequences,
# and if not, wrap them with the appropriate markers so that we can direct the
# prompt bytes to the appropriate grids.
function warp_update_prompt_vars() {
# 133;A and 133;B are standard prompt marker OSCs. We also follow the standard for the rprompt OSC below.
# See https://learn.microsoft.com/en-us/windows/terminal/tutorials/shell-integration and
# https://gitlab.freedesktop.org/terminal-wg/specifications/-/merge_requests/6/diffs for details.
local prompt_prefix=$'\e]133;A\a'
local rprompt_prefix=$'\e]133;P;k=r\a'
local prompt_suffix=$'\e]133;B\a'
if [[ "$WARP_HONOR_PS1" != "1" ]] && [ "$WARP_USING_WINDOWS_CON_PTY" = true ]; then
local suffix="$prompt_suffix$OSC_RESET_GRID"
else
local suffix="$prompt_suffix"
fi
local prompt_prefix_with_cursor_marker="%{$prompt_prefix"
local suffix_with_cursor_marker="$suffix%}"
local prompt_prefix_with_cursor_marker_surrounded="%{$prompt_prefix%}"
local suffix_with_cursor_marker_surrounded="%{$suffix%}"
# Clear the user-defined prompt again, if using Warp's built-in prompt, before the command
# is rendered as it could have been reset by the user's zshrc or by setting
# the variable on the command line. This is used for same-line prompt and leads to the temporary
# product behavior of Warp prompt switches only taking effect in new sessions.
# Certain prompt plugins like p10k can reset the prompt to a non-empty value, after we've initially unset it.
# Confirm that it is unset, if using built-in Warp prompt (update prompt vars is forced to run as the last precmd fn).
if [[ "$WARP_HONOR_PS1" != "1" ]]; then
# If the PROMPT has its original value (i.e. we haven't modified it yet), we save it to SAVED_PROMPT
# so we can recover it, via bindkey, if we switch back from Warp prompt to PS1 (intra-session).
if [[ "$PROMPT" != "%{$prompt_prefix"*"%}" ]]; then
SAVED_PROMPT=$PROMPT
fi
# Similarly, we also save the RPROMPT if it has its original value, for later use in intra-session switching.
if [[ "${RPROMPT:-}" != "%{$rprompt_prefix$suffix%}" ]]; then
SAVED_RPROMPT=${RPROMPT:-}
fi
# We don't unset the $PROMPT since we want to show the lprompt preview in the edit prompt modal (and onboarding blocks).
# Note that the prompt grid is separate from the combined prompt/command grid and ONLY used for prompt previews, in the
# case of the combined grid being enabled.
# Clear the rprompt, so it doesn't accidentally appear in selections/any other relevant logic.
unset RPROMPT
fi
if [[ -n "$PROMPT" ]]; then
# We may have previously modified the prompt to add prompt and cursor
# markers. If they exist, we remove the first occurrence of the prefix
# and the last occurrence of the suffix, which should be the ones that
# Warp has added, to avoid duplicating the prefix and suffix. Shell
# parameter expansion is used to remove the first and last occurrences.
# Specifically note that virtualenvs can add content to the prompt, so we need to
# remove the markers before re-adding them.
# https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
if [[ "$PROMPT" == *"$prompt_prefix_with_cursor_marker_surrounded"* ]]; then
local preceding_prefix=${PROMPT%%$prompt_prefix_with_cursor_marker_surrounded*}
local following_prefix=${PROMPT#*$prompt_prefix_with_cursor_marker_surrounded}
PROMPT=$preceding_prefix$following_prefix
fi
if [[ "$PROMPT" == *"$suffix_with_cursor_marker_surrounded"* ]]; then
local preceding_suffix=${PROMPT%$suffix_with_cursor_marker_surrounded*}
local following_suffix=${PROMPT##*$suffix_with_cursor_marker_surrounded}
PROMPT=$preceding_suffix$following_suffix
fi
# In the case of prompt previews, we may have non-fully surrounded markers that we should remove too!
# Specifically, we surround the ENTIRE prompt with cursor markers, to prevent the shell from moving its
# internal cursor position when printing the prompt in the prompt preview grid. This is different
# than the usual case, where we only surround the OSCs (prefix/suffix) with cursor markers.
if [[ "$PROMPT" == *"$prompt_prefix_with_cursor_marker"* ]]; then
local preceding_prefix=${PROMPT%%$prompt_prefix_with_cursor_marker*}
local following_prefix=${PROMPT#*$prompt_prefix_with_cursor_marker}
PROMPT=$preceding_prefix$following_prefix
fi
if [[ "$PROMPT" == *"$suffix_with_cursor_marker"* ]]; then
local preceding_suffix=${PROMPT%$suffix_with_cursor_marker*}
local following_suffix=${PROMPT##*$suffix_with_cursor_marker}
PROMPT=$preceding_suffix$following_suffix
fi
# If the prompt we extracted is exactly the glitch-stripped value that we
# installed on a previous refresh, keep the existing ORIGINAL_PROMPT: it
# holds the pristine value, whose width annotations are still needed if
# we later switch to honoring the PS1.
if [[ "$PROMPT" != "${WARP_STRIPPED_ORIGINAL_PROMPT:-}" ]]; then
if [[ -n "${WARP_STRIPPED_ORIGINAL_PROMPT:-}" && "$PROMPT" == *"$WARP_STRIPPED_ORIGINAL_PROMPT"* ]]; then
# Another hook added content around the stripped prompt that we
# installed (e.g. a virtualenv prefix). Rehydrate the stripped
# portion back to its pristine value before saving, so that the
# width annotations survive alongside the added content.
ORIGINAL_PROMPT=${PROMPT//$WARP_STRIPPED_ORIGINAL_PROMPT/$ORIGINAL_PROMPT}
else
ORIGINAL_PROMPT=$PROMPT
fi
fi
PROMPT="$prompt_prefix$PROMPT$suffix"
fi
if [[ -n "${RPROMPT:-}" && "${RPROMPT:-}" != *"$rprompt_prefix"* ]]; then
ORIGINAL_RPROMPT=$RPROMPT
RPROMPT="$rprompt_prefix$RPROMPT$suffix"
fi
# The "%{" and "%}" indicate to zsh that the sequence between the markers
# should not change the position of the cursor. This is necessary to
# ensure proper rendering of the command grid when the combined prompt +
# command length is longer than a single row. When the prompt has a
# non-zero width, the redraw of the initial line when it exceeds the max
# columns leads to undesired artifacts in the command grid.
# Note that we only need cursor markers for the prefix/suffix when using a combined prompt &
# command grid.
# If we are using the Warp prompt, we pass a "hidden left prompt" to the prompt
# preview grid (the hidden prompt grid) with cursor markers surrounding the entire prompt.
if [[ "$WARP_HONOR_PS1" != "1" ]]; then
# Even though the entire prompt is surrounded by cursor markers below,
# zsh still counts explicit-width constructs (%n{...%} and %G) within it
# as visible "glitch" columns. Since the prompt is routed to the hidden
# prompt grid and occupies zero columns of the combined prompt/command
# grid, any nonzero counted width desyncs zle's internal cursor position
# from the physical one, which corrupts partial redraws of the command
# (e.g. when zsh-syntax-highlighting recolors individual tokens). Strip
# those constructs before wrapping; this only changes zsh's width
# accounting, never the rendered prompt bytes.
local REPLY
warp_strip_glitch_width_constructs "$ORIGINAL_PROMPT"
WARP_STRIPPED_ORIGINAL_PROMPT=$REPLY
if [[ "$PROMPT" != "%{$prompt_prefix$WARP_STRIPPED_ORIGINAL_PROMPT$suffix%}" ]]; then
# We purposefully surround this entire prompt with cursor markers to prevent
# the shell from moving its internal state of the cursor position, for purposes
# of printing the command with the Warp prompt.
# Note that the Warp prompt is always ABOVE the combined grid in finished blocks
# (same line prompt only affects the input editor with Warp prompt, not
# finished blocks).
PROMPT="%{$prompt_prefix$WARP_STRIPPED_ORIGINAL_PROMPT$suffix%}"
fi
# Otherwise, if we are using the PS1, we use the normal prompt markers.
else
if [[ "$PROMPT" != "%{"*"%}" ]]; then
# We surround the non-printable OSCs with cursor markers to make sure the shell does NOT
# account for them when keeping track of its internal cursor position.
PROMPT="%{$prompt_prefix%}$ORIGINAL_PROMPT%{$suffix%}"
fi
fi
# Do not synthesize an empty right prompt. Even without visible content, zsh reserves
# right-prompt layout space and may corrupt wrapped command redraws in the command grid.
if [[ -n "${RPROMPT:-}" && "${RPROMPT:-}" != "%{"*"%}" ]]; then
RPROMPT="%{${RPROMPT:-}%}"
fi
# Ensure that this is always the last precmd hook. This prevents any other precmd hook, which might
# modify $PROMPT, from interfering with our prompt-escaping logic.
#
# Remove warp_update_prompt_vars from the precmd_functions list and then re-append it to ensure it's
# ordered last.
precmd_functions=("${(@)precmd_functions[@]:#warp_update_prompt_vars}")
precmd_functions+=(warp_update_prompt_vars)
}
# Switches to PS1 prompt by restoring the prompt/rprompt to their original values and flipping
# WARP_HONOR_PS1 to "1" (they had originally been unset for the Warp prompt). Resets the prompt,
# forcing a re-print.
function warp_change_prompt_modes_to_ps1() {
PROMPT="$SAVED_PROMPT"
RPROMPT="$SAVED_RPROMPT"
WARP_HONOR_PS1=1
warp_update_prompt_vars
zle .reset-prompt
}
# The following line creates a new widget with ZLE (the Zsh line editor) with the custom function above,
# so we can reference this when we register it with a bindkey.
zle -N warp_change_prompt_modes_to_ps1
# Switches to Warp prompt by flipping WARP_HONOR_PS1 to "0", which will result
# in unsetting the PROMPT variables to avoid a double prompt. Resets the prompt, forcing
# a re-print.
function warp_change_prompt_modes_to_warp_prompt() {
WARP_HONOR_PS1=0
warp_update_prompt_vars
zle .reset-prompt
}
# The following line creates a new widget with ZLE (the Zsh line editor) with the custom function above,
# so we can reference this when we register it with a bindkey.
zle -N warp_change_prompt_modes_to_warp_prompt
# The SSH logic only applies to local sessions, because we don't yet have support for bootstrapping
# recursive SSH sessions.
if [[ $GALAXY_IS_LOCAL_SHELL_SESSION == "1" ]]; then
# This helper function determines whether the user's ssh arguments imply
# creation of a non-interactive session or otherwise would conflict with
# our SSH wrapper. Returns 0 for an interactive session; >0 otherwise.
function is_interactive_ssh_session() {
ARGS=() # this array holds any positional arguments
while [ $# -gt 0 ]; do
# Initialize this to 1 before each call, as per getopts documentation.
OPTIND=1
# Parse through all ssh options, as defined in the ssh man pages.
while getopts :1246AaCfgKkMNnqsTtVvXxYyb:c:D:e:F:i:L:l:m:O:o:p:R:S:W:w: OPTION; do
case $OPTION in
# -T disables pty allocation (aka a non-interactive session)
T) return 1;;
# -W implies -T
W) return 1;;
# The user provided an invalid option; kick it to real ssh.
\?) return 1;;
# The user omitted a required argument; kick it to real ssh.
:) return 1;;
esac
done
[ $? -eq 0 ] || return 2 # getopts failed
[ $OPTIND -gt $# ] && break # we reached the end of the parameters
shift "$((OPTIND - 1))" # skip all options processed so far
ARGS+=($1) # save first non-option argument (a.k.a. positional argument)
shift # remove saved arg
done
# If there is more than one positional argument, the user is attempting to
# run a command, not start an interactive session. If there is less than
# one positional argument, the user should be shown the usage text.
if [[ ${#ARGS[@]} -ne 1 ]]; then
return 1
fi
}
function warp_ssh_helper() {
local remote_session_id=$(command -p od -An -N8 -tu8 /dev/urandom 2>/dev/null | command -p tr -d ' \n')
if [[ -z "$remote_session_id" || "$remote_session_id" == "0" ]]; then
# If we cannot generate a non-zero random token, run plain SSH instead.
command ssh "${@:1}"
return
fi
# Hex-encode the ZSH environment script we use to bootstrap remote zsh b/c it contains control characters
# We decode on the SSH server using xxd if its available, otherwise fall back to a for-loop over each byte
# and use printf to convert back to plaintext
local zsh_env_script=$(printf '%s' 'unsetopt ZLE; unset RCS; unset GLOBAL_RCS; WARP_SESSION_ID='$remote_session_id'; WARP_USING_WINDOWS_CON_PTY=@@USING_CON_PTY_BOOLEAN@@; _hostname=$(command -pv hostname >/dev/null 2>&1 && command -p hostname 2>/dev/null || command -p uname -n); _user=$(command -pv whoami >/dev/null 2>&1 && command -p whoami 2>/dev/null || echo $USER); _msg=$(printf "{\"hook\": \"InitShell\", \"value\": {\"session_id\": $WARP_SESSION_ID, \"shell\": \"zsh\", \"user\": \"%s\", \"hostname\": \"%s\"}}" "$_user" "$_hostname" | command -p od -An -v -tx1 | command -p tr -d '"'"' \n'"'"'); printf '"'"'\e]9278;d;%s\x07'"'"' $_msg; unset _hostname _user _msg' | command -p od -An -v -tx1 | command -p tr -d ' \n')
# Optionally attach to an existing ControlMaster the user already
# runs for this destination instead of creating our own. Resolve
# the user's configured ControlPath with `ssh -G` (which expands
# tokens like %h/%p/%r/%C into a literal path), then verify the
# master is alive with `ssh -O check`. Both probes are local-only
# commands. On any failure we fall back to creating a Warp-owned
# master, preserving the existing behavior.
local control_path="$SSH_SOCKET_DIR/$WARP_SESSION_ID"
local control_master_mode="yes"
local external_control_master="false"
if [[ "$GALAXY_SSH_REUSE_CONTROL_MASTER" == "1" ]]; then
local user_control_path=$(command ssh -G "${@:1}" 2>/dev/null | command -p sed -n 's/^controlpath //p')
case "$user_control_path" in
"" | none)
# No ControlPath configured for this destination.
;;
*[![:alnum:]._/~@:+,-]*)
# The resolved path contains characters we cannot safely
# embed in the SSH hook JSON below (e.g. an unexpanded %
# token, quotes, or whitespace); fall back to a
# Warp-owned master.
;;
*)
if command ssh -O check -o ControlPath="$user_control_path" "${@:1}" >/dev/null 2>&1; then
# A live master exists: multiplex through it and let
# the client know Warp does not own it.
control_path="$user_control_path"
control_master_mode="no"
external_control_master="true"
fi
;;
esac
fi
# Keep remote commands up-to-date with shell.rs & bash.sh.
# Note that in this command, we're passing a string to the remote shell. Any variable expansions need to be
# escaped with "''" to avoid the local shell from expanding them before they're passed to the remote shell.
# We check the SHELL env var and use shell string manipulation to get the contents after the last slash to
# determine what shell is the login shell on the remote machine. We perform a preliminary check to see if
# the remote shell is the Bourne shell to avoid asking it to parse later lines that use syntax it doesn't
# support.
command ssh -o ControlMaster=$control_master_mode -o ControlPath="$control_path" \
-t "${@:1}" \
"
export TERM_PROGRAM='WarpTerminal'
# Mark the remote side of a Warp-managed SSH session so the bootstrap
# body can distinguish it from local shells. Used to gate the ExitShell
# hook which tears down the remote-server-proxy subprocess.
export WARP_IS_SSH='1'
test -n '$GALAXY_CLIENT_VERSION' && export GALAXY_CLIENT_VERSION='$GALAXY_CLIENT_VERSION'
# Only forward the protocol version if it was set locally (i.e. the HOANotifications feature flag is on).
test -n '$GALAXY_CLI_AGENT_PROTOCOL_VERSION' && export GALAXY_CLI_AGENT_PROTOCOL_VERSION='$GALAXY_CLI_AGENT_PROTOCOL_VERSION'
hook="'$(printf "{\"hook\": \"SSH\", \"value\": {\"socket_path\": \"'$control_path'\", \"remote_shell\": \"%s\", \"session_id\": '"$WARP_SESSION_ID"', \"remote_session_id\": '"$remote_session_id"', \"external_control_master\": '"$external_control_master"'}}" "${SHELL##*/}" | command -p od -An -v -tx1 | command -p tr -d " \n")'"
printf '$OSC_START$DCS_JSON_MARKER$OSC_PARAM_SEPARATOR%s$OSC_END' "'$hook'"
if test "'"${SHELL##*/}" != "bash" -a "${SHELL##*/}" != "zsh"'"; then
# Emulate the SSHD logic to print the MotD. Because the Warp SSH wrapper passes
# a command to run, SSHD does a quiet login, updating utmp and other login
# state, but not printing the MotD. For bash and zsh, this is instead handled
# by our bootstrap script.
if test ! -e "'$HOME/.hushlogin'"; then
# This uses an if-else chain instead of a for-loop to avoid expansion issues on older shells.
if test -r /etc/motd; then
command -p cat /etc/motd
elif test -r /run/motd; then
command -p cat /run/motd
elif test -r /run/motd.dynamic; then
command -p cat /run/motd.dynamic
elif test -r /usr/lib/motd; then
command -p cat /usr/lib/motd
elif test -r /usr/lib/motd.dynamic; then
command -p cat /usr/lib/motd.dynamic
fi
fi
# Likewise, emulate a login shell by sourcing /etc/profile
if test -r /etc/profile; then
. /etc/profile
fi
exec "'$SHELL'"
fi
case "'${SHELL##*/}'" in
bash)
exec -a bash bash --rcfile <(echo '"'
command -p stty raw
HISTCONTROL=ignorespace
HISTIGNORE=" *"
WARP_SESSION_ID='$remote_session_id'
WARP_HONOR_PS1="'$WARP_HONOR_PS1'"
_hostname=$(command -pv hostname >/dev/null 2>&1 && command -p hostname 2>/dev/null || command -p uname -n)
_user=$(command -pv whoami >/dev/null 2>&1 && command -p whoami 2>/dev/null || echo $USER)
_msg=$(printf "{\"hook\": \"InitShell\", \"value\": {\"session_id\": $WARP_SESSION_ID, \"shell\": \"bash\", \"user\": \"%s\", \"hostname\": \"%s\"}}" "$_user" "$_hostname" | command -p od -An -v -tx1 | command -p tr -d " \n")'"
WARP_USING_WINDOWS_CON_PTY=@@USING_CON_PTY_BOOLEAN@@
if [[ "'$OS'" == Windows_NT ]]; then WARP_IN_MSYS2=true; else WARP_IN_MSYS2=false; fi
printf '\''"'\e]9278;d;%s\x07'"'\'' \""'$_msg'"\"'
unset _hostname _user _msg
)
;;
zsh) WARP_TMP_DIR="'$(command -p mktemp -d warptmp.XXXXXX)'"
local ZSH_ENV_SCRIPT='$zsh_env_script'
local WARP_HONOR_PS1='$WARP_HONOR_PS1'
if [[ "'$?'" == 0 ]]; then
if command -pv xxd >/dev/null 2>&1; then
echo "'$ZSH_ENV_SCRIPT'" | command -p xxd -p -r > "'$WARP_TMP_DIR'"/.zshenv
else
for i in {0..\$((\${#ZSH_ENV_SCRIPT} - 1))..2}; do
builtin printf "'"\x${ZSH_ENV_SCRIPT:$i:2}"'"
done > "'$WARP_TMP_DIR'"/.zshenv
fi
else
echo \"Failed to bootstrap warp. Continuing with a non-bootstrapped shell.\"
fi
TMPPREFIX="'$HOME/.zshtmp-'" WARP_SSH_RCFILES="'${ZDOTDIR:-$HOME}'" WARP_HONOR_PS1="'$WARP_HONOR_PS1'" ZDOTDIR="'$WARP_TMP_DIR'" exec -l zsh -g $TRACE_FLAG_IF_WARP_SHELL_DEBUG_MODE
;;
esac
"
}
function ssh() {
if is_interactive_ssh_session "$@"; then
warp_send_json_message "{\"hook\": \"PreInteractiveSSHSession\", \"value\": {\"session_id\": $WARP_SESSION_ID}}"
# If the SSH wrapper is not enabled for this session, don't use it.
if [ "$GALAXY_USE_SSH_WRAPPER" = "1" ]; then
local TRACE_FLAG_IF_WARP_SHELL_DEBUG_MODE=""
if [[ "$WARP_SHELL_DEBUG_MODE" == "1" ]]; then
TRACE_FLAG_IF_WARP_SHELL_DEBUG_MODE="-x"
fi
warp_ssh_helper "$@"
else
command ssh "$@"
fi
else
command ssh "$@"
fi
}
fi
# Send a precmd message to the terminal to differentiate between the warp
# bootstrap logic pasted into the PTY and the output of shell startup files.
warp_precmd
# Before calling rcfiles, print the MotD if this is a login shell. Normally,
# login(1) or pam_motd(8) would do this. However, Warp does not use login(1)
# for local sessions and for remote sessions, SSHD thinks it is starting a
# non-interactive session, so it does not print PAM messages.
if [[ -o login && ! -e "$HOME/.hushlogin" ]]; then
for motd_file in /etc/motd /run/motd /run/motd.dynamic /usr/lib/motd /usr/lib/motd.dynamic; do
if [[ -r "$motd_file" ]]; then
command -p cat "$motd_file"
break
fi
done
fi
# We need to restore the stty before any user bootstrap files are evaluated
# in case they ask for user input
setopt ZLE
# If powerlevel instant prompt is on, we need to disable it because it
# interferes with warp bootstrapping. The functionality is part of warp anyways.
typeset -g POWERLEVEL9K_INSTANT_PROMPT=off
# Add the Warp title precmd functions before the bootstrap sequence is sourced so that a user's custom tab title
# behavior is respected over Warp's.
precmd_functions+=(warp_set_title_idle_on_precmd)
preexec_functions+=(warp_set_title_active_on_preexec)
# Clean up after ourselves, restore ZDOTDIR, and remove the temporary directory in the ssh case.
# We need to do this before the rcfiles are sourced, since rcfiles can reference ZDOTDIR.
# In this case, we created a temp dir that starts with our template prefix and set the ZDOTDIR
# to that dir.
# Note that when called with a template, mktemp will work in the local directory, not the tmp filesystem.
TEMPLATE_PREFIX="warptmp."
if [[ -n $ZDOTDIR ]]; then
if [[ ${ZDOTDIR:0:${#TEMPLATE_PREFIX}} == $TEMPLATE_PREFIX ]]; then
command -p rm -r "$ZDOTDIR"
# Restore ZDOTDIR. Note that if it was originally unset, it'd be home instead of unset.
ZDOTDIR=$WARP_SSH_RCFILES
fi
fi
# Load the EPOCHREALTIME variable from the zsh/datetime module so we can
# accurately measure how long it takes to source the user's rcfiles.
zmodload -F zsh/datetime +p:EPOCHREALTIME >/dev/null 2>&1
# Make sure we force the locale used for number formatting to "C", to avoid
# issues in locales that use a comma as the decimal separator.
local rcfiles_start_time="$(LC_ALL="C"; echo $EPOCHREALTIME)"
# This reflects the bootstrap sequence in a login shell. We want to
# Do other shell startup first so we can ensure Warp goes last.
# If this is a subshell, the user and system RC files have already been sourced.
if [[ -z $WARP_IS_SUBSHELL ]]; then
if [[ -e ${ZDOTDIR:-$HOME}/.zshenv ]]; then
source ${ZDOTDIR:-$HOME}/.zshenv;
fi
if [[ -e /etc/zprofile ]]; then
source /etc/zprofile;
fi
if [[ -e ${ZDOTDIR:-$HOME}/.zprofile ]]; then
source ${ZDOTDIR:-$HOME}/.zprofile;
fi
if [[ -e /etc/zshrc ]]; then
source /etc/zshrc;
fi
if [[ -e ${ZDOTDIR:-$HOME}/.zshrc ]]; then
source ${ZDOTDIR:-$HOME}/.zshrc;
fi
if [[ -e /etc/zlogin ]]; then
source /etc/zlogin;
fi
if [[ -e ${ZDOTDIR:-$HOME}/.zlogin ]]; then
source ${ZDOTDIR:-$HOME}/.zlogin;
fi
fi
local rcfiles_end_time="$(LC_ALL="C"; echo $EPOCHREALTIME)"
# If the user is running powerlevel10k and they selected "sparse" for the "Prompt Spacing"
# option, this var will be true. It tells p10k to output an extra newline in its precmd function
# which visually separates commands. These are generally undesired in Warp, since blocks provide
# enough visual separation. Although generally benign, this causes an issue on Windows when
# ConPTY is involved. The extra newline is output by p10k's precmd which runs after Warp's
# precmd, i.e. after the "reset grid" sequence. It ends up causing Warp's grid content to be out
# of sync with ConPTY, causing cursor positioning problems.
if [[ ${POWERLEVEL9K_PROMPT_ADD_NEWLINE:-} == true ]]; then
POWERLEVEL9K_PROMPT_ADD_NEWLINE=false
fi
# Returns exit code 1 if the command starts with 'warp_run_generator_command'.
#
# This is intended to be used as a zshaddhistory function to prevent in-band
# generators from being added to the zsh history file.
# zshaddhistory functions.
#
# See https://zsh.sourceforge.io/Doc/Release/Functions.html for more context
# on the zshaddhistory hook.
_warp_zshaddhistory() {
_is_warp_generator_command "$1"
}
# Register this zshaddhistory hook after the user's RC files have been sourced,
# to ensure that it gets added (the user's RC files could entirely reset the
# hook function array).
zshaddhistory_functions+=(_warp_zshaddhistory)
# Append additional PATH entries if provided via WARP_PATH_APPEND. This is after the user's RC
# files are sourced in case they reset PATH (/etc/profile on Debian does this, for example).
if [[ -n "${WARP_PATH_APPEND:-}" ]]; then
export PATH="$PATH:$WARP_PATH_APPEND"
unset WARP_PATH_APPEND
fi
local -a shell_plugins
if [[ ${precmd_functions[(I)_p9k_precmd]} != 0 ]]; then
# The variable P9K_VERSION was added in the first version of p10k that
# supports Warp, so if it is non-empty, the user is on a supported version.
if [[ -z "${P9K_VERSION:-}" ]]; then
# If the user is running an unsupported version of p10k, remove the precmd
# hook entirely to prevent the p10k prompt from appearing in typeahead and
# in the command grid.
precmd_functions=(${precmd_functions:#_p9k_precmd})
shell_plugins+=(p10k_unsupported)
else
shell_plugins+=(p10k)
fi
fi
# Remove the pure precmd hook. Pure uses zsh-async to load
# the prompt asynchronously, which means that the prompt can be
# re-rendered (and entered as typeahead characters) once the async
# callback completes. This means that any sort of `unset PS1` or
# `unset PROMPT` calls in precmd don't work if the callback
# completes after the `precmd`.
if [[ ${precmd_functions[(I)prompt_pure_precmd]} != 0 ]]; then
precmd_functions=(${precmd_functions:#prompt_pure_precmd})
shell_plugins+=(pure)
fi
# Read through shell options to determine if the user has enabled vi mode.
shell_options="$(setopt)"
for i in ${(f)shell_options}; do
if [[ "$i" == "vi" ]]; then
vi_mode_in_opts=1
fi
done
NVIM_RE='([[:space:]]|^)nvim([[:space:]]|$)'
ZLE_BINDKEY="$(bindkey -lL main)"
# Check if the shell's native "vi" option has been set.
if [[ -n "${vi_mode_in_opts:-}" ]]; then
shell_plugins+=(vi)
# Check if nvim has been set as the default editor.
# We don't check for vi/vim because it already the default in Linux,
# which means it is set even for non-vim users who haven't deliberately
# chosen it.
elif [[ "${EDITOR:-}" =~ "$NVIM_RE" ]] || [[ "${VISUAL:-}" =~ "$NVIM_RE" ]]; then
shell_plugins+=(vi)
# Check if the zsh line editor bindings include vi-related commands.
elif [[ "$ZLE_BINDKEY" = *viins* ]] || [[ "$ZLE_BINDKEY" = *vicmd* ]]; then
shell_plugins+=(vi)
# Check if the zsh-vi-mode plugin is being used.
elif [[ ${precmd_functions[(I)zvm_init]} != 0 ]]; then
shell_plugins+=(vi)
fi
if kernel_name="$(uname)"; then
if [[ "$kernel_name" == "Darwin" ]]; then
os_category="MacOS"
elif [[ "$kernel_name" == "Linux" ]]; then
os_category="Linux"
default_os_release_filepath="/etc/os-release"
fallback_os_release_filepath="/usr/lib/os-release"
# We first try /etc/os-release and then try /usr/lib/os-release as a fallback.
if test -f "$default_os_release_filepath"; then
os_release_file="$default_os_release_filepath"
elif test -f "$fallback_os_release_filepath"; then
os_release_file="$fallback_os_release_filepath"
fi
if test -f "$os_release_file"; then
linux_distribution="$(cat $os_release_file | sed -nE 's/^NAME="(.*)"$/\1/p')"
fi
fi
fi
# Restore the built-in bracketed-paste widget. This works around a buggy interaction we observed
# with the bracketed-paste-magic plugin (included in oh-my-zsh by default), zsh's "allexport"
# option (set -a), and Warp's bootstrapping code.
# https://github.com/warpdotdev/warp/issues/11520
zle -A .bracketed-paste bracketed-paste
precmd_functions+=(warp_precmd warp_update_prompt_vars)
preexec_functions+=(warp_preexec)
WARP_BOOTSTRAPPED=1
# Unset the prompt environment variable: Warp doesn't render the user's default prompt.
# We explicitly unset this for performance optimizations and so that the we can read the
# command directly from the command grid without having to parse the prompt.
export CONDA_CHANGEPS1=false
warp_update_prompt_vars
# Set history to flush after every command
setopt share_history
# Overrides compadd so that we can hook into parts of the completion stack
# where richer completions data is available.
#
# Adapted from https://github.com/Valodim/zsh-capture-completion/blob/740fce754393513d57408bc585fde14e4404ba5a/capture.zsh#L51
#
# Licensed under the MIT license - Copyright (c) 2015 Vincent Breitmoser.
function compadd () {
# If we're not expecting to override compadd or if any of -O, -A or -D are given,
# then just delegate to the main compadd.
if [[ -z "${COMPADD_OVERRIDE}" || "${COMPADD_OVERRIDE}" == "false" || ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then
# if that is the case, just delegate and leave
builtin compadd "$@"
return $?
fi
# be careful with namespacing here, we don''t want to mess with stuff that
# should be passed to compadd!
typeset -a __hits __dscr __tmp
# do we have a description parameter?
# note we don''t use zparseopts here because of combined option parameters
# with arguments like -default- confuse it.
if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn''t work because of line noise overload
# next param after -d
__tmp=${@[$[${@[(i)-d]}+1]]}
# description can be given as an array parameter name, or inline () array
if [[ $__tmp == \(* ]]; then
eval "__dscr=$__tmp"
else
__dscr=( "${(@P)__tmp}" )
fi
fi
# capture completions by injecting -A parameter into the compadd call.
# this takes care of matching for us.
builtin compadd -A __hits -D __dscr "$@"
setopt localoptions norcexpandparam extendedglob
# extract prefixes and suffixes from compadd call. we can''t do zsh''s cool
# -r remove-func magic, but it''s better than nothing.
typeset -A apre hpre hsuf asuf
# Parse compadd options, based on the documentation. Unused flags are left
# in the array extra_args. There are additional arguments we don't check
# for here, but they all take arguments, so wouldn't interfere with parsing
# of consolidated flags (e.g.: -Qf being parsed as -Q and -f).
zparseopts -E -a extra_args - f=dirsuf P:=apre p:=hpre S:=asuf s:=hsuf a k q Q e n U l 1 2 C
# Change dirsuf to store whether or not the -f flag was provided.
integer dirsuf=${#dirsuf}
# just drop
[[ -n $__hits ]] || return
# this is the point where we have all matches in $__hits and all
# descriptions in $__dscr!
# display all matches
local dsuf dscr
for i in {1..$#__hits}; do
# add a dir suffix?
(( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf=
# description to be displayed afterwards
(( $#__dscr >= $i )) && dscr="${${__dscr[$i]}##$__hits[$i] #}" || dscr=""
local match="$__hits[$i]$dsuf"
print -n "\e]9280;C"$OSC_PARAM_SEPARATOR$match$OSC_END
print -n "\e]9280;D?description"$OSC_PARAM_SEPARATOR$dscr$OSC_END
done
}
# Marks the start of completions generation using a custom OSC.
# Expects the `format` as the first positional argument.
function warp_mark_start_of_completions () {
printf '\e]9280;A;%s\a' $1
}
function warp_mark_start_of_completions_for_list_choices () {
warp_mark_start_of_completions 'raw'
}
function warp_mark_start_of_completions_for_compadd_override () {
warp_mark_start_of_completions 'incrementally_typed'
}
# Marks the end of completions generation using a custom OSC.
function warp_mark_end_of_completions () {
printf '\e]9280;B\a'
}
# The main logic for generating completions.
function warp_main_completer () {
(( ${+functions[_generic]} )) || return 0
# We want all the results listed.
compstate[list_max]=-1
# Delegate to `_generic` to kick off the completion pipeline. We call `_generic` instead of `_main_complete` to
# ensure the proper completion context is set. Internally, `_generic` will call `_main_complete`.
# We fake the number of columns to some large, arbitrary amount as a best-effort approach
# to mitigate description truncation.
COLUMNS=500 _generic
}
# Lists completion matches via the builtin list-choices widget.
function warp_complete_via_list_choices () {
# Start by reading in the completion buffer.
zle warp_read_completion_buffer
# Adding a post-hook here is not helpful because
# it doesn't tell us when the completions have all been _listed_.
# So instead, we unset ALWAYS_LAST_PROMPT so that the prompt
# is always returned and then use prompt markers to determine
# when completions output is finished.
unsetopt ALWAYS_LAST_PROMPT
compprefuncs=( warp_mark_start_of_completions_for_list_choices )
zle warp_complete_via_list_choices_internal
BUFFER=""
}
# Gathers completion matches by overriding compadd
# and emitting the completions directly there.
function warp_complete_via_compadd_override () {
# Start by reading in the completion buffer.
zle warp_read_completion_buffer
# Own the response frame even when compinit is missing or completion fails.
warp_mark_start_of_completions_for_compadd_override
{
local -a compprefuncs=() comppostfuncs=()
COMPADD_OVERRIDE=true
zle warp_complete_via_compadd_override_internal
} always {
unset COMPADD_OVERRIDE
warp_mark_end_of_completions
BUFFER=""
}
}
function warp_read_completion_buffer() {
# Read data from the terminal into a temporary variable and set it as the
# current zle buffer. We want to prevent anything visible from being sent
# to the terminal (it would be treated as background output), so we use -s
# to suppress echoing and send an OSC as the synchronization signal (so the
# terminal knows when to send the input buffer that needs completions).
local TEMP
IFS= read -d $'\4' -s "$(echo -e "TEMP?\e]9280;P\a")" < /dev/tty
BUFFER="$TEMP"
# We push and pop the buffer stack to get zle to properly treat the buffer
# as the data for the completer run. Without this, the completer will
# attempt to complete on an empty string.
#
# We use DCS start and end markers to swallow the line editor redraw that
# occurs when we call `get-line`; we want to make sure it doesn't get
# shown in a background block. The "a" after the DCS start sequence
# ensures we don't try to parse this as a JSON-encoded hook.
echo -n "${DCS_START}a"
zle push-line
zle get-line
echo -n "$DCS_END"
}
zle -N warp_read_completion_buffer
# Registers the custom completion widgets and hooks them up to
# the main logic for completing.
zle -C warp_complete_via_list_choices_internal list-choices warp_main_completer
zle -C warp_complete_via_compadd_override_internal list-choices warp_main_completer
# Registers widgets for generating native-shell completions
# and sets up bindkeys to trigger them.
#
# We use intermediate widgets rather than binding
# directly to the completion widgets so that we can
# access normal widget features (e.g. BUFFER).
zle -N warp_complete_via_list_choices
zle -N warp_complete_via_compadd_override
bindkey '^X' warp_complete_via_list_choices
bindkey '^Y' warp_complete_via_compadd_override
# Set style for the list-choices approach
zstyle ':completion:warp_complete_via_list_choices:*' verbose no
zstyle ':completion:warp_complete_via_list_choices:*' list-packed yes
zstyle ':completion:warp_complete_via_list_choices:*' list-rows-first yes
zstyle ':completion:warp_complete_via_list_choices:*' list-prompt ''
# Avoid grouping. Under certain conditions, grouping can cause options to be printed
# after the compostfunc hook is called.
zstyle ':completion:warp_complete_via_compadd_override:*' list-grouped false
zstyle ':completion:warp_complete_via_compadd_override:*' insert-tab false
zstyle ':completion:warp_complete_via_compadd_override:*' verbose yes
# Setting list-separator to an empty string avoids an extra `--` from being added
# between the hit and the description.
zstyle ':completion:warp_complete_via_compadd_override:*' list-separator ''
function warp_bootstrapped () {
# Note that for now we don't support dynamically changing HISTFILE within a session.
local escaped_histfile="$(warp_escape_json $HISTFILE)"
# The output of `alias` can include control characters that need to be escaped.
local escaped_aliases="$(warp_escape_json "`alias`")"
local escaped_abbrs=""
local env_var_names="$(warp_escape_json "`echo ${(k)parameters[(R)*export*]}`")"
local function_names="$(warp_escape_json "`builtin print -l -- ${(ok)functions}`")"
local escaped_builtins="$(warp_escape_json "`builtin print -l -- ${(ok)builtins}`")"
local escaped_keywords="$(warp_escape_json "`builtin print -l -- ${(ok)reswords}`")"
local escaped_path="$(warp_escape_json "$PATH")"
local escaped_shell_plugins="$(warp_escape_json "`builtin print -l -- ${shell_plugins}`")"
# The list of options enabled for the current shell.
local shell_options="$(warp_escape_json "`setopt`")"
local escaped_editor="$(warp_escape_json "$EDITOR")"
local escaped_shell_path="$(warp_escape_json "${commands[zsh]}")"
local escaped_cdpath="$(warp_escape_json "$CDPATH")"
local escaped_json="{\"hook\": \"Bootstrapped\", \"value\": {\"histfile\": \"$escaped_histfile\", \"session_id\": $WARP_SESSION_ID, \"shell\": \"zsh\", \"home_dir\": \"$HOME\", \"path\": \"$escaped_path\", \"cdpath\": \"$escaped_cdpath\", \"editor\": \"$escaped_editor\", \"env_var_names\": \"$env_var_names\", \"abbreviations\": \"$escaped_abbrs\", \"aliases\": \"$escaped_aliases\", \"function_names\": \"$function_names\", \"builtins\": \"$escaped_builtins\", \"keywords\": \"$escaped_keywords\", \"shell_version\": \"$ZSH_VERSION\", \"shell_options\": \"$shell_options\", \"rcfiles_start_time\": \"$rcfiles_start_time\", \"rcfiles_end_time\": \"$rcfiles_end_time\", \"shell_plugins\": \"$escaped_shell_plugins\", \"os_category\": \"$os_category\", \"linux_distribution\": \"$linux_distribution\", \"wsl_name\": \"${WSL_DISTRO_NAME:-}\", \"shell_path\": \"$escaped_shell_path\"}}"
warp_send_json_message "$escaped_json"
}
warp_bootstrapped
fi