warp_escape_ps1 () { tr '\n\n' ' ' <<< "$*" | xxd -p | tr -d '\n' } # Format a string value according to JSON syntax - Adapted from https://github.com/lework/script. 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. sed -E 's/(["\\])/\\\1/g; s/'$'\b''/\\b/g; s/'$'\t''/\\t/g; s/'$'\f''/\\f/g; s/'$'\r''/\\r/g; $!s/$/\\n/' <<<"$*" | tr -d '\n' } warp_precmd () { # $? is relative to the process so we MUST check this first # or else the exit code will correspond to the commands # executed within this block instead of the actual last # command that was run. local exit_code=$? # Clear the prompt again before the command is rendered as it could # have been reset by the user's bashrc or by setting the variable # on the command line. if [[ -n $PS1 ]]; then WARP_PS1="$PS1" fi unset PS1 unset PROMPT # Escaped PS1 variable local escaped_ps1 if [[ $WARP_FEATURE_FLAG_HONOR_PS1 == "1" ]]; then # Tricking the shell into rendering the prompt # Note that in more modern versions of bash we could use ${PS1@P} to achieve the same, # but macOs comes by default with a much older version of bash, and we want to be compatible. deref_ps1=$(echo -e "\n" | PS1="$WARP_PS1" bash --norc -i 2>&1 | head -2 | tail -1) escaped_ps1=$(warp_escape_ps1 "$(echo "$deref_ps1")") fi # Flush history history -a # Reset the custom kill-whole-line binding as the user's bashrc (which is sourced after bashrc_warp) # could have added another bind. This won't have any user-impact because these shortcuts are only run # in the context of the bash editor, which isn't displayed in Warp. bind -r '"\C-p"' bind "\C-p":kill-whole-line local escaped_pwd escaped_pwd=$(warp_escape_json "$PWD") local escaped_virtual_env="" if [ ! -z "$VIRTUAL_ENV" ]; then escaped_virtual_env=$(warp_escape_json "$VIRTUAL_ENV") fi local escaped_conda_env="" if [ ! -z "$CONDA_DEFAULT_ENV" ]; then escaped_conda_env=$(warp_escape_json "$CONDA_DEFAULT_ENV") fi local git_branch git_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "") local escaped_git_branch escaped_git_branch=$(warp_escape_json "$git_branch") # At this point, escaped prompt looks something like # \\u{001B}\\u{005B}\\u{0030}\\u{0031}\\u{003B} ... # We need to maintain the double quoting of \\u in the message that # is sent otherwise the receiving side will interpret the value # as JS string literals of the form \uHEX, and will include # ctrl characters (like ESC) in the json, which will cause a JSON # parse error. # Note WARP_SESSION_ID doesn't need to be escaped since it's a number local escaped_json="{\"hook\": \"Precmd\", \"value\": {\"pwd\": \"$escaped_pwd\", \"ps1\": \"$escaped_ps1\", \"git_branch\": \"$escaped_git_branch\", \"virtual_env\": \"$escaped_virtual_env\", \"conda_env\": \"$escaped_conda_env\", \"exit_code\": $exit_code, \"session_id\": $WARP_SESSION_ID}}" warp_send_message "$escaped_json" }