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 else
{ {
generators = new List<IGenerator>() { _subGenerator }; generators = new List<IGenerator>();
if (_subGenerator != null)
{
generators.Add(_subGenerator);
}
} }
foreach (KeyScope childScope in scopes) foreach (KeyScope childScope in scopes)
{ {

View File

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

View File

@ -45,6 +45,18 @@ namespace mustache
_tagLookup.Add(definition.Name, definition); _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> /// <summary>
/// Finds the tag definition with the given name. /// Finds the tag definition with the given name.
/// </summary> /// </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="TagParameter.cs" />
<Compile Include="KeyScope.cs" /> <Compile Include="KeyScope.cs" />
<Compile Include="TagScope.cs" /> <Compile Include="TagScope.cs" />
<Compile Include="Trimmer.cs" />
<Compile Include="WithGenerator.cs" /> <Compile Include="WithGenerator.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>