Jinja: Mempertahankan awalan spasi putih dalam string multiline

Dibuat pada 16 Feb 2013  ·  12Komentar  ·  Sumber: pallets/jinja

Di mesin StringTemplate - yang saya gunakan di beberapa proyek untuk memancarkan kode C - awalan spasi secara otomatis ditambahkan di baris output:

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

Saat template ini dirender di StringTemplate, spasi putih yang mengawali baris multilinesGlobal dan linesLocal strings, disalin untuk semua baris yang dipancarkan. Kode C yang dihasilkan misalnya:

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

Saya baru mengenal Jinja2 - dan mencoba meniru ini:

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

...tapi melihatnya menghasilkan ini:

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

... yang tidak apa yang saya inginkan. Saya berhasil membuat output memancarkan awalan spasi putih yang tepat dengan ini:

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

...tapi ini bisa dibilang buruk, karena saya perlu menghitung spasi putih secara manual untuk setiap string yang saya pancarkan...

Apakah ada cara yang lebih baik yang saya lewatkan?

Komentar yang paling membantu

Saat memancarkan YAML atau Python, ini menjadi sangat penting.

Semua 12 komentar

Saya tertarik pada hal yang pada dasarnya sama. Masalah ini juga muncul di stackoverflow: http://stackoverflow.com/questions/10821539/jinja-keep-indentation-on-include-or-macro

+1

Juga benar saat menggunakan formulir:

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

Formulir ini tidak berperilaku seperti yang diharapkan - karena jinja2 adalah yang memancarkan baris baru, itu harus memastikan bahwa mereka tetap selaras dengan tingkat lekukan terakhir.

Ini akan sangat menyenangkan untuk dimiliki! Ini akan menghasilkan template yang jauh lebih bagus dan output yang diberikan pada saat yang bersamaan.

Mengapa tidak membuat opsi spasi putih lain yang mirip dengan {%+ dan {%- yang menambahkan lekukan saat ini pada apa pun yang dievaluasi? Bisa jadi {%= atau {%|

+1

+1

diperlukan di sini untuk membuat template dokumentasi cetak biru API:

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

+ Response 200 (application/json):

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

diberikan sekarang:

+ Response 200 (application/json):

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

}

            ]
        }

Saat memancarkan YAML atau Python, ini menjadi sangat penting.

Berlari ke masalah yang sama.

Apakah ada solusi untuk saat ini selain mendefinisikan makro untuk setiap tempkate yang disertakan dan memasukkan lekukan secara manual?

Maaf telah menghidupkan kembali masalah lama ini, saya baru saja menemukan masalah yang sama dan googling membawa saya ke sini. Setelah melihat-lihat lagi, saya menemukan bahwa sekarang ada cara yang bagus untuk mencapai ini melalui filter indent

@kaikuchn Terima kasih,

@kaikuchn , @Cigizmoond-Vyhuholev Teman-teman, saya tidak yakin saya mengikuti... seperti yang Anda lihat dalam laporan asli saya di atas, saya menyebutkan solusi dengan filter indent - tetapi juga dengan jelas menyatakan itu itu tidak mengatasi masalah dengan cara yang sederhana dan kuat yang dilakukan misalnya StringTemplate, karena memaksa Anda untuk menghitung ruang lekukan setiap kali Anda perlu memancarkan blok baris ... Jika Anda harus melakukan itu dan Anda menghasilkan kode dalam bentuk apa pun (C, Python, apa pun) Anda akan segera mengabaikan prosesnya sama sekali...

Kemudian lagi, saya mungkin telah salah memahami apa yang Anda maksud... Bisakah Anda membagikan dengan tepat bagaimana Anda menerapkan persyaratan awal saya yang ditunjukkan di atas? yaitu menghasilkan jenis output yang sama dengan sintaks Jinja2? Ini yang saya tidak suka...

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

... karena saya perlu menghitung "8" dan "12" di setiap template tempat saya mengeluarkan kode. Sebagai perbandingan, di StringTemplate...

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

Saya perhatikan bahwa #919 ditutup karena perubahan kode yang tampaknya memerlukan beberapa refactoring besar dari PR. Namun saya sangat ingin melihat fitur ini diimplementasikan di mesin templating favorit saya.

Jika ini masih sesuatu yang ingin dilihat oleh para pengembang inti diimplementasikan (komunitas pasti menginginkannya karena ini adalah PR dan masalah terbuka dengan paling acungan jempol) saya akan sangat ingin membantu dan bahkan mungkin mencoba mengimplementasikannya sendiri.

Juga ingin melihat fitur ini. Saya perhatikan bahwa solusi indent tidak dapat digunakan ketika level indentasi tidak diketahui. misalnya:

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

Dimana tingkat lekukan yang akan dipertahankan tergantung pada panjang dua nilai pertama.

Saya punya satu hipotesis. Bagaimana dengan lekukan level 1 yang dipangkas kiri dalam deklarasi blok?

Contoh:

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

Rendernya akan menjadi:

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

Pada dasarnya, ketika menyelesaikan blok dengan ~%} , Jinja akan:

  1. Hapus karakter pertama jika itu adalah urutan EOL, seperti yang ditunjukkan dalam parameter Lingkungan newline_sequence .
  2. Render konten secara internal.
  3. Hitung berapa banyak karakter spasi umum yang mengawali baris yang dirender tersebut.
  4. Strip mereka dari awal setiap baris.

Jika nanti Anda perlu menyertakan blok ini dengan beberapa lekukan tertentu, yang Anda butuhkan hanyalah menyebutnya seperti some_yaml_block|indent . Karena indentasi dinormalisasi pada deklarasi blok, Anda nanti dapat menentukannya tanpa masalah. Dan blok akan berperilaku secara konsisten di seluruh panggilan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat