code: def linesplit(string, columns):
      # type: (Union[Text, FmtStr], int) -> List[FmtStr]
      
      if not isinstance(string, FmtStr):
          string = fmtstr(string)
  
      string_s = string.s
      matches = list(re.finditer(r'\s+', string_s))
      spaces = [string[m.start():m.end()] for m in matches if m.start() != 0 and m.end() != len(string_s)]
      words = [string[start:end] for start, end in zip(
              [0] + [m.end() for m in matches],
              [m.start() for m in matches] + [len(string_s)]) if start != end]
  
      word_to_lines = lambda word: [word[columns*i:columns*(i+1)] for i in range((len(word) - 1) // columns + 1)]
  
      lines = word_to_lines(words[0])
      for word, space in zip(words[1:], spaces):
          if len(lines[-1]) + len(word) < columns:
              lines[-1] += fmtstr(' ', **space.shared_atts)
              lines[-1] += word
          else:
              lines.extend(word_to_lines(word))
      return lines
docs: Returns a list of lines, split on the last possible space of each line.
  
      Split spaces will be removed. Whitespaces will be normalized to one space.
      Spaces will be the color of the first whitespace character of the
      normalized whitespace.
      If a word extends beyond the line, wrap it anyway.
  
      >>> linesplit(fmtstr(" home    is where the heart-eating mummy is", 'blue'), 10)
      [blue('home')+blue(' ')+blue('is'), blue('where')+blue(' ')+blue('the'), blue('heart-eati'), blue('ng')+blue(' ')+blue('mummy'), blue('is')]