Jinja: Beibehalten des Whitespace-Präfixes in mehrzeiligen Strings

Erstellt am 16. Feb. 2013  ·  12Kommentare  ·  Quelle: pallets/jinja

In der StringTemplate-Engine - die ich in einigen Projekten zum Ausgeben von C-Code verwendet habe - werden Whitespace-Präfixe automatisch in die Ausgabezeilen eingefügt:

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

Wenn diese Vorlage in StringTemplate gerendert wird, wird der Leerraum, der den mehrzeiligen Strings linesGlobal und linesLocal vorangestellt ist, für alle ausgegebenen Zeilen kopiert. Der generierte C-Code ist zB:

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

Ich bin neu bei Jinja2 - und habe versucht, dies zu replizieren:

#!/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)

...aber sah, wie es das produzierte:

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

...was ich nicht will. Ich habe es geschafft, dass die Ausgabe die richtigen Whitespace-Präfixe ausgibt:

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

...aber das ist wohl schlecht, da ich für jede von mir ausgesendete Zeichenfolge manuell Leerzeichen zählen muss ...

Gibt es einen besseren Weg, den ich vermisse?

Hilfreichster Kommentar

Beim Ausgeben von YAML oder Python wird dies ziemlich entscheidend.

Alle 12 Kommentare

Mich interessiert im Grunde das gleiche. Das Problem ist auch bei stackoverflow aufgetreten: http://stackoverflow.com/questions/10821539/jinja-keep-indentation-on-include-or-macro

+1

Gilt auch bei Verwendung des Formulars:

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

Dieses Formular verhält sich nicht wie erwartet - da jinja2 die Zeilenumbrüche ausgibt, sollte es sicherstellen, dass sie mit der letzten Einrückungsebene ausgerichtet bleiben.

Das wäre sehr schön! Es würde zu viel schöneren Vorlagen und gleichzeitig gerenderten Ausgaben führen.

Warum nicht eine weitere Whitespace-Option ähnlich wie {%+ und {%- erstellen, die dem aktuellen Einzug alles voranstellt, was es auswertet? Könnte {%= oder {%| . sein

+1

+1

wird hier benötigt, um eine API-Blueprint-Dokumentation zu erstellen:

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

+ Response 200 (application/json):

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

wird jetzt gerendert:

+ Response 200 (application/json):

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

}

            ]
        }

Beim Ausgeben von YAML oder Python wird dies ziemlich entscheidend.

Hatte das gleiche Problem.

Gibt es derzeit eine andere Problemumgehung, als für jedes enthaltene Tempkate ein Makro zu definieren und den Einzug manuell einzugeben?

Entschuldigung, dass ich dieses alte Problem wiederbelebt habe, ich bin gerade auf das gleiche Problem gestoßen und habe mich durch googeln hierher gebracht. Nach etwas mehr Umschauen habe ich festgestellt, dass es mittlerweile eine schöne Möglichkeit gibt, dies durch den Einrückungsfilter zu erreichen

@kaikuchn Danke, Alter! Es klappt.

@kaikuchn , @Cigizmoond-Vyhuholev Leute, ich bin mir nicht sicher, ob ich folge ... wie Sie in meinem ursprünglichen Bericht oben sehen können, erwähne ich einen Workaround mit dem indent -Filter - aber erkläre das auch klar Es behebt das Problem nicht auf die einfache und leistungsstarke Weise, wie es zB StringTemplate tut, da Sie jedes Mal, wenn Sie einen Zeilenblock ausgeben müssen, Einrückungsräume zählen müssen ... Wenn Sie dies tun müssen und Code generieren egal in welcher Form (C, Python, was auch immer) Sie werden den Prozess sehr schnell ganz aufgeben ...

Andererseits habe ich vielleicht falsch verstanden, was Sie meinten... Können Sie mir sagen, wie Sie meine ursprüngliche Anforderung, die oben gezeigt wurde, genau umsetzen würden? dh die gleiche Art von Ausgabe mit Jinja2-Syntax generieren? Das gefällt mir nicht...

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

...weil ich in jeder Vorlage, in der ich Code aussende, die "8" und "12" zählen muss. Im Vergleich dazu in StringTemplate...

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

Mir ist aufgefallen, dass #919 aufgrund einer Codeänderung geschlossen wurde, die anscheinend eine größere Umgestaltung des PR erfordert. Ich würde diese Funktion jedoch gerne in meiner bevorzugten Templating-Engine implementiert sehen.

Wenn dies immer noch etwas ist, das die Core-Entwickler gerne implementiert sehen würden (die Community möchte es auf jeden Fall, da es das PR- und offene Problem mit den meisten Daumen hoch ist), würde ich gerne helfen und vielleicht sogar versuchen, dies selbst zu implementieren.

Würde diese Funktion auch gerne sehen. Beachten Sie, dass die indent nicht verwendet werden kann, wenn die Einrückungsebene nicht bekannt ist. z.B:

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

Wo die Einrückungsebene beibehalten werden soll, hängt von der Länge der ersten beiden Werte ab.

Ich habe eine Hypothese. Was ist mit dem linken Abschneiden der ersten Einrückungsebene in der Blockdeklaration?

Beispiel:

{%- 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) }}

Die Wiedergabe wäre:

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

Grundsätzlich würde Jinja beim Beenden eines Blocks mit ~%} :

  1. Entfernen Sie das erste Zeichen, wenn es sich um eine EOL-Sequenz handelt, wie im Parameter newline_sequence Environment angegeben.
  2. Rendern Sie den Inhalt intern.
  3. Zählen Sie, wie viele gängige Leerzeichen diese gerenderten Zeilen voranstellen.
  4. Ziehen Sie sie am Anfang jeder Zeile ab.

Wenn Sie diesen Block später mit einer bestimmten Einrückung einfügen müssen, müssen Sie ihn nur wie some_yaml_block|indent aufrufen. Da der Einzug bei der Blockdeklaration normalisiert wurde, können Sie ihn später problemlos angeben. Und der Block würde sich bei allen Anrufen konsistent verhalten.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen