commit 89940c7d72b76e5e9362c9ecffe76767cdef8aa9 Author: meh Date: Wed Nov 4 18:32:45 2015 +0100 Fix hardstatus padding with unicode backticks diff --git a/src/display.c b/src/display.c index c510adb..86f75cc 100644 --- a/src/display.c +++ b/src/display.c @@ -1584,19 +1584,10 @@ static void RemoveStatusMinWait() static int strlen_onscreen(char *c, char *end) { int len = 0; - while (*c && (!end || c < end)) { - int v, dec = 0; - do { - v = FromUtf8(*c++, &dec); - if (v == -2) - c--; - } - while (v < 0 && (!end || c < end)); - if (!utf8_iscomb(v)) { - if (utf8_isdouble(v)) - len++; - len++; - } + + while (*c && (!end || c <= end)) { + len += utf8_width(c); + c += utf8_size(c); } return len; @@ -1608,9 +1599,9 @@ static int PrePutWinMsg(char *s, int start, int max) Ideally, this would not be necessary. But fixing it the Right Way will probably take way more time. So this will have to do for now. */ if (D_encoding == UTF8) { - int chars = strlen_onscreen((s + start), (s + max)); + int chars = strlen_onscreen((s + start), NULL); D_encoding = 0; - PutWinMsg(s, start, max + ((max - start) - chars)); /* Multibyte count */ + PutWinMsg(s, start, strlen(s + start)); /* Multibyte count */ D_encoding = UTF8; D_x -= (max - chars); /* Yak! But this is necessary to count for the fact that not every byte represents a diff --git a/src/encoding.c b/src/encoding.c index 45967a4..5769671 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -1504,3 +1504,39 @@ void LoadFontTranslationsForEncoding(int encoding) if (f > 0 && recodetabs[f].flags == 0) LoadFontTranslation(f, 0); } + +int utf8_width(char* buf) +{ + wchar_t result = 0; + + if (buf[0] > 0) { + return 1; + } + + mbtowc(&result, buf, 4); + return wcwidth(result); +} + +int utf8_size(char* buf) +{ + unsigned char* utf = (unsigned char*) buf; + + if (utf[0] <= 0x7F) { + return 1; + } + else if (utf[0] <= 0xBF) { + return 0; + } + else if (utf[0] <= 0xDF) { + return 2; + } + else if (utf[0] <= 0xEF) { + return 3; + } + else if (utf[0] <= 0xF4) { + return 4; + } + else { + return 0; + } +} diff --git a/src/encoding.h b/src/encoding.h index ec284e4..8be6e78 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -1,6 +1,9 @@ #ifndef SCREEN_ENCODING_H #define SCREEN_ENCODING_H +#include +#include + void InitBuiltinTabs (void); struct mchar *recode_mchar (struct mchar *, int, int); struct mline *recode_mline (struct mline *, int, int, int); @@ -25,4 +28,7 @@ int RecodeBuf (unsigned char *, int, int, int, unsigned char *); int PrepareEncodedChar (int); int EncodeChar (char *, int, int, int *); +int utf8_width(char *buf); +int utf8_size(char* buf); + #endif /* SCREEN_ENCODING_H */ diff --git a/src/screen.c b/src/screen.c index a9a845b..2246e26 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1604,6 +1604,7 @@ void PutWinMsg(char *s, int start, int max) if (n > max) n = max; max -= n; + max += utf8_width(s) - 1; p += n; while (n-- > 0) { if (start-- > 0) diff --git a/src/winmsg.c b/src/winmsg.c index 4d7db12..1e0c8d8 100644 --- a/src/winmsg.c +++ b/src/winmsg.c @@ -39,6 +39,7 @@ #include "process.h" #include "sched.h" #include "mark.h" +#include "encoding.h" /* TODO: rid global variable (has been renamed to point this out; see commit * history) */ @@ -73,36 +74,57 @@ extern Backtick *backticks; static void _MakeWinMsgEvRec(WinMsgBufContext *, WinMsgCond *, char *, Window *, int *, int); - /* TODO: remove the redundant arguments */ static char *pad_expand(WinMsgBuf *winmsg, char *buf, char *p, int numpad, int padlen) { - char *pn, *pn2; - int i, r; - - padlen = padlen - (p - buf); /* space for rent */ - if (padlen < 0) - padlen = 0; - pn2 = pn = p + padlen; - r = winmsg->numrend; - while (p >= buf) { - if (r && *p != CHRPAD && p - buf == winmsg->rendpos[r - 1]) { - winmsg->rendpos[--r] = pn - buf; + char *pp, *pd, padded[MAXSTR] = {0}; + int offset, pads, r, i; + + pp = buf; + while (pp <= p) { + if (*pp == CHRPAD) { + pp++; + } + else { + padlen -= utf8_width(pp); + pp += utf8_size(pp); + } + } + + r = 0; + offset = 0; + pads = 0; + pp = buf; + pd = padded; + + while (pp <= p) { + if (r < winmsg->numrend && pp - buf == winmsg->rendpos[r]) { + winmsg->rendpos[r] += offset; + r++; continue; } - *pn-- = *p; - if (*p-- == CHRPAD) { - pn[1] = ' '; - i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0; - padlen -= i; + + if (*pp == CHRPAD) { + i = (padlen / numpad); + if (pads == 0 && padlen % 2 == 1) + i++; + offset += i - 1; while (i-- > 0) - *pn-- = ' '; - numpad--; - if (r && p - buf == winmsg->rendpos[r - 1]) - winmsg->rendpos[--r] = pn - buf; + *pd++ = ' '; + pd--; + pads++; + } + else { + *pd = *pp; } + + pp++; + pd++; } - return pn2; + + strcpy(buf, padded); + + return p + padlen; } int AddWinMsgRend(WinMsgBuf *winmsg, const char *str, uint64_t r)