summary refs log tree commit diff
path: root/Src/Zle/zle_refresh.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/zle_refresh.c')
-rw-r--r--Src/Zle/zle_refresh.c205
1 files changed, 176 insertions, 29 deletions
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 3967b110d..6be6ca467 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -326,6 +326,11 @@ static const REFRESH_ELEMENT zr_start_ellipsis[] = {
 #define ZR_START_ELLIPSIS_SIZE	\
     ((int)(sizeof(zr_start_ellipsis)/sizeof(zr_start_ellipsis[0])))
 
+/* Defines standard ANSI colour names in index order */
+static const char *ansi_colours[] = {
+    "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white",
+    NULL
+};
 
 /* Defines the available types of highlighting */
 struct highlight {
@@ -342,6 +347,101 @@ static const struct highlight highlights[] = {
     { NULL, 0, 0 }
 };
 
+/* Structure and array for holding special colour terminal sequences */
+
+/* Start of escape sequence for foreground colour */
+#define TC_COL_FG_START	"\033[3"
+/* End of escape sequence for foreground colour */
+#define TC_COL_FG_END	"m"
+/* Code to reset foreground colour */
+#define TC_COL_FG_DEFAULT	"9"
+
+/* Start of escape sequence for background colour */
+#define TC_COL_BG_START	"\033[4"
+/* End of escape sequence for background colour */
+#define TC_COL_BG_END	"m"
+/* Code to reset background colour */
+#define TC_COL_BG_DEFAULT	"9"
+
+struct colour_sequences {
+    char *start;		/* Escape sequence start */
+    char *end;			/* Escape sequence terminator */
+    char *def;			/* Code to reset default colour */
+};
+struct colour_sequences fg_bg_sequences[2];
+
+#define COL_SEQ_FG	(0)
+#define COL_SEQ_BG	(1)
+#define COL_SEQ_COUNT	(2)
+
+/*
+ * We need a buffer for colour sequence compostion.  It may
+ * vary depending on the sequences set.  However, it's inefficient
+ * allocating it separately every time we send a colour sequence,
+ * so do it once per refresh.
+ */
+static char *colseq_buf;
+
+static void
+set_default_colour_sequences(void)
+{
+    fg_bg_sequences[COL_SEQ_FG].start = ztrdup(TC_COL_FG_START);
+    fg_bg_sequences[COL_SEQ_FG].end = ztrdup(TC_COL_FG_END);
+    fg_bg_sequences[COL_SEQ_FG].def = ztrdup(TC_COL_FG_DEFAULT);
+
+    fg_bg_sequences[COL_SEQ_BG].start = ztrdup(TC_COL_BG_START);
+    fg_bg_sequences[COL_SEQ_BG].end = ztrdup(TC_COL_BG_END);
+    fg_bg_sequences[COL_SEQ_BG].def = ztrdup(TC_COL_BG_DEFAULT);
+}
+
+static void
+free_colour_sequences(void)
+{
+    int i;
+
+    for (i = 0; i < COL_SEQ_COUNT; i++) {
+	zsfree(fg_bg_sequences[i].start);
+	zsfree(fg_bg_sequences[i].end);
+	zsfree(fg_bg_sequences[i].def);
+    }
+}
+
+/*
+ * Return index of ANSI colour for which *teststrp is an abbreviation.
+ * Any non-alphabetic character ends the abbreviation.
+ */
+
+static int
+match_colour(const char **teststrp)
+{
+    const char *teststr = *teststrp, *end, **cptr;
+    int len;
+
+    for (end = teststr; ialpha(*end); end++)
+	;
+    len = end - teststr;
+    *teststrp = end;
+
+    for (cptr = ansi_colours; *cptr; cptr++) {
+	if (!strncmp(teststr, *cptr, len))
+	    return cptr - ansi_colours;
+    }
+
+    return -1;
+}
+
+static void
+set_colour_code(char *str, char **var)
+{
+    char *keyseq;
+    int len;
+
+    zsfree(*var);
+    keyseq = getkeystring(str, &len, GETKEYS_BINDKEY, NULL);
+    *var = metafy(keyseq, len, META_DUP);
+}
+
+
 /*
  * Match a set of highlights in the given teststr.
  * Set *on_var to reflect the values found.
@@ -359,15 +459,20 @@ match_highlight(const char *teststr, int *on_var)
 	found = 0;
 	if (strpfx("fg=", teststr) || strpfx("bg=", teststr)) {
 	    int is_fg = (teststr[0] == 'f');
-	    int colour = (int)zstrtol(teststr+3, (char **)&teststr, 10);
-	    int shft, on;
+	    int colour, shft, on;
+
+	    teststr += 3;
+	    if (ialpha(*teststr))
+		colour = match_colour(&teststr);
+	    else
+		colour = (int)zstrtol(teststr, (char **)&teststr, 10);
 	    if (*teststr == ',')
 		teststr++;
 	    else if (*teststr)
 		break;
 	    found = 1;
 	    /* skip out of range colours but keep scanning attributes */
-	    if (colour >= 256)
+	    if (colour < 0 || colour >= 256)
 		continue;
 	    if (is_fg) {
 		shft = TXT_ATTR_FG_COL_SHIFT;
@@ -404,12 +509,14 @@ match_highlight(const char *teststr, int *on_var)
  */
 
 /**/
-void zle_set_highlight(void)
+static void
+zle_set_highlight(void)
 {
     char **atrs = getaparam("zle_highlight");
     int special_atr_on_set = 0;
     int region_atr_on_set = 0;
     int isearch_atr_on_set = 0;
+    int lenfg, lenbg, len;
     struct region_highlight *rhp;
 
     special_atr_on = 0;
@@ -442,6 +549,18 @@ void zle_set_highlight(void)
 	    } else if (strpfx("isearch:", *atrs)) {
 		match_highlight(*atrs + 8, &(region_highlights[1].atr));
 		isearch_atr_on_set = 1;
+	    } else if (strpfx("fg_start_code:", *atrs)) {
+		set_colour_code(*atrs + 14, &fg_bg_sequences[COL_SEQ_FG].start);
+	    } else if (strpfx("fg_default_code:", *atrs)) {
+		set_colour_code(*atrs + 16, &fg_bg_sequences[COL_SEQ_FG].def);
+	    } else if (strpfx("fg_end_code:", *atrs)) {
+		set_colour_code(*atrs + 12, &fg_bg_sequences[COL_SEQ_FG].end);
+	    } else if (strpfx("bg_start_code:", *atrs)) {
+		set_colour_code(*atrs + 14, &fg_bg_sequences[COL_SEQ_BG].start);
+	    } else if (strpfx("bg_default_code:", *atrs)) {
+		set_colour_code(*atrs + 16, &fg_bg_sequences[COL_SEQ_BG].def);
+	    } else if (strpfx("bg_end_code:", *atrs)) {
+		set_colour_code(*atrs + 12, &fg_bg_sequences[COL_SEQ_BG].end);
 	    }
 	}
     }
@@ -453,9 +572,35 @@ void zle_set_highlight(void)
 	region_highlights->atr = TXTSTANDOUT;
     if (!isearch_atr_on_set)
 	region_highlights[1].atr = TXTUNDERLINE;
+
+    /* Allocate buffer for colour code composition */
+    lenfg = strlen(fg_bg_sequences[COL_SEQ_FG].def);
+    /* always need 1 character for non-default code */
+    if (lenfg < 1)
+	lenfg = 1;
+    lenfg += strlen(fg_bg_sequences[COL_SEQ_FG].start) +
+	strlen(fg_bg_sequences[COL_SEQ_FG].end);
+
+    lenbg = strlen(fg_bg_sequences[COL_SEQ_BG].def);
+    /* always need 1 character for non-default code */
+    if (lenbg < 1)
+	lenbg = 1;
+    lenbg += strlen(fg_bg_sequences[COL_SEQ_BG].start) +
+	strlen(fg_bg_sequences[COL_SEQ_BG].end);
+
+    len = lenfg > lenbg ? lenfg : lenbg;
+    colseq_buf = (char *)zalloc(len+1);
 }
 
 
+/**/
+static void
+zle_free_highlight(void)
+{
+    /* Free buffer for colour code composition */
+    free(colseq_buf);
+}
+
 /*
  * Interface to the region_highlight ZLE parameter.
  * Converts betwen a format like "P32 42 underline,bold" to
@@ -942,26 +1087,12 @@ snextline(Rparams rpms)
     rpms->sen = rpms->s + winw;
 }
 
-/*
- * HERE: these need to be made configurable, somehow.
- * Ideally we need to make the complist stuff use the
- * same system, but that may be too much tied to the GNU ls
- * interface to make that possible.
- */
-/* Start of escape sequence for foreground colour */
-#define TC_COL_FG_START	"\033[3"
-/* Start of escape sequence for background colour */
-#define TC_COL_BG_START	"\033[4"
-/* End of either escape sequence */
-#define TC_COL_END	"m"
-/* Numeric code (to be turned into ASCII) to reset default colour */
-#define TC_COL_DEFAULT	9
 
 static void
-setcolourattribute(int colour, char *start, int tc, int def,
+setcolourattribute(int colour, int fg_bg, int tc, int def,
 		   int use_termcap)
 {
-    char out[16], *ptr;
+    char *ptr;
     /*
      * If we're not restoring the default, and either have a
      * colour value that is too large for ANSI, or have been told
@@ -980,14 +1111,17 @@ setcolourattribute(int colour, char *start, int tc, int def,
 	    return;
     }
 
-    strcpy(out, start);
-    if (def)
-	colour = TC_COL_DEFAULT;
+    strcpy(colseq_buf, fg_bg_sequences[fg_bg].start);
 
-    ptr = out + strlen(start);
-    *ptr++ = colour + '0';
-    strcpy(ptr, TC_COL_END);
-    tputs(out, 1, putshout);
+    ptr = colseq_buf + strlen(colseq_buf);
+    if (def) {
+	strcpy(ptr, fg_bg_sequences[fg_bg].def);
+	while (*ptr)
+	    ptr++;
+    } else
+	*ptr++ = colour + '0';
+    strcpy(ptr, fg_bg_sequences[fg_bg].end);
+    tputs(colseq_buf, 1, putshout);
 }
 
 /**/
@@ -1008,13 +1142,13 @@ settextattributes(int atr)
 	tsetcap(TCUNDERLINEBEG, 0);
     if (txtchangeisset(atr, TXTFGCOLOUR|TXTNOFGCOLOUR)) {
 	setcolourattribute(txtchangeget(atr, TXT_ATTR_FG_COL),
-			   TC_COL_FG_START, TCFGCOLOUR,
+			   COL_SEQ_FG, TCFGCOLOUR,
 			   txtchangeisset(atr, TXTNOFGCOLOUR),
 			   txtchangeisset(atr, TXT_ATTR_FG_TERMCAP));
     }
     if (txtchangeisset(atr, TXTBGCOLOUR|TXTNOBGCOLOUR)) {
 	setcolourattribute(txtchangeget(atr, TXT_ATTR_BG_COL),
-			   TC_COL_BG_START, TCBGCOLOUR,
+			   COL_SEQ_BG, TCBGCOLOUR,
 			   txtchangeisset(atr, TXTNOBGCOLOUR),
 			   txtchangeisset(atr, TXT_ATTR_BG_TERMCAP));
     }
@@ -1796,6 +1930,8 @@ singlelineout:
     if (tmpalloced)
 	zfree(tmpline, tmpll * sizeof(*tmpline));
 
+    zle_free_highlight();
+
     /* if we have a new list showing, note it; if part of the list has been
     overwritten, redisplay it. We have to metafy line back before calling
     completion code */
@@ -2711,6 +2847,15 @@ singmoveto(int pos)
     vcs = pos;
 }
 
+/* Provided for loading the module in a modular fashion */
+
+/**/
+void
+zle_refresh_boot(void)
+{
+    set_default_colour_sequences();
+}
+
 /* Provided for unloading the module in a modular fashion */
 
 /**/
@@ -2722,4 +2867,6 @@ zle_refresh_finish(void)
     if (region_highlights)
 	zfree(region_highlights,
 	      sizeof(struct region_highlight) * n_region_highlights);
+
+    free_colour_sequences();
 }