Revision of Twine: <<if>> and whitespace from Sun, 09/15/2013 - 00:13

This is just a summary of how <<if>>, by default, handles whitespace characters (that is, line breaks, spaces, tabs, and such.)

The behaviour

The rule is: the <<if>> macro removes all whitespace contained between the <<if>>, <<endif>> or <<else>> tags and any non-whitespace contained text.

Consider this code sample, in which the line breaks are marked:

The magenta line breaks (those contained between the <<if>> and <<endif>> and the actual text) will be removed by the macro. Thus, this will render as follows:

A slice of marmalade toast on a plate,
a bit of quiet,
and a spot of tea.

A slice of marmalade toast 
on a plate,
a bit of quiet,
and a spot of tea.

Resisting this behaviour

The <<if>> macro was primarily designed for inserting whole paragraphs. This behaviour is, however, less useful for, say, inserting sentence fragments into paragraphs, which often have leading spaces. There are a few ways to get around this. Such as:

* Empty comment syntax

If you pad the interiors of <<if>> macros with an empty comment tag "/%%/", then the behaviour will be overridden, because the comment tags will be treated as text despite not appearing in the final story.

First line. <<if $a gt 0>>/%%/
Second line.
/%%/<<endif>>

This might be the easiest method of all listed here (although the last one may be more convenient if you use <<if>> a lot).

* Using <<print>>
The <<print>> macro can also be used.

A complete sentence<<if $a gt 0>>
<<print " with an extra amendment">>
<<endif>>.

However, it isn't obvious how to add line breaks using this method. There is a way, obscure though it is:

<<if $a gt 0>><<print "First line." + String.fromCharCode(13) + "Second line.">>
<<endif>>

* Using a HTML <br>

If you want to preserve a line break inside <<if>>, you can do so by the forceful method of using inline HTML.

First line.<<if $a gt 0>>
<br>
Second line.
<<endif>>

* Patching <<if>> to not remove whitespace

Much like most undesirable Twine behaviour, this can be patched out on a story-by-story basis. The script code for doing so is as follows... however, using this will conflict with my <<else if>> script, so you can't have one and the other.

version.extensions.ifMacros={major:1,minor:1,revision:0};macros["if"]={handler:function(place,macroName,params,parser){
var conditions=[],clauses=[],srcOffset=parser.source.indexOf(">>",parser.matchStart)+2,src=parser.source.slice(srcOffset),endPos=-1,currentCond=parser.fullArgs(),currentClause="",t=0,nesting=0;
for(var i=0;i<src.length;i++){if(src.substr(i,9)=="<<endif>>"){nesting--;if(nesting<0){endPos=srcOffset+i+9;
conditions.push(currentCond);clauses.push(currentClause);break;}}if((src.substr(i,6)=="<<else")&&nesting==0){conditions.push(currentCond);
clauses.push(currentClause);currentClause="";t=src.indexOf(">>",i+6);if(src.substr(i+6,4)==" if "){currentCond=Wikifier.parse(src.slice(i+10,t));
}else{currentCond="true";}i=t+2;}if(src.substr(i,5)=="<<if "){nesting++;}currentClause+=src.charAt(i);
}try{if(endPos!=-1){parser.nextMatch=endPos;for(i=0;i<clauses.length;i++){if(eval(conditions.shift())){new Wikifier(place,clauses[i ]);
break;}}}else{throwError(place,"can't find matching endif");}}catch(e){throwError(place,"bad condition: "+e.message);
}}};

The future
The next version of Twine 1 may change the behaviour of <<if>> to not remove whitespace. I'm still debating how or whether this should be enabled, and how to enable current story code to continue to function correctly.

pensive-mosquitoes