@Override
  protected boolean processSubstitutionChunk(@NotNull SubstitutionChunk subsChunk, @NotNull StringBuilder fStringText) {
    final char conversionChar = subsChunk.getConversionType();

    String widthAndPrecision = StringUtil.notNullize(subsChunk.getWidth());
    if (StringUtil.isNotEmpty(subsChunk.getPrecision())) {
      widthAndPrecision += "." + subsChunk.getPrecision();
    }

    final String conversionFlags = subsChunk instanceof PercentSubstitutionChunk ?
                                   ((PercentSubstitutionChunk)subsChunk).getConversionFlags() :
                                   ((NewStyleSubstitutionChunk)subsChunk).getConversion();

    fStringText.append("{");
    final PySubstitutionChunkReference reference = createReference(subsChunk);
    final PyExpression resolveResult = adjustResolveResult(reference.resolve());
    assert resolveResult != null;

    final PsiElement adjusted = prepareExpressionToInject(resolveResult, subsChunk);
    if (adjusted == null) return false;

    fStringText.append(adjusted.getText());

    // TODO mostly duplicates the logic of ConvertFormatOperatorToMethodIntention
    if (conversionChar == 'r') {
      fStringText.append("!r");
    }

    if ((conversionChar != 'r' && conversionChar != 's')
        || StringUtil.isNotEmpty(conversionFlags)
        || StringUtil.isNotEmpty(widthAndPrecision)) {
      fStringText.append(":");
    }

    fStringText.append(convertFormatSpec(StringUtil.notNullize(conversionFlags), widthAndPrecision, String.valueOf(conversionChar)));

    if (StringUtil.isNotEmpty(widthAndPrecision)) {
      fStringText.append(widthAndPrecision);
    }

    if ('i' == conversionChar || 'u' == conversionChar) {
      fStringText.append("d");
    }
    else if ('s' != conversionChar && 'r' != conversionChar) {
      fStringText.append(conversionChar);
    }
    fStringText.append("}");
    return true;
  }
@Override
  protected boolean processSubstitutionChunk(@NotNull SubstitutionChunk subsChunk, @NotNull StringBuilder fStringText)