diff --git a/assets/disk0/tvdos/TVDOS.SYS b/assets/disk0/tvdos/TVDOS.SYS index fa9cc28..c76e39d 100644 --- a/assets/disk0/tvdos/TVDOS.SYS +++ b/assets/disk0/tvdos/TVDOS.SYS @@ -1390,6 +1390,27 @@ unicode.println = (str) => { unicode.print(str+'\n\n') } +unicode.strlen = (str) => { + // Convert string to an array of codepoints using spread operator + // This correctly handles surrogate pairs and counts each codepoint as one + return unicode.utf8toCodepoints(str).length +} + +unicode.visualStrlen = (str) => { + function isTripleWidth(c) { + return (0xAC00 <= c && c <= 0xD7FF) && [1,4,8,10,13].includes(((c - 0xAC00) / 588)|0) + } + + function isDoubleWidth(c) { + return (0x3000 <= c && c <= 0x303f) || (0x3100 <= c && c <= 0x312f) || (0x3200 <= c && c <= 0x33ff) || + (0xAC00 <= c && c <= 0xD7FF) || (0xFE30 <= c && c <= 0xFE4F) || (0xFF00 <= c && c <= 0xff60) + } + + // Convert string to an array of codepoints using spread operator + // This correctly handles surrogate pairs and counts each codepoint as one + return unicode.utf8toCodepoints(str).reduce((acc, c) => acc + (isTripleWidth(c) ? 3 : isDoubleWidth(c) ? 2 : 1), 0) +} + Object.freeze(unicode); /////////////////////////////////////////////////////////////////////////////// diff --git a/assets/disk0/tvdos/include/playgui.mjs b/assets/disk0/tvdos/include/playgui.mjs index 978bda0..3e17b8f 100644 --- a/assets/disk0/tvdos/include/playgui.mjs +++ b/assets/disk0/tvdos/include/playgui.mjs @@ -22,33 +22,9 @@ function clearSubtitleArea() { } function getVisualLength(line) { - // Calculate the visual length of a line excluding formatting tags - let visualLength = 0 - let i = 0 - - while (i < line.length) { - if (i < line.length - 2 && line[i] === '<') { - // Check for formatting tags and skip them - if (line.substring(i, i + 3).toLowerCase() === '' || - line.substring(i, i + 3).toLowerCase() === '') { - i += 3 // Skip tag - } else if (i < line.length - 3 && - (line.substring(i, i + 4).toLowerCase() === '' || - line.substring(i, i + 4).toLowerCase() === '')) { - i += 4 // Skip closing tag - } else { - // Not a formatting tag, count the character - visualLength++ - i++ - } - } else { - // Regular character, count it - visualLength++ - i++ - } - } - - return visualLength + // Remove HTML tags and count the remaining text using unicode.strlen() + const withoutTags = line.replace(/<\/?[bi]>/gi, '') + return unicode.visualStrlen(withoutTags) } function displayFormattedLine(line) {