From cb0f508f1cca86cf6fed97c8604b9759ebded2f7 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 29 Jun 2016 18:55:02 -0700 Subject: [PATCH] tty message history line-wrapping fix Reported directly to devteam last October, for 3.4.3 on NAO, subject "UI flaw in message history": "Applying the stethoscope at self informs: "Status of Xxxxxxxx (piously neutral): Level 14 HP 138(138) AC -15, very "fast, invisible.--More-- This is reproducible with shorter character name "wizard" by being "nominally neutral" or "nominally chaotic". I had a 2 digit level but didn't notice that my AC took up only 1 digit and ended up using 125ish blessed potions of full healing to get 4 digits of hit points in order to get the line to wrap between "very" and "fast". "But the message history with Ctrl-P shows: "Message History " "Status of Xxxxxxxx (piously neutral): Level 14 HP 138(138) AC -15, very "invisible. The key was "Message History", indicating msg_window:full or other setting which causes ^P to bypass the top line message window and use a general text window to deliver all history lines at once. The original feedback splits the line by replacing the space between "very" and "fast" with a newline, which topline handling notices and processes as special, but then leaves in place. msg_window:full results in tty_putstr() case NHW_TEXT, which treats newline as an ordinary character since it doesn't expect to see that in text. Squeezing out three doubled spaces made room for "very\nfast," on the top line. process_text_window() attempted to write it there, but putchar() wrote up through "very," on one line, then output the newline which resulted in "fast," on the next line. Then explicit cursor positioning set things up to put "invisible" at the start of that line, overwriting "fast," so making it appear to be missing. --- doc/fixes36.1 | 2 ++ win/tty/topl.c | 17 ++++++++--------- win/tty/wintty.c | 33 +++++++++++++++++++-------------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 3b8bd6ca1..90b9a6a8a 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -347,6 +347,8 @@ tty: if color is disabled and use_inverse is enabled, display lava in inverse tty: if "--More--" was written to leftmost column (beginning of second line) while hero was swallowed, cursor would end up in wrong place (at end of status line instead back on map) after message line was cleared +tty: long message lines which wrap when shown on the top line might be + re-displayed incorrectly by ^P for msg_window={full,combo,reverse} unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) unix: options file with CR+LF line ends and an invalid option line resulted in diff --git a/win/tty/topl.c b/win/tty/topl.c index 4c857cb81..dd6758a4e 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -8,7 +8,6 @@ #include "tcap.h" #include "wintty.h" -#include #ifndef C /* this matches src/cmd.c */ #define C(c) (0x1f & (c)) @@ -48,8 +47,7 @@ tty_doprev_message() do { morc = 0; if (cw->maxcol == cw->maxrow) { - ttyDisplay->dismiss_more = - C('p'); /* allowed at --More-- */ + ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */ redotoplin(toplines); cw->maxcol--; if (cw->maxcol < 0) @@ -57,8 +55,7 @@ tty_doprev_message() if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } else if (cw->maxcol == (cw->maxrow - 1)) { - ttyDisplay->dismiss_more = - C('p'); /* allowed at --More-- */ + ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */ redotoplin(cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) @@ -130,6 +127,7 @@ redotoplin(str) const char *str; { int otoplin = ttyDisplay->toplin; + home(); if (*str & 0x80) { /* kludge for the / command, the only time we ever want a */ @@ -251,10 +249,11 @@ register const char *bp; (void) strncpy(toplines, bp, TBUFSZ); toplines[TBUFSZ - 1] = 0; - for (tl = toplines; n0 >= CO;) { + for (tl = toplines; n0 >= CO; ) { otl = tl; - for (tl += CO - 1; tl != otl && !isspace(*tl); --tl) - ; + for (tl += CO - 1; tl != otl; --tl) + if (*tl == ' ') + break; if (tl == otl) { /* Eek! A huge token. Try splitting after it. */ tl = index(otl, ' '); @@ -299,7 +298,7 @@ char c; break; default: if (ttyDisplay->curx == CO - 1) - topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */ + topl_putsym('\n'); /* 1 <= curx < CO; avoid CO */ #ifdef WIN32CON (void) putchar(c); #endif diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 8ceb1dc4e..e38e3e7c8 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2443,22 +2443,27 @@ compress_str(str) const char *str; { static char cbuf[BUFSZ]; - /* compress in case line too long */ - if ((int) strlen(str) >= CO) { + + /* compress out consecutive spaces if line is too long; + topline wrapping converts space at wrap point into newline, + we reverse that here */ + if ((int) strlen(str) >= CO || index(str, '\n')) { register const char *bp0 = str; - register char *bp1 = cbuf; + char c, nxtc, *bp1 = cbuf, *endbp1 = &cbuf[sizeof cbuf - 1]; + cbuf[0] = cbuf[sizeof cbuf - 1] = '\0'; /* superfluous */ + nxtc = (*bp0 == '\n') ? ' ' : *bp0; do { -#ifdef CLIPPING - if (*bp0 != ' ' || bp0[1] != ' ') -#else - if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ') -#endif - *bp1++ = *bp0; - } while (*bp0++); - } else - return str; - return cbuf; + c = nxtc; + nxtc = bp0[1]; + if (nxtc == '\n') + nxtc = ' '; + if (c != ' ' || nxtc != ' ') + *bp1++ = c; + } while (*bp0++ && bp1 < endbp1); + str = cbuf; + } + return str; } void @@ -2601,7 +2606,7 @@ const char *str; } if (cw->data[cw->cury]) free((genericptr_t) cw->data[cw->cury]); - n0 = strlen(str) + 1; + n0 = (long) strlen(str) + 1L; ob = cw->data[cw->cury] = (char *) alloc((unsigned) n0 + 1); *ob++ = (char) (attr + 1); /* avoid nuls, for convenience */ Strcpy(ob, str); -- 2.40.0