24
24
#include " magic_enum.hpp"
25
25
26
26
27
+ // Returns the number of UTF‑8 code points in s.
27
28
int utf8_length (const std::string &s) {
28
29
return static_cast <int >(utf8::distance (s.begin (), s.end ()));
29
30
}
30
31
32
+ // Returns the first 'count' UTF‑8 code points of s.
31
33
std::string utf8_substr (const std::string &s, int count) {
32
34
auto it = s.begin ();
33
35
int i = 0 ;
34
36
while (it != s.end () && i < count) {
35
37
utf8::next (it, s.end ());
36
38
++i;
37
39
}
38
- return std::string (s.begin (), it);
40
+ return {s.begin (), it};
41
+ }
42
+
43
+ // Returns the remainder of s after consuming the first 'count' UTF‑8 code points.
44
+ std::string utf8_consume (const std::string &s, int count) {
45
+ auto it = s.begin ();
46
+ int i = 0 ;
47
+ while (it != s.end () && i < count) {
48
+ utf8::next (it, s.end ());
49
+ ++i;
50
+ }
51
+ return {it, s.end ()};
39
52
}
40
53
41
54
template <typename T, T Max>
@@ -400,73 +413,70 @@ struct Batch {
400
413
std::deque<ChatLine> lines;
401
414
};
402
415
403
-
404
- std::vector<std::string> wrapText (const std::string &text, int maxChars, int prefixSize) {
416
+ std::pair<std::string, std::vector<std::string>> wrapMessage (std::string username,
417
+ std::string separator,
418
+ const std::string &message,
419
+ int maxWidth) {
405
420
std::vector<std::string> lines;
406
- if (text.empty () || maxChars <= 0 || prefixSize >= maxChars)
407
- return lines;
421
+ int availableSpace = maxWidth;
422
+ if (utf8_length (username) > maxWidth) {
423
+ username = utf8_substr (username, maxWidth);
424
+ lines.push_back (" " );
425
+ } else {
426
+ availableSpace -= utf8_length (username);
427
+ }
428
+ if (utf8_length (separator) > availableSpace) {
429
+ separator = utf8_substr (separator, availableSpace);
430
+ }
431
+ if (utf8_length (separator) > 0 ) {
432
+ lines.push_back (separator);
433
+ availableSpace -= utf8_length (separator);
434
+ }
408
435
409
- int firstLineMaxChars = maxChars - prefixSize ;
410
- std::istringstream iss (text) ;
436
+ std::istringstream iss (message) ;
437
+ std::vector<std::string> words ;
411
438
std::string word;
412
- std::string line;
413
- bool isFirstLine = true ;
414
-
439
+ bool firstWord = true ;
415
440
while (iss >> word) {
416
- int currentMaxChars = isFirstLine ? firstLineMaxChars : maxChars;
417
- int lineLen = utf8_length (line);
418
- int wordLen = utf8_length (word);
419
-
420
- if (!line.empty () && (lineLen + 1 + wordLen > currentMaxChars)) {
421
- lines.push_back (line);
422
- line.clear ();
423
- isFirstLine = false ;
424
- }
425
-
426
-
427
- if (wordLen > currentMaxChars) {
428
- if (!line.empty ()) {
429
- lines.push_back (line);
430
- line.clear ();
431
- isFirstLine = false ;
432
- }
433
- auto wordIt = word.begin ();
434
- while (wordIt != word.end ()) {
435
- auto startIt = wordIt;
436
- int count = 0 ;
437
- while (wordIt != word.end () && count < currentMaxChars) {
438
- utf8::next (wordIt, word.end ());
439
- ++count;
441
+ bool bigWord = false ;
442
+ while (utf8_length (word) > maxWidth) {
443
+ bigWord = true ;
444
+ if (availableSpace < 2 ) {
445
+ availableSpace = maxWidth;
446
+ lines.push_back (utf8_substr (word, availableSpace));
447
+ firstWord = false ;
448
+
449
+ } else {
450
+
451
+ if (!firstWord) {
452
+ lines.back () += " " ;
453
+ availableSpace--;
440
454
}
441
- lines.emplace_back (startIt, wordIt);
442
- currentMaxChars = maxChars;
443
- isFirstLine = false ;
455
+ lines.back () += utf8_substr (word, availableSpace);
456
+ firstWord = false ;
444
457
}
458
+ word = utf8_consume (word, availableSpace);// add split
459
+ availableSpace = 0 ;
460
+ }
461
+ if (bigWord) {
462
+ // if (utf8_length(word) < availableSpace) word += " ";
463
+ lines.push_back (word);
464
+ availableSpace = maxWidth - utf8_length (word);
465
+ firstWord = false ;
445
466
continue ;
446
467
}
447
-
448
- if (!line.empty ()) {
449
- line.append (" " );
468
+ if (utf8_length (word) < availableSpace) {
469
+ if (!firstWord) lines.back () += " " ;
470
+ lines.back () += word;
471
+ availableSpace -= utf8_length (word);
472
+ } else {
473
+ // if (utf8_length(word) < maxWidth) word += " ";
474
+ lines.push_back (word);
475
+ availableSpace = maxWidth - utf8_length (word);
450
476
}
451
- line.append (word);
452
- }
453
-
454
- if (!line.empty ())
455
- lines.push_back (line);
456
- return lines;
457
- }
458
-
459
- std::vector<std::string> wrapMessage (std::string &username,
460
- const std::string &usernameSeparator,
461
- const std::string &message,
462
- int maxCharsPerLine) {
463
- if (utf8_length (username) > maxCharsPerLine) {
464
- int charsToKeep = maxCharsPerLine - utf8_length (usernameSeparator);
465
- if (charsToKeep < 0 ) charsToKeep = 0 ;
466
- username = utf8_substr (username, charsToKeep);
467
-
477
+ firstWord = false ;
468
478
}
469
- return wrapText (usernameSeparator + message, maxCharsPerLine, utf8_length (username)); ;
479
+ return {username, lines} ;
470
480
}
471
481
472
482
@@ -483,8 +493,9 @@ std::string generateXML(const std::vector<ChatMessage> &messages, const ChatPara
483
493
std::vector<Batch> batches;
484
494
std::deque<ChatLine> currentLines;
485
495
for (const auto &msg: messages) {
486
- std::string username = msg.user .name ;
487
- auto wrapped = wrapMessage (username, params.usernameSeparator , msg.message , params.maxCharsPerLine );
496
+
497
+ auto [username, wrapped] = wrapMessage (msg.user .name , params.usernameSeparator , msg.message ,
498
+ params.maxCharsPerLine );
488
499
if (wrapped.empty ())
489
500
continue ;
490
501
@@ -605,5 +616,27 @@ Color getRandomColor(const std::string &username) {
605
616
606
617
}
607
618
619
+ int test () {
620
+ // Example inputs.
621
+ std::string username = " Alice1234" ;
622
+ std::string separator = " : " ;
623
+ std::string message = " Hello this is a long message that we will try to wrap correctly even if there are verylongwordswithoutanyspaces" ;
624
+ int maxWidth = 30 ;
625
+
626
+ auto [displayName, wrappedLines] = wrapMessage (username, separator, message, maxWidth);
627
+
628
+ // Print the results.
629
+ std::cout << " Username: " << displayName << " \n " ;
630
+ std::cout << " Message:\n " ;
631
+ // Print the full first line as it would appear when concatenated.
632
+ std::string fullFirstLine = displayName + wrappedLines[0 ];
633
+ std::cout << fullFirstLine << " |" << utf8_length (fullFirstLine) << " \n " ;
634
+ for (size_t i = 1 ; i < wrappedLines.size (); ++i) {
635
+ std::cout << wrappedLines[i] << " |" << utf8_length (wrappedLines[i]) << " \n " ;
636
+ }
637
+
638
+ return 0 ;
639
+ }
640
+
608
641
609
642
0 commit comments