private void appendLines(StringBuilder res, String[] srcLines, int from, int to, int requiredLineNumber) {
    if (to - from > requiredLineNumber) {
      List<String> strings = compactLines(Arrays.asList(srcLines).subList(from, to) ,requiredLineNumber);
      int separatorsRequired = requiredLineNumber - 1;
      for (String s : strings) {
        res.append(s);
        if (separatorsRequired-- > 0) {
          res.append(myLineSeparator);
        }
      }
      res.append(myLineSeparator);
    }
    else if (to - from <= requiredLineNumber) {
      for (int i = from; i < to; i++) {
        res.append(srcLines[i]).append(myLineSeparator);
      }
      for (int i = 0; i < requiredLineNumber - to + from; i++) {
        res.append(myLineSeparator);
      }
    }
  }
Recursive reformatting of groups.
If the group's content would take you over the specified preferred line length, then the group is applied.

- This algorithm usually ensures that if a group is applied, then all the group's parents in the tree are also
  applied. This tends to produce a nice structured output with well-placed potential newlines.
- The formatter keeps track of the offset as a result of the reformat at each character in the text buffer, and
  applies them to the bytecode offsets afterwards, so that the line number mappings don't get messed up.
src/org/jetbrains/java/decompiler/util/TextBuffer.java