DougBeney / jekyll-pug

Jekyll Plugin That Allows You To Use Pug
MIT License
37 stars 2 forks source link

Indentation when mixing pug with Liquid #8

Closed tgoorden closed 6 years ago

tgoorden commented 6 years ago

OK, so I can't figure out how to make this work:

ul.navbar-nav.ml-auto
| {% for page in site.pages %}{% if page.title %}
   li.nav-item
      a.nav-link(href='{{ page.url | prepend: site.baseurl }}') {{ page.title }}
| {% endif %}{% endfor %}

If the li tag has an indent before it, the code won't compile. However if you don't indent it, it will not be placed within the ul tag.

DougBeney commented 6 years ago

Hi, @tgoorden! Thank you for using Jekyll-Pug.

The solution to this problem is to also indent the for-loop like so:

ul.navbar-nav.ml-auto
    | {% for page in site.pages %} {% if page.title %}
    li.nav-item
      a.nav-link(href='{{ page.url | prepend: site.baseurl }}') {{ page.title }}
    | {% endif %} {% endfor %}
tgoorden commented 6 years ago

OK, it does work with this very specific indentation. Could you explain why though? It sees counter-intuitive, no?

DougBeney commented 6 years ago

It's important to understand how Pug works.

Unlike HTML, ending tags are not needed. When you indent a line of code, it wraps it with the parent.

So, look at this example:

div
    p Welcome

In this case, the pug output would simply be:

<div>
<p>Welcome</p>
</div>

Now, let's take a look at your code example and why it does not work.

ul.navbar-nav.ml-auto
| {% for page in site.pages %}{% if page.title %}
   li.nav-item
      a.nav-link(href='{{ page.url | prepend: site.baseurl }}') {{ page.title }}
| {% endif %}{% endfor %}

The first thing pug will see is your ul element. It sees that there are no child elements (Indented lines of code) directly under it, so it will render this:

<ul class="navbar-nav ml-auto">
</ul>

The next thing it looks at is the plain-text for the start of your jekyll for-loop.

The error arises when you try to indent the li element and put it inside the for loop.

Going back to what was said earlier, Pug needs to generate an ending tag when generating HTML to wrap the child items.

The question now is how do you create an ending tag for | {% for page in site.pages %} {% if page.title %}?

You can't, so it errors out.

Let me know if that makes sense to you.

In conclusion, you can't provide any children to plain-text in Pug. You can only indent true elements.

Read more about how Pug handles plain-text here.

tgoorden commented 6 years ago

It's quite interesting behaviour. Going by what you said, I tried out the following:

ul
   | {%for page in site.pages %} 
p {{ page.title }}
   | {% endfor %}

Which compiles just fine! It seems the compiler is doing the following:

This implies you can write really weird, but correct code like this:

.example
   ul
      | {%for page in site.pages %}
   | {% if page.title %} 
p {{ page.title }}
| {% endif %} 
| {% endfor %} 

This compiles as well! However... Try using that block of code as {{ content }} in a layout. It actually "breaks out" of the containing divs, decreasing the indentation level at which the p tags are dropped in the resulting page.

In short, it seems that the way this currently works has severe issues. It seems that inner code shouldn't be able to affect its "surrounding" tags, but it totally can. And, obviously, the readability of the code is terribly confusing.

tgoorden commented 6 years ago

To add some constructive ideas: Meteor solved the combination of Jade + Spacebars (their templating engine) a bit more elegantly, essentially with custom tags. You would end up writing code like this:

ul
   for page in page.sites
       li {{ page.title }}

No ending endfor needed. Wouldn't that work here as well?

DougBeney commented 6 years ago

I don't think there is any problem here. It makes complete sense when you understand how Pug works. Keep in mind, I didn't code the functionality of for loops.The piped for-loops are a part of Liquid's template engine - What Jekyll uses with HTML. All this plugin does is allow you to code in familiar Pug code and be able to access all of Jekyll's features and variables.

Maybe, in the future, I'll completely replace the Liquid Template Engine for Pug, but that could possibly sacrifice the ability for users to add plugins that use custom template tags and such.

For now, Jekyll-Pug works wonderfully and I find it a dream to code in.