title: Split text into equal length strings keeping words intact
body: <p>I have this code that break longer lines into array of equal length strings keeping words it also take into account the formatting like <code>[[u;#fff;]some text]</code>, it split text so each string can be converted into html independently:</p>
  
  <pre class="lang-js prettyprint-override"><code>var format_re = /\[\[([!gbiuso]*;[^;\]]*;[^;\]]*(?:;|[^\]()]*);?[^\]]*)\]([^\]]*\\\][^\]]*|[^\]]*|[^\[]*\[[^\]]*)\]?/gi;
  var format_begin_re = /(\[\[[!gbiuso]*;[^;]*;[^\]]*\])/i;
  var format_last_re = /\[\[[!gbiuso]*;[^;]*;[^\]]*\]?$/i;
  $.terminal.split_equal = function(str, length, words) {
    var formatting = false;
    var in_text = false;
    var prev_format = '';
    var result = [];
    // add format text as 5th paramter to formatting it's used for
    // data attribute in format function
    var array = str.replace(format_re, function(_, format, text) {
      var semicolons = format.match(/;/g).length;
      // missing semicolons
      if (semicolons == 2) {
        semicolons = ';;';
      } else if (semicolons == 3) {
        semicolons = ';';
      } else {
        semicolons = '';
      }
      // return '[[' + format + ']' + text + ']';
      // closing braket will break formatting so we need to escape
      // those using html entity equvalent
      return '[[' + format + semicolons +
        text.replace(/\\\]/g, '&amp;#93;').replace(/\n/g, '\\n') + ']' +
        text + ']';
    }).split(/\n/g);
    for (var i = 0, len = array.length; i &lt; len; ++i) {
      if (array[i] === '') {
        result.push('');
        continue;
      }
      var line = array[i];
      var first_index = 0;
      var count = 0;
      var space = -1;
      for (var j=0, jlen=line.length; j&lt;jlen; ++j) {
        if (line[j] === '[' &amp;&amp; line[j+1] === '[') {
          formatting = true;
        } else if (formatting &amp;&amp; line[j] === ']') {
          if (in_text) {
            formatting = false;
            in_text = false;
          } else {
            in_text = true;
          }
        } else if ((formatting &amp;&amp; in_text) || !formatting) {
          if (line[j] === '&amp;') { // treat entity as one character
            var m = line.substring(j).match(/^(&amp;[^;]+;)/);
            if (!m) {
              // should never happen if used by terminal,
              // because it always calls $.terminal.encode
              // before this function
              throw new Error("Unclosed html entity in line " +
                              (i+1) + ' at char ' + (j+1));
            }
            j+=m[1].length-2; // because continue adds 1 to j
            // if entity is at the end there is no next loop
            // issue #77
            if (j === jlen-1) {
              result.push(output + m[1]);
            }
            continue;
          } else if (line[j] === ']' &amp;&amp; line[j-1] === '\\') {
            // escape \] counts as one character
            --count;
          } else {
            ++count;
          }
        }
        function is_space() {
          return line.substring(j-6, j) == '&amp;nbsp;' ||
            line.substring(j-1, j) == ' ';
        }
        if (is_space() &amp;&amp; ((formatting &amp;&amp; in_text) || !formatting)) {
          space = j;
        }
        if ((count === length || j === jlen-1) &amp;&amp;
            ((formatting &amp;&amp; in_text) || !formatting)) {
          var output;
          var after = line.substring(space, j+length+1);
          var text = $('&lt;span&gt;' + after + '&lt;/span&gt;').text();
          var can_break = text.match(/\s/);
          if (words &amp;&amp; space != -1 &amp;&amp; j !== jlen-1 &amp;&amp; can_break) {
            // get text to last space
            output = line.substring(first_index, space);
            j = space-1;
            space = -1;
          } else {
            output = line.substring(first_index, j+1);
          }
          if (words) {
            output = output.replace(/^(&amp;nbsp;|\s)+|(&amp;nbsp;|\s)+$/g, '');
          }
          first_index = j+1;
          count = 0;
          if (prev_format) {
            output = prev_format + output;
            if (output.match(']')) {
              prev_format = '';
            }
          }
          // Fix output if formatting not closed
          var matched = output.match(format_re);
          if (matched) {
            var last = matched[matched.length-1];
            if (last[last.length-1] !== ']') {
              prev_format = last.match(format_begin_re)[1];
              output += ']';
            } else if (output.match(format_last_re)) {
              var line_len = output.length;
              // why this line ???
              //var f_len = line_len-last[last.length-1].length;
              output = output.replace(format_last_re, '');
              prev_format = last.match(format_begin_re)[1];
            }
          }
          result.push(output);
        }
      }
    }
    return result;
  };
  </code></pre>
  
  <p>It work almost right but some lines are shorter then it should like:</p>
  
  <pre><code>is cracker.The term
  </code></pre>
  
  <p>in this <a href="https://jsfiddle.net/bjrdamgg/6/" rel="nofollow"><strong>FIDDLE</strong></a>, it work right when you strip formatting, checking checkbox. I work on this for couple of hours and have no clue why that line is shorter, any help will be very appreciated.</p>