ractivejs/ractive

Feature Request: Handling white-spaces as first class citizen in textOnlyMode

Closed this issue · 9 comments

Description:

I recently started to use Ractive as a template engine in a project to generate the necessary C header and source files regarding to user supplied data.

Ractive might not be the intended tool for that purpose, that's okay. However, I would love to use Ractive for this type of tasks in the future as it's both familiar to me and already the part of the rest of the system. I guess there is no harm to open a feature request for this one.

Versions affected:

All?

Platforms affected:

All?

Reproduction:

Here is the reproduction for my intention.

Template

#define hello there 
{{#if hey}}
    #define hi 5
{{/if}}

{{#each myObj}}
    {{#with myObj[@key] as val}}
        #define {{val.x}} {{val.y}}
    {{/with}}
{{/each}}

Expected

#define hello there 
#define hi 5

#define foo bar
#define baz qux

Observed

#define hello there 
    #define hi 5

    
        #define foo bar
    

    
        #define baz qux

Except for the whitespace on empty lines, about which I'm not sure, The indentation matches exactly what's in the template (think white-space: pre). If you wanted to only preserve line breaks but no indentation (like white-space: pre-line), it would only make sense with a separate config option.

Applying a white-space: pre-line style resolves the prefixed whitespaces, but absolutely interferes with indentation-sensitive parts. Here is what I mean: playground

Template

#define hello there 
{{#if hey}}
    #define hi 5
{{/if}}

{{#each myObj}}
    {{#with myObj[@key] as val}}
        #define {{val.x}} {{val.y}}
    {{/with}}
{{/each}}

# This section is Python-code
if foo:
    bar = baz
    {{#each myObj}}
        {{#with myObj[@key] as val}}
            hey{{@key}} = {{val.x}}/{{val.y}}
        {{/with}}
    {{/each}}

Expected

#define hello there
#define hi 5

#define foo bar
#define baz qux

# This section is Python-code
if foo:
    bar = baz
    heya1 = foo/bar
    heya2 = baz/qux

Observed

#define hello there
#define hi 5


#define foo bar



#define baz qux

# This section is Python-code
if foo:
bar = baz

heya1 = foo/bar


heya2 = baz/qux

Proposal

What I propose is:

  • Ractive will have an indent: REGEX option (eg. \s{4} or \t or \s\s or ) for user defined indentation.
  • Any block ({{#if}}, {{#each}}, {{#with}}, ...) will subtract that configured number of whitespaces for its child nodes.
  • Blocks ({{#if}}, ...) will not introduce a newline.

@evs-chris is it a wontfix?

Edit

It turns out this feature is documented in FreeMarker library: https://freemarker.apache.org/docs/dgui_misc_whitespace.html

I don't think it's a wontfix, as I think it definitely makes sense to allow more control over whitespace. I won't be able to implement it for a while though, unfortunately.

I was kinda thinking something more along the lines of https://shopify.github.io/liquid/basics/whitespace/, but it would probably make sense to have a mode that just strips out the lines with only block tags. I'll poke at the parser a bit and see what that would take.

That'd be very nice. By the way, I saw another project, modm.io, that uses Jinja as the initial templating stage, which IMHO proves that this "using a full-blown template engine in front of a regular compiler" approach has a valid rationale.

I've added some experimental support for something along these lines on edge. It's a sort of extension of preserveWhitespace, which is required because otherwise consecutive whitespace is collapsed in the template (where allowed i.e. almost everywhere), since HTML doesn't really care in most cases. It gives you manual control of collapsing the line contains section tags by adding a - before the end of the tag e.g. {{#if foo -}}. Alternate blocks (else, elseif, etc) are also handled based on the flag on the opening tag.

It's not particularly easy to describe, but this example in playground will hopefully make it clear. There's also a test case.

This doesn't cover automatic handling of indentation, and I don't think it reasonably could. That leaves you nesting the sections with whatever indentation but leaving the content where it should appear on its own line. Let me know what you think.

Well, this example outputs what's expected. Awesome!

This doesn't cover automatic handling of indentation,

Thinking again, not handling indentation (leaving it as is) is kind of a "feature". I like it more, because we can easily determine the resulting indentation of a code without tracing its surrounding blocks. Now I vote for "leave indentation handling as is".

However, the - character... Is it too hard to remove that dependency? It seems annoying. We could perfectly use it, okay, but removing the need for - sign would be awesome.