GRMustache icon indicating copy to clipboard operation
GRMustache copied to clipboard

Indentation of multi-line values in text templates

Open KosmicTask opened this issue 12 years ago • 11 comments

Hi Gwendal

What is the best approach for trying to preserve newline formatting and indentation when processing text (as opposed to HTML) templates?

As a practical example consider the following text template that generates a C file to echo its inputs:

#include <stdio.h>

int main(int argc, char *argv[])
{

{{ task-input-variables }}
{{ task-input-result }}    
    return 0;
}

The minimal template variable dict for this is:

{
  "task-input-result" : "\t\/\/ Return inputs as task result\n\tprintf(\"%s\\n\", taskInput1);\n\tprintf(\"%s\\n\", taskInput2);\n\t",
  "task-input-variables" : "\t\/\/ Task input variables \n\tchar *taskInput1 = argv[1];\n\tchar *taskInput2 = argv[2];\n"
}

The output is :

#include <stdio.h>

int main(int argc, char *argv[])
{

    // Task input variables 
    char *taskInput1 = argv[1];
    char *taskInput2 = argv[2];

    // Return inputs as task result
    printf("%s\n", taskInput1);
    printf("%s\n", taskInput2);

    return 0;
}

So the above works. However the issues are that I have pre-empt indentation and new line creation. So I have to embed tabs in my variables (otherwise only the first line of say {{ task-input-variables }} will be indented) which is less than desirable. What this boils down to is that I would like to be able to format my template as below while maintaining the final rendering shown above.

#include <stdio.h>

int main(int argc, char *argv[])
{

    {{ task-input-variables }}

    {{ task-input-result }}   

    return 0;
}

Any thoughts?

KosmicTask avatar Feb 22 '13 10:02 KosmicTask

GRMustache is a bad Mustache citizen: it does not provide the white-space processing that is documented by the Mustache spec. My opinion on it that it was half-thought, painful to implement, for very little benefit since the main produced language was HTML, a language that is white-space insensitive unless it gets ultra-sensitive.

My opinion was that GRMustache had better avoiding all white-space management, with three benefits: 1. users who don't care about white space won't be bothered, 2. those who need precise white-space management will have a tool that obey to the letter and will not fuck their output, 3. I can focus on more interesting features in the library :-)

And now you come. And it looks like your issue is not exactly handled by the Mustache spec. Another reason for me to think it is half-thought.

That said, thank you for the interesing use case. Please give me some time to think about it.

groue avatar Feb 22 '13 10:02 groue

Thanks for the reply. I know that I am bending Mustache in this regard.

I would imagine that whitespace handling etc for text and HTML content may have to be quite different. As the CONTENT_TYPE pragma is a GRMustache extension you are free to implement text whitespace handling as you see fit.

KosmicTask avatar Feb 22 '13 11:02 KosmicTask

Yep, I'm free to do whatever I want - especially solve my users' problems. Mustache looks like it will remain a very bare spec forever - nothing that ties me very strongly. GRMustache has already evolved so much, just to make sure the template engine isn't painful to use. I'll try to figure out a sensible solution for you.

groue avatar Feb 22 '13 12:02 groue

I've rewritten the issue title - it now exactly describes my interpretation of your story. Let me know if you believe I missed something.

groue avatar Feb 22 '13 12:02 groue

Title is much better thanks.

KosmicTask avatar Feb 22 '13 12:02 KosmicTask

@thelucid had a neat idea that at first sight looks flawless to me (thanks!).

It would require:

  • you to turn your strings into template instances before rendering them (through a new API that would make sure embedded {{...}} would not be interpreted as tags).
  • GRMustache to have partials templates honor the indentation level of their invocation tag when rendered - which would be a step towards spec-compliance.

Please tell me if this looks doable for you without polluting too much your code base. I'm planning to take some rest in the next couple of days. I hope you're not too much impatient :)

groue avatar Feb 22 '13 13:02 groue

I am not impatient at all.

I am implementing templates in my 20 or so languages so it's only now that I am really using GRMustache in earnest for text based templating.

I will get back with thoughts soon.

KosmicTask avatar Feb 22 '13 13:02 KosmicTask

I need to spend some time getting to grips with the GRMustache rendering API but the approach suggested by @theLucid (if I understand it correctly) seems sensible. Representing the strings as template instances would be simple to implement in my code I think.

That would hopefully resolve the indentation issue. I think that I can resolve the extraneous newline issue with the following approach. The template below generates the task-input-variables key referred to above. By explicitly identifying the last item in a collection with a last key I can output an eol (End Of Line - which renders as \n) item where appropriate. This gives a simple rule: to render a multiline value that occupies minimal vertical space code the template itself in one line.

{{#task-inputs}}{{#first}}{{tab}}// {{task-input-variables-message}}{{eol}}{{/}}{{tab}}{{name}}{{^last}}{{eol}}{{/}}{{^}}{{tab}}// {{task-inputs-undefined-message}} {{/}}

I use tab , tab2 etc to insert \t characters at present to force the indenting. If partial template indention was respected in a future GRMustache release then I could merely render these as NULL and all would well.

So now I can hopefully write templates that work more or less as I require in the knowledge that they may work much better in the future.

Thanks for your interest.

KosmicTask avatar Feb 22 '13 15:02 KosmicTask

Hi Gwendal

Just wondering how you are getting on. If I can be of any help with this issue let me know.

Hope you are well.

KosmicTask avatar Mar 25 '13 11:03 KosmicTask

Hi Jonathan. I'm sorry I've been very busy last weeks.

The more I've been looking at our goal, the more I convinced myself I need to implement spec-compliance regarding white space. Plus extra bits for your use cases that I consider quite well-founded.

My initial attemps were lousy, I must admit. Closer to random programming than anything else, mostly supported by existing tests, not by any clear trend of thought. I've been looking at the way other implementations do - so far I've not been rejoiced by what I've seen. I'm not rejoiced by the inconsistencies of the spec, neither.

A motivation crisis, that's what I'm in.

groue avatar Mar 26 '13 08:03 groue

HI Gwendal

In my own case I find that motivational issues arise when I don't have a really clear view of what I am trying to do. In this situation I would ask myself:

  1. Do I really want to spend time doing this? Striving towards something as relatively abstract as delivering spec compliance can be underwhelming. If that's really the case then move on to something else. However, it may still be possible to get a handle on things. #46 has been more less cracked from an external point of view (regardless of anything that may arise as a result of approaching #45).
  2. What are the exact problems I have with the spec and the other implementations with regard to whitespace? If we can pin those down then perhaps we can plot a path out of the maze. Quite often I find myself looking at the surface of a problem unable to penetrate into the substance of it. I normally feel more contented when I have really comprehended the true nature of the problem regardless of its implications for the amount of work that needs to be done. The actual implementation isn't usually a problem once the actual requirements have been truly identified.

Sometimes, not always, I find that any elegant solution can be wrangled from what lies before me (this is more likely to be the case if the existent code has been thoughtfully constructed - which is the case here).

So, insight or insanity! If you want we can try and kick #45 around until the ball bounces out of the maze.

KosmicTask avatar Mar 26 '13 09:03 KosmicTask