diff --git a/README.md b/README.md index 0b0b70ef..5eb43eec 100644 --- a/README.md +++ b/README.md @@ -563,9 +563,9 @@ A character provided as argument to any of the Turbo Vision API functions that d For example, the string `"╔[\xFE]╗"` may be displayed as `╔[■]╗`. This means that box-drawing characters can be mixed with UTF-8 in general, which is useful for backward compatibility. If you rely on this behaviour, though, you may get unexpected results: for instance, `"\xC4\xBF"` is a valid UTF-8 sequence and is displayed as `Ŀ` instead of `─┐`. -One of the issues of Unicode support is the existence of [multi-width](https://convertcase.net/vaporwave-wide-text-generator/) characters and [combining](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) characters. This conflicts with Turbo Vision's original assumption that the screen is a grid of cells occupied by a single character each. Nevertheless, these cases are handled in the following way: +One of the issues of Unicode support is the existence of [double-width](https://convertcase.net/vaporwave-wide-text-generator/) characters and [combining](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) characters. This conflicts with Turbo Vision's original assumption that the screen is a grid of cells occupied by a single character each. Nevertheless, these cases are handled in the following way: -* Multi-width characters can be drawn anywhere on the screen and nothing bad happens if they overlap partially with other characters. +* Double-width characters can be drawn anywhere on the screen and nothing bad happens if they overlap partially with other characters. * Zero-width characters overlay the previous character. For example, the sequence `में` consists of the single-width character `म` and the combining characters `े` and `ं`. In this case, three Unicode codepoints are fit into the same cell. The `ZERO WIDTH JOINER` (`U+200D`) is always omitted, as it complicates things too much. For example, it can turn a string like `"👩👦"` (4 columns wide) into `"👩‍👦"` (2 columns wide). Not all terminal emulators respect the ZWJ, so, in order to produce predictable results, Turbo Vision will print both `"👩👦"` and `"👩‍👦"` as `👩👦`. @@ -591,14 +591,14 @@ ushort TDrawBuffer::moveCStr(ushort indent, TStringView str, TAttrPair attrs); `str` is interpreted according to the rules exposed previously. ```c++ -ushort TDrawBuffer::moveStr(ushort indent, TStringView str, TColorAttr attr, ushort maxWidth, ushort strIndent = 0); // New -ushort TDrawBuffer::moveCStr(ushort indent, TStringView str, TColorAttr attr, ushort maxWidth, ushort strIndent = 0); // New +ushort TDrawBuffer::moveStr(ushort indent, TStringView str, TColorAttr attr, ushort maxWidth, ushort strOffset = 0); // New +ushort TDrawBuffer::moveCStr(ushort indent, TStringView str, TColorAttr attr, ushort maxWidth, ushort strOffset = 0); // New ``` `str` is interpreted according to the rules exposed previously, but: -* `maxWidth` specifies the maximum amount of text that should be copied from `str`, measured in text width. -* `strIndent` specifies the initial position `str` where to copy from, measured in text width. This is useful for horizontal scrolling. If `strIndent` is in the middle of a multi-width character, the remaining positions in that character are filled with spaces. +* `maxWidth` specifies the maximum amount of text that should be copied from `str`, measured in text width (not in bytes). +* `strOffset` specifies the initial position in `str` where to copy from, measured in text width (not in bytes). This is useful for horizontal scrolling. If `strOffset` points to the middle of a double-width character, a space will be copied instead of the right half of the double-width character, since it is not possible to do such a thing. -The return values are the number of display columns that were actually filled with text. +The return values are the number of cells in the buffer that were actually filled with text (which is the same as the width of the copied text). ```c++ void TDrawBuffer::moveBuf(ushort indent, const void *source, TColorAttr attr, ushort count); diff --git a/include/tvision/drawbuf.h b/include/tvision/drawbuf.h index 78c15418..0ea554d5 100644 --- a/include/tvision/drawbuf.h +++ b/include/tvision/drawbuf.h @@ -35,9 +35,9 @@ class TDrawBuffer void moveChar( ushort indent, char c, TColorAttr attr, ushort count ) noexcept; ushort moveStr( ushort indent, TStringView str, TColorAttr attr ) noexcept; - ushort moveStr( ushort indent, TStringView str, TColorAttr attr, ushort maxWidth, ushort strIndent = 0 ) noexcept; + ushort moveStr( ushort indent, TStringView str, TColorAttr attr, ushort maxWidth, ushort strOffset = 0 ) noexcept; ushort moveCStr( ushort indent, TStringView str, TAttrPair attrs ) noexcept; - ushort moveCStr( ushort indent, TStringView str, TAttrPair attrs, ushort maxWidth, ushort strIndent = 0 ) noexcept; + ushort moveCStr( ushort indent, TStringView str, TAttrPair attrs, ushort maxWidth, ushort strOffset = 0 ) noexcept; void moveBuf( ushort indent, const void _FAR *source, TColorAttr attr, ushort count ) noexcept; void putAttribute( ushort indent, TColorAttr attr ) noexcept; diff --git a/include/tvision/scrncell.h b/include/tvision/scrncell.h index 887fd8e2..e2687778 100644 --- a/include/tvision/scrncell.h +++ b/include/tvision/scrncell.h @@ -60,13 +60,13 @@ struct TCellChar TCellChar() = default; inline void moveChar(char ch); - inline void moveInt(uint32_t mbc, bool wide=false); - inline void moveStr(TStringView mbc, bool wide=false); + inline void moveMultiByteChar(uint32_t mbc, bool wide = false); + inline void moveMultiByteChar(TStringView mbc, bool wide = false); inline void moveWideCharTrail(); constexpr inline bool isWide() const; constexpr inline bool isWideCharTrail() const; - constexpr inline void appendZeroWidth(TStringView mbc); + constexpr inline void appendZeroWidthChar(TStringView mbc); constexpr inline TStringView getText() const; constexpr inline size_t size() const; @@ -80,7 +80,7 @@ inline void TCellChar::moveChar(char ch) _text[0] = ch; } -inline void TCellChar::moveInt(uint32_t mbc, bool wide) +inline void TCellChar::moveMultiByteChar(uint32_t mbc, bool wide) // Pre: 'mbc' is a bit-casted multibyte-encoded character. { memset(this, 0, sizeof(*this)); @@ -88,7 +88,7 @@ inline void TCellChar::moveInt(uint32_t mbc, bool wide) _flags = -int(wide) & fWide; } -inline void TCellChar::moveStr(TStringView mbc, bool wide) +inline void TCellChar::moveMultiByteChar(TStringView mbc, bool wide) { static_assert(sizeof(_text) >= 4, ""); memset(this, 0, sizeof(*this)); @@ -121,7 +121,7 @@ constexpr inline bool TCellChar::isWideCharTrail() const return _flags & fTrail; } -constexpr inline void TCellChar::appendZeroWidth(TStringView mbc) +constexpr inline void TCellChar::appendZeroWidthChar(TStringView mbc) // Pre: !isWideCharTrail(); { size_t sz = size(); diff --git a/source/platform/buffdisp.cpp b/source/platform/buffdisp.cpp index 666e1f90..4d4ee797 100644 --- a/source/platform/buffdisp.cpp +++ b/source/platform/buffdisp.cpp @@ -197,14 +197,14 @@ void DisplayBuffer::flushScreen(DisplayStrategy &display) noexcept inline void DisplayBuffer::validateCell(TScreenCell &cell) const noexcept { auto &ch = cell._ch; - if (!ch[1]) // size 1 + if (ch[1] == '\0') // size 1 { uchar c = ch[0]; if (c == '\0') ch[0] = ' '; else if (c < ' ' || 0x7F <= c) // Translate from codepage as fallback. - ch.moveInt(CpTranslator::toPackedUtf8(c)); + ch.moveMultiByteChar(CpTranslator::toPackedUtf8(c)); } } diff --git a/source/platform/stdioctl.cpp b/source/platform/stdioctl.cpp index 7099a73c..31f07489 100644 --- a/source/platform/stdioctl.cpp +++ b/source/platform/stdioctl.cpp @@ -187,7 +187,7 @@ StdioCtl::StdioCtl() noexcept // still work. // // So, in order to find out if a console needs to be allocated, we - // check whether at least of the standard handles is a console. If none + // check whether at least one of the standard handles is a console. If none // of them is, we allocate a new console. Yes, this will always spawn a // console if all three standard handles are redirected, but this is not // a common use case. diff --git a/source/platform/ttext.cpp b/source/platform/ttext.cpp index df9d992d..37944eac 100644 --- a/source/platform/ttext.cpp +++ b/source/platform/ttext.cpp @@ -285,7 +285,7 @@ TText::Lw TText::scrollImpl(TSpan text, int count, Boolean inclu namespace ttext { -static inline bool isZWJ(TStringView mbc) +static inline bool isZeroWidthJoiner(TStringView mbc) // We want to avoid printing certain characters which are usually represented // differently by different terminal applications or which can combine different // characters together, changing the width of a whole string. @@ -312,7 +312,7 @@ TText::Lw TText::drawOneImpl( TSpan cells, size_t i, if (text[j] == '\0') cells[i]._ch.moveChar(' '); else if (text[j] < ' ' || '\x7F' <= text[j]) - cells[i]._ch.moveInt(CpTranslator::toPackedUtf8(text[j])); + cells[i]._ch.moveMultiByteChar(CpTranslator::toPackedUtf8(text[j])); else cells[i]._ch.moveChar(text[j]); return {1, 1}; @@ -324,7 +324,7 @@ TText::Lw TText::drawOneImpl( TSpan cells, size_t i, { if (i < cells.size()) { - cells[i]._ch.moveStr("�"); + cells[i]._ch.moveMultiByteChar("�"); return {(size_t) mb.length, 1}; } } @@ -332,11 +332,11 @@ TText::Lw TText::drawOneImpl( TSpan cells, size_t i, { TStringView zwc {&text[j], (size_t) mb.length}; // Append to the previous cell, if present. - if (i > 0 && !isZWJ(zwc)) + if (i > 0 && !isZeroWidthJoiner(zwc)) { size_t k = i; while (cells[--k]._ch.isWideCharTrail() && k > 0); - cells[k]._ch.appendZeroWidth(zwc); + cells[k]._ch.appendZeroWidthChar(zwc); } return {(size_t) mb.length, 0}; } @@ -345,7 +345,7 @@ TText::Lw TText::drawOneImpl( TSpan cells, size_t i, if (i < cells.size()) { bool wide = mb.width > 1; - cells[i]._ch.moveStr({&text[j], (size_t) mb.length}, wide); + cells[i]._ch.moveMultiByteChar({&text[j], (size_t) mb.length}, wide); bool drawTrail = (wide && i + 1 < cells.size()); if (drawTrail) cells[i + 1]._ch.moveWideCharTrail(); @@ -372,18 +372,18 @@ TText::Lw TText::drawOneImpl( TSpan cells, size_t i, { if (i < cells.size()) { - cells[i]._ch.moveStr("�"); + cells[i]._ch.moveMultiByteChar("�"); return {1, 1}; } } else if (textU32[j] != 0 && width == 0) { // Append to the previous cell, if present. - if (i > 0 && !isZWJ(textU8)) + if (i > 0 && !isZeroWidthJoiner(textU8)) { size_t k = i; while (cells[--k]._ch.isWideCharTrail() && k > 0); - cells[k]._ch.appendZeroWidth(textU8); + cells[k]._ch.appendZeroWidthChar(textU8); } return {1, 0}; } @@ -395,7 +395,7 @@ TText::Lw TText::drawOneImpl( TSpan cells, size_t i, if (textU32[j] == '\0') cells[i]._ch.moveChar(' '); else - cells[i]._ch.moveStr(textU8, wide); + cells[i]._ch.moveMultiByteChar(textU8, wide); bool drawTrail = (wide && i + 1 < cells.size()); if (drawTrail) cells[i + 1]._ch.moveWideCharTrail(); diff --git a/source/tvision/drivers.cpp b/source/tvision/drivers.cpp index 82abce73..3ae09e62 100644 --- a/source/tvision/drivers.cpp +++ b/source/tvision/drivers.cpp @@ -265,8 +265,8 @@ ushort TDrawBuffer::moveCStr( ushort indent, TStringView str, TAttrPair attrs ) /* maxWidth - maximum amount of data to be moved, measured in */ /* text width */ /* */ -/* strIndent - position in str where to start moving from, */ -/* measured in text width */ +/* strOffset - position in str where to start moving from, */ +/* measured in text width (not in bytes) */ /* */ /* returns: */ /* */ @@ -274,7 +274,7 @@ ushort TDrawBuffer::moveCStr( ushort indent, TStringView str, TAttrPair attrs ) /* */ /*------------------------------------------------------------------------*/ -ushort TDrawBuffer::moveCStr( ushort indent, TStringView str, TAttrPair attrs, ushort maxWidth, ushort strIndent ) noexcept +ushort TDrawBuffer::moveCStr( ushort indent, TStringView str, TAttrPair attrs, ushort maxWidth, ushort strOffset ) noexcept { size_t i = indent, j = 0, w = 0; int toggle = 1; @@ -289,7 +289,7 @@ ushort TDrawBuffer::moveCStr( ushort indent, TStringView str, TAttrPair attrs, u } else { - if (strIndent <= w) + if (strOffset <= w) { if (!TText::drawOne(dest, i, str, j, curAttr)) break; @@ -298,8 +298,8 @@ ushort TDrawBuffer::moveCStr( ushort indent, TStringView str, TAttrPair attrs, u { if (!TText::next(str, j, w)) break; - if (strIndent < w && i < dest.size()) - // 'strIndent' is in the middle of a double-width character. + if (strOffset < w && i < dest.size()) + // 'strOffset' is in the middle of a double-width character. ::setCell(dest[i++], ' ', curAttr); } } @@ -373,8 +373,8 @@ ushort TDrawBuffer::moveStr( ushort indent, TStringView str, TColorAttr attr ) n /* maxWidth - maximum amount of data to be moved, measured in */ /* text width */ /* */ -/* strIndent - position in str where to start moving from, */ -/* measured in text width */ +/* strOffset - position in str where to start moving from, */ +/* measured in text width (not in bytes) */ /* */ /* returns: */ /* */ @@ -383,17 +383,17 @@ ushort TDrawBuffer::moveStr( ushort indent, TStringView str, TColorAttr attr ) n /*------------------------------------------------------------------------*/ ushort TDrawBuffer::moveStr( ushort indent, TStringView str, TColorAttr attr, - ushort maxWidth, ushort strIndent ) noexcept + ushort maxWidth, ushort strOffset ) noexcept { #ifdef __BORLANDC__ - if (strIndent < str.size()) - return moveStr(indent, str.substr(strIndent, maxWidth), attr); + if (strOffset < str.size()) + return moveStr(indent, str.substr(strOffset, maxWidth), attr); return 0; #else if (attr != 0) - return TText::drawStr(data.subspan(0, indent + maxWidth), indent, str, strIndent, attr); + return TText::drawStr(data.subspan(0, indent + maxWidth), indent, str, strOffset, attr); else - return TText::drawStr(data.subspan(0, indent + maxWidth), indent, str, strIndent); + return TText::drawStr(data.subspan(0, indent + maxWidth), indent, str, strOffset); #endif } diff --git a/source/tvision/drivers2.cpp b/source/tvision/drivers2.cpp index 54d9c1d3..ddef96bd 100644 --- a/source/tvision/drivers2.cpp +++ b/source/tvision/drivers2.cpp @@ -64,7 +64,7 @@ const ushort arrowCodes[] = /* */ /* returns */ /* */ -/* length of string, ignoring '~' characters. */ +/* displayed length of string, ignoring '~' characters. */ /* */ /* Comments: */ /* */