Added support for trimming unnecessary newlines.

This commit is contained in:
Travis Parks 2013-01-09 21:58:45 -05:00
parent 0b84ca8877
commit 49f9478c79
5 changed files with 119 additions and 7 deletions

View File

@ -71,7 +71,11 @@ namespace mustache
}
else
{
generators = new List<IGenerator>() { _subGenerator };
generators = new List<IGenerator>();
if (_subGenerator != null)
{
generators.Add(_subGenerator);
}
}
foreach (KeyScope childScope in scopes)
{

View File

@ -49,7 +49,8 @@ namespace mustache
public Generator Compile(string format)
{
CompoundGenerator generator = new CompoundGenerator(_master, new ArgumentCollection());
int formatIndex = buildCompoundGenerator(_master, _tagScope, generator, format, 0);
Trimmer trimmer = new Trimmer();
int formatIndex = buildCompoundGenerator(_master, _tagScope, generator, trimmer, format, 0);
string trailing = format.Substring(formatIndex);
StaticGenerator staticGenerator = new StaticGenerator(trailing);
generator.AddGenerator(staticGenerator);
@ -60,7 +61,7 @@ namespace mustache
{
foreach (TagDefinition childTag in definition.ChildTags)
{
scope.AddTag(childTag);
scope.TryAddTag(childTag);
}
}
@ -122,6 +123,7 @@ namespace mustache
TagDefinition tagDefinition,
TagScope scope,
CompoundGenerator generator,
Trimmer trimmer,
string format, int formatIndex)
{
while (true)
@ -139,11 +141,10 @@ namespace mustache
}
string leading = format.Substring(formatIndex, match.Index - formatIndex);
StaticGenerator staticGenerator = new StaticGenerator(leading);
generator.AddGenerator(staticGenerator);
if (match.Groups["key"].Success)
{
trimmer.AddStaticGenerator(generator, true, leading);
formatIndex = match.Index + match.Length;
string key = match.Groups["key"].Value;
string alignment = match.Groups["alignment"].Value;
@ -161,13 +162,14 @@ namespace mustache
string message = String.Format(Resources.UnknownTag, tagName);
throw new FormatException(message);
}
trimmer.AddStaticGeneratorBeforeTag(generator, true, leading);
if (nextDefinition.HasBody)
{
ArgumentCollection arguments = getArguments(nextDefinition, match);
CompoundGenerator compoundGenerator = new CompoundGenerator(nextDefinition, arguments);
TagScope nextScope = new TagScope(scope);
registerTags(nextDefinition, nextScope);
formatIndex = buildCompoundGenerator(nextDefinition, nextScope, compoundGenerator, format, formatIndex);
formatIndex = buildCompoundGenerator(nextDefinition, nextScope, compoundGenerator, trimmer, format, formatIndex);
generator.AddGenerator(nextDefinition, compoundGenerator);
}
else
@ -181,6 +183,8 @@ namespace mustache
else if (match.Groups["close"].Success)
{
string tagName = match.Groups["name"].Value;
TagDefinition nextDefinition = scope.Find(tagName);
trimmer.AddStaticGeneratorBeforeTag(generator, false, leading);
formatIndex = match.Index;
if (tagName == tagDefinition.Name)
{
@ -190,6 +194,7 @@ namespace mustache
}
else if (match.Groups["comment"].Success)
{
trimmer.AddStaticGenerator(generator, false, leading);
formatIndex = match.Index + match.Length;
}
}

View File

@ -45,6 +45,18 @@ namespace mustache
_tagLookup.Add(definition.Name, definition);
}
/// <summary>
/// Trys to register the tag in the current scope.
/// </summary>
/// <param name="definition">The tag to add to the current scope.</param>
public void TryAddTag(TagDefinition definition)
{
if (Find(definition.Name) == null)
{
_tagLookup.Add(definition.Name, definition);
}
}
/// <summary>
/// Finds the tag definition with the given name.
/// </summary>

90
mustache-sharp/Trimmer.cs Normal file
View File

@ -0,0 +1,90 @@
using System;
namespace mustache
{
/// <summary>
/// Removes unnecessary whitespace from static text.
/// </summary>
internal sealed class Trimmer
{
private bool hasHeader;
private bool hasFooter;
private bool hasTag;
private bool canTrim;
/// <summary>
/// Initializes a new instance of a Trimmer.
/// </summary>
public Trimmer()
{
hasTag = false;
canTrim = true;
}
/// <summary>
/// Processes the given text, creating a StaticGenerator and adding it to the current compound generator.
/// </summary>
/// <param name="generator">The compound generator to add the static generator to.</param>
/// <param name="isHeader">Gets whether we're encountered the header tag.</param>
/// <param name="value">The static text to trim.</param>
public void AddStaticGeneratorBeforeTag(CompoundGenerator generator, bool isHeader, string value)
{
string trimmed = processLines(value);
hasHeader |= isHeader;
hasFooter |= hasHeader && !isHeader;
addStaticGenerator(generator, trimmed);
}
/// <summary>
/// Processes the given text, creating a StaticGenerator and adding it to the current compound generator.
/// </summary>
/// <param name="generator">The compound generator to add the static generator to.</param>
/// <param name="isOutput">Specifies whether the tag results in output.</param>
/// <param name="value">The static text to trim.</param>
public void AddStaticGenerator(CompoundGenerator generator, bool isOutput, string value)
{
string trimmed = processLines(value);
canTrim &= !isOutput;
addStaticGenerator(generator, trimmed);
}
private string processLines(string value)
{
string trimmed = value;
int newline = value.IndexOf(Environment.NewLine);
if (newline == -1)
{
canTrim &= String.IsNullOrWhiteSpace(value);
}
else
{
// finish processing the previous line
if (canTrim && hasTag && (!hasHeader || !hasFooter))
{
string lineEnd = trimmed.Substring(0, newline);
if (String.IsNullOrWhiteSpace(lineEnd))
{
trimmed = trimmed.Substring(newline + Environment.NewLine.Length);
}
}
// start processing the next line
hasTag = false;
hasHeader = false;
hasFooter = false;
int lastNewline = value.LastIndexOf(Environment.NewLine);
string lineStart = value.Substring(lastNewline + Environment.NewLine.Length);
canTrim = String.IsNullOrWhiteSpace(lineStart);
}
return trimmed;
}
private static void addStaticGenerator(CompoundGenerator generator, string trimmed)
{
if (trimmed.Length > 0)
{
StaticGenerator leading = new StaticGenerator(trimmed);
generator.AddGenerator(leading);
}
}
}
}

View File

@ -60,6 +60,7 @@
<Compile Include="TagParameter.cs" />
<Compile Include="KeyScope.cs" />
<Compile Include="TagScope.cs" />
<Compile Include="Trimmer.cs" />
<Compile Include="WithGenerator.cs" />
</ItemGroup>
<ItemGroup>