Search code examples
templatesjinja2whitespace

Remove empty lines and don't join non-empty lines in Jinja


I want to make something like the following list of badges look nice:

Badge
{% if cond %}Other badge {% endif %}
Another badge
{% if not cond %}One more badge {% endif %}
Last badge

I am hoping for:

  • Every badge in its own line
  • If the badge is not being added, then don't add a blank line

I tried 16 combinations of adding - to the {% or %} delimiters, but I can't achieve both things at once.

More details:

  • I have a list of conditional badges
  • The example above is a simplified version that has cond and not cond at the same time so the issue is always present
  • In real, I don't have an if-else situation, it's only for the MRE
  • The 16 combinations are
    Badge (-,-,-,-)
    {%- if cond -%}Other badge {%- endif -%}
    Another badge
    {%- if not cond -%}One more badge {%- endif -%}
    Last badge
    
    Badge (,-,-,-)
    {% if cond -%}Other badge {%- endif -%}
    Another badge
    {% if not cond -%}One more badge {%- endif -%}
    Last badge
    
    Badge (-,,-,-)
    {%- if cond %}Other badge {%- endif -%}
    Another badge
    {%- if not cond %}One more badge {%- endif -%}
    Last badge
    
    Badge (,,-,-)
    {% if cond %}Other badge {%- endif -%}
    Another badge
    {% if not cond %}One more badge {%- endif -%}
    Last badge
    
    Badge (-,-,,-)
    {%- if cond -%}Other badge {% endif -%}
    Another badge
    {%- if not cond -%}One more badge {% endif -%}
    Last badge
    
    Badge (,-,,-)
    {% if cond -%}Other badge {% endif -%}
    Another badge
    {% if not cond -%}One more badge {% endif -%}
    Last badge
    
    Badge (-,,,-)
    {%- if cond %}Other badge {% endif -%}
    Another badge
    {%- if not cond %}One more badge {% endif -%}
    Last badge
    
    Badge (,,,-)
    {% if cond %}Other badge {% endif -%}
    Another badge
    {% if not cond %}One more badge {% endif -%}
    Last badge
    
    Badge (-,-,-,)
    {%- if cond -%}Other badge {%- endif %}
    Another badge
    {%- if not cond -%}One more badge {%- endif %}
    Last badge
    
    Badge (,-,-,)
    {% if cond -%}Other badge {%- endif %}
    Another badge
    {% if not cond -%}One more badge {%- endif %}
    Last badge
    
    Badge (-,,-,)
    {%- if cond %}Other badge {%- endif %}
    Another badge
    {%- if not cond %}One more badge {%- endif %}
    Last badge
    
    Badge (,,-,)
    {% if cond %}Other badge {%- endif %}
    Another badge
    {% if not cond %}One more badge {%- endif %}
    Last badge
    
    Badge (-,-,,)
    {%- if cond -%}Other badge {% endif %}
    Another badge
    {%- if not cond -%}One more badge {% endif %}
    Last badge
    
    Badge (,-,,)
    {% if cond -%}Other badge {% endif %}
    Another badge
    {% if not cond -%}One more badge {% endif %}
    Last badge
    
    Badge (-,,,)
    {%- if cond %}Other badge {% endif %}
    Another badge
    {%- if not cond %}One more badge {% endif %}
    Last badge
    
    Badge (,,,)
    {% if cond %}Other badge {% endif %}
    Another badge
    {% if not cond %}One more badge {% endif %}
    Last badge
    
    which can be pasted in https://j2live.ttl255.com with the variable cond: true (or false) to show what happens
  • I am using copier, not Jinja directly, if that makes any difference

Related questions:


Solution

  • The thing is, the manual whitespace control mechanism treats a range of spacing characters the same, upon those characters are tabulations, spaces and new lines.

    For the record, the definition of a whitespace is given in Python's documentation:

    A character is whitespace if in the Unicode character database (see unicodedata), either its general category is Zs (“Separator, space”), or its bidirectional class is one of WS, B, or S.

    Source: https://docs.python.org/3/library/stdtypes.html#str.isspace


    This being said, it means you will probably not find a good one-liner solution, because using a whitespace control character will also chomp your new lines.

    The only one I can think of that would make you trick the whitespace control is to print the new line inside a Jinja expression:

    Badge
    {% if cond %}Other badge{{ "\n" }}{% endif -%}
    Another badge
    {% if not cond %}One more badge{{ "\n" }}{% endif -%}
    Last badge
    

    There are a bunch of other suggestion that are definitely more verbose that you can choose from, though, here are three that I can think of:

    1. Put the new line inside the condition and use a whitespace control on the end of the condition (which is actually kind-of the same as the one-liner):
      Badge
      {% if cond %}Other badge
      {% endif -%}
      Another badge
      {% if not cond %}One more badge
      {% endif -%}
      Last badge
      
    2. With the use of whitespace controls, you can end up with clear indentation in your conditions:
      Badge
      {% if cond -%}
          Other badge 
      {% endif -%}
      Another badge
      {% if not cond -%}
          One more badge 
      {% endif -%}
      Last badge 
      
      or keep it flat:
      Badge
      {% if cond -%}
      Other badge 
      {% endif -%}
      Another badge
      {% if not cond -%}
      One more badge 
      {% endif -%}
      Last badge 
      
    3. Without whitespace control characters, you'll have to start your condition on the previous line:
      Badge{% if cond %}
      Other badge{% endif %}
      Another badge{% if not cond %}
      One more badge{% endif %}
      Last badge
      
      or end the condition on the next line
      Badge
      {% if cond %}Other badge
      {% endif %}Another badge
      {% if not cond %}One more badge
      {% endif %}Last badge