| Index: pkg/source_maps/lib/printer.dart
|
| diff --git a/pkg/source_maps/lib/printer.dart b/pkg/source_maps/lib/printer.dart
|
| index 333aadcd429c4e951c0aef2c78a2f47db287e442..95539d2b77bf549a41d81bc90208581a71aa1260 100644
|
| --- a/pkg/source_maps/lib/printer.dart
|
| +++ b/pkg/source_maps/lib/printer.dart
|
| @@ -12,8 +12,8 @@ import 'span.dart';
|
| const int _LF = 10;
|
| const int _CR = 13;
|
|
|
| -/// A printer that keeps track of offset locations and records source maps
|
| -/// locations.
|
| +/// A simple printer that keeps track of offset locations and records source
|
| +/// maps locations.
|
| class Printer {
|
| final String filename;
|
| final StringBuffer _buff = new StringBuffer();
|
| @@ -87,3 +87,159 @@ class Printer {
|
| _loc = loc;
|
| }
|
| }
|
| +
|
| +/// A more advanced printer that keeps track of offset locations to record
|
| +/// source maps, but additionally allows nesting of different kind of items,
|
| +/// including [NestedPrinter]s, and it let's you automatically indent text.
|
| +///
|
| +/// This class is especially useful when doing code generation, where different
|
| +/// peices of the code are generated independently on separate printers, and are
|
| +/// finally put together in the end.
|
| +class NestedPrinter implements NestedItem {
|
| +
|
| + /// Items recoded by this printer, which can be [String] literals,
|
| + /// [NestedItem]s, and source map information like [Location] and [Span].
|
| + List _items = [];
|
| +
|
| + /// Internal buffer to merge consecutive strings added to this printer.
|
| + StringBuffer _buff;
|
| +
|
| + /// Current indentation, which can be updated from outside this class.
|
| + int indent;
|
| +
|
| + /// Item used to indicate that the following item is copied from the original
|
| + /// source code, and hence we should preserve source-maps on every new line.
|
| + static final _ORIGINAL = new Object();
|
| +
|
| + NestedPrinter([this.indent = 0]);
|
| +
|
| + /// Adds [object] to this printer. [object] can be a [String],
|
| + /// [NestedPrinter], or anything implementing [NestedItem]. If [object] is a
|
| + /// [String], the value is appended directly, without doing any formatting
|
| + /// changes. If you wish to add a line of code with automatic indentation, use
|
| + /// [addLine] instead. [NestedPrinter]s and [NestedItem]s are not processed
|
| + /// until [build] gets called later on. We ensure that [build] emits every
|
| + /// object in the order that they were added to this printer.
|
| + ///
|
| + /// The [location] and [span] parameters indicate the corresponding source map
|
| + /// location of [object] in the original input. Only one, [location] or
|
| + /// [span], should be provided at a time.
|
| + ///
|
| + /// Indicate [isOriginal] when [object] is copied directly from the user code.
|
| + /// Setting [isOriginal] will make this printer propagate source map locations
|
| + /// on every line-break.
|
| + void add(object, {Location location, Span span, bool isOriginal: false}) {
|
| + if (object is! String || location != null || span != null || isOriginal) {
|
| + _flush();
|
| + assert(location == null || span == null);
|
| + if (location != null) _items.add(location);
|
| + if (span != null) _items.add(span);
|
| + if (isOriginal) _items.add(_ORIGINAL);
|
| + }
|
| +
|
| + if (object is String) {
|
| + _appendString(object);
|
| + } else {
|
| + _items.add(object);
|
| + }
|
| + }
|
| +
|
| + /// Append `2 * indent` spaces to this printer.
|
| + void insertIndent() => _indent(indent);
|
| +
|
| + /// Add a [line], autoindenting to the current value of [indent]. Note,
|
| + /// indentation is not inferred from the contents added to this printer. If a
|
| + /// line starts or ends an indentation block, you need to also update [indent]
|
| + /// accordingly. Also, indentation is not adapted for nested printers. If
|
| + /// you add a [NestedPrinter] to this printer, its indentation is set
|
| + /// separately and will not include any the indentation set here.
|
| + ///
|
| + /// The [location] and [span] parameters indicate the corresponding source map
|
| + /// location of [object] in the original input. Only one, [location] or
|
| + /// [span], should be provided at a time.
|
| + void addLine(String line, {Location location, Span span}) {
|
| + if (location != null || span != null) {
|
| + _flush();
|
| + assert(location == null || span == null);
|
| + if (location != null) _items.add(location);
|
| + if (span != null) _items.add(span);
|
| + }
|
| + if (line == null) return;
|
| + if (line != '') {
|
| + // We don't indent empty lines.
|
| + _indent(indent);
|
| + _appendString(line);
|
| + }
|
| + _appendString('\n');
|
| + }
|
| +
|
| + /// Appends a string merging it with any previous strings, if possible.
|
| + void _appendString(String s) {
|
| + if (_buff == null) _buff = new StringBuffer();
|
| + _buff.write(s);
|
| + }
|
| +
|
| + /// Adds all of the current [_buff] contents as a string item.
|
| + void _flush() {
|
| + if (_buff != null) {
|
| + _items.add(_buff.toString());
|
| + _buff = null;
|
| + }
|
| + }
|
| +
|
| + void _indent(int indent) {
|
| + for (int i = 0; i < indent; i++) _appendString(' ');
|
| + }
|
| +
|
| + /// Returns a string representation of all the contents appended to this
|
| + /// printer, including source map location tokens.
|
| + String toString() {
|
| + _flush();
|
| + return (new StringBuffer()..writeAll(_items)).toString();
|
| + }
|
| +
|
| + /// [Printer] used during the last call to [build], if any.
|
| + Printer printer;
|
| +
|
| + /// Returns the text produced after calling [build].
|
| + String get text => printer.text;
|
| +
|
| + /// Returns the source-map information produced after calling [build].
|
| + String get map => printer.map;
|
| +
|
| + /// Builds the output of this printer and source map information. After
|
| + /// calling this function, you can use [text] and [map] to retrieve the
|
| + /// geenrated code and source map information, respectively.
|
| + void build(String filename) {
|
| + writeTo(printer = new Printer(filename));
|
| + }
|
| +
|
| + /// Implements the [NestedItem] interface.
|
| + void writeTo(Printer printer) {
|
| + _flush();
|
| + bool propagate = false;
|
| + for (var item in _items) {
|
| + if (item is NestedItem) {
|
| + item.writeTo(printer);
|
| + } else if (item is String) {
|
| + printer.add(item, projectMarks: propagate);
|
| + propagate = false;
|
| + } else if (item is Location || item is Span) {
|
| + printer.mark(item);
|
| + } else if (item == _ORIGINAL) {
|
| + // we insert booleans when we are about to quote text that was copied
|
| + // from the original source. In such case, we will propagate marks on
|
| + // every new-line.
|
| + propagate = true;
|
| + } else {
|
| + throw new UnsupportedError('Unknown item type: $item');
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +/// An item added to a [NestedPrinter].
|
| +abstract class NestedItem {
|
| + /// Write the contents of this item into [printer].
|
| + void writeTo(Printer printer);
|
| +}
|
|
|