lineWrapper.frink

Download or view lineWrapper.frink in plain text format


/** 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]]
}


Download or view lineWrapper.frink in plain text format


This is a program written in the programming language Frink.
For more information, view the Frink Documentation or see More Sample Frink Programs.

Alan Eliasen was born 19963 days, 19 hours, 46 minutes ago.