private void removeLastLine() {
    // when \r happens, need to delete the last line
    while (!tokens.isEmpty() && tokens.peekLast() != CR_TOKEN) {
      TokenInfo last = tokens.removeLast();
      String text = last.getText();
      int lfIndex = text.lastIndexOf('\n');
      if (lfIndex != -1) {
        // split token
        TokenInfo newToken = new TokenInfo(last.contentType, text.substring(0, lfIndex + 1), last.getHyperlinkInfo());
        tokens.addLast(newToken);
        size -= text.length() - newToken.length();
        return;
      }
      // remove the token entirely, move to the previous
      size -= text.length();
    }
    if (tokens.isEmpty()) {
      // \r at the very beginning. return CR_TOKEN to signal this
      tokens.addLast(CR_TOKEN);
      size ++;
    }
  }
private void removeLastLine()