blob: db4cf3a8f2ce07b54d1bfd4804b216dbe3b7d7fc [file] [log] [blame]
part of mustache.impl;
class Template implements m.Template {
Template.fromSource(String source,
{bool lenient: false,
bool htmlEscapeValues : true,
String name,
m.PartialResolver partialResolver})
: source = source,
_nodes = parse(source, lenient, name, '{{ }}'),
_lenient = lenient,
_htmlEscapeValues = htmlEscapeValues,
_name = name,
_partialResolver = partialResolver;
final String source;
final List<Node> _nodes;
final bool _lenient;
final bool _htmlEscapeValues;
final String _name;
final m.PartialResolver _partialResolver;
String get name => _name;
String renderString(values) {
var buf = new StringBuffer();
render(values, buf);
return buf.toString();
}
void render(values, StringSink sink) {
var ctx = new RenderContext(sink, [values], _lenient, _htmlEscapeValues,
_partialResolver, _name, '', source);
renderWithContext(ctx, _nodes);
}
}
class TemplateException implements m.TemplateException {
TemplateException(this.message, this.templateName, this.source, this.offset);
final String message;
final String templateName;
final String source;
final int offset;
bool _isUpdated = false;
int _line;
int _column;
String _context;
int get line {
_update();
return _line;
}
int get column {
_update();
return _column;
}
String get context {
_update();
return _context;
}
String toString() {
var list = [];
if (templateName != null) list.add(templateName);
if (line != null) list.add(line);
if (column != null) list.add(column);
var location = list.isEmpty ? '' : ' (${list.join(':')})';
return '$message$location\n$context';
}
// This source code is a modified version of FormatException.toString().
void _update() {
if (_isUpdated) return;
_isUpdated = true;
if (source == null
|| offset == null
|| (offset < 0 || offset > source.length))
return;
// Find line and character column.
int lineNum = 1;
int lineStart = 0;
bool lastWasCR;
for (int i = 0; i < offset; i++) {
int char = source.codeUnitAt(i);
if (char == 0x0a) {
if (lineStart != i || !lastWasCR) {
lineNum++;
}
lineStart = i + 1;
lastWasCR = false;
} else if (char == 0x0d) {
lineNum++;
lineStart = i + 1;
lastWasCR = true;
}
}
_line = lineNum;
_column = offset - lineStart + 1;
// Find context.
int lineEnd = source.length;
for (int i = offset; i < source.length; i++) {
int char = source.codeUnitAt(i);
if (char == 0x0a || char == 0x0d) {
lineEnd = i;
break;
}
}
int length = lineEnd - lineStart;
int start = lineStart;
int end = lineEnd;
String prefix = "";
String postfix = "";
if (length > 78) {
// Can't show entire line. Try to anchor at the nearest end, if
// one is within reach.
int index = offset - lineStart;
if (index < 75) {
end = start + 75;
postfix = "...";
} else if (end - offset < 75) {
start = end - 75;
prefix = "...";
} else {
// Neither end is near, just pick an area around the offset.
start = offset - 36;
end = offset + 36;
prefix = postfix = "...";
}
}
String slice = source.substring(start, end);
int markOffset = offset - start + prefix.length;
_context = "$prefix$slice$postfix\n${" " * markOffset}^\n";
}
}