diff options
Diffstat (limited to 'lib/functions.zsh')
-rw-r--r-- | lib/functions.zsh | 144 |
1 files changed, 140 insertions, 4 deletions
diff --git a/lib/functions.zsh b/lib/functions.zsh index 0d632a268..ec6f37214 100644 --- a/lib/functions.zsh +++ b/lib/functions.zsh @@ -28,7 +28,12 @@ function open_command() { ;; esac - nohup $open_cmd "$@" &>/dev/null + # don't use nohup on OSX + if [[ "$OSTYPE" == darwin* ]]; then + $open_cmd "$@" &>/dev/null + else + nohup $open_cmd "$@" &>/dev/null + fi } # @@ -67,7 +72,7 @@ function try_alias_value() { # # Arguments: # 1. name - The variable to set -# 2. val - The default value +# 2. val - The default value # Return value: # 0 if the variable exists, 3 if it was set # @@ -81,11 +86,142 @@ function default() { # # Arguments: # 1. name - The env variable to set -# 2. val - The default value +# 2. val - The default value # Return value: # 0 if the env variable exists, 3 if it was set # function env_default() { - env | grep -q "^$1=" && return 0 + 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] [-P] <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" +} |