From 7dbfc390f31543dbee2d8bf442de5e051ec6f761 Mon Sep 17 00:00:00 2001 From: Scott Wallace Date: Thu, 21 Sep 2017 18:19:40 +0100 Subject: [PATCH] New version of iTerm2's shell integration script(s). --- .iterm2/shell_integration.bash | 741 ++++++++++++++++++++++----------- 1 file changed, 489 insertions(+), 252 deletions(-) mode change 100644 => 100755 .iterm2/shell_integration.bash diff --git a/.iterm2/shell_integration.bash b/.iterm2/shell_integration.bash old mode 100644 new mode 100755 index 21f0a0d..172587b --- a/.iterm2/shell_integration.bash +++ b/.iterm2/shell_integration.bash @@ -1,208 +1,434 @@ #!/bin/bash -# This is based on "preexec.bash" but is customized for iTerm2. -# Note: this module requires 2 bash features which you must not otherwise be -# using: the "DEBUG" trap, and the "PROMPT_COMMAND" variable. iterm2_preexec_install -# will override these and if you override one or the other this _will_ break. - -# This is known to support bash3, as well as *mostly* support bash2.05b. It -# has been tested with the default shells on MacOS X 10.4 "Tiger", Ubuntu 5.10 -# "Breezy Badger", Ubuntu 6.06 "Dapper Drake", and Ubuntu 6.10 "Edgy Eft". - -# tmux and screen are not supported; even using the tmux hack to get escape -# codes passed through, ncurses interferes and the cursor isn't in the right -# place at the time it's passed through. +# -- BEGIN ITERM2 CUSTOMIZATIONS -- if [[ "$TERM" != screen && "$ITERM_SHELL_INTEGRATION_INSTALLED" = "" && "$-" == *i* ]]; then - ITERM_SHELL_INTEGRATION_INSTALLED=Yes - # Saved copy of your PS1. This is used to detect if the user changes PS1 - # directly. ITERM_PREV_PS1 will hold the last value that this script set PS1 to - # (including various custom escape sequences). - ITERM_PREV_PS1="$PS1" +ITERM_SHELL_INTEGRATION_INSTALLED=Yes +# Saved copy of your PS1. This is used to detect if the user changes PS1 +# directly. ITERM_PREV_PS1 will hold the last value that this script set PS1 to +# (including various custom escape sequences). +ITERM_PREV_PS1="$PS1" - # This variable describes whether we are currently in "interactive mode"; - # i.e. whether this shell has just executed a prompt and is waiting for user - # input. It documents whether the current command invoked by the trace hook is - # run interactively by the user; it's set immediately after the prompt hook, - # and unset as soon as the trace hook is run. - ITERM_PREEXEC_INTERACTIVE_MODE="" +# -- END ITERM2 CUSTOMIZATIONS -- - # Default do-nothing implementation of preexec. - function preexec () { - true +# The following chunk of code, bash-preexec.sh, is licensed like this: +# The MIT License +# +# Copyright (c) 2015 Ryan Caloras and contributors (see https://github.com/rcaloras/bash-preexec) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# -- BEGIN BASH-PREEXEC.SH -- +#!/bin/bash +# +# bash-preexec.sh -- Bash support for ZSH-like 'preexec' and 'precmd' functions. +# https://github.com/rcaloras/bash-preexec +# +# +# 'preexec' functions are executed before each interactive command is +# executed, with the interactive command as its argument. The 'precmd' +# function is executed before each prompt is displayed. +# +# Author: Ryan Caloras (ryan@bashhub.com) +# Forked from Original Author: Glyph Lefkowitz +# +# V0.3.3 +# + +# General Usage: +# +# 1. Source this file at the end of your bash profile so as not to interfere +# with anything else that's using PROMPT_COMMAND. +# +# 2. Add any precmd or preexec functions by appending them to their arrays: +# e.g. +# precmd_functions+=(my_precmd_function) +# precmd_functions+=(some_other_precmd_function) +# +# preexec_functions+=(my_preexec_function) +# +# 3. If you have anything that's using the Debug Trap, change it to use +# preexec. (Optional) change anything using PROMPT_COMMAND to now use +# precmd instead. +# +# Note: This module requires two bash features which you must not otherwise be +# using: the "DEBUG" trap, and the "PROMPT_COMMAND" variable. prexec_and_precmd_install +# will override these and if you override one or the other this will most likely break. + +# Avoid duplicate inclusion +if [[ "$__bp_imported" == "defined" ]]; then + return 0 +fi +__bp_imported="defined" + +# Should be available to each precmd and preexec +# functions, should they want it. +__bp_last_ret_value="$?" +__bp_last_argument_prev_command="$_" + +# Command to set our preexec trap. It's invoked once via +# PROMPT_COMMAND and then removed. +__bp_trap_install_string="trap '__bp_preexec_invoke_exec \"\$_\"' DEBUG;" + +# Remove ignorespace and or replace ignoreboth from HISTCONTROL +# so we can accurately invoke preexec with a command from our +# history even if it starts with a space. +__bp_adjust_histcontrol() { + local histcontrol + histcontrol="${HISTCONTROL//ignorespace}" + # Replace ignoreboth with ignoredups + if [[ "$histcontrol" == *"ignoreboth"* ]]; then + histcontrol="ignoredups:${histcontrol//ignoreboth}" + fi; + export HISTCONTROL="$histcontrol" +} + +# This variable describes whether we are currently in "interactive mode"; +# i.e. whether this shell has just executed a prompt and is waiting for user +# input. It documents whether the current command invoked by the trace hook is +# run interactively by the user; it's set immediately after the prompt hook, +# and unset as soon as the trace hook is run. +__bp_preexec_interactive_mode="" + +__bp_trim_whitespace() { + local var=$@ + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + echo -n "$var" +} + +# This function is installed as part of the PROMPT_COMMAND; +# It sets a variable to indicate that the prompt was just displayed, +# to allow the DEBUG trap to know that the next command is likely interactive. +__bp_interactive_mode() { + __bp_preexec_interactive_mode="on"; +} + + +# This function is installed as part of the PROMPT_COMMAND. +# It will invoke any functions defined in the precmd_functions array. +__bp_precmd_invoke_cmd() { + + # Save the returned value from our last command + __bp_last_ret_value="$?" + + # For every function defined in our function array. Invoke it. + local precmd_function + for precmd_function in "${precmd_functions[@]}"; do + + # Only execute this function if it actually exists. + # Test existence of functions with: declare -[Ff] + if type -t "$precmd_function" 1>/dev/null; then + __bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command" + $precmd_function + fi + done +} + +# Sets a return value in $?. We may want to get access to the $? variable in our +# precmd functions. This is available for instance in zsh. We can simulate it in bash +# by setting the value here. +__bp_set_ret_value() { + return $1 +} + +__bp_in_prompt_command() { + + local prompt_command_array + IFS=';' read -ra prompt_command_array <<< "$PROMPT_COMMAND" + + local trimmed_arg + trimmed_arg=$(__bp_trim_whitespace "$1") + + local command + for command in "${prompt_command_array[@]}"; do + local trimmed_command + trimmed_command=$(__bp_trim_whitespace "$command") + # Only execute each function if it actually exists. + if [[ "$trimmed_command" == "$trimmed_arg" ]]; then + return 0 + fi + done + + return 1 +} + +# This function is installed as the DEBUG trap. It is invoked before each +# interactive prompt display. Its purpose is to inspect the current +# environment to attempt to detect if the current command is being invoked +# interactively, and invoke 'preexec' if so. +__bp_preexec_invoke_exec() { + + + # Save the contents of $_ so that it can be restored later on. + # https://stackoverflow.com/questions/40944532/bash-preserve-in-a-debug-trap#40944702 + __bp_last_argument_prev_command="$1" + + # Checks if the file descriptor is not standard out (i.e. '1') + # __bp_delay_install checks if we're in test. Needed for bats to run. + # Prevents preexec from being invoked for functions in PS1 + if [[ ! -t 1 && -z "$__bp_delay_install" ]]; then + return + fi + + if [[ -n "$COMP_LINE" ]]; then + # We're in the middle of a completer. This obviously can't be + # an interactively issued command. + return + fi + if [[ -z "$__bp_preexec_interactive_mode" ]]; then + # We're doing something related to displaying the prompt. Let the + # prompt set the title instead of me. + return + else + # If we're in a subshell, then the prompt won't be re-displayed to put + # us back into interactive mode, so let's not set the variable back. + # In other words, if you have a subshell like + # (sleep 1; sleep 2) + # You want to see the 'sleep 2' as a set_command_title as well. + if [[ 0 -eq "$BASH_SUBSHELL" ]]; then + __bp_preexec_interactive_mode="" + fi + fi + + if __bp_in_prompt_command "$BASH_COMMAND"; then + # If we're executing something inside our prompt_command then we don't + # want to call preexec. Bash prior to 3.1 can't detect this at all :/ + __bp_preexec_interactive_mode="" + return + fi + + local this_command + this_command=$(HISTTIMEFORMAT= history 1 | { read -r _ this_command; echo "$this_command"; }) + + # Sanity check to make sure we have something to invoke our function with. + if [[ -z "$this_command" ]]; then + return + fi + + # If none of the previous checks have returned out of this function, then + # the command is in fact interactive and we should invoke the user's + # preexec functions. + + # For every function defined in our function array. Invoke it. + local preexec_function + local preexec_ret_value=0 + for preexec_function in "${preexec_functions[@]}"; do + + # Only execute each function if it actually exists. + # Test existence of function with: declare -[fF] + if type -t "$preexec_function" 1>/dev/null; then + __bp_set_ret_value $__bp_last_ret_value + $preexec_function "$this_command" + preexec_ret_value="$?" + fi + done + + # Restore the last argument of the last executed command + # Also preserves the return value of the last function executed in preexec + # If `extdebug` is enabled a non-zero return value from the last function + # in prexec causes the command not to execute + # Run `shopt -s extdebug` to enable + __bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command" +} + +# Returns PROMPT_COMMAND with a semicolon appended +# if it doesn't already have one. +__bp_prompt_command_with_semi_colon() { + + # Trim our existing PROMPT_COMMAND + local trimmed + trimmed=$(__bp_trim_whitespace "$PROMPT_COMMAND") + + # Take our existing prompt command and append a semicolon to it + # if it doesn't already have one. + local existing_prompt_command + if [[ -n "$trimmed" ]]; then + existing_prompt_command=${trimmed%${trimmed##*[![:space:]]}} + existing_prompt_command=${existing_prompt_command%;} + existing_prompt_command=${existing_prompt_command/%/;} + else + existing_prompt_command="" + fi + + echo -n "$existing_prompt_command" +} + +__bp_install() { + + # Remove setting our trap from PROMPT_COMMAND + PROMPT_COMMAND="${PROMPT_COMMAND//$__bp_trap_install_string}" + + # Remove this function from our PROMPT_COMMAND + PROMPT_COMMAND="${PROMPT_COMMAND//__bp_install;}" + + # Exit if we already have this installed. + if [[ "$PROMPT_COMMAND" == *"__bp_precmd_invoke_cmd"* ]]; then + return 1; + fi + + # Adjust our HISTCONTROL Variable if needed. + __bp_adjust_histcontrol + + + # Issue #25. Setting debug trap for subshells causes sessions to exit for + # backgrounded subshell commands (e.g. (pwd)& ). Believe this is a bug in Bash. + # + # Disabling this by default. It can be enabled by setting this variable. + if [[ -n "$__bp_enable_subshells" ]]; then + + # Set so debug trap will work be invoked in subshells. + set -o functrace > /dev/null 2>&1 + shopt -s extdebug > /dev/null 2>&1 + fi; + + + local existing_prompt_command + existing_prompt_command=$(__bp_prompt_command_with_semi_colon) + + # Install our hooks in PROMPT_COMMAND to allow our trap to know when we've + # actually entered something. + PROMPT_COMMAND="__bp_precmd_invoke_cmd; ${existing_prompt_command} __bp_interactive_mode" + eval "$__bp_trap_install_string" + + # Add two functions to our arrays for convenience + # of definition. + precmd_functions+=(precmd) + preexec_functions+=(preexec) + + # Since this is in PROMPT_COMMAND, invoke any precmd functions we have defined. + __bp_precmd_invoke_cmd + # Put us in interactive mode for our first command. + __bp_interactive_mode +} + +# Sets our trap and __bp_install as part of our PROMPT_COMMAND to install +# after our session has started. This allows bash-preexec to be inlucded +# at any point in our bash profile. Ideally we could set our trap inside +# __bp_install, but if a trap already exists it'll only set locally to +# the function. +__bp_install_after_session_init() { + + # Make sure this is bash that's running this and return otherwise. + if [[ -z "$BASH_VERSION" ]]; then + return 1; + fi + + local existing_prompt_command + existing_prompt_command=$(__bp_prompt_command_with_semi_colon) + + # Add our installation to be done last via our PROMPT_COMMAND. These are + # removed by __bp_install when it's invoked so it only runs once. + PROMPT_COMMAND="${existing_prompt_command} $__bp_trap_install_string __bp_install;" +} + +# Run our install so long as we're not delaying it. +if [[ -z "$__bp_delay_install" ]]; then + __bp_install_after_session_init +fi; + +# -- BEGIN BASH-PREEXEC.SH -- + +# -- BEGIN ITERM2 CUSTOMIZATIONS -- + +# We don't care about whitespace, but users care about not changing their histcontrol variables. +# We overwrite the upstream __bp_adjust_histcontrol function whcih gets called from the next +# PROMPT_COMMAND invocation. +function __bp_adjust_histcontrol() { + true +} + +function iterm2_begin_osc { + printf "\033]" +} + +function iterm2_end_osc { + printf "\007" +} + +function iterm2_print_state_data() { + iterm2_begin_osc + printf "1337;RemoteHost=%s@%s" "$USER" "$iterm2_hostname" + iterm2_end_osc + + iterm2_begin_osc + printf "1337;CurrentDir=%s" "$PWD" + iterm2_end_osc + + iterm2_print_user_vars +} + +# Usage: iterm2_set_user_var key value +function iterm2_set_user_var() { + iterm2_begin_osc + printf "1337;SetUserVar=%s=%s" "$1" $(printf "%s" "$2" | base64 | tr -d '\n') + iterm2_end_osc +} + +if [ -z "$(type -t iterm2_print_user_vars)" ] || [ "$(type -t iterm2_print_user_vars)" != function ]; then + # iterm2_print_user_vars is not already defined. Provide a no-op default version. + # + # Users can write their own version of this function. It should call + # iterm2_set_user_var but not produce any other output. + function iterm2_print_user_vars() { + true } +fi - # Default do-nothing implementation of precmd. - function precmd () { - true - } +function iterm2_prompt_prefix() { + iterm2_begin_osc + printf "133;D;\$?" + iterm2_end_osc +} - # This function is installed as the PROMPT_COMMAND; it is invoked before each - # interactive prompt display. It sets a variable to indicate that the prompt - # was just displayed, to allow the DEBUG trap, below, to know that the next - # command is likely interactive. - function iterm2_preexec_invoke_cmd () { - # Ideally we could do this in iterm2_preexec_install but CentOS 7.2 and - # RHEL 7.2 complain about bashdb-main.inc not existing if you do that - # (issue 4160). - # *BOTH* of these options need to be set for the DEBUG trap to be invoked - # in ( ) subshells. This smells like a bug in bash to me. The null stackederr - # redirections are to quiet errors on bash2.05 (i.e. OSX's default shell) - # where the options can't be set, and it's impossible to inherit the trap - # into subshells. - set -o functrace > /dev/null 2>&1 - shopt -s extdebug > /dev/null 2>&1 +function iterm2_prompt_mark() { + iterm2_begin_osc + printf "133;A" + iterm2_end_osc +} - \local s=$? - last_hist_ent="$(HISTTIMEFORMAT= builtin history 1)"; - precmd; - # This is an iTerm2 addition to try to work around a problem in the - # original preexec.bash. - # When the PS1 has command substitutions, this gets invoked for each - # substitution and each command that's run within the substitution, which - # really adds up. It would be great if we could do something like this at - # the end of this script: - # PS1="$(iterm2_prompt_prefix)$PS1($iterm2_prompt_suffix)" - # and have iterm2_prompt_prefix set a global variable that tells precmd not to - # output anything and have iterm2_prompt_suffix reset that variable. - # Unfortunately, command substitutions run in subshells and can't - # communicate to the outside world. - # Instead, we have this workaround. We save the original value of PS1 in - # $ITERM_ORIG_PS1. Then each time this function is run (it's called from - # PROMPT_COMMAND just before the prompt is shown) it will change PS1 to a - # string without any command substitutions by doing eval on ITERM_ORIG_PS1. At - # this point ITERM_PREEXEC_INTERACTIVE_MODE is still the empty string, so preexec - # won't produce output for command substitutions. +function iterm2_prompt_suffix() { + iterm2_begin_osc + printf "133;B" + iterm2_end_osc +} - # The first time this is called ITERM_ORIG_PS1 is unset. This tests if the variable - # is undefined (not just empty) and initializes it. We can't initialize this at the - # top of the script because it breaks with liquidprompt. liquidprompt wants to - # set PS1 from a PROMPT_COMMAND that runs just before us. Setting ITERM_ORIG_PS1 - # at the top of the script will overwrite liquidprompt's PS1, whose value would - # never make it into ITERM_ORIG_PS1. Issue 4532. It's important to check - # if it's undefined before checking if it's empty because some users have - # bash set to error out on referencing an undefined variable. - if [ -z "${ITERM_ORIG_PS1+xxx}" ] - then - # ITERM_ORIG_PS1 always holds the last user-set value of PS1. - # You only get here on the first time iterm2_preexec_invoke_cmd is called. - export ITERM_ORIG_PS1="$PS1" - fi +function iterm2_print_version_number() { + iterm2_begin_osc + printf "1337;ShellIntegrationVersion=8;shell=bash" + iterm2_end_osc +} - if [[ "$PS1" != "$ITERM_PREV_PS1" ]] - then - export ITERM_ORIG_PS1="$PS1" - fi - # Get the value of the prompt prefix, which will change $? - \local iterm2_prompt_prefix_value="$(iterm2_prompt_prefix)" +# If hostname -f is slow on your system, set iterm2_hostname before sourcing this script. +if [ -z "${iterm2_hostname:-}" ]; then + iterm2_hostname=$(hostname -f 2>/dev/null) + # some flavors of BSD (i.e. NetBSD and OpenBSD) don't have the -f option + if [ $? -ne 0 ]; then + iterm2_hostname=$(hostname) + fi +fi - # Reset $? to its saved value, which might be used in $ITERM_ORIG_PS1. - sh -c "exit $s" +# Runs after interactively edited command but before execution +__iterm2_preexec() { + # Save the returned value from our last command + __iterm2_last_ret_value="$?" - # Set PS1 to various escape sequences, the user's preferred prompt, and more escape sequences. - export PS1="\[$iterm2_prompt_prefix_value\]$ITERM_ORIG_PS1\[$(iterm2_prompt_suffix)\]" - - # Save the value we just set PS1 to so if the user changes PS1 we'll know and we can update ITERM_ORIG_PS1. - export ITERM_PREV_PS1="$PS1" - sh -c "exit $s" - - # This must be the last line in this function, or else - # iterm2_preexec_invoke_exec will do its thing at the wrong time. - ITERM_PREEXEC_INTERACTIVE_MODE="yes"; - } - - # This function is installed as the DEBUG trap. It is invoked before each - # interactive prompt display. Its purpose is to inspect the current - # environment to attempt to detect if the current command is being invoked - # interactively, and invoke 'preexec' if so. - function iterm2_preexec_invoke_exec () { - if [ ! -t 1 ] - then - # We're in a piped subshell (STDOUT is not a TTY) like - # (echo -n A; sleep 1; echo -n B) | wc -c - # ...which should return "2". - return - fi - if [[ -n "${COMP_LINE:-}" ]] - then - # We're in the middle of a completer. This obviously can't be - # an interactively issued command. - return - fi - if [[ -z "$ITERM_PREEXEC_INTERACTIVE_MODE" ]] - then - # We're doing something related to displaying the prompt. Let the - # prompt set the title instead of me. - return - else - # If we're in a subshell, then the prompt won't be re-displayed to put - # us back into interactive mode, so let's not set the variable back. - # In other words, if you have a subshell like - # (sleep 1; sleep 2) - # You want to see the 'sleep 2' as a set_command_title as well. - if [[ 0 -eq "$BASH_SUBSHELL" ]] - then - ITERM_PREEXEC_INTERACTIVE_MODE="" - fi - fi - if [[ "iterm2_preexec_invoke_cmd" == "$BASH_COMMAND" ]] - then - # Sadly, there's no cleaner way to detect two prompts being displayed - # one after another. This makes it important that PROMPT_COMMAND - # remain set _exactly_ as below in iterm2_preexec_install. Let's switch back - # out of interactive mode and not trace any of the commands run in - # precmd. - - # Given their buggy interaction between BASH_COMMAND and debug traps, - # versions of bash prior to 3.1 can't detect this at all. - ITERM_PREEXEC_INTERACTIVE_MODE="" - return - fi - - # In more recent versions of bash, this could be set via the "BASH_COMMAND" - # variable, but using history here is better in some ways: for example, "ps - # auxf | less" will show up with both sides of the pipe if we use history, - # but only as "ps auxf" if not. - hist_ent="$(HISTTIMEFORMAT= builtin history 1)"; - \local prev_hist_ent="${last_hist_ent}"; - last_hist_ent="${hist_ent}"; - if [[ "${prev_hist_ent}" != "${hist_ent}" ]]; then - \local this_command="$(echo "${hist_ent}" | sed -e "s/^[ ]*[0-9]*[ ]*//g")"; - else - \local this_command=""; - fi; - - # If none of the previous checks have earlied out of this function, then - # the command is in fact interactive and we should invoke the user's - # preexec hook with the running command as an argument. - preexec "$this_command"; - } - - # Execute this to set up preexec and precmd execution. - function iterm2_preexec_install () { - # Finally, install the actual traps. - if ( [ x"${PROMPT_COMMAND:-}" = x ]); then - PROMPT_COMMAND="iterm2_preexec_invoke_cmd"; - else - # If there's a trailing semicolon folowed by spaces, remove it (issue 3358). - PROMPT_COMMAND="$(echo -n $PROMPT_COMMAND | sed -e 's/; *$//'); iterm2_preexec_invoke_cmd"; - fi - # The $_ is ignored, but prevents it from changing (issue 3932). - trap 'iterm2_preexec_invoke_exec "$_"' DEBUG; - } - - # -- begin iTerm2 customization - - function iterm2_begin_osc { - printf "\033]" - } - - function iterm2_end_osc { - printf "\007" - } - - # Runs after interactively edited command but before execution - function preexec() { iterm2_begin_osc printf "133;C;" iterm2_end_osc @@ -214,79 +440,90 @@ if [[ "$TERM" != screen && "$ITERM_SHELL_INTEGRATION_INSTALLED" = "" && "$-" == export PS1="$ITERM_ORIG_PS1" fi iterm2_ran_preexec="yes" - } - function precmd () { - # Work around a bug in CentOS 7.2 where preexec doesn't run if you press - # ^C while entering a command. - if [[ -z "${iterm2_ran_preexec:-}" ]] - then - preexec "" - fi - iterm2_ran_preexec="" - } + __bp_set_ret_value "$__iterm2_last_ret_value" "$__bp_last_argument_prev_command" +} - function iterm2_print_state_data() { - iterm2_begin_osc - printf "1337;RemoteHost=%s@%s" "$USER" "$iterm2_hostname" - iterm2_end_osc +function __iterm2_precmd () { + __iterm2_last_ret_value="$?" - iterm2_begin_osc - printf "1337;CurrentDir=%s" "$PWD" - iterm2_end_osc + # Work around a bug in CentOS 7.2 where preexec doesn't run if you press + # ^C while entering a command. + if [[ -z "${iterm2_ran_preexec:-}" ]] + then + __iterm2_preexec "" + fi + iterm2_ran_preexec="" - iterm2_print_user_vars - } - # Usage: iterm2_set_user_var key value - function iterm2_set_user_var() { - iterm2_begin_osc - printf "1337;SetUserVar=%s=%s" "$1" $(printf "%s" "$2" | base64) - iterm2_end_osc - } - if [ -z "$(type -t iterm2_print_user_vars)" ] || [ "$(type -t iterm2_print_user_vars)" != function ]; then - # iterm2_print_user_vars is not already defined. Provide a no-op default version. - # - # Users can write their own version of this function. It should call - # iterm2_set_user_var but not produce any other output. - function iterm2_print_user_vars() { - true - } - fi + # This is an iTerm2 addition to try to work around a problem in the + # original preexec.bash. + # When the PS1 has command substitutions, this gets invoked for each + # substitution and each command that's run within the substitution, which + # really adds up. It would be great if we could do something like this at + # the end of this script: + # PS1="$(iterm2_prompt_prefix)$PS1($iterm2_prompt_suffix)" + # and have iterm2_prompt_prefix set a global variable that tells precmd not to + # output anything and have iterm2_prompt_suffix reset that variable. + # Unfortunately, command substitutions run in subshells and can't + # communicate to the outside world. + # Instead, we have this workaround. We save the original value of PS1 in + # $ITERM_ORIG_PS1. Then each time this function is run (it's called from + # PROMPT_COMMAND just before the prompt is shown) it will change PS1 to a + # string without any command substitutions by doing eval on ITERM_ORIG_PS1. At + # this point ITERM_PREEXEC_INTERACTIVE_MODE is still the empty string, so preexec + # won't produce output for command substitutions. - function iterm2_prompt_prefix() { - iterm2_begin_osc - printf "133;D;\$?" - iterm2_end_osc + # The first time this is called ITERM_ORIG_PS1 is unset. This tests if the variable + # is undefined (not just empty) and initializes it. We can't initialize this at the + # top of the script because it breaks with liquidprompt. liquidprompt wants to + # set PS1 from a PROMPT_COMMAND that runs just before us. Setting ITERM_ORIG_PS1 + # at the top of the script will overwrite liquidprompt's PS1, whose value would + # never make it into ITERM_ORIG_PS1. Issue 4532. It's important to check + # if it's undefined before checking if it's empty because some users have + # bash set to error out on referencing an undefined variable. + if [ -z "${ITERM_ORIG_PS1+xxx}" ] + then + # ITERM_ORIG_PS1 always holds the last user-set value of PS1. + # You only get here on the first time iterm2_preexec_invoke_cmd is called. + export ITERM_ORIG_PS1="$PS1" + fi + if [[ "$PS1" != "$ITERM_PREV_PS1" ]] + then + export ITERM_ORIG_PS1="$PS1" + fi + + # Get the value of the prompt prefix, which will change $? + \local iterm2_prompt_prefix_value="$(iterm2_prompt_prefix)" + + # Add the mark unless the prompt includes '$(iterm2_prompt_mark)' as a substring. + if [[ $ITERM_ORIG_PS1 != *'$(iterm2_prompt_mark)'* ]] + then + iterm2_prompt_prefix_value="$iterm2_prompt_prefix_value$(iterm2_prompt_mark)" + fi + + # Send escape sequences with current directory and hostname. iterm2_print_state_data - iterm2_begin_osc - printf "133;A" - iterm2_end_osc - } + # Reset $? to its saved value, which might be used in $ITERM_ORIG_PS1. + __bp_set_ret_value "$__iterm2_last_ret_value" "$__bp_last_argument_prev_command" - function iterm2_prompt_suffix() { - iterm2_begin_osc - printf "133;B" - iterm2_end_osc - } + # Set PS1 to various escape sequences, the user's preferred prompt, and more escape sequences. + export PS1="\[$iterm2_prompt_prefix_value\]$ITERM_ORIG_PS1\[$(iterm2_prompt_suffix)\]" - function iterm2_print_version_number() { - iterm2_begin_osc - printf "1337;ShellIntegrationVersion=2;shell=bash" - iterm2_end_osc - } + # Save the value we just set PS1 to so if the user changes PS1 we'll know and we can update ITERM_ORIG_PS1. + export ITERM_PREV_PS1="$PS1" + __bp_set_ret_value "$__iterm2_last_ret_value" "$__bp_last_argument_prev_command" +} +# Install my functions +preexec_functions+=(__iterm2_preexec) +precmd_functions+=(__iterm2_precmd) - # If hostname -f is slow on your system, set iterm2_hostname before sourcing this script. - if [ -z "${iterm2_hostname:-}" ]; then - iterm2_hostname=$(hostname -f) - fi - iterm2_preexec_install - - # This is necessary so the first command line will have a hostname and current directory. - iterm2_print_state_data - iterm2_print_version_number fi + +# -- END ITERM2 CUSTOMIZATIONS -- + +alias imgcat=~/.iterm2/imgcat;alias imgls=~/.iterm2/imgls;alias it2attention=~/.iterm2/it2attention;alias it2check=~/.iterm2/it2check;alias it2copy=~/.iterm2/it2copy;alias it2dl=~/.iterm2/it2dl;alias it2getvar=~/.iterm2/it2getvar;alias it2setcolor=~/.iterm2/it2setcolor;alias it2setkeylabel=~/.iterm2/it2setkeylabel;alias it2ul=~/.iterm2/it2ul;alias it2universion=~/.iterm2/it2universion