splitStringIntoLines(str, mod = "normal", appendLast = false) {
    // Set the canvas context font, based upon the current selected/hover state
    // and the provided mod, so the text measurement performed by getLongestFit
    // will be accurate - and not just use the font of whoever last used the canvas.
    this.parent.getFormattingValues(this.ctx, this.selected, this.hover, mod);

    // Still-present spaces are relevant, retain them
    str = str.replace(/^( +)/g, "$1\r");
    str = str.replace(/([^\r][^ ]*)( +)/g, "$1\r$2\r");
    let words = str.split("\r");

    while (words.length > 0) {
      let w = this.getLongestFit(words);

      if (w === 0) {
        // Special case: the first word is already larger than the max width.
        const word = words[0];

        // Break the word to the largest part that fits the line
        const x = this.getLongestFitWord(word);
        this.lines.newLine(word.slice(0, x), mod);

        // Adjust the word, so that the rest will be done next iteration
        words[0] = word.slice(x);
      } else {
        // skip any space that is replaced by a newline
        let newW = w;
        if (words[w - 1] === " ") {
          w--;
        } else if (words[newW] === " ") {
          newW++;
        }

        const text = words.slice(0, w).join("");

        if (w == words.length && appendLast) {
          this.lines.append(text, mod);
        } else {
          this.lines.newLine(text, mod);
        }

        // Adjust the word, so that the rest will be done next iteration
        words = words.slice(newW);
      }
    }
  }
Split the passed text into lines, according to width constraint (if any).

The method assumes that the input string is a single line, i.e. without lines break.

This method retains spaces, if still present (case `font.multi: false`).
A space which falls on an internal line break, will be replaced by a newline.
There is no special handling of tabs; these go along with the flow.
@param {string} str
@param {string} [mod]
@param {boolean} [appendLast]
@private