Jinja: Сохранение префикса пробелов в многострочных строках

Созданный на 16 февр. 2013  ·  12Комментарии  ·  Источник: pallets/jinja

В движке StringTemplate, который я использовал в некоторых проектах для генерации кода C, в выходные строки автоматически добавляются префиксы пробелов:

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

Когда этот шаблон отображается в StringTemplate, пробел, предшествующий многострочным строкам linesGlobal и linesLocal, копируется для всех генерируемых строк. Сгенерированный код C, например:

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

Я новичок в Jinja2 - и попытался воспроизвести это:

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

... но видел, как это произвело:

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

... чего я не хочу. Мне удалось заставить вывод выдавать правильные префиксы пробелов с помощью этого:

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

... но это, возможно, плохо, так как мне нужно вручную подсчитывать пробелы для каждой строки, которую я испускаю ...

Есть ли лучший способ, который мне не хватает?

Самый полезный комментарий

При передаче YAML или Python это становится очень важным.

Все 12 Комментарий

Меня интересует в основном то же самое. Проблема также возникла в stackoverflow: http://stackoverflow.com/questions/10821539/jinja-keep-indentation-on-include-or-macro

+1

Также верно при использовании формы:

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

Эта форма ведет себя не так, как можно было бы ожидать - поскольку именно jinja2 испускает символы новой строки, она должна следить за тем, чтобы они оставались выровненными с последним уровнем отступа.

Это было бы очень хорошо! Это привело бы к созданию гораздо более хороших шаблонов и одновременно к рендерингу.

Почему бы не создать еще одну опцию пробелов, подобную {% + и {% -, которая добавляет текущий отступ к тому, что он оценивает? Может быть {% = или {% |

+1

+1

здесь необходимо для создания документации по шаблону API:

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

+ Response 200 (application/json):

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

отображается сейчас:

+ Response 200 (application/json):

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

}

            ]
        }

При передаче YAML или Python это становится очень важным.

Столкнулся с той же проблемой.

Есть ли на данный момент обходной путь, кроме определения макроса для каждого включенного tempkate и ручного ввода отступа?

Извините за возрождение этой старой проблемы, я столкнулся с той же проблемой, и поиск в Google привел меня сюда. Еще немного осмотревшись, я обнаружил, что к настоящему времени есть хороший способ добиться этого с помощью фильтра отступа.

@kaikuchn Спасибо, чувак! Оно работает.

@kaikuchn , @ Cigizmoond-Vyhuholev Ребята, я не уверен, что следую ... как вы можете видеть в моем исходном отчете вверху, я упоминаю обходной путь с помощью фильтра indent - но также четко заявляю, что он не решает проблему простым и мощным способом, как, например, StringTemplate, потому что заставляет вас подсчитывать пространства отступов каждый раз, когда вам нужно создать блок строк ... Если вам нужно это сделать, и вы генерируете код любой формы (C, Python, что угодно) вы очень быстро просто откажетесь от процесса ...

Опять же, я, возможно, неправильно понял, что вы имели в виду ... Не могли бы вы рассказать, как именно вы бы реализовали мое первоначальное требование, показанное вверху? т.е. генерировать такой же вывод с синтаксисом Jinja2? Это то, что мне не нравится ...

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

... потому что мне нужно считать «8» и «12» в каждом шаблоне, в котором я отправляю код. Для сравнения, в StringTemplate ...

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

Я заметил, что # 919 был закрыт из-за изменения кода, которое, по-видимому, потребовало серьезного рефакторинга PR. Однако мне бы очень хотелось, чтобы эта функция была реализована в моем любимом движке шаблонов.

Если это все еще то, что основные разработчики хотели бы видеть реализованным (сообщество определенно хочет этого, поскольку это PR и открытая проблема с большим количеством пальцев), я был бы рад помочь и, возможно, даже попытался бы реализовать это самостоятельно.

Также хотелось бы увидеть эту функцию. Замечу, что обходной путь indent нельзя использовать, если уровень отступа неизвестен. например:

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

Сохранение уровня отступа зависит от длины первых двух значений.

У меня есть одна гипотеза. А как насчет обрезки слева 1-го уровня отступа в объявлении блока?

Пример:

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

Рендеринг будет:

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

Обычно, завершая блок с помощью ~%} , Jinja:

  1. Удалите первые символы, если это последовательность EOL, как указано в параметре newline_sequence Environment.
  2. Внутренняя визуализация контента.
  3. Подсчитайте, сколько общих пробельных символов префикс этих отображаемых строк.
  4. Снимите их с начала каждой строки.

Если позже вам потребуется включить этот блок с каким-то определенным отступом, все, что вам нужно, это назвать его как some_yaml_block|indent . Поскольку отступ был нормализован при объявлении блока, вы можете без проблем указать его позже. И блок будет вести себя одинаково во всех вызовах.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги