Skip to content

Commit

Permalink
g.wrapString fix issues wrapping long words in UTF8 strings over mult…
Browse files Browse the repository at this point in the history
…iple lines

fix espruino/BangleApps#3037
  • Loading branch information
gfwilliams committed Feb 20, 2024
1 parent 1cffe1b commit 41e3995
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 8 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Emulator: force stack alignment of 'data' variable when accessing ArrayBuffers (fix #2463)
Swapped GCC version from 8.2.1 to 13.2.1 (fix #2455)
nRF52: Write flash in 2k blocks (not 4k) as SD 6.1.1 can crash (probably good for earlier SD too)
g.wrapString fix issues wrapping long words in UTF8 strings over multiple lines

2v21 : nRF52: free up 800b more flash by removing vector table padding
Throw Exception when a Promise tries to resolve with another Promise (#2450)
Expand Down
21 changes: 16 additions & 5 deletions libs/graphics/jswrap_graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -2410,7 +2410,6 @@ JsVar *jswrap_graphics_wrapString(JsVar *parent, JsVar *str, int maxWidth) {
// add the space/etc before (but not a space at the start of a newline)
jsvAppendCharacter(currentLine, wordBreakCharacter);
lineWidth += spaceWidth;
wordBreakCharacter = 0;
}
jsvAppendStringVar(currentLine, str, (size_t)wordStartIdx, (size_t)(currentPos-(wordStartIdx+1)));
lineWidth += wordWidth;
Expand All @@ -2424,19 +2423,30 @@ JsVar *jswrap_graphics_wrapString(JsVar *parent, JsVar *str, int maxWidth) {
while (wordWidth > maxWidth) {
int width = 0;
currentLine = jsvNewFromEmptyString();
while (wordStartIdx < currentPos) {
char wordCh = (char)jsvGetCharInString(str, (size_t)wordStartIdx);
JsvStringIterator wordIt;
jsvStringIteratorNew(&wordIt, str, wordStartIdx); // not UTF8 as wordStartIdx isn't UTF8 indexed
while (jsvStringIteratorGetIndex(&wordIt) < currentPos) {
int wordCh = jsvStringIteratorGetUTF8CharAndNext(&wordIt);
int w = _jswrap_graphics_getCharWidth(&info, wordCh);
if (width+w < maxWidth || !width) { // add while it fits OR it's the first character
// !width stops us locking up if char width>split width
wordStartIdx++;
wordWidth -= w;
lineWidth -= w;
width += w;
jsvAppendCharacter(currentLine, wordCh); // FIXME: UTF8?
wordStartIdx = jsvStringIteratorGetIndex(&wordIt);
#ifdef ESPR_UNICODE_SUPPORT
jsvAppendUTF8Character(currentLine, wordCh);
#else
jsvAppendCharacter(currentLine, wordCh);
#endif
} else
break;
}
jsvStringIteratorFree(&wordIt);
#ifdef ESPR_UNICODE_SUPPORT
if (jsvIsUTF8String(str))
currentLine = jsvNewUTF8StringAndUnLock(currentLine);
#endif
jsvArrayPush(lines, currentLine);
jsvUnLock(currentLine);
}
Expand All @@ -2449,6 +2459,7 @@ JsVar *jswrap_graphics_wrapString(JsVar *parent, JsVar *str, int maxWidth) {
#endif
if (wasNewLine) wordBreakCharacter = ' ';
}
wordBreakCharacter = 0;
if (canSplitAfter && !canBreakOnCh) currentPos--; // include the current ch in the next word
if (canBreakOnCh && ch>0)
wordBreakCharacter = (char)ch;
Expand Down
8 changes: 8 additions & 0 deletions src/jsvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,14 @@ void jsvAppendStringBuf(JsVar *var, const char *str, size_t length); ///< Append
void jsvAppendPrintf(JsVar *var, const char *fmt, ...); ///< Append the formatted string to a variable (see vcbprintf)
JsVar *jsvVarPrintf( const char *fmt, ...); ///< Create a var from the formatted string
static ALWAYS_INLINE void jsvAppendCharacter(JsVar *var, char ch) { jsvAppendStringBuf(var, &ch, 1); }; ///< Append the given character to this string
#ifdef ESPR_UNICODE_SUPPORT
///< Append the given UTF8 character to this string
static ALWAYS_INLINE void jsvAppendUTF8Character(JsVar *var, int ch) {
char utf8buf[4];
int utf8len = jsUTF8Encode(ch, utf8buf);
jsvAppendStringBuf(var, utf8buf, utf8len);
}
#endif
#define JSVAPPENDSTRINGVAR_MAXLENGTH (0x7FFFFFFF)
void jsvAppendStringVar(JsVar *var, const JsVar *str, size_t stridx, size_t maxLength); ///< Append str to var. Both must be strings. stridx = start char or str, maxLength = max number of characters (can be JSVAPPENDSTRINGVAR_MAXLENGTH)
void jsvAppendStringVarComplete(JsVar *var, const JsVar *str); ///< Append all of str to var. Both must be strings.
Expand Down
8 changes: 5 additions & 3 deletions tests/test_graphics_wrapString.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,15 @@ g.clear().setFont("4x6");
lines = g.wrapString("F\u00F6n K\u00FCr B\u00E4r", 200);
SHOULD_BE(lines, ["F\u00F6n K\u00FCr B\u00E4r"]);

// UTF8 https://github.com/espruino/BangleApps/issues/3037
g.clear().setFont("6x8");
lines = g.wrapString("Talmannen Kevin McCarthy avs\u00E4tts \u2014 partikamrater avgjorde\nF\u00F6rsta g\u00F6rsta i USA:s historia \u2022 Republikanen förlorar posten i represent\u2022anthuset test",100)
SHOULD_BE(lines, ["Talmannen Kevin","McCarthy avs\u00E4tts","\u2014partikamrater","avgjorde","F\u00F6rsta g\u00F6rsta i","USA:s historia \u2022","Republikanen","f\u00F6rlorar posten","i","represent\u2022anthuse","t test"]);

// Using wrapstring from Storage
require("Storage").write("x","Compacting...\nTakes approx\n1 minute")
lines = g.wrapString(require("Storage").read("x"), 176)
require("Storage").erase("x")
SHOULD_BE(lines, ["Compacting...","Takes approx","1 minute"]);




result = ok;

0 comments on commit 41e3995

Please sign in to comment.