From 95640318f6a6642d8ccd6d42247baa2de35798d8 Mon Sep 17 00:00:00 2001 From: Alexandros Kozak Date: Wed, 15 Aug 2018 06:37:07 -0700 Subject: [PATCH 1/6] zsh-async v1.7.0 --- lib/async.zsh | 72 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/lib/async.zsh b/lib/async.zsh index 8cd828e..d35f128 100644 --- a/lib/async.zsh +++ b/lib/async.zsh @@ -3,15 +3,26 @@ # # zsh-async # -# version: 1.6.2 +# version: 1.7.0 # author: Mathias Fredriksson # url: https://github.com/mafredri/zsh-async # -typeset -g ASYNC_VERSION=1.6.2 +typeset -g ASYNC_VERSION=1.7.0 # Produce debug output from zsh-async when set to 1. typeset -g ASYNC_DEBUG=${ASYNC_DEBUG:-0} +# Execute commands that can manipulate the environment inside the async worker. Return output via callback. +_async_eval() { + local ASYNC_JOB_NAME + # Rename job to _async_eval and redirect all eval output to cat running + # in _async_job. Here, stdout and stderr are not separated for + # simplicity, this could be improved in the future. + { + eval "$@" + } &> >(ASYNC_JOB_NAME=[async/eval] _async_job 'cat') +} + # Wrapper for jobs executed by the async worker, gives output in parseable format with execution time _async_job() { # Disable xtrace as it would mangle the output. @@ -26,6 +37,7 @@ _async_job() { # block, after the command block has completed, the stdin for `cat` is # closed, causing stderr to be appended with a $'\0' at the end to mark the # end of output from this job. + local jobname=${ASYNC_JOB_NAME:-$1} local stdout stderr ret tok { stdout=$(eval "$@") @@ -36,7 +48,7 @@ _async_job() { read -r -k 1 -p tok || exit 1 # Return output ( ). - print -r -n - $'\0'${(q)1} $ret ${(q)stdout} $duration + print -r -n - $'\0'${(q)jobname} $ret ${(q)stdout} $duration } 2> >(stderr=$(cat) && print -r -n - " "${(q)stderr}$'\0') # Unlock mutex by inserting a token. @@ -132,7 +144,7 @@ _async_worker() { coproc_pid=0 # Reset pid. } - local request + local request do_eval=0 local -a cmd while :; do # Wait for jobs sent by async_job. @@ -147,8 +159,9 @@ _async_worker() { # Check for non-job commands sent to worker case $request in - _unset_trap) notify_parent=0; continue;; - _killjobs) killjobs; continue;; + _unset_trap) notify_parent=0; continue;; + _killjobs) killjobs; continue;; + _async_eval*) do_eval=1;; esac # Parse the request using shell parsing (z) to allow commands @@ -181,18 +194,27 @@ _async_worker() { print -n -p "t" fi - # Run job in background, completed jobs are printed to stdout. - _async_job $cmd & - # Store pid because zsh job manager is extremely unflexible (show jobname as non-unique '$job')... - storage[$job]="$!" + if (( do_eval )); then + shift cmd # Strip _async_eval from cmd. + _async_eval $cmd + do_eval=0 + else + # Run job in background, completed jobs are printed to stdout. + _async_job $cmd & + # Store pid because zsh job manager is extremely unflexible (show jobname as non-unique '$job')... + storage[$job]="$!" + fi processing=0 # Disable guard. done } # -# Get results from finnished jobs and pass it to the to callback function. This is the only way to reliably return the -# job name, return code, output and execution time and with minimal effort. +# Get results from finished jobs and pass it to the to callback function. This is the only way to reliably return the +# job name, return code, output and execution time and with minimal effort. +# +# If the async process buffer becomes corrupt, the callback will be invoked with the first argument being `[async]` (job +# name), non-zero return code and fifth argument describing the error (stderr). # # usage: # async_process_results @@ -252,7 +274,7 @@ async_process_results() { else # In case of corrupt data, invoke callback with *async* as job # name, non-zero exit status and an error message on stderr. - $callback "async" 1 "" 0 "$0:$LINENO: error: bad format, got ${#items} items (${(q)items})" $has_next + $callback "[async]" 1 "" 0 "$0:$LINENO: error: bad format, got ${#items} items (${(q)items})" $has_next fi done done @@ -299,6 +321,30 @@ async_job() { zpty -w $worker "$cmd"$'\0' } +# +# Evaluate a command (like async_job) inside the async worker, then worker environment can be manipulated. For example, +# issuing a cd command will change the PWD of the worker which will then be inherited by all future async jobs. +# +# Output will be returned via callback, job name will be [async/eval]. +# +# usage: +# async_worker_eval [] +# +async_worker_eval() { + setopt localoptions noshwordsplit noksharrays noposixidentifiers noposixstrings + + local worker=$1; shift + + local -a cmd + cmd=("$@") + if (( $#cmd > 1 )); then + cmd=(${(q)cmd}) # Quote special characters in multi argument commands. + fi + + # Quote the cmd in case RC_EXPAND_PARAM is set. + zpty -w $worker "_async_eval $cmd"$'\0' +} + # This function traps notification signals and calls all registered callbacks _async_notify_trap() { setopt localoptions noshwordsplit From e4568754e0fb1ca8274d82742c4c4138569470d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandros=20Koz=C3=A1k?= Date: Wed, 15 Aug 2018 19:36:45 -0700 Subject: [PATCH 2/6] AGKOZAK_NAMED_DIRS is set to 1 by default --- agkozak-zsh-prompt.plugin.zsh | 1 + 1 file changed, 1 insertion(+) diff --git a/agkozak-zsh-prompt.plugin.zsh b/agkozak-zsh-prompt.plugin.zsh index 58a0f48..ca08724 100644 --- a/agkozak-zsh-prompt.plugin.zsh +++ b/agkozak-zsh-prompt.plugin.zsh @@ -137,6 +137,7 @@ _agkozak_is_ssh() { ############################################################ _agkozak_prompt_dirtrim() { [[ $1 -ge 1 ]] || set 2 + AGKOZAK_NAMED_DIRS=${AGKOZAK_NAMED_DIRS:-1} if (( AGKOZAK_NAMED_DIRS )); then local zsh_pwd zsh_pwd=$(print -Pn '%~') From a628c100b5e77b47035661ec1a222d59d9270e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandros=20Koz=C3=A1k?= Date: Wed, 15 Aug 2018 19:50:16 -0700 Subject: [PATCH 3/6] Documentation --- README.md | 5 +++-- agkozak-zsh-prompt.plugin.zsh | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 792eb22..3cfd98e 100644 --- a/README.md +++ b/README.md @@ -122,11 +122,12 @@ If you would like to display a different number of directory elements, set the e ![AGKOZAK_PROMPT_DIRTRIM](img/AGKOZAK_PROMPT_DIRTRIM.png) -By default, [static named directories created with `hash -d`](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Static-named-directories) will be displayed in the prompt just like any others. If you use them extensively, though, you may opt to set `AGKOZAK_NAMED_DIRS=1`. The prompt will then use the named directories as base directories for its path. For example, if you execute +By default, [static named directories created with `hash -d`](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Static-named-directories) will be used as base directories in the path the prompt displays. For example, +if you have executed hash -d wp-content=/var/www/html/wp-content -then `/var/www/html/wp-content` will appear in the prompt as `~wp-content`, and `/var/www/html/wp-content/plugins/redirection/actions` will be represented as `~wp-content/.../redirection/actions`. +then `/var/www/html/wp-content` will appear in the prompt as `wp-content`, and `/var/www/html/wp-content/plugins/redirection/actions` will be represented as `~wp-content/.../redirection/actions`. If you prefer to have named directories displayed just like any others, set `AGKOZAK_NAMED_DIRS=0`. ## Git Branch and Status diff --git a/agkozak-zsh-prompt.plugin.zsh b/agkozak-zsh-prompt.plugin.zsh index ca08724..e06bee9 100644 --- a/agkozak-zsh-prompt.plugin.zsh +++ b/agkozak-zsh-prompt.plugin.zsh @@ -129,8 +129,9 @@ _agkozak_is_ssh() { # # ~/.../polyglot/img # -# If AGKOZAK_NAMED_DIRS is set to 1, ZSH named directories -# will be displayed using their aliases in the prompt. +# Named directories will by default be displayed using their +# aliases in the prompt. Set AGKOZAK_NAMED_DIRS=0 to have +# them displayed just like any other directory. # # Arguments: # $1 Number of directory elements to display (default: 2) From 2ecde4b51cc6f20e1fe0a1aa1b86d42b9c26c8a1 Mon Sep 17 00:00:00 2001 From: Alexandros Kozak Date: Wed, 15 Aug 2018 20:16:04 -0700 Subject: [PATCH 4/6] AGKOZAK_NAMED_DIRS global --- agkozak-zsh-prompt.plugin.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agkozak-zsh-prompt.plugin.zsh b/agkozak-zsh-prompt.plugin.zsh index ca08724..bfdeb83 100644 --- a/agkozak-zsh-prompt.plugin.zsh +++ b/agkozak-zsh-prompt.plugin.zsh @@ -137,7 +137,7 @@ _agkozak_is_ssh() { ############################################################ _agkozak_prompt_dirtrim() { [[ $1 -ge 1 ]] || set 2 - AGKOZAK_NAMED_DIRS=${AGKOZAK_NAMED_DIRS:-1} + typeset -g AGKOZAK_NAMED_DIRS=${AGKOZAK_NAMED_DIRS:-1} if (( AGKOZAK_NAMED_DIRS )); then local zsh_pwd zsh_pwd=$(print -Pn '%~') From d46ad6ee7bf0ea5494ab6228952bfc4eb6370a42 Mon Sep 17 00:00:00 2001 From: Alexandros Kozak Date: Wed, 15 Aug 2018 21:17:48 -0700 Subject: [PATCH 5/6] Async.zsh wasn't loading --- agkozak-zsh-prompt.plugin.zsh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/agkozak-zsh-prompt.plugin.zsh b/agkozak-zsh-prompt.plugin.zsh index 93a38d6..b15e543 100644 --- a/agkozak-zsh-prompt.plugin.zsh +++ b/agkozak-zsh-prompt.plugin.zsh @@ -222,19 +222,22 @@ TRAPWINCH() { # ASYNCHRONOUS FUNCTIONS ########################################################### +typeset -g AGKOZAK_PROMPT_DIR="${0:A:h}" + ########################################################### # If zsh-async has not already been loaded, try to load it; # the exit code should indicate success or failure # # Globals: # AGKOZAK_PROMPT_DEBUG +# AGKOZAK_PROMPT_DIR ########################################################### _agkozak_load_async_lib() { if ! whence -w async_init &> /dev/null; then # Don't load zsh-async twice if (( AGKOZAK_PROMPT_DEBUG )); then - source "${0:A:h}/lib/async.zsh" + source "${AGKOZAK_PROMPT_DIR}/lib/async.zsh" else - source "${0:A:h}/lib/async.zsh" &> /dev/null + source "${AGKOZAK_PROMPT_DIR}/lib/async.zsh" &> /dev/null fi local success=$? return $success From 751fb597561bce9f9d18e1bce06a90e625a03413 Mon Sep 17 00:00:00 2001 From: Alexandros Kozak Date: Wed, 15 Aug 2018 21:17:48 -0700 Subject: [PATCH 6/6] async.zsh wasn't loading --- agkozak-zsh-prompt.plugin.zsh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/agkozak-zsh-prompt.plugin.zsh b/agkozak-zsh-prompt.plugin.zsh index 93a38d6..b15e543 100644 --- a/agkozak-zsh-prompt.plugin.zsh +++ b/agkozak-zsh-prompt.plugin.zsh @@ -222,19 +222,22 @@ TRAPWINCH() { # ASYNCHRONOUS FUNCTIONS ########################################################### +typeset -g AGKOZAK_PROMPT_DIR="${0:A:h}" + ########################################################### # If zsh-async has not already been loaded, try to load it; # the exit code should indicate success or failure # # Globals: # AGKOZAK_PROMPT_DEBUG +# AGKOZAK_PROMPT_DIR ########################################################### _agkozak_load_async_lib() { if ! whence -w async_init &> /dev/null; then # Don't load zsh-async twice if (( AGKOZAK_PROMPT_DEBUG )); then - source "${0:A:h}/lib/async.zsh" + source "${AGKOZAK_PROMPT_DIR}/lib/async.zsh" else - source "${0:A:h}/lib/async.zsh" &> /dev/null + source "${AGKOZAK_PROMPT_DIR}/lib/async.zsh" &> /dev/null fi local success=$? return $success