Fix partials handling of whitespace
diff --git a/lib/mustache.dart b/lib/mustache.dart
index 0fa0e7e..39dfb75 100644
--- a/lib/mustache.dart
+++ b/lib/mustache.dart
@@ -4,7 +4,6 @@
import 'dart:mirrors';
part 'src/char_reader.dart';
-part 'src/prefixing_string_sink.dart';
part 'src/scanner.dart';
part 'src/template.dart';
diff --git a/lib/src/prefixing_string_sink.dart b/lib/src/prefixing_string_sink.dart
deleted file mode 100644
index fffeb2b..0000000
--- a/lib/src/prefixing_string_sink.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-part of mustache;
-
-class PrefixingStringSink implements StringSink {
-
- bool _started = false;
- final StringSink _sink;
- final String _prefix;
-
- PrefixingStringSink(this._sink, this._prefix);
-
- void write(Object obj) {
- if (!_started) {
- _started = true;
- _sink.write(_prefix);
- }
- var s = obj.toString();
- _sink.write(s.replaceAll('\n', '\n$_prefix'));
- }
-
- void writeCharCode(int charCode) {
- if (!_started) {
- _started = true;
- _sink.write(_prefix);
- }
- _sink.writeCharCode(charCode);
- if (charCode == _NEWLINE) _sink.write(_prefix);
- }
-
- void writeAll(Iterable objects, [String separator = ""]) {
- Iterator iterator = objects.iterator;
- if (!iterator.moveNext()) return;
- if (separator.isEmpty) {
- do {
- write(iterator.current);
- } while (iterator.moveNext());
- } else {
- write(iterator.current);
- while (iterator.moveNext()) {
- write(separator);
- write(iterator.current);
- }
- }
- }
-
- void writeln([Object obj = ""]) {
- write(obj);
- _sink.write('\n');
- _sink.write(_prefix);
- }
-
-}
diff --git a/lib/src/template.dart b/lib/src/template.dart
index 3e2a365..be0fa89 100644
--- a/lib/src/template.dart
+++ b/lib/src/template.dart
@@ -100,7 +100,7 @@
void render(values, StringSink sink) {
var renderer = new _Renderer(_root, sink, values, [values],
- _lenient, _htmlEscapeValues, _partialResolver, _name);
+ _lenient, _htmlEscapeValues, _partialResolver, _name, '');
renderer.render();
}
}
@@ -116,20 +116,20 @@
this._htmlEscapeValues,
this._partialResolver,
this._templateName,
- [this._indent])
+ this._indent)
: _stack = new List.from(stack);
_Renderer.partial(_Renderer renderer, _Template partial, String indent)
: this(partial._root,
- indent == null || indent == ''
- ? renderer._sink
- : new PrefixingStringSink(renderer._sink, indent),
+ renderer._sink,
renderer._values,
renderer._stack,
renderer._lenient,
renderer._htmlEscapeValues,
renderer._partialResolver,
- renderer._templateName);
+ renderer._templateName,
+ //FIXME nesting renderer._indent + indent);
+ indent);
_Renderer.subtree(_Renderer renderer, _Node node, StringSink sink)
: this(node,
@@ -139,7 +139,8 @@
renderer._lenient,
renderer._htmlEscapeValues,
renderer._partialResolver,
- renderer._templateName);
+ renderer._templateName,
+ renderer._indent);
final _Node _root;
final StringSink _sink;
@@ -152,7 +153,30 @@
final String _indent;
void render() {
- _root.children.forEach(_renderNode);
+ if (_indent == null || _indent == '') {
+ _root.children.forEach(_renderNode);
+ } else {
+ _renderWithIndent();
+ }
+ }
+
+ void _renderWithIndent() {
+ // Special case to make sure there is not an extra indent after the last
+ // line in the partial file.
+ if (_root.children.isEmpty) return;
+
+ _write(_indent);
+
+ for (int i = 0; i < _root.children.length - 1; i++) {
+ _renderNode(_root.children[i]);
+ }
+
+ var node = _root.children.last;
+ if (node.type != _TEXT) {
+ _renderNode(node);
+ } else {
+ _renderText(node, lastNode: true);
+ }
}
_write(String output) => _sink.write(output);
@@ -184,8 +208,18 @@
}
}
- _renderText(node) {
- _write(node.value);
+ _renderText(_Node node, {bool lastNode: false}) {
+ var s = node.value;
+ if (s == '') return;
+ if (_indent == null || _indent == '') {
+ _write(s);
+ } else if (lastNode && s.runes.last == _NEWLINE) {
+ s = s.substring(0, s.length - 1);
+ _write(s.replaceAll('\n', '\n$_indent'));
+ _write('\n');
+ } else {
+ _write(s.replaceAll('\n', '\n$_indent'));
+ }
}
// Walks up the stack looking for the variable.
@@ -356,8 +390,6 @@
? null
: _partialResolver(partialName);
if (template != null) {
- print('render partial with indent "${node.indent}"');
- //TODO Check if nested partials indent correctly?
var renderer = new _Renderer.partial(this, template, node.indent);
renderer.render();
} else if (_lenient) {
diff --git a/test/mustache_test.dart b/test/mustache_test.dart
index 4f25776..c357b2d 100644
--- a/test/mustache_test.dart
+++ b/test/mustache_test.dart
@@ -385,6 +385,28 @@
lenient: true);
expect(output, equals('X<Y<>>'));
});
+
+
+ test('standalone without previous', () {
+ var output = _partialTest(
+ { },
+ {'root': ' {{>partial}}\n>',
+ 'partial': '>\n>'},
+ 'root',
+ lenient: true);
+ expect(output, equals(' >\n >>'));
+ });
+
+
+ test('standalone indentation', () {
+ var output = _partialTest(
+ { 'content': "<\n->" },
+ {'root': "\\\n {{>partial}}\n\/\n",
+ 'partial': "|\n{{{content}}}\n|\n"},
+ 'root',
+ lenient: true);
+ expect(output, equals("\\\n |\n <\n->\n |\n\/\n"));
+ });
});