Jinja non rendering blocks adds whitespaces to next rendering block - jinja2

I have the following import on a jinja template that is rendered by ansible:
labels:
{% set name = 'jellyfin' %}
{% set port = '8096' %}
{% filter indent(width=8, first=True) %}
{% include './labels.yml.jinja' %}
{% endfilter %}
As you can see, there are some non rendering blocks to set some local variables and stuff. When the template is rendered by ansible, the first row of the template is shifted by the same amount of spaces that the non rendering blocks sum + 2 (32 in this case = 5 blocks with 6 spaces + 2).
For example:
labels:
# this are the labels, fools
- "traefik.enable=true"
- "traefik.backend=jellyfin"
I can remove the indentation of ALL the {% %} blocks, and then it will work properly, but looks ugly and off place.
Even if I add a minus sign to remove whitespaces to the non rendering blocks like this:
{% set name = 'jellyfin' -%}
{% set port = '8096' -%}
{% filter indent(width=8, first=True) -%}
{% include './labels.yml.jinja' -%}
{% endfilter -%}
The first line is still shifted (albeit much less)
How can I fix this?

I just had to add #jinja2: lstrip_blocks: "True" to the very top of the importing template, and that did the trick.
I gathered that information from this article, explaining my exact problem and showing a solution: https://radeksprta.eu/posts/control-whitespace-in-ansible-templates/
But I have to say that the default behaviour is very confusing.

Related

DBT macro ignores leading if block

I defined a macro that starts with:
{% macro my_macro(table, first=false) %}
{%- if first -%} WITH
{%- else -%} ,
{% endif %}
tmp AS (...
In the compiled SQL I see this is completely ignored. If I paste this exact same block after the first CTE, it inserts fine. If I put any text before the if-block, it will also render the text + content of if-block.
I don't understand this behaviour. How can I make this macro work leading either with WITH or ","?
Even if I replace first with true it doesn't show up.
Additional information:
I'm working with BigQuery and dbt version 0.18.2
After trial and error I realised that using "-" to reduce white space on the first line somehow removes the text coming after it as well.
So
{%- if first -%}
WITH
...
Doesn't work, but
{% if first %}
WITH
...
is fine. It was a simple fix, but I doubt this is expected behaviour.
interesting problem! A couple of questions:
What database are you working with?
What version of dbt are you working with?
Where does first come from in your query?
On Azure Synapse and with dbt version 0.18.1, I was able to successfully use the following:
{% set first = true %}
{%- if first -%}
WITH
{%- else -%} ,
{% endif %}
top_100 AS (
SELECT 100 AS MyNumber
),
top_10 AS (
SELECT TOP 10 * FROM top_100
)
SELECT * FROM top_10

Searching for page in site.pages by path without iteration

I have a path to some page from root in Jekyll as a variable path. I want to get some variables from FrontMatter of that page. How could I find this page in site.pages without iterating over all pages?
I mean something like
{% assign aim = site.pages[path] %}
instead of
{% for p in site.pages %}
{% if p.path == path %}
{% assign aim = p %}
{% endif %}
{% endfor %}
Will this solution be faster for a site with a thousand of pages?
You can use the where liquid filter for this:
{% assign aim = site.pages | where:"path",path %}
Thanks #β.εηοιτ.βε for the hint!
That was what I expected, but when I used this template, I've faced the problem: the output of {{aim.title}} was empty.
The where filter produces list even it consists of just one element! But each filepath in a file system points exactly at one file, so I expected that aim will be the page, not a list. To fix this, I've added first filter:
{% assign aim = site.pages | where:"path",path | first %}
And now aim is the page variable I am searching for.
About speed. This solution builds a site 2X faster on my hardware.

Overriding YAML frontmatter variables from Liquid

I would like my outermost Liquid template file to reference a JavaScript file only when the page requires it. I created a page variable, page.slideshow, which controls this:
default.html:
{% if page.slideshow %}
<script type="text/javascript" src="/js/slideshow.js"></script>
{% endif %}
Now I have a template that "inherits" from default.html, which allows the page to specify in its YAML frontmatter a list of images (page.images). Only when this list has more than one element do I want slideshow.js to be included in the page.
My attempt at this looks something like:
other.html
---
layout: default
---
{% assign imagecount = page.images | size %}
{% if imagecount > 1 %}
{% assign page.slideshow = true %}
{% endif %}
However, this does not seem to affect the rendering of default.html, because the script tag is not included in the final page.
As a workaround, I can modify the frontmatter of each page that lists multiple images to explicitly set slideshow: Yes, or change default.html to check page.slideshow or (page.images | size) > 0 but I'd prefer to structure it closer to what I attempted above.
I've had a play about and you can't really do it the way you've suggested. It seems page variables just cant be modified once they're set. You might be able to set it with Jekyll plugins, but that's a whole other thing.
The cleanest way I have found to do it is to put all the logic in your main, outermost template.
{% assign imageCount = page.images | size %}
{% if page.slideshow or imageCount > 1 %}
{{ page.images | size }}
<script src="/js/slideshow.js"></script>
{% endif %}

Strip url to 1 word in Jekyll

I am building a Jekyll blog, and I have come across an issue with permalinks.
My permalinks to blog posts are set like this in
_config.yml:
permalink: /:page/:categories/:title
It outputs like this when navigating to a blog post:
http://localhost:4000/blog/travel/netherlands-trip-prequesites/
I have some static pages in the site: Blog, Travel
The variable page.url outputs this url: /blog/travel/netherlands-trip-prequesites
The code my navigation bar uses to highlight the current page (giving it an "active" class):
{% assign url = page.url|remove:'index.html' %}
{% for nav in site.navigation %}
{% if nav.href == url %}
<li class="active">{{nav.name}}</li>
{% else %}
<li>{{nav.name}}</li>
{% endif %}
{%endfor%}
It works great when navigating to static pages, however when I click a blog post it doesn't highlight the correct static page. (ex.: If i navigate to a blog post with the url /blog/smth/title it should automatically highlight "Blog" in my navigation. When I navigate to /travel/smth/title it should highlight "Travel")
What I'd like to do is to strip down the output of page.url to its first part. For example I'd like to stip the following output
/blog/travel/netherlands-trip-prequesites
down to
/blog/
Why? So I can use it to check which static page it belongs to and highlight it accordigly.
The easiest way is to use split:
{{ page.url | split:'/' | first }}
That will give you the URL content up to the first / character.
I managed to solve it with three filters:
{{ page.url | replace:'/',' ' | truncatewords: 1 | remove:'...' }}
page.url outputs: /page/cat/title, then replace removes the forward slashes producing: page cat title. truncatewords truncates the string down to one word, producing: page... (for some reason three dots gets inserted after the remaining word). After all this I only needed to remove those dots with remove and voilá, my final string: page.
Hope this helps someone.
The answer provided by PeterInvincible was almost perfect, however, there's no need to get piping to remove involved...
The following also will produce desired output
{{ page.url | replace:'/',' ' | truncatewords: 1,"" }}
And to save it to a variable use capture redirection
{{ capture url_base }}{{ page.url | replace:'/',' ' | truncatewords: 1,"" }}{{ endcapture }}
Which can be called via {{url_base}} or mixed with other processing calls.
Also for file paths instead of URLs page.dir works well if you're not using permalink settings for layout, check the gh-pages branch (specifically _includes/nav_gen.html for functional, though rough'round the edges, example) for hosted examples of similar code examples related to liquid syntax and other magic.
Edits & Updates
The above linked script is now live/mostly-working/modular and auto-serving parsed sub-directories viewed currently at the related https://s0ands0.github.io/Perinoid_Pipes/ project site providing examples of recursive parsing of directories. Including and modding for nearly any theme should be possible just check the commented section at the top for currently recognized commands that maybe passed at inclusion call... on that note of inclusion and modularization here's how to turn the above example code for directory parsing into a function
{% comment %}
# Save this to _include/dir_path_by_numbers.html
# import with the following assigning arguments if needed
# {% include dir_path_by_numbers.html directory_argument_path="blog" directory_argument_depth=1 %}
{% endcomment %}
{% assign default_arg_directory_path = page.url %}
{% assign default_arg_directory_depth = 1 %}
{% if directory_argument_path %}
{% assign directory_to_inspect = directory_argument_path %}
{% else %}
{% assign directory_to_inspect = default_arg_directory_path %}
{% endif %}
{% if directory_argument_depth %}
{% assign directory_to_inspect_depth = directory_argument_path %}
{% else %}
{% assign directory_to_inspect_depth = default_arg_directory_depth %}
{% endif %}
{% comment %}
# Defaults read and assigned now to output results
{% endcomment %}
{{ directory_to_inspect_depth | replace:'/',' ' | truncatewords: directory_to_inspect_depth,"" | remove_first: '/' | replace:' ','/' }}
The above should output directory path lengths of whatever size desired and maybe included as shown previously or if feeling adventurous try what's shown below; though for looping and recursive features look to the linked script for how I've worked around stack size restrictions.
{% capture dir_sub_path %}{{include dir_path_by_numbers.html directory_argument_path="blog" directory_argument_depth=1}}{% endcapture %}
Note above is just speculation, untested, and maybe more buggy than scripts tested and hosted publicly... in other words inspiration.
Simplest way would be using
if page.url contains
example:
<li class="{% if page.url contains '/docs/' %}current{% endif %}">
Docs

Twig adding "%0A" to imagepath (Email-Template)

i am havin problems with some image urls generated partly through twig.
Here is how i am currently doing it:
{% autoescape false %}
{% set imageurl %}
http://www.someurl.com/mails/images/emails
{% endset %}
{% endautoescape %}
And this is how i am using it in the template itself:
{{imageurl}}/spacer.gif
The problem now is, that these images are not getting displayed properly in the final email because of a "%0A" inside the url. It looks like this:
/emails%0A/spacer.gif
I have no idea what is causing this problem, maybe you guys can help me..
Thanks in advance.
%0A is the Line Feed character. It is appended because of the newline after .../emails.
Either set the variable in one line:
{% set imageurl %}http://www.someurl.com/mails/images/emails{% endset %}
Or use Twig's tag level whitespace control:
{%- set imageurl -%}
http://www.someurl.com/mails/images/emails
{%- endset -%}