Jinja: Préservation du préfixe d'espace dans les chaînes multilignes

Créé le 16 févr. 2013  ·  12Commentaires  ·  Source: pallets/jinja

Dans le moteur StringTemplate - que j'ai utilisé dans certains projets pour émettre du code C - les préfixes d'espaces sont automatiquement ajoutés dans les lignes de sortie :

PrintCFunction(linesGlobal, linesLocal) ::= <<
void foo() {
    if (someRuntimeFlag) {
        <linesGlobal>
        if (anotherRuntimeFlag) {
            <linesLocal>
        }
    }
}
>>

Lorsque ce modèle est rendu dans StringTemplate, l'espace blanc préfixant les chaînes multilignes linesGlobal et linesLocal, est copié pour toutes les lignes émises. Le code C généré est par exemple :

void foo() {
    if (someRuntimeFlag) {
        int i;
        i=1;   // <=== whitespace prefix copied in 2nd
        i++;   // <=== and 3rd line
        if (anotherRuntimeFlag) {
            int j=i;
            j++; //  <=== ditto
        }
    }
}

Je suis nouveau sur Jinja2 - et j'ai essayé de reproduire ceci :

#!/usr/bin/env python
from jinja2 import Template

linesGlobal='\n'.join(['int i;', 'i=1;'])
linesLocal='\n'.join(['int j=i;', 'j++;'])

tmpl = Template(u'''\
void foo() {
    if (someRuntimeFlag) {
        {{linesGlobal}}
        if (anotherRuntimeFlag) {
            {{linesLocal}}
        }
    }
}
''')

print tmpl.render(
    linesGlobal=linesGlobal,
    linesLocal=linesLocal)

... mais je l'ai vu produire ceci :

void foo() {
    if (someRuntimeFlag) {
        int i;
i=1;
        if (anotherRuntimeFlag) {
            int j=i;
j++;
        }
    }
}

... ce qui n'est pas ce que je veux. J'ai réussi à faire en sorte que la sortie émette des préfixes d'espace blanc appropriés avec ceci :

...
if (someRuntimeFlag) {
    {{linesGlobal|indent(8)}}
    if (anotherRuntimeFlag) {
        {{linesLocal|indent(12)}}
    }
}

... mais c'est sans doute mauvais, car je dois compter manuellement les espaces blancs pour chaque chaîne que j'émets ...

Y a-t-il un meilleur moyen qui me manque?

Commentaire le plus utile

Lors de l'émission de YAML ou de Python, cela devient assez crucial.

Tous les 12 commentaires

Je m'intéresse fondamentalement à la même chose. Le problème est également apparu sur stackoverflow : http://stackoverflow.com/questions/10821539/jinja-keep-indentation-on-include-or-macro

+1

Vrai également lors de l'utilisation du formulaire :

    {{linesGlobal|join('\n')}}

Cette forme ne se comporte pas comme on pourrait s'y attendre - puisque jinja2 est celui qui émet les nouvelles lignes, il doit s'assurer qu'elles restent alignées avec le dernier niveau d'indentation.

Ce serait très sympa à avoir ! Cela conduirait à des modèles beaucoup plus agréables et à une sortie rendue en même temps.

Pourquoi ne pas créer une autre option d'espace similaire à {%+ et {%- qui ajoute l'indentation actuelle à ce qu'elle évalue ? Peut être {%= ou {%|

+1

+1

nécessaire ici pour modéliser la documentation du plan d'API :

{% macro entity_one() -%}
{
    "one": 1,
    "two": 2
}
{% endmacro -%}

+ Response 200 (application/json):

        {
            "entity": [
                {{ entity_one() }}
            ]
        }

est rendu maintenant :

+ Response 200 (application/json):

        {
            "entity": [
                {
    "one": 1,
    "two": 2

}

            ]
        }

Lors de l'émission de YAML ou de Python, cela devient assez crucial.

A couru dans le même problème.

Existe-t-il pour le moment une solution de contournement autre que la définition d'une macro pour chaque tempkate inclus et la saisie manuelle de l'indentation ?

Désolé d'avoir ravivé ce vieux problème, je viens de rencontrer le même problème et la recherche sur Google m'a amené ici. Après un peu plus de recherche, j'ai trouvé qu'il existe maintenant un bon moyen d'y parvenir grâce au filtre d'indentation

@kaikuchn Merci, mec ! Ça marche.

@kaikuchn , @Cigizmoond-Vyhuholev Guys, je ne suis pas sûr de suivre... comme vous pouvez le voir dans mon rapport original en haut, je mentionne une solution de contournement avec le filtre indent - mais je précise aussi clairement que il ne résout pas le problème de la manière simple et puissante que, par exemple, StringTemplate, car il vous oblige à compter les espaces d'indentation chaque fois que vous devez émettre un bloc de lignes... Si vous devez le faire et que vous générez du code de n'importe quelle forme (C, Python, peu importe), vous abandonnerez très rapidement le processus complètement...

Là encore, j'ai peut-être mal compris ce que vous vouliez dire... Pouvez-vous partager exactement comment vous mettriez en œuvre mon exigence d'origine indiquée en haut ? c'est-à-dire générer le même type de sortie avec la syntaxe Jinja2 ? C'est ce que je n'aime pas...

if (someRuntimeFlag) {
    {{linesGlobal|indent(8)}}
    if (anotherRuntimeFlag) {
        {{linesLocal|indent(12)}}
    }
}

...parce que je dois compter les "8" et "12" dans chaque modèle où j'émets du code. En comparaison, dans StringTemplate...

PrintCFunction(linesGlobal, linesLocal) ::= <<
void foo() {
    if (someRuntimeFlag) {
        <linesGlobal>
        if (anotherRuntimeFlag) {
            <linesLocal>
        }
    }
}
>>

J'ai remarqué que le numéro 919 était fermé en raison d'un changement de code qui nécessiterait apparemment une refactorisation majeure du PR. Cependant, j'aimerais vraiment voir cette fonctionnalité implémentée dans mon moteur de création de modèles préféré.

Si c'est toujours quelque chose que les développeurs principaux aimeraient voir mis en œuvre (la communauté le veut bien sûr car il s'agit du problème de relations publiques et ouvert avec le plus de pouces levés), je serais impatient d'aider et peut-être même d'essayer de le mettre en œuvre par moi-même.

J'aimerais aussi voir cette fonctionnalité. Je noterai que la solution indent contournement

{{field.type}} {{field.name}}; {{field.comment|indent(??)}}

L'emplacement du niveau d'indentation à conserver dépend de la longueur des deux premières valeurs.

J'ai une hypothèse. Qu'en est-il du rognage à gauche du 1er niveau d'indentation dans la déclaration de bloc ?

Exemple:

{%- macro some_yaml_block(sub_block) ~%}
  label indented with how many spaces: 2
  amount of spaces that will be trimmed due to that "~" char above: 2
  {%- if sub_block ~%}
    "yay! we can indent ifs!": true
    the minimal indent in this if block is 2, so:
      this extra-indented value is still indented properly
  {%- endif %}
{%- endmacro -%}

now we invoke that here:
  {{ some_yaml_block(true) }}

Le rendu serait :

now we invoke that here:
  label indented with how many spaces: 2
  amount of spaces that will be trimmed due to that "~" char above: 2
  "yay! we can indent ifs!": true
  the minimal indent in this if block is 2, so:
    this extra-indented value is still indented properly

Fondamentalement, lors de la fin d'un bloc avec ~%} , Jinja :

  1. Supprimez les 1ers caractères s'il s'agit d'une séquence EOL, comme indiqué dans le paramètre d'environnement newline_sequence .
  2. Rendre le contenu en interne.
  3. Comptez le nombre de caractères d'espacement communs préfixant ces lignes rendues.
  4. Dénudez-les dès le début de chaque ligne.

Si, plus tard, vous devez inclure ce bloc avec une indentation spécifique, il vous suffit de l'appeler comme some_yaml_block|indent . Étant donné que l'indentation a été normalisée lors de la déclaration de bloc, vous pouvez la spécifier ultérieurement sans problème. Et le bloc se comporterait de manière cohérente d'un appel à l'autre.

Cette page vous a été utile?
0 / 5 - 0 notes