Browse Source

Merge pull request #3582 from apjanke/fold-terminalapp-plugin-into-termsupport

Fold terminalapp plugin in to lib/termsupport
Robby Russell 9 years ago
parent
commit
3c782f78f1
4 changed files with 169 additions and 55 deletions
  1. 132 0
      lib/functions.zsh
  2. 26 11
      lib/termsupport.zsh
  3. 5 5
      plugins/svn/svn.plugin.zsh
  4. 6 39
      plugins/terminalapp/terminalapp.plugin.zsh

+ 132 - 0
lib/functions.zsh

@@ -89,3 +89,135 @@ function env_default() {
     env | grep -q "^$1=" && return 0 
     export "$1=$2"       && return 3
 }
+
+
+# Required for $langinfo
+zmodload zsh/langinfo
+
+# URL-encode a string
+#
+# Encodes a string using RFC 2396 URL-encoding (%-escaped).
+# See: https://www.ietf.org/rfc/rfc2396.txt
+#
+# By default, reserved characters and unreserved "mark" characters are
+# not escaped by this function. This allows the common usage of passing
+# an entire URL in, and encoding just special characters in it, with 
+# the expectation that reserved and mark characters are used appropriately.
+# The -r and -m options turn on escaping of the reserved and mark characters,
+# respectively, which allows arbitrary strings to be fully escaped for
+# embedding inside URLs, where reserved characters might be misinterpreted.
+#
+# Prints the encoded string on stdout.
+# Returns nonzero if encoding failed.
+#
+# Usage:
+#  omz_urlencode [-r] [-m] <string>
+#  
+#    -r causes reserved characters (;/?:@&=+$,) to be escaped
+#
+#    -m causes "mark" characters (_.!~*''()-) to be escaped
+#
+#    -P causes spaces to be encoded as '%20' instead of '+'
+function omz_urlencode() {
+  emulate -L zsh
+  zparseopts -D -E -a opts r m P
+
+  local in_str=$1
+  local url_str=""
+  local spaces_as_plus
+  if [[ -z $opts[(r)-P] ]]; then spaces_as_plus=1; fi
+  local str="$in_str"
+
+  # URLs must use UTF-8 encoding; convert str to UTF-8 if required
+  local encoding=$langinfo[CODESET]
+  local safe_encodings
+  safe_encodings=(UTF-8 utf8 US-ASCII)
+  if [[ -z ${safe_encodings[(r)$encoding]} ]]; then
+    str=$(echo -E "$str" | iconv -f $encoding -t UTF-8)
+    if [[ $? != 0 ]]; then
+      echo "Error converting string from $encoding to UTF-8" >&2
+      return 1
+    fi
+  fi
+
+  # Use LC_CTYPE=C to process text byte-by-byte
+  local i byte ord LC_ALL=C
+  export LC_ALL
+  local reserved=';/?:@&=+$,'
+  local mark='_.!~*''()-'
+  local dont_escape="[A-Za-z0-9"
+  if [[ -z $opts[(r)-r] ]]; then
+    dont_escape+=$reserved
+  fi
+  # $mark must be last because of the "-"
+  if [[ -z $opts[(r)-m] ]]; then
+    dont_escape+=$mark
+  fi
+  dont_escape+="]"
+
+  # Implemented to use a single printf call and avoid subshells in the loop,
+  # for performance (primarily on Windows).
+  local url_str=""
+  for (( i = 1; i <= ${#str}; ++i )); do
+    byte="$str[i]"
+    if [[ "$byte" =~ "$dont_escape" ]]; then
+      url_str+="$byte"
+    else
+      if [[ "$byte" == " " && -n $spaces_as_plus ]]; then
+        url_str+="+"
+      else
+        ord=$(( [##16] #byte ))
+        url_str+="%$ord"
+      fi
+    fi
+  done
+  echo -E "$url_str"
+}
+
+# URL-decode a string
+#
+# Decodes a RFC 2396 URL-encoded (%-escaped) string.
+# This decodes the '+' and '%' escapes in the input string, and leaves 
+# other characters unchanged. Does not enforce that the input is a 
+# valid URL-encoded string. This is a convenience to allow callers to
+# pass in a full URL or similar strings and decode them for human
+# presentation.
+#
+# Outputs the encoded string on stdout.
+# Returns nonzero if encoding failed.
+#
+# Usage:
+#   omz_urldecode <urlstring>  - prints decoded string followed by a newline
+function omz_urldecode {
+  emulate -L zsh
+  local encoded_url=$1
+
+  # Work bytewise, since URLs escape UTF-8 octets
+  local caller_encoding=$langinfo[CODESET]
+  local LC_ALL=C
+  export LC_ALL
+  
+  # Change + back to ' '
+  local tmp=${encoded_url:gs/+/ /}
+  # Protect other escapes to pass through the printf unchanged
+  tmp=${tmp:gs/\\/\\\\/}
+  # Handle %-escapes by turning them into `\xXX` printf escapes
+  tmp=${tmp:gs/%/\\x/}
+  local decoded
+  eval "decoded=\$'$tmp'"
+
+  # Now we have a UTF-8 encoded string in the variable. We need to re-encode
+  # it if caller is in a non-UTF-8 locale.
+  local safe_encodings
+  safe_encodings=(UTF-8 utf8 US-ASCII)
+  if [[ -z ${safe_encodings[(r)$caller_encoding]} ]]; then
+    decoded=$(echo -E "$decoded" | iconv -f UTF-8 -t $caller_encoding)
+    if [[ $? != 0 ]]; then
+      echo "Error converting string from UTF-8 to $caller_encoding" >&2
+      return 1
+    fi
+  fi
+
+  echo -E "$decoded"
+}
+

+ 26 - 11
lib/termsupport.zsh

@@ -33,6 +33,7 @@ fi
 
 # Runs before showing the prompt
 function omz_termsupport_precmd {
+  emulate -L zsh
   if [[ $DISABLE_AUTO_TITLE == true ]]; then
     return
   fi
@@ -42,11 +43,11 @@ function omz_termsupport_precmd {
 
 # Runs before executing the command
 function omz_termsupport_preexec {
+  emulate -L zsh
   if [[ $DISABLE_AUTO_TITLE == true ]]; then
     return
   fi
 
-  emulate -L zsh
   setopt extended_glob
 
   # cmd name only, or if this is sudo or ssh, the next cmd
@@ -60,14 +61,28 @@ precmd_functions+=(omz_termsupport_precmd)
 preexec_functions+=(omz_termsupport_preexec)
 
 
-# Runs before showing the prompt, to update the current directory in Terminal.app
-function omz_termsupport_cwd {
-  # Notify Terminal.app of current directory using undocumented OSC sequence
-  # found in OS X 10.9 and 10.10's /etc/bashrc
-  if [[ $TERM_PROGRAM == Apple_Terminal ]] && [[ -z $INSIDE_EMACS ]]; then
-    local PWD_URL="file://$HOSTNAME${PWD// /%20}"
-    printf '\e]7;%s\a' "$PWD_URL"
-  fi
-}
+# Keep Apple Terminal.app's current working directory updated
+# Based on this answer: http://superuser.com/a/315029
+# With extra fixes to handle multibyte chars and non-UTF-8 locales
 
-precmd_functions+=(omz_termsupport_cwd)
+if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then
+
+  # Emits the control sequence to notify Terminal.app of the cwd
+  function update_terminalapp_cwd() {
+    emulate -L zsh
+    # Identify the directory using a "file:" scheme URL, including
+    # the host name to disambiguate local vs. remote paths.
+
+    # Percent-encode the pathname.
+    local URL_PATH=$(omz_urlencode -P $PWD)
+    [[ $? != 0 ]] && return 1
+    local PWD_URL="file://$HOST$URL_PATH"
+    # Undocumented Terminal.app-specific control sequence
+    printf '\e]7;%s\a' $PWD_URL
+  }
+
+  # Use a precmd hook instead of a chpwd hook to avoid contaminating output
+  precmd_functions+=(update_terminalapp_cwd)
+  # Run once to get initial cwd set
+  update_terminalapp_cwd
+fi

+ 5 - 5
plugins/svn/svn.plugin.zsh

@@ -1,16 +1,17 @@
 # vim:ft=zsh ts=2 sw=2 sts=2
 #
 function svn_prompt_info() {
+  local _DISPLAY
   if in_svn; then
     if [ "x$SVN_SHOW_BRANCH" = "xtrue" ]; then
       unset SVN_SHOW_BRANCH
       _DISPLAY=$(svn_get_branch_name)
     else
       _DISPLAY=$(svn_get_repo_name)
+      _DISPLAY=$(omz_urldecode "${_DISPLAY}")
     fi
     echo "$ZSH_PROMPT_BASE_COLOR$ZSH_THEME_SVN_PROMPT_PREFIX\
 $ZSH_THEME_REPO_NAME_COLOR$_DISPLAY$ZSH_PROMPT_BASE_COLOR$ZSH_THEME_SVN_PROMPT_SUFFIX$ZSH_PROMPT_BASE_COLOR$(svn_dirty)$(svn_dirty_pwd)$ZSH_PROMPT_BASE_COLOR"
-    unset _DISPLAY
   fi
 }
 
@@ -30,7 +31,7 @@ function svn_get_repo_name() {
 }
 
 function svn_get_branch_name() {
-  _DISPLAY=$(
+  local _DISPLAY=$(
     svn info 2> /dev/null | \
       awk -F/ \
       '/^URL:/ { \
@@ -49,7 +50,6 @@ function svn_get_branch_name() {
   else
     echo $_DISPLAY
   fi
-  unset _DISPLAY
 }
 
 function svn_get_rev_nr() {
@@ -60,7 +60,7 @@ function svn_get_rev_nr() {
 
 function svn_dirty_choose() {
   if in_svn; then
-    root=`svn info 2> /dev/null | sed -n 's/^Working Copy Root Path: //p'`
+    local root=`svn info 2> /dev/null | sed -n 's/^Working Copy Root Path: //p'`
     if $(svn status $root 2> /dev/null | command grep -Eq '^\s*[ACDIM!?L]'); then
       # Grep exits with 0 when "One or more lines were selected", return "dirty".
       echo $1
@@ -77,7 +77,7 @@ function svn_dirty() {
 
 function svn_dirty_choose_pwd () {
   if in_svn; then
-    root=$PWD
+    local root=$PWD
     if $(svn status $root 2> /dev/null | command grep -Eq '^\s*[ACDIM!?L]'); then
       # Grep exits with 0 when "One or more lines were selected", return "dirty".
       echo $1

+ 6 - 39
plugins/terminalapp/terminalapp.plugin.zsh

@@ -1,39 +1,6 @@
-# Set Apple Terminal.app resume directory
-# based on this answer: http://superuser.com/a/315029
-# 2012-10-26: (javageek) Changed code using the updated answer
-
-# Tell the terminal about the working directory whenever it changes.
-if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then
-  update_terminal_cwd() {
-        # Identify the directory using a "file:" scheme URL, including
-        # the host name to disambiguate local vs. remote paths.
-
-        # Percent-encode the pathname.
-        local URL_PATH=''
-        {
-            # Use LANG=C to process text byte-by-byte.
-            local i ch hexch LANG=C
-            for ((i = 1; i <= ${#PWD}; ++i)); do
-                ch="$PWD[i]"
-                if [[ "$ch" =~ [/._~A-Za-z0-9-] ]]; then
-                    URL_PATH+="$ch"
-                else
-                    hexch=$(printf "%02X" "'$ch")
-                    URL_PATH+="%$hexch"
-                fi
-            done
-        }
-
-        local PWD_URL="file://$HOST$URL_PATH"
-        #echo "$PWD_URL"        # testing
-        printf '\e]7;%s\a' "$PWD_URL"
-    }
-
-    # Register the function so it is called whenever the working
-    # directory changes.
-    autoload add-zsh-hook
-    add-zsh-hook precmd update_terminal_cwd
-
-    # Tell the terminal about the initial directory.
-    update_terminal_cwd
-fi
+# This file is intentionally empty.
+#
+# The terminalapp plugin is deprecated and may be removed in a future release.
+# Its functionality has been folded in to the core lib/termsupport.zsh, which
+# is loaded for all users. You can remove terminalapp from your $plugins list
+# once all your systems are updated to the current version of Oh My Zsh.