@Nullable
  static TextContent joinWithWhitespace(char whitespace, List<? extends @NotNull TextContent> components) {
    if (!Character.isWhitespace(whitespace)) {
      throw new IllegalArgumentException("Whitespace expected, got " + StringUtil.escapeStringCharacters(String.valueOf(whitespace)));
    }
    if (components.isEmpty()) return null;
    if (components.size() == 1) return components.get(0);

    TextContentImpl.WSTokenInfo wsToken = new TextContentImpl.WSTokenInfo(whitespace);
    return new TextContentImpl(commonDomain(components), StreamEx.of(components)
      .map(c -> ((TextContentImpl) c).tokens)
      .intersperse(Collections.singletonList(wsToken))
      .toFlatList(Function.identity()));
  }
@Nullable
  static TextContent joinWithWhitespace(char whitespace, List<? extends @NotNull TextContent> components)