chiark / gitweb /
@@@ more tty mess
authorMark Wooding <mdw@distorted.org.uk>
Fri, 25 Apr 2025 09:02:03 +0000 (10:02 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 25 Apr 2025 10:43:25 +0000 (11:43 +0100)
ui/tty.c

index 001878c27a4aec5ab777c8e3c49b64fff629c233..ff24256cb4b240a4054ee9e8cb6e54a92a1f6e7c 100644 (file)
--- a/ui/tty.c
+++ b/ui/tty.c
@@ -294,13 +294,11 @@ static void common_init(struct tty *tty, FILE *fp)
    * weird code, so we have to convert it into an actual rate in bits per
    * second.
    */
-  if (!fp || tcgetattr(fileno(fp), &c))
-    tty->baud = 0;
-  else {
+  tty->baud = 0; tty->wd = tty->ht = 0;
+  if (fp && !tcgetattr(fileno(fp), &c)) {
     code = cfgetospeed(&c);
     for (b = baudtab; b->baud; b++)
       if (b->code == code) { tty->baud = b->baud; goto found_baud; }
-    tty->baud = 0;
   found_baud:
     tty_resized(tty);
   }
@@ -774,13 +772,17 @@ static void clamp_attr(struct tty_attr *a_out,
   if (acaps&TTACF_INVV) ff |= f&TTAF_INVV;
 
   /* Foreground and background colours. */
-  if (acaps&TTACF_FG) {
+  if (!(acaps&TTACF_FG))
+    a_out->fg = 0;
+  else {
     clamp_colours(&t, &a_out->fg,
                  (f&TTAF_FGSPCMASK) >> TTAF_FGSPCSHIFT, a ? a->fg : 0,
                  acaps);
     ff |= t << TTAF_FGSPCSHIFT;
   }
-  if (acaps&TTACF_BG) {
+  if (!(acaps&TTACF_BG))
+    a_out->bg = 0;
+  else {
     clamp_colours(&t, &a_out->bg,
                  (f&TTAF_BGSPCMASK) >> TTAF_BGSPCSHIFT, a ? a->bg : 0,
                  acaps);
@@ -1098,6 +1100,13 @@ struct tty_capslots {
 #undef DEF_BOOLCAP
 #undef DEF_INTCAP
 #undef DEF_STRCAP
+#define LEN_BOOLCAP(uix, info, cap)
+#define LEN_INTCAP(uix, info, cap)
+#define LEN_STRCAP(uix, info, cap) unsigned info##_cost;
+    ATTRCAPS(LEN_BOOLCAP, LEN_INTCAP, LEN_STRCAP)
+#undef LEN_BOOLCAP
+#undef LEN_INTCAP
+#undef LEN_STRCAP
 };
 #define TTY_CAPSPFX                                                    \
   struct tty tty;                                                      \
@@ -1141,10 +1150,21 @@ static void init_caps(struct tty_caps *t)
 #undef GETINT
 #undef GETSTR
 
+#define COST_BOOLCAP(uix, info, cap_)
+#define COST_INTCAP(uix, info, cap_)
+#define COST_STRCAP(uix, info, cap_)                                   \
+    if (!t->cap.info) t->cap.info##_cost = -1;                         \
+    else t->cap.info##_cost =                                          \
+          strlen(tgoto(t->cap.info, 0, t->cap.colors - 1));
+  ATTRCAPS(COST_BOOLCAP, COST_INTCAP, COST_STRCAP)
+#undef COST_BOOLCAP
+#undef COST_INTCAP
+#undef COST_STRCAP
+
 #define CLEAR_BOOL(uix, info, cap_) t->cap.info = 0;
 #define CLEAR_INT(uix, info, cap_) t->cap.info = 0;
 #define CLEAR_STR(uix, info, cap_) t->cap.info = 0;
-#define CLEAR_CAPS(caplist)                                            \
+#define CLEARCAPS(caplist)                                             \
     do { caplist(CLEAR_BOOL, CLEAR_INT, CLEAR_STR) } while (0)
 
   /* Basic capabilities. */
@@ -1152,18 +1172,21 @@ static void init_caps(struct tty_caps *t)
   if (!t->cap.nel) t->cap.nel = "\r\n";
 
   /* Attribute capabilities. */
-  if (ops->cap.intcap(&t->tty, CAP_XMC) > 0 || !t->cap.sgr0)
-    CLEAR_CAPS(ATTRCAPS);
+  if (ops->cap.intcap(&t->tty, CAP_XMC) > 0)
+    CLEARCAPS(ATTRCAPS);
   else {
-    if (t->cap.smul) t->tty.acaps |= TTACF_ULINE;
-    if (t->cap.bold) t->tty.acaps |= TTACF_BOLD;
-    if (t->cap.dim) t->tty.acaps |= TTACF_DIM;
-    if (t->cap.sitm) t->tty.acaps |= TTACF_ITAL;
-    if (t->cap.rev) t->tty.acaps |= TTACF_INVV;
-
-    if (!t->cap.op || (!t->cap.setaf && !t->cap.setab))
-      CLEAR_CAPS(COLOURCAPS);
-    else {
+    if (t->cap.smul && (t->cap.rmul || t->cap.sgr0))
+      t->tty.acaps |= TTACF_ULINE;
+    if (t->cap.bold && t->cap.sgr0)
+      t->tty.acaps |= TTACF_BOLD;
+    if (t->cap.dim && t->cap.sgr0)
+      t->tty.acaps |= TTACF_DIM;
+    if (t->cap.sitm && (t->cap.ritm || t->cap.sgr0))
+      t->tty.acaps |= TTACF_ITAL;
+    if (t->cap.rev && t->cap.sgr0)
+      t->tty.acaps |= TTACF_INVV;
+
+    if ((t->cap.setaf || t->cap.setab) && (t->cap.op || t->cap.sgr0)) {
       if (t->cap.setaf) t->tty.acaps |= TTACF_FG;
       if (t->cap.setab) t->tty.acaps |= TTACF_BG;
       t->tty.acaps |= TTACF_1BPC;
@@ -1225,6 +1248,11 @@ static void init_caps(struct tty_caps *t)
     { wd = ops->cap.intcap(&t->tty, CAP_WD); if (wd > 0) t->tty.wd = wd; }
   if (!t->tty.ht)
     { ht = ops->cap.intcap(&t->tty, CAP_HT); if (ht > 0) t->tty.ht = ht; }
+
+#undef CLEAR_BOOL
+#undef CLEAR_INT
+#undef CLEAR_STR
+#undef CLEARCAPS
 }
 
 /* Macros for formatting capabilities. */
@@ -1282,6 +1310,8 @@ static int caps_setattr_internal(struct tty_caps *t,
   const struct tty_capops *ops = (const struct tty_capops *)t->tty.ops;
   uint32 diff;
   int rc;
+  unsigned c, z, f = 0;
+#define f_clrall 1u
 
   /* Work out what needs doing. */
   diff = a->f ^ t->tty.st.attr.f;
@@ -1293,11 +1323,36 @@ static int caps_setattr_internal(struct tty_caps *t,
    * to do that, we need to restore the other active attributes, so we must
    * check up front.
    */
-  if (((diff&TTAF_LNMASK) && !(a->f&TTAF_LNMASK) && !t->cap.rmul) ||
-      ((diff&TTAF_WTMASK) && !(a->f&TTAF_WTMASK)) ||
-      ((diff&~a->f&TTAF_ITAL) && !t->cap.ritm) ||
-      (diff&~a->f&TTAF_INVV))
-    { PUT0(0, sgr0); diff = a->f; }
+
+  c = 0;
+#define CLEARP(mask) ((diff&(mask)) && !(a->f&(mask)))
+#define ADDCOST(cap_) do {                                             \
+  if (t->cap.cap_) c += t->cap.cap_##_cost;                            \
+  else f |= f_clrall;                                                  \
+} while (0)
+  if (CLEARP(TTAF_LNMASK)) ADDCOST(rmul);
+  if (CLEARP(TTAF_WTMASK)) f |= f_clrall;
+  if (diff&~a->f&TTAF_INVV) f |= f_clrall;
+  if (diff&~a->f&TTAF_ITAL) ADDCOST(ritm);
+  if (CLEARP(TTAF_FGSPCMASK) || CLEARP(TTAF_BGSPCMASK)) ADDCOST(op);
+#undef CLEARP
+#undef ADDCOST
+
+  z = 0;
+  switch ((a->f&TTAF_LNMASK) >> TTAF_LNSHIFT) {
+    case TTLN_ULINE: z += t->cap.smul_cost; break;
+  }
+  switch ((a->f&TTAF_WTMASK) >> TTAF_WTSHIFT) {
+    case TTWT_BOLD: z += t->cap.bold_cost; break;
+    case TTWT_DIM: z += t->cap.dim_cost; break;
+  }
+  if (a->f&TTAF_INVV) z += t->cap.rev_cost;
+  if (a->f&TTAF_ITAL) z += t->cap.sitm_cost;
+  if (a->f&TTAF_FGSPCMASK) z += t->cap.setaf_cost;
+  if (a->f&TTAF_BGSPCMASK) z += t->cap.setab_cost;
+
+  if ((t->cap.sgr0 && z + t->cap.sgr0_cost < c) || (f&f_clrall))
+    { PUT0(0, sgr0); diff = a->f; t->tty.st.attr.fg = t->tty.st.attr.bg; }
 
   /* Line style. */
   if (diff&TTAF_LNMASK)
@@ -1319,11 +1374,11 @@ static int caps_setattr_internal(struct tty_caps *t,
     }
 
   /* Other text effects. */
+  if (diff&a->f&TTAF_INVV) PUT0(0, rev);
   if (diff&TTAF_ITAL) {
     if (a->f&TTAF_ITAL) PUT0(0, sitm);
     else PUT0(0, ritm);
   }
-  if (diff&a->f&TTAF_INVV) PUT0(0, rev);
 
   /* Colours. */
   if (((diff&TTAF_FGSPCMASK) && !(a->f&TTAF_FGSPCMASK)) ||
@@ -1347,6 +1402,8 @@ static int caps_setattr_internal(struct tty_caps *t,
   rc = 0;
 end:
   t->tty.st.attr = *a; return (rc);
+
+#undef f_clrall
 }
 
 static int caps_setattr(struct tty *tty,
@@ -2259,7 +2316,7 @@ static int ansi_setattr(struct tty *tty,
 
   PUTLIT("\33[");
 
-  if (z <= c)
+  if (z < c || (c && !(t->ansi.f&TAF_CNCATTR)))
     { SEMI; diff = a->f; t->tty.st.attr.fg = t->tty.st.attr.bg = 0; }
 
   if (diff&TTAF_LNMASK)
@@ -2833,7 +2890,6 @@ void tty_close(struct tty *tty)
   }
 }
 
-
 int tty_resized(struct tty *tty)
 {
   struct winsize ws;