From: Peter Stephenson <p.stephenson@samsung.com>
To: Zsh Hackers' List <zsh-workers@zsh.org>
Subject: PATCH: trailing components
Date: Tue, 18 Jun 2019 14:00:06 +0100 [thread overview]
Message-ID: <1560862806.7731.11.camel@samsung.com> (raw)
In-Reply-To: <CGME20190618130008eucas1p176cc19c1c8b831fc30b4bf7b3294f3af@eucas1p1.samsung.com>
I needed to preserve a number of trailing components of a path (other
than one) and couldn't think of an easy way of doing it. Rather than
craft obscure pattern substitutions, or use an ad-hoc expression to
strip the prefix, I came up with a patch to add an optional number after
the "t" in history style modifiers to do this. I put it after rather
than before because history-style colon expressions are quite sensitive
to what the first character is after the colon.
Before I come up with tests and fix up the ensuing failures, you can let
me know if there's a better way of doing this to save me the trouble.
pws
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index a212d742d..d28a30767 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -316,9 +316,11 @@ immediately by a tt(g). In parameter expansion the tt(&) must appear
inside braces, and in filename generation it must be quoted with a
backslash.
)
-item(tt(t))(
+item(tt(t) [ var(digits) ])(
Remove all leading pathname components, leaving the tail. This works
-like `tt(basename)'.
+like `tt(basename)'. Any trailing slashes are first removed.
+If followed by any number of decimal digits, that number of trailing
+components is preserved.
)
item(tt(u))(
Convert the words to all uppercase.
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index f963d5712..f242e1b28 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -2511,7 +2511,7 @@ makecomplistcmd(char *os, int incmd, int flags)
else if (!(cmdstr &&
(((ccp = (Compctlp) compctltab->getnode(compctltab, cmdstr)) &&
(cc = ccp->cc)) ||
- ((s = dupstring(cmdstr)) && remlpaths(&s) &&
+ ((s = dupstring(cmdstr)) && remlpaths(&s, 1) &&
(ccp = (Compctlp) compctltab->getnode(compctltab, s)) &&
(cc = ccp->cc))))) {
if (flags & CFN_DEFAULT)
diff --git a/Src/hist.c b/Src/hist.c
index 901cd3b1a..2117f2bd6 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -798,7 +798,7 @@ histsubchar(int c)
c = (cflag) ? ':' : ingetc();
cflag = 0;
if (c == ':') {
- int gbal = 0;
+ int gbal = 0, count;
if ((c = ingetc()) == 'g') {
gbal = 1;
@@ -856,7 +856,18 @@ histsubchar(int c)
}
break;
case 't':
- if (!remlpaths(&sline)) {
+ c = ingetc();
+ if (idigit(c)) {
+ count = 0;
+ do {
+ count = 10 * count + (c - '0');
+ c = ingetc();
+ } while (idigit(c));
+ }
+ else
+ count = 1;
+ inungetc(c);
+ if (!remlpaths(&sline, count)) {
herrflush();
zerr("modifier failed: t");
return -1;
@@ -2040,7 +2051,7 @@ rembutext(char **junkptr)
/**/
mod_export int
-remlpaths(char **junkptr)
+remlpaths(char **junkptr, int count)
{
char *str = strend(*junkptr);
@@ -2050,12 +2061,21 @@ remlpaths(char **junkptr)
--str;
str[1] = '\0';
}
- for (; str >= *junkptr; --str)
- if (IS_DIRSEP(*str)) {
- *str = '\0';
- *junkptr = dupstring(str + 1);
- return 1;
+ for (;;) {
+ for (; str >= *junkptr; --str) {
+ if (IS_DIRSEP(*str)) {
+ if (--count > 0 && str > *junkptr) {
+ --str;
+ break;
+ }
+ *str = '\0';
+ *junkptr = dupstring(str + 1);
+ return 1;
+ }
}
+ if (str <= *junkptr)
+ break;
+ }
return 0;
}
diff --git a/Src/subst.c b/Src/subst.c
index 60eb33390..d1fff2e67 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -4193,7 +4193,7 @@ modify(char **str, char **ptr)
{
char *ptr1, *ptr2, *ptr3, *lptr, c, *test, *sep, *t, *tt, tc, *e;
char *copy, *all, *tmp, sav, sav1, *ptr1end;
- int gbal, wall, rec, al, nl, charlen, dellen;
+ int gbal, wall, rec, al, nl, charlen, dellen, count = 1;
convchar_t del;
test = NULL;
@@ -4217,7 +4217,6 @@ modify(char **str, char **ptr)
case 'h':
case 'r':
case 'e':
- case 't':
case 'l':
case 'u':
case 'q':
@@ -4226,6 +4225,17 @@ modify(char **str, char **ptr)
c = **ptr;
break;
+ case 't':
+ c = **ptr;
+ if (idigit((*ptr)[1])) {
+ count = 0;
+ do {
+ count = 10 * count + ((*ptr)[1] - '0');
+ ++(*ptr);
+ } while (idigit((*ptr)[1]));
+ }
+ break;
+
case 's':
c = **ptr;
(*ptr)++;
@@ -4401,7 +4411,7 @@ modify(char **str, char **ptr)
rembutext(©);
break;
case 't':
- remlpaths(©);
+ remlpaths(©, count);
break;
case 'l':
copy = casemodify(tt, CASMOD_LOWER);
@@ -4487,7 +4497,7 @@ modify(char **str, char **ptr)
rembutext(str);
break;
case 't':
- remlpaths(str);
+ remlpaths(str, count);
break;
case 'l':
*str = casemodify(*str, CASMOD_LOWER);
next parent reply other threads:[~2019-06-18 13:01 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20190618130008eucas1p176cc19c1c8b831fc30b4bf7b3294f3af@eucas1p1.samsung.com>
2019-06-18 13:00 ` Peter Stephenson [this message]
2019-06-18 13:37 ` Daniel Shahaf
2019-06-18 13:54 ` Peter Stephenson
2019-06-18 14:45 ` Mikael Magnusson
2019-06-18 15:39 ` Peter Stephenson
2019-06-18 19:37 ` Daniel Shahaf
2019-06-19 15:02 ` Peter Stephenson
2019-06-20 10:14 ` Peter Stephenson
2019-06-18 14:42 ` Mikael Magnusson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1560862806.7731.11.camel@samsung.com \
--to=p.stephenson@samsung.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).