Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Add option like tcsh's dextract
- X-seq: zsh-workers 51958
- From: Tim Eliseo <tre-zsh@xxxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: [PATCH] Add option like tcsh's dextract
- Date: Tue, 18 Jul 2023 02:54:11 -0700
- Archived-at: <https://zsh.org/workers/51958>
- Dkim-filter: OpenDKIM Filter v2.11.0 racky2.crushedhat.com 51D3D381872
- List-id: <zsh-workers.zsh.org>
Hi all!
This is my first post to the group. I’d been using tcsh as an
interactive shell since way back when it was still cool, before zsh or
bash even existed. Zsh is the first shell that’s a worthy successor. One
of the small things that kept me from jumping to bash (along with
everyone else in the Linux world) is that it doesn’t have a proper
implementation of asynchronous notify of job completion (-b), which zsh
does. Another thing that bugged me about bash was that there is no clean
way to emulate tcsh’s dextract option, which rearranges the pushd stack
differently. I eventually discovered that zsh can do the basic function
through the cd/chdir builtin with the auto_pushd option set, but coding
a pushd replacement function was complicated to get right for all option
cases (see attached).
However, I found that adding this pushd mode to zsh natively was trivial
(simply testing for the new option in one place), and I’m still baffled
why it wasn’t included a long time ago while someone was looking for
ways to increase compatibility with other shells. The attached patch
(based on the current master branch) does just that, and I hope you see
fit to merge it into the codebase. I believe I’ve done all the
appropriate option handling, documentation, and unit test to make this
painless. I didn’t write a ChangeLog entry since I wasn’t sure of the
appropriate format, or how to derive the number. (Is that an SVN
revision number?)
Tim
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 5393cb149..47c15583b 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1459,6 +1459,7 @@ pindex(PUSHD_TO_HOME, use of)
pindex(PUSHD_MINUS, use of)
pindex(CDABLE_VARS, use of)
pindex(PUSHD_SILENT, use of)
+pindex(PUSHD_EXTRACT, use of)
xitem(tt(pushd) [ tt(-qsLP) ] [ var(arg) ])
xitem(tt(pushd) [ tt(-qsLP) ] var(old) var(new))
item(tt(pushd) [ tt(-qsLP) ] {tt(PLUS())|tt(-)}var(n))(
@@ -1473,8 +1474,10 @@ Otherwise, var(arg) is interpreted as it would be by tt(cd).
The meaning of var(old) and var(new) in the second form is also
the same as for tt(cd).
-The third form of tt(pushd) changes directory by rotating the
-directory list. An argument of the form `tt(PLUS())var(n)' identifies a stack
+The third form of tt(pushd) changes directory either by rotating the
+directory list (the default), or by extracting an entry from the directory
+list and pushing it on top (when the tt(PUSHD_EXTRACT) option is set).
+An argument of the form `tt(PLUS())var(n)' identifies a stack
entry by counting from the left of the list shown by the tt(dirs)
command, starting with zero. An argument of the form `tt(-)var(n)' counts
from the right. If the tt(PUSHD_MINUS) option is set, the meanings
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index cbd3d0f8e..3a3e4b629 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -162,6 +162,18 @@ shells); and any use of a component of tt(CDPATH), including a `tt(.)' but
excluding an empty component that is otherwise treated as `tt(.)', causes
the directory to be printed.
)
+pindex(PUSHD_EXTRACT)
+pindex(NO_PUSHD_EXTRACT)
+pindex(PUSHDEXTRACT)
+pindex(NOPUSHDEXTRACT)
+cindex(directory stack, altering reordering)
+item(tt(PUSHD_EXTRACT))(
+A push using `tt(PLUS())' or `tt(-)' will reorder by moving the specified
+entry to the top, preserving the order of the remainder below (like the
+tt(dextract) option of bf(tcsh)), instead of the default which rotates the
+stack so that the specified entry is on top. This option makes tt(pushd)
+using `tt(PLUS())' or `tt(-)' behave like tt(cd) with tt(AUTO_PUSHD) set.
+)
pindex(PUSHD_IGNORE_DUPS)
pindex(NO_PUSHD_IGNORE_DUPS)
pindex(PUSHDIGNOREDUPS)
diff --git a/NEWS b/NEWS
index 0e726699f..47c063b40 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,9 @@ consistent and better aligned with the POSIX-2017 specification of
`set -e`. For details on what exactly changed, see the list of
incompatibilities in the README file.
+The option PUSHD_EXTRACT was added to alter how pushd reorders the stack,
+in the same way as the dextract option of tcsh.
+
Changes since 5.8.1
-------------------
diff --git a/Src/builtin.c b/Src/builtin.c
index 669a47092..3b1705a0f 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1194,7 +1194,7 @@ cd_new_pwd(int func, LinkNode dir, int quiet)
struct stat st1, st2;
int dirstacksize;
- if (func == BIN_PUSHD)
+ if (func == BIN_PUSHD && unset(PUSHDEXTRACT))
rolllist(dirstack, dir);
new_pwd = remnode(dirstack, dir);
diff --git a/Src/options.c b/Src/options.c
index a994b563e..b0bee7e6d 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -231,6 +231,7 @@ static struct optname optns[] = {
{{NULL, "promptpercent", OPT_NONBOURNE}, PROMPTPERCENT},
{{NULL, "promptsp", OPT_ALL}, PROMPTSP},
{{NULL, "promptsubst", OPT_BOURNE}, PROMPTSUBST},
+{{NULL, "pushdextract", OPT_EMULATE}, PUSHDEXTRACT},
{{NULL, "pushdignoredups", OPT_EMULATE}, PUSHDIGNOREDUPS},
{{NULL, "pushdminus", OPT_EMULATE}, PUSHDMINUS},
{{NULL, "pushdsilent", 0}, PUSHDSILENT},
diff --git a/Src/zsh.h b/Src/zsh.h
index a0243e98e..85bd97fba 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2508,6 +2508,7 @@ enum {
PROMPTPERCENT,
PROMPTSP,
PROMPTSUBST,
+ PUSHDEXTRACT,
PUSHDIGNOREDUPS,
PUSHDMINUS,
PUSHDSILENT,
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index 533e08773..89860c78f 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -938,6 +938,25 @@
>waaah
>`echo waaah`
+ mkdir newpd
+ cd $mydir
+ pushd $mydir/tmpcd
+ pushd $mydir/newpd
+ dirs
+ pushd +1
+ dirs
+ setopt pushdextract
+ pushd +1
+ dirs
+ unsetopt pushdextract
+ popd >/dev/null
+ popd >/dev/null
+ cd $mydir
+0q:PUSHD_EXTRACT option
+>$mydirt/newpd $mydirt/tmpcd $mydirt
+>$mydirt/tmpcd $mydirt $mydirt/newpd
+>$mydirt $mydirt/tmpcd $mydirt/newpd
+
dirs
pushd $mydir/tmpcd
dirs
@@ -1459,7 +1478,7 @@ F:If this test fails at the first unsetopt, refer to P01privileged.ztst.
fi
BEL=$'\a'
0q:RM_STAR_SILENT
-*>zsh: sure you want to delete all 15 files in ${PWD:h}/options.tmp \[yn\]\? ${BEL}(|n)
+*>zsh: sure you want to delete all 16 files in ${PWD:h}/options.tmp \[yn\]\? ${BEL}(|n)
*>zsh: sure you want to delete (all <->|more than <->) files in / \[yn\]\? ${BEL}(|n)
() {
# In zsh, emulate the behavior of pushd with tcsh's dextract option
# Version 1.0, written by Timothy R. Eliseo
# Don't need the function def if native option exists
if ! setopt pushd_extract 2> /dev/null; then
pushd() {
setopt local_options extended_glob auto_pushd cd_silent
zmodload zsh/parameter # Need $dirstack[]
# Gather any option flags, duplicating builtin behavior of only recognizing
# certain options, and only before non-option arguments.
local -a opts
while [[ $# -gt 0 && $1 == -[qsLP]## ]]; do
opts+=("$1")
[[ $1 != *q* ]] || setopt pushd_silent
shift
done
# The chdir/cd builtin, with one argument in [+|-]n form and with
# the auto_pushd option set, has the desired stack extract behavior,
# instead of pushd's stack rotation. For better error output, we also
# check if the index is in the range that would have different behavior than
# pushd. This range check is the same regardless of +/- because pushing
# either the first or last entry has the same result with extraction or
# rotation.
if [[ $# -eq 1 && ! -o posix_cd &&
$1 == [+-][0-9]## && $1 -ne 0 && ${1:1} -lt ${#dirstack[@]} ]]; then
# Use chdir to pushd with extract. cd_silent suppresses its normal
# output, and then we execute dirs, as pushd would, if appropriate.
builtin chdir "${opts[@]}" "$@" && { [[ ! -o interactive ||
-o pushd_silent ]] || builtin dirs; }
else # Otherwise just execute pushd with original args
builtin pushd "${opts[@]}" "$@"
fi
}
fi
Messages sorted by:
Reverse Date,
Date,
Thread,
Author