Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: trailing components



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(&copy);
 			break;
 		    case 't':
-			remlpaths(&copy);
+			remlpaths(&copy, 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);



Messages sorted by: Reverse Date, Date, Thread, Author