summary refs log tree commit diff
path: root/Src/Zle/zle_utils.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2005-08-10 10:56:40 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2005-08-10 10:56:40 +0000
commit2a888b3d5ae1f485649b811ea433f286238fd308 (patch)
tree11f21c9ee2e716c8ab247c6d4ca834c6586ba101 /Src/Zle/zle_utils.c
parentef913283407fdc8166e5b937dcb08d1b4abde10d (diff)
downloadzsh-2a888b3d5ae1f485649b811ea433f286238fd308.tar.gz
zsh-2a888b3d5ae1f485649b811ea433f286238fd308.tar.xz
zsh-2a888b3d5ae1f485649b811ea433f286238fd308.zip
c.f. 21590: metafy_line()/unmetafy_line() now support wide characters
Diffstat (limited to 'Src/Zle/zle_utils.c')
-rw-r--r--Src/Zle/zle_utils.c229
1 files changed, 176 insertions, 53 deletions
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index aa691bcdc..f8c4d2013 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -66,21 +66,36 @@ int linesz;
 void
 sizeline(int sz)
 {
-    while (sz > linesz)
+    int cursz = (zlemetaline != NULL) ? metalinesz : linesz;
+
+    while (sz > cursz)
     {
-	if (linesz < 256)
-	    linesz = 256;
+	if (cursz < 256)
+	    cursz = 256;
 	else
-	    linesz *= 4;
+	    cursz *= 4;
 
-	zleline =
-	    (ZLE_STRING_T)realloc(zleline,
-				  (linesz + 2) * ZLE_CHAR_SIZE);
+	if (zlemetaline != NULL) {
+	    /* One spare character for the NULL */
+	    zlemetaline = (unsigned char *)realloc(zlemetaline, cursz + 1);
+	} else {
+	    /* One spare character for the NULL, one for the newline */
+	    zleline =
+		(ZLE_STRING_T)realloc(zleline,
+				      (cursz + 2) * ZLE_CHAR_SIZE);
+	}
     }
+
+    if (zlemetaline != NULL)
+	metalinesz = cursz;
+    else
+	linesz = cursz;
 }
 
 /*
  * Insert a character, called from main shell.
+ * Note this always operates on the metafied multibyte version of the
+ * line.
  */
 
 /**/
@@ -88,20 +103,7 @@ mod_export void
 zleaddtoline(int chr)
 {
     spaceinline(1);
-#ifdef ZLE_UNICODE_SUPPORT
-    /*
-     * TODO: the main shell has as yet very little notion of multibyte
-     * characters.  Until this gets fixed we just have to assume
-     * this is a complete character.
-     *
-     * Possibly we could get away with attempting to build up a
-     * multibyte character here, storing partial characters between
-     * calls.
-     */
-    zleline[zlecs++] = (ZLE_CHAR_T)chr;
-#else
-    zleline[zlecs++] = chr;
-#endif
+    zlemetaline[zlemetacs++] = chr;
 }
 
 /*
@@ -125,9 +127,11 @@ zleaddtoline(int chr)
 
 /**/
 mod_export unsigned char *
-zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll,
-		int *outcs, int useheap)
+zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp,
+		int *outcsp, int useheap)
 {
+    int outcs, outll;
+
 #ifdef ZLE_UNICODE_SUPPORT
     char *s;
     int i, j;
@@ -135,9 +139,10 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll,
 
     s = zalloc(inll * MB_CUR_MAX + 1);
 
+    outcs = 0;
     for(i=0; i < inll; i++, incs--) {
-	if (outcs != NULL && incs == 0)
-	    *outcs = mb_len;
+	if (incs == 0)
+	    outcs = mb_len;
 	j = wctomb(s + mb_len, instr[i]);
 	if (j == -1) {
 	    /* invalid char; what to do? */
@@ -147,8 +152,41 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll,
     }
     s[mb_len] = '\0';
 
-    if (outll != NULL)
-	*outll = mb_len;
+    outll = mb_len;
+#else
+    outll = inll;
+    outcs = incs;
+#endif
+
+    /*
+     * *outcsp and *outllp are to be indexes into the final string,
+     * not character offsets, so we need to take account of any
+     * metafiable characters.
+     */
+    if (outcsp != NULL || outllp != NULL) {
+#ifdef ZLE_UNICODE_SUPPORT
+	unsigned char *strp = (unsigned char *)s;
+#else
+	unsigned char *strp = instr;
+#endif
+	unsigned char *stopcs = strp + outcs;
+	unsigned char *stopll = strp + outll;
+
+	while (strp < stopll) {
+	    if (imeta(*strp)) {
+		if (strp < stopcs)
+		    outcs++;
+		outll++;
+	    }
+	    strp++;
+	}
+	if (outcsp != NULL)
+	    *outcsp = outcs;
+	if (outllp != NULL)
+	    *outllp = outll;
+    }
+
+#ifdef ZLE_UNICODE_SUPPORT
     if (useheap)
     {
 	unsigned char *ret =
@@ -163,11 +201,6 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll,
 	return (unsigned char *) metafy((char *) s, mb_len, META_REALLOC);
     }
 #else
-    if (outll != NULL)
-	*outll = inll;
-    if (outcs != NULL)
-	*outcs = incs;
-
     return (unsigned char *) metafy((char *) instr, inll,
 				    useheap ? META_HEAPDUP : META_DUP);
 #endif
@@ -186,6 +219,11 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll,
  * may take a newline and a null at a later stage.)  These are not
  * included in *outsz.
  *
+ * If outcs is non-NULL, the character position in the original
+ * string incs (a standard string offset, i.e. incremented 2 for
+ * each metafied character) is converted into the corresponding
+ * character position in *outcs.
+ *
  * Note that instr is modified in place, hence should be copied
  * first if necessary;
  *
@@ -196,7 +234,8 @@ zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outll,
 
 /**/
 mod_export ZLE_STRING_T
-stringaszleline(unsigned char *instr, int *outll, int *outsz)
+stringaszleline(unsigned char *instr, int incs,
+		int *outll, int *outsz, int *outcs)
 {
     ZLE_STRING_T outstr;
     int ll, sz;
@@ -204,7 +243,23 @@ stringaszleline(unsigned char *instr, int *outll, int *outsz)
     mbstate_t ps;
 #endif
 
-    unmetafy(instr, &ll);
+    if (outcs) {
+	/*
+	 * Take account of Meta characters in the input string
+	 * before we unmetafy it.  This does not yet take account
+	 * of multibyte characters.  If there are none, this
+	 * is all the processing required to calculate outcs.
+	 */
+	unsigned char *inptr = instr, *cspos = instr + incs;
+	while (*inptr && inptr < cspos) {
+	    if (*inptr == STOUC(Meta)) {
+		inptr++;
+		incs--;
+	    }
+	    inptr++;
+	}
+    }
+    unmetafy((char *)instr, &ll);
 
     /*
      * ll is the maximum number of characters there can be in
@@ -246,29 +301,53 @@ stringaszleline(unsigned char *instr, int *outll, int *outsz)
 	    if (*outptr == L'\0' && ret == 0)
 		ret = 1;
 
+	    if (outcs) {
+		int offs = inptr - (char *)instr;
+		if (offs <= incs && incs < offs + ret)
+		    *outcs = outptr - outstr;
+	    }
+
 	    inptr += ret;
 	    outptr++;
 	    ll -= ret;
 	}
 	*outll = outptr - outstr;
-    }
-    else
+    } else {
 	*outll = 0;
+	if (outcs)
+	    *outcs = 0;
+    }
 #else
     memcpy((char *)outstr, (char *)instr, ll);
     *outll = ll;
+    if (outcs)
+	*outcs = incs;
 #endif
 
     return outstr;
 }
 
-
+/*
+ * This function is called when we are playing very nasty tricks
+ * indeed: see bufferwords in hist.c.  Consequently we can make
+ * absolutely no assumption about the state whatsoever, except
+ * that it has one.
+ */
 
 /**/
 mod_export unsigned char *
 zlegetline(int *ll, int *cs)
 {
-    return zlelineasstring(zleline, zlell, zlecs, ll, cs, 0);
+    if (zlemetaline != NULL) {
+	*ll = zlemetall;
+	*cs = zlemetacs;
+	return (unsigned char *)ztrdup((char *)zlemetaline);
+    } else if (zleline) {
+	return zlelineasstring(zleline, zlell, zlecs, ll, cs, 0);
+    } else {
+	*ll = *cs = 0;
+	return (unsigned char *)ztrdup("");
+    }
 }
 
 
@@ -280,14 +359,25 @@ spaceinline(int ct)
 {
     int i;
 
-    sizeline(ct + zlell);
-    for (i = zlell; --i >= zlecs;)
-	zleline[i + ct] = zleline[i];
-    zlell += ct;
-    zleline[zlell] = ZWC('\0');
+    if (zlemetaline) {
+	sizeline(ct + zlemetall);
+	for (i = zlemetall; --i >= zlemetacs;)
+	    zlemetaline[i + ct] = zlemetaline[i];
+	zlemetall += ct;
+	zlemetaline[zlemetall] = '\0';
 
-    if (mark > zlecs)
-	mark += ct;
+	if (mark > zlemetacs)
+	    mark += ct;
+    } else {
+	sizeline(ct + zlell);
+	for (i = zlell; --i >= zlecs;)
+	    zleline[i + ct] = zleline[i];
+	zlell += ct;
+	zleline[zlell] = ZWC('\0');
+
+	if (mark > zlecs)
+	    mark += ct;
+    }
 }
 
 /**/
@@ -299,11 +389,19 @@ shiftchars(int to, int cnt)
     else if (mark > to)
 	mark = to;
 
-    while (to + cnt < zlell) {
-	zleline[to] = zleline[to + cnt];
-	to++;
+    if (zlemetaline) {
+	while (to + cnt < zlemetall) {
+	    zlemetaline[to] = zlemetaline[to + cnt];
+	    to++;
+	}
+	zlemetaline[zlemetall = to] = '\0';
+    } else {
+	while (to + cnt < zlell) {
+	    zleline[to] = zleline[to + cnt];
+	    to++;
+	}
+	zleline[zlell = to] = ZWC('\0');
     }
-    zleline[zlell = to] = ZWC('\0');
 }
 
 /**/
@@ -333,6 +431,7 @@ cut(int i, int ct, int dir)
     if (!ct)
 	return;
 
+    UNMETACHECK();
     if (zmod.flags & MOD_VIBUF) {
 	struct cutbuffer *b = &vibuf[zmod.vibuf];
 
@@ -411,14 +510,20 @@ cut(int i, int ct, int dir)
 mod_export void
 backdel(int ct)
 {
-    shiftchars(zlecs -= ct, ct);
+    if (zlemetaline != NULL)
+	shiftchars(zlemetacs -= ct, ct);
+    else
+	shiftchars(zlecs -= ct, ct);
 }
 
 /**/
 mod_export void
 foredel(int ct)
 {
-    shiftchars(zlecs, ct);
+    if (zlemetaline != NULL)
+	shiftchars(zlemetacs, ct);
+    else
+	shiftchars(zlecs, ct);
 }
 
 /**/
@@ -437,7 +542,7 @@ setline(char *s, int flags)
      */
     free(zleline);
 
-    zleline = stringaszleline(scp, &zlell, &linesz);
+    zleline = stringaszleline((unsigned char *)scp, 0, &zlell, &linesz, NULL);
 
     if ((flags & ZSL_TOEND) && (zlecs = zlell) && invicmdmode())
 	zlecs--;
@@ -760,6 +865,19 @@ freechanges(struct change *p)
 mod_export void
 handleundo(void)
 {
+    int remetafy;
+
+    /*
+     * Yuk: we call this from within the completion system,
+     * so we need to convert back to the form which can be
+     * copied into undo entries.
+     */
+    if (zlemetaline != NULL) {
+	unmetafy_line();
+	remetafy = 1;
+    } else
+	remetafy = 0;
+
     mkundoent();
     if(!nextchanges)
 	return;
@@ -780,6 +898,9 @@ handleundo(void)
     curchange->prev = endnextchanges;
     endnextchanges->next = curchange;
     nextchanges = endnextchanges = NULL;
+
+    if (remetafy)
+	metafy_line();
 }
 
 /* add an entry to the undo system, if anything has changed */
@@ -792,7 +913,8 @@ mkundoent(void)
     int sh = zlell < lastll ? zlell : lastll;
     struct change *ch;
 
-    if(lastll == zlell && !memcmp(lastline, zleline, zlell * ZLE_CHAR_SIZE))
+    UNMETACHECK();
+    if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell))
 	return;
     for(pre = 0; pre < sh && zleline[pre] == lastline[pre]; )
 	pre++;
@@ -840,6 +962,7 @@ mkundoent(void)
 void
 setlastline(void)
 {
+    UNMETACHECK();
     if(lastlinesz != linesz)
 	lastline = realloc(lastline, (lastlinesz = linesz) * ZLE_CHAR_SIZE);
     ZS_memcpy(lastline, zleline, (lastll = zlell));