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);
} }
} }
@ -122,6 +123,7 @@ namespace mustache
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>