Added support for trimming unnecessary newlines.
This commit is contained in:
parent
0b84ca8877
commit
49f9478c79
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue