/** This contains routines for wrapping a string to a specified width. It uses Frink's smart Unicode-aware routines for finding line-wrapping points that understand punctuation, numbers, and hyphenated words and by counting graphemes correctly. */ /** Wrap a string to an array of lines, removing any newline characters in the string. The linebreaks are found intelligently using Frink's smart lineBreakList function which intelligently handles punctuation, numbers, and hyphenated words. It is human-language-aware and can wrap according to a different human language by specifying the languageSpecifier variable. If languageSpecifier is undef (the default) this uses the language defined in your JVM. Otherwise, the language can be specfied with one of Frink's language specifiers which can be a string like "en", "en_US", or a java.util.Locale. See: https://frinklang.org/#LanguageSpecifiers It is also smart in that it correctly counts composed Unicode characters by counting graphemes and not just characters nor codepoints. TODO: Attempt to hyphenate words if it gives better fill? Should these be options? TODO: Attempt to hyphenate words that are fully too long for the line? THINK ABOUT: Disregard (trim) whitespace at the end of lines so centering or right-justifying is cleaner? THINK ABOUT: Disregard multiple sequential whitespaces? */ wrapToArray[str, cols, languageSpecifier=undef] := { length = 0 result = new array currLine = "" if languageSpecifier == undef lineBreaker = lineBreakList[str] else lineBreaker = lineBreakList[str, languageSpecifier] WORD: for word = lineBreaker { //println[toASCII[word]] finishLine = false // lineBreakList returns words with the \n or \r character appended when // that occurs in the input. // If word ends with line terminator, remove it and finalize the line if word =~ %r/\r\n|\r|\n|\u2028|\u2029|\u000B|\u000C|\u0085$/ { word =~ %s/(.*)\r\n|\r|\n|\u2028|\u2029|\u000B|\u000C|\u0085$/$1/ finishLine = true } wordLen = graphemeLength[word] if length + wordLen <= cols { // Word fits on the line currLine = currLine + word length = length + wordLen } else { // Word doesn't fit, create new line if length > 0 // Unless the current line is already empty result.push[currLine] // Trim here? currLine = word length = wordLen } if (finishLine) { result.push[currLine] // Trim here? currLine = "" length = 0 } } // Append any remaining text if length > 0 result.push[currLine] // Trim here? return result } /** Wrap a string to the specified width, returning the result as a single big string with embedded newlines. */ wrap[str, cols, languageSpecifier=undef] := { return joinln[wrapToArray[str, cols, languageSpecifier]] }