summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Doc/Zsh/zle.yo19
-rw-r--r--Src/Zle/zle_refresh.c214
-rw-r--r--Src/init.c8
-rw-r--r--Src/zsh.h59
5 files changed, 242 insertions, 62 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c5e49aad..7f0a190db 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2008-04-29 Peter Stephenson <pws@csr.com>
+ * 24894: Doc/Zsh/zle.yo, Src/init.c, Src/zsh.h,
+ Src/Zle/zle_refresh.c: enable colouring of highlighted text
+ in editor.
+
* 24893: Src/Zle/zle_refresh.c: duplicate statusline to avoid
crashes when it's passed from a constant string.
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 888c87ea1..c137d0d24 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -2097,6 +2097,25 @@ No highlighting is applied to the given context. It is not useful for
this to appear with other types of highlighting; it is used to override
a default.
)
+item(tt(fg=)var(colour))(
+The foreground colour should be set to var(colour), a decimal integer. Not
+all terminals support this, and of those that do not all provide facilities
+to test the support, hence the user should decide based on the terminal
+type. Most terminals with colour support accept the numbers 0 to 7, and
+may generate additional colours if the tt(bold) attributes is also present.
+On recent terminals and on systems with an up-to-date terminal database the
+number of colours supported may be tested by with the command `tt(echotc
+Co)'; if this succeeds, it indicates a limit on the number of colours which
+will be enforced by the line editor. The number of colours is in case
+limited to 256 (i.e. the range 0 to 255).
+
+Colour is also known as color.
+)
+item(tt(bg=)var(colour))(
+The background colour should be set to var(colour), a decimal integer.
+This works similarly to the foreground colour, except the background is
+not usually affected by the bold attribute.
+)
item(tt(bold))(
The characters in the given context are shown in a bold font.
)
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 798541646..3967b110d 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -207,7 +207,7 @@ int predisplaylen, postdisplaylen;
* displayed on screen.
*/
-static int special_atr_on, special_atr_off;
+static int special_atr_on;
/* Flags for the region_highlight structure */
enum {
@@ -357,19 +357,41 @@ match_highlight(const char *teststr, int *on_var)
const struct highlight *hl;
found = 0;
- for (hl = highlights; hl->name; hl++) {
- if (strpfx(hl->name, teststr)) {
- const char *val = teststr + strlen(hl->name);
+ 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;
+ if (*teststr == ',')
+ teststr++;
+ else if (*teststr)
+ break;
+ found = 1;
+ /* skip out of range colours but keep scanning attributes */
+ if (colour >= 256)
+ continue;
+ if (is_fg) {
+ shft = TXT_ATTR_FG_COL_SHIFT;
+ on = TXTFGCOLOUR;
+ } else {
+ shft = TXT_ATTR_BG_COL_SHIFT;
+ on = TXTBGCOLOUR;
+ }
+ *on_var |= on | (colour << shft);
+ } else {
+ for (hl = highlights; hl->name; hl++) {
+ if (strpfx(hl->name, teststr)) {
+ const char *val = teststr + strlen(hl->name);
- if (*val == ',')
- val++;
- else if (*val)
- break;
+ if (*val == ',')
+ val++;
+ else if (*val)
+ break;
- *on_var |= hl->mask_on;
- *on_var &= ~hl->mask_off;
- teststr = val;
- found = 1;
+ *on_var |= hl->mask_on;
+ *on_var &= ~hl->mask_off;
+ teststr = val;
+ found = 1;
+ }
}
}
}
@@ -431,7 +453,6 @@ void zle_set_highlight(void)
region_highlights->atr = TXTSTANDOUT;
if (!isearch_atr_on_set)
region_highlights[1].atr = TXTUNDERLINE;
- special_atr_off = special_atr_on << TXT_ATTR_OFF_ON_SHIFT;
}
@@ -610,19 +631,23 @@ zwcputc(const REFRESH_ELEMENT *c, int *curatrp)
if (lastatr & ~c->atr) {
/* Stuff on we don't want, turn it off */
- settextattributes((lastatr & ~c->atr) << TXT_ATTR_OFF_ON_SHIFT);
+ settextattributes(TXT_ATTR_OFF_FROM_ON(lastatr & ~c->atr));
lastatr = 0;
}
/*
* Don't output "on" attributes in a string of characters with
- * the same attributes.
+ * the same attributes. Be careful in case a different colour
+ * needs setting.
*/
if ((c->atr & TXT_ATTR_ON_MASK) &&
(!curatrp ||
- ((*curatrp & TXT_ATTR_ON_MASK) != (c->atr & TXT_ATTR_ON_MASK)))) {
+ ((*curatrp & TXT_ATTR_ON_VALUES_MASK) !=
+ (c->atr & TXT_ATTR_ON_VALUES_MASK)))) {
+ /* Record just the control flags we might need to turn off... */
lastatr = c->atr & TXT_ATTR_ON_MASK;
- settextattributes(lastatr);
+ /* ...but set including the values for colour attributes */
+ settextattributes(c->atr & TXT_ATTR_ON_VALUES_MASK);
}
#ifdef MULTIBYTE_SUPPORT
@@ -656,9 +681,11 @@ zwcputc(const REFRESH_ELEMENT *c, int *curatrp)
if (curatrp) {
/*
* Remember the current attributes: those that are turned
- * on, less those that are turned off again.
+ * on, less those that are turned off again. Include
+ * colour attributes here in case the colour changes to
+ * another non-default one.
*/
- *curatrp = (c->atr & TXT_ATTR_ON_MASK) &
+ *curatrp = (c->atr & TXT_ATTR_ON_VALUES_MASK) &
~((c->atr & TXT_ATTR_OFF_MASK) >> TXT_ATTR_OFF_ON_SHIFT);
}
}
@@ -915,6 +942,54 @@ 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,
+ int use_termcap)
+{
+ char out[16], *ptr;
+ /*
+ * If we're not restoring the default, and either have a
+ * colour value that is too large for ANSI, or have been told
+ * to use the termcap sequence (which at the time of writing
+ * we never are), try to use the termcap sequence.
+ */
+ if (!def && (colour > 7 || use_termcap)) {
+ /*
+ * We can if it's available, and either we couldn't get
+ * the maximum number of colours, or the colour is in range.
+ */
+ if (tccan(tc) && (tccolours < 0 || colour < tccolours))
+ tcoutarg(tc, colour);
+ /* for 0 to 7 assume standard ANSI works, otherwise it won't. */
+ if (colour > 7)
+ return;
+ }
+
+ strcpy(out, start);
+ if (def)
+ colour = TC_COL_DEFAULT;
+
+ ptr = out + strlen(start);
+ *ptr++ = colour + '0';
+ strcpy(ptr, TC_COL_END);
+ tputs(out, 1, putshout);
+}
+
/**/
static void
settextattributes(int atr)
@@ -931,6 +1006,18 @@ settextattributes(int atr)
tsetcap(TCSTANDOUTBEG, 0);
if (txtchangeisset(atr, TXTUNDERLINE))
tsetcap(TCUNDERLINEBEG, 0);
+ if (txtchangeisset(atr, TXTFGCOLOUR|TXTNOFGCOLOUR)) {
+ setcolourattribute(txtchangeget(atr, TXT_ATTR_FG_COL),
+ TC_COL_FG_START, 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,
+ txtchangeisset(atr, TXTNOBGCOLOUR),
+ txtchangeisset(atr, TXT_ATTR_BG_TERMCAP));
+ }
}
#ifdef MULTIBYTE_SUPPORT
@@ -1209,6 +1296,7 @@ zrefresh(void)
rpms.sen = *nbuf + winw;
for (t = tmpline, tmppos = 0; tmppos < tmpll; t++, tmppos++) {
int base_atr_on = 0, base_atr_off = 0, ireg;
+ int all_atr_on, all_atr_off;
struct region_highlight *rhp;
/*
* Calculate attribute based on region.
@@ -1223,12 +1311,27 @@ zrefresh(void)
offset = predisplaylen; /* increment over it */
if (rhp->start + offset <= tmppos &&
tmppos < rhp->end + offset) {
- base_atr_on |= rhp->atr;
+ if (base_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) {
+ /* keep colour already set */
+ base_atr_on |= rhp->atr & ~TXT_ATTR_COLOUR_ON_MASK;
+ } else {
+ /* no colour set yet */
+ base_atr_on |= rhp->atr;
+ }
if (tmppos == rhp->end + offset - 1 ||
tmppos == tmpll - 1)
- base_atr_off |= rhp->atr << TXT_ATTR_OFF_ON_SHIFT;
+ base_atr_off |= TXT_ATTR_OFF_FROM_ON(rhp->atr);
}
}
+ if (special_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) {
+ /* keep colours from special attributes */
+ all_atr_on = special_atr_on |
+ (base_atr_on & ~TXT_ATTR_COLOUR_ON_MASK);
+ } else {
+ /* keep colours from standard attributes */
+ all_atr_on = special_atr_on | base_atr_on;
+ }
+ all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on);
if (t == scs) /* if cursor is here, remember it */
rpms.nvcs = rpms.s - nbuf[rpms.nvln = rpms.ln];
@@ -1264,11 +1367,11 @@ zrefresh(void)
rpms.s->chr = ZWC(' ');
if (!started)
started = 1;
- rpms.s->atr = special_atr_on | base_atr_on;
+ rpms.s->atr = all_atr_on;
rpms.s++;
} while (rpms.s < rpms.sen);
if (started)
- rpms.s[-1].atr |= special_atr_off | base_atr_off;
+ rpms.s[-1].atr |= all_atr_off;
if (nextline(&rpms, 1))
break;
if (t == scs) {
@@ -1292,8 +1395,7 @@ zrefresh(void)
* occurrence.
*/
rpms.s->chr = ZWC('?');
- rpms.s->atr = special_atr_on | special_atr_off |
- base_atr_on | base_atr_off;
+ rpms.s->atr = all_atr_on | all_atr_off;
rpms.s++;
} else {
/* We can fit it without reaching the end of the line. */
@@ -1334,18 +1436,17 @@ zrefresh(void)
#endif
) { /* other control character */
rpms.s->chr = ZWC('^');
- rpms.s->atr = special_atr_on | base_atr_on;
+ rpms.s->atr = all_atr_on;
rpms.s++;
if (rpms.s == rpms.sen) {
/* text wrapped */
- rpms.s[-1].atr |= special_atr_off | base_atr_off;
+ rpms.s[-1].atr |= all_atr_off;
if (nextline(&rpms, 1))
break;
}
rpms.s->chr = (((unsigned int)*t & ~0x80u) > 31) ?
ZWC('?') : (*t | ZWC('@'));
- rpms.s->atr = special_atr_on | special_atr_off |
- base_atr_on | base_atr_off;
+ rpms.s->atr = all_atr_on | all_atr_off;
rpms.s++;
}
#ifdef MULTIBYTE_SUPPORT
@@ -1370,12 +1471,12 @@ zrefresh(void)
rpms.s->chr = wc;
if (!started)
started = 1;
- rpms.s->atr = special_atr_on | base_atr_on;
+ rpms.s->atr = all_atr_on;
rpms.s++;
if (rpms.s == rpms.sen) {
/* text wrapped */
if (started) {
- rpms.s[-1].atr |= special_atr_off | base_atr_off;
+ rpms.s[-1].atr |= all_atr_off;
started = 0;
}
if (nextline(&rpms, 1))
@@ -1385,7 +1486,7 @@ zrefresh(void)
dispptr++;
}
if (started)
- rpms.s[-1].atr |= special_atr_off | base_atr_off;
+ rpms.s[-1].atr |= all_atr_off;
if (*dispptr) /* nextline said stop processing */
break;
}
@@ -1417,11 +1518,14 @@ zrefresh(void)
more_end = 1;
if (statusline) {
- int outll, outsz;
+ int outll, outsz, all_atr_on, all_atr_off;
char *statusdup = ztrdup(statusline);
ZLE_STRING_T outputline =
stringaszleline(statusdup, 0, &outll, &outsz, NULL);
+ all_atr_on = special_atr_on;
+ all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on);
+
rpms.tosln = rpms.ln + 1;
nbuf[rpms.ln][winw + 1] = zr_zr; /* text not wrapped */
snextline(&rpms);
@@ -1440,7 +1544,7 @@ zrefresh(void)
}
if (width > rpms.sen - rpms.s) {
rpms.s->chr = ZWC('?');
- rpms.s->atr = special_atr_on | special_atr_off;
+ rpms.s->atr = all_atr_on | all_atr_off;
rpms.s++;
} else {
rpms.s->chr = *u;
@@ -1457,7 +1561,7 @@ zrefresh(void)
#endif
if (ZC_icntrl(*u)) { /* simplified processing in the status line */
rpms.s->chr = ZWC('^');
- rpms.s->atr = special_atr_on;
+ rpms.s->atr = all_atr_on;
rpms.s++;
if (rpms.s == rpms.sen) {
nbuf[rpms.ln][winw + 1] = zr_nl;/* text wrapped */
@@ -1465,7 +1569,7 @@ zrefresh(void)
}
rpms.s->chr = (((unsigned int)*u & ~0x80u) > 31)
? ZWC('?') : (*u | ZWC('@'));
- rpms.s->atr = special_atr_on | special_atr_off;
+ rpms.s->atr = all_atr_on | all_atr_off;
rpms.s++;
} else {
rpms.s->chr = *u;
@@ -2037,7 +2141,7 @@ refreshline(int ln)
*/
int now_off = ol->atr & ~nl->atr & TXT_ATTR_ON_MASK;
if (now_off)
- settextattributes(now_off << TXT_ATTR_OFF_ON_SHIFT);
+ settextattributes(TXT_ATTR_OFF_FROM_ON(now_off));
zputc(nl);
nl++, ol++;
@@ -2324,7 +2428,7 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
if (tmpcs < 0) {
#ifdef DEBUG
fprintf(stderr, "BUG: negative cursor position\n");
- fflush(stderr);
+ fflush(stderr);
#endif
tmpcs = 0;
}
@@ -2336,6 +2440,7 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
for (t0 = 0; t0 < tmpll; t0++) {
int base_atr_on = 0, base_atr_off = 0, ireg;
+ int all_atr_on, all_atr_off;
struct region_highlight *rhp;
/*
* Calculate attribute based on region.
@@ -2350,12 +2455,27 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
offset = predisplaylen; /* increment over it */
if (rhp->start + offset <= t0 &&
t0 < rhp->end + offset) {
- base_atr_on |= rhp->atr;
+ if (base_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) {
+ /* keep colour already set */
+ base_atr_on |= rhp->atr & ~TXT_ATTR_COLOUR_ON_MASK;
+ } else {
+ /* no colour set yet */
+ base_atr_on |= rhp->atr;
+ }
if (t0 == rhp->end + offset - 1 ||
t0 == tmpll - 1)
- base_atr_off |= rhp->atr << TXT_ATTR_OFF_ON_SHIFT;
+ base_atr_off |= TXT_ATTR_OFF_FROM_ON(rhp->atr);
}
}
+ if (special_atr_on & (TXTFGCOLOUR|TXTBGCOLOUR)) {
+ /* keep colours from special attributes */
+ all_atr_on = special_atr_on |
+ (base_atr_on & ~TXT_ATTR_COLOUR_ON_MASK);
+ } else {
+ /* keep colours from standard attributes */
+ all_atr_on = special_atr_on | base_atr_on;
+ }
+ all_atr_off = TXT_ATTR_OFF_FROM_ON(all_atr_on);
if (tmpline[t0] == ZWC('\t')) {
REFRESH_ELEMENT sp = zr_sp;
@@ -2365,11 +2485,10 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
vp[-1].atr |= base_atr_off;
} else if (tmpline[t0] == ZWC('\n')) {
vp->chr = ZWC('\\');
- vp->atr = special_atr_on | base_atr_on;
+ vp->atr = all_atr_on;
vp++;
vp->chr = ZWC('n');
- vp->atr = special_atr_on | special_atr_off |
- base_atr_on | base_atr_off;
+ vp->atr = all_atr_on | all_atr_off;
vp++;
#ifdef MULTIBYTE_SUPPORT
} else if (iswprint(tmpline[t0]) &&
@@ -2406,12 +2525,11 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
ZLE_INT_T t = tmpline[++t0];
vp->chr = ZWC('^');
- vp->atr = special_atr_on | base_atr_on;
+ vp->atr = all_atr_on;
vp++;
vp->chr = (((unsigned int)t & ~0x80u) > 31) ?
ZWC('?') : (t | ZWC('@'));
- vp->atr = special_atr_on | special_atr_off | base_atr_on |
- base_atr_off;
+ vp->atr = all_atr_on | all_atr_off;
vp++;
}
#ifdef MULTIBYTE_SUPPORT
@@ -2431,13 +2549,13 @@ singlerefresh(ZLE_STRING_T tmpline, int tmpll, int tmpcs)
vp->chr = wc;
if (!started)
started = 1;
- vp->atr = special_atr_on | base_atr_on;
+ vp->atr = all_atr_on;
vp++;
}
dispptr++;
}
if (started)
- vp[-1].atr |= special_atr_off | base_atr_off;
+ vp[-1].atr |= all_atr_off;
}
#else
else {
diff --git a/Src/init.c b/Src/init.c
index df859a619..253a689b6 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -79,6 +79,11 @@ int tclines, tccolumns;
/**/
mod_export int hasam, hasxn;
+/* Value of the Co (max_colors) entry: may not be set */
+
+/**/
+mod_export int tccolours;
+
/* Pointer to read-key function from zle */
/**/
@@ -531,7 +536,7 @@ static char *tccapnams[TC_COUNT] = {
"cl", "le", "LE", "nd", "RI", "up", "UP", "do",
"DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
"md", "so", "us", "me", "se", "ue", "ch",
- "ku", "kd", "kl", "kr", "sc", "rc", "bc"
+ "ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB"
};
/* Initialise termcap */
@@ -590,6 +595,7 @@ init_term(void)
tclines = tgetnum("li");
tccolumns = tgetnum("co");
+ tccolours = tgetnum("Co");
/* if there's no termcap entry for cursor up, use single line mode: *
* this is flagged by termflags which is examined in zle_refresh.c *
diff --git a/Src/zsh.h b/Src/zsh.h
index 6bf682265..54a31507f 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1949,7 +1949,9 @@ struct ttyinfo {
#define TCSAVECURSOR 29
#define TCRESTRCURSOR 30
#define TCBACKSPACE 31
-#define TC_COUNT 32
+#define TCFGCOLOUR 32
+#define TCBGCOLOUR 33
+#define TC_COUNT 34
#define tccan(X) (tclen[X])
@@ -1957,32 +1959,63 @@ struct ttyinfo {
* Text attributes for displaying in ZLE
*/
-#define TXTBOLDFACE 0x01
-#define TXTSTANDOUT 0x02
-#define TXTUNDERLINE 0x04
-#define TXTDIRTY 0x80
+#define TXTBOLDFACE 0x0001
+#define TXTSTANDOUT 0x0002
+#define TXTUNDERLINE 0x0004
+#define TXTFGCOLOUR 0x0008
+#define TXTBGCOLOUR 0x0010
+#define TXTDIRTY 0x0020
-#define TXT_ATTR_ON_MASK 0x07
+#define TXT_ATTR_ON_MASK 0x001F
#define txtisset(X) (txtattrmask & (X))
#define txtset(X) (txtattrmask |= (X))
#define txtunset(X) (txtattrmask &= ~(X))
-#define TXTNOBOLDFACE 0x10
-#define TXTNOSTANDOUT 0x20
-#define TXTNOUNDERLINE 0x40
+#define TXTNOBOLDFACE 0x0040
+#define TXTNOSTANDOUT 0x0080
+#define TXTNOUNDERLINE 0x0100
+#define TXTNOFGCOLOUR 0x0200
+#define TXTNOBGCOLOUR 0x0400
-#define TXT_ATTR_OFF_MASK 0x70
+#define TXT_ATTR_OFF_MASK 0x07C0
/* Bits to shift off right to get on */
-#define TXT_ATTR_OFF_ON_SHIFT (4)
-
+#define TXT_ATTR_OFF_ON_SHIFT 6
+#define TXT_ATTR_OFF_FROM_ON(attr) \
+ (((attr) & TXT_ATTR_ON_MASK) << TXT_ATTR_OFF_ON_SHIFT)
/*
* Indicates to zle_refresh.c that the character entry is an
* index into the list of multiword symbols.
*/
-#define TXT_MULTIWORD_MASK 0x100
+#define TXT_MULTIWORD_MASK 0x0800
+
+/* Mask for colour to use in foreground */
+#define TXT_ATTR_FG_COL_MASK 0x000FF000
+/* Bits to shift the foreground colour */
+#define TXT_ATTR_FG_COL_SHIFT (12)
+/* Mask for colour to use in background */
+#define TXT_ATTR_BG_COL_MASK 0x0FF00000
+/* Bits to shift the background colour */
+#define TXT_ATTR_BG_COL_SHIFT (20)
+
+/* Flag to use termcap AF sequence to set colour, if available */
+#define TXT_ATTR_FG_TERMCAP 0x10000000
+/* Flag to use termcap AB sequence to set colour, if available */
+#define TXT_ATTR_BG_TERMCAP 0x20000000
+
+/* Things to turn on, including values for the colour elements */
+#define TXT_ATTR_ON_VALUES_MASK \
+ (TXT_ATTR_ON_MASK|TXT_ATTR_FG_COL_MASK|TXT_ATTR_BG_COL_MASK|\
+ TXT_ATTR_FG_TERMCAP|TXT_ATTR_BG_TERMCAP)
+
+/* Mask out everything to do with activating colours */
+#define TXT_ATTR_COLOUR_ON_MASK \
+ (TXTFGCOLOUR|TXTBGCOLOUR| \
+ TXT_ATTR_FG_COL_MASK|TXT_ATTR_BG_COL_MASK| \
+ TXT_ATTR_FG_TERMCAP|TXT_ATTR_BG_TERMCAP)
#define txtchangeisset(T,X) ((T) & (X))
+#define txtchangeget(T,A) (((T) & A ## _MASK) >> A ## _SHIFT)
#define txtchangeset(X, Y) (txtchange |= (X), txtchange &= ~(Y))
/****************************************/