| Index: dart_style/lib/src/line_writer.dart
 | 
| diff --git a/dart_style/lib/src/line_writer.dart b/dart_style/lib/src/line_writer.dart
 | 
| deleted file mode 100644
 | 
| index 055892ea0b251639921cc77b7391411a96a5e421..0000000000000000000000000000000000000000
 | 
| --- a/dart_style/lib/src/line_writer.dart
 | 
| +++ /dev/null
 | 
| @@ -1,277 +0,0 @@
 | 
| -// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
 | 
| -// for details. All rights reserved. Use of this source code is governed by a
 | 
| -// BSD-style license that can be found in the LICENSE file.
 | 
| -
 | 
| -library dart_style.src.line_writer;
 | 
| -
 | 
| -import 'chunk.dart';
 | 
| -import 'dart_formatter.dart';
 | 
| -import 'debug.dart' as debug;
 | 
| -import 'line_splitting/line_splitter.dart';
 | 
| -import 'whitespace.dart';
 | 
| -
 | 
| -/// Given a series of chunks, splits them into lines and writes the result to
 | 
| -/// a buffer.
 | 
| -class LineWriter {
 | 
| -  final _buffer = new StringBuffer();
 | 
| -
 | 
| -  final List<Chunk> _chunks;
 | 
| -
 | 
| -  final String _lineEnding;
 | 
| -
 | 
| -  /// The number of characters allowed in a single line.
 | 
| -  final int pageWidth;
 | 
| -
 | 
| -  /// The number of characters of additional indentation to apply to each line.
 | 
| -  ///
 | 
| -  /// This is used when formatting blocks to get the output into the right
 | 
| -  /// column based on where the block appears.
 | 
| -  final int _blockIndentation;
 | 
| -
 | 
| -  /// The cache of blocks that have already been formatted.
 | 
| -  final Map<_BlockKey, FormatResult> _blockCache;
 | 
| -
 | 
| -  /// The offset in [_buffer] where the selection starts in the formatted code.
 | 
| -  ///
 | 
| -  /// This will be `null` if there is no selection or the writer hasn't reached
 | 
| -  /// the beginning of the selection yet.
 | 
| -  int _selectionStart;
 | 
| -
 | 
| -  /// The offset in [_buffer] where the selection ends in the formatted code.
 | 
| -  ///
 | 
| -  /// This will be `null` if there is no selection or the writer hasn't reached
 | 
| -  /// the end of the selection yet.
 | 
| -  int _selectionEnd;
 | 
| -
 | 
| -  /// The number of characters that have been written to the output.
 | 
| -  int get length => _buffer.length;
 | 
| -
 | 
| -  LineWriter(DartFormatter formatter, this._chunks)
 | 
| -      : _lineEnding = formatter.lineEnding,
 | 
| -        pageWidth = formatter.pageWidth,
 | 
| -        _blockIndentation = 0,
 | 
| -        _blockCache = {};
 | 
| -
 | 
| -  /// Creates a line writer for a block.
 | 
| -  LineWriter._(this._chunks, this._lineEnding, this.pageWidth,
 | 
| -      this._blockIndentation, this._blockCache) {
 | 
| -    // There is always a newline after the opening delimiter.
 | 
| -    _buffer.write(_lineEnding);
 | 
| -  }
 | 
| -
 | 
| -  /// Gets the results of formatting the child block of [chunk] at with
 | 
| -  /// starting [column].
 | 
| -  ///
 | 
| -  /// If that block has already been formatted, reuses the results.
 | 
| -  ///
 | 
| -  /// The column is the column for the delimiters. The contents of the block
 | 
| -  /// are always implicitly one level deeper than that.
 | 
| -  ///
 | 
| -  ///     main() {
 | 
| -  ///       function(() {
 | 
| -  ///         block;
 | 
| -  ///       });
 | 
| -  ///     }
 | 
| -  ///
 | 
| -  /// When we format the anonymous lambda, [column] will be 2, not 4.
 | 
| -  FormatResult formatBlock(Chunk chunk, int column) {
 | 
| -    var key = new _BlockKey(chunk, column);
 | 
| -
 | 
| -    // Use the cached one if we have it.
 | 
| -    var cached = _blockCache[key];
 | 
| -    if (cached != null) return cached;
 | 
| -
 | 
| -    var writer = new LineWriter._(
 | 
| -        chunk.blockChunks, _lineEnding, pageWidth, column, _blockCache);
 | 
| -
 | 
| -    // TODO(rnystrom): Passing in an initial indent here is hacky. The
 | 
| -    // LineWriter ensures all but the first chunk have a block indent, and this
 | 
| -    // handles the first chunk. Do something cleaner.
 | 
| -    var result = writer.writeLines(Indent.block, flushLeft: chunk.flushLeft);
 | 
| -    return _blockCache[key] = result;
 | 
| -  }
 | 
| -
 | 
| -  /// Takes all of the chunks and divides them into sublists and line splits
 | 
| -  /// each list.
 | 
| -  ///
 | 
| -  /// Since this is linear and line splitting is worse it's good to feed the
 | 
| -  /// line splitter smaller lists of chunks when possible.
 | 
| -  FormatResult writeLines(int firstLineIndent,
 | 
| -      {bool isCompilationUnit: false, bool flushLeft: false}) {
 | 
| -    // Now that we know what hard splits there will be, break the chunks into
 | 
| -    // independently splittable lines.
 | 
| -    var newlines = 0;
 | 
| -    var indent = firstLineIndent;
 | 
| -    var totalCost = 0;
 | 
| -    var start = 0;
 | 
| -
 | 
| -    for (var i = 0; i < _chunks.length; i++) {
 | 
| -      var chunk = _chunks[i];
 | 
| -      if (!chunk.canDivide) continue;
 | 
| -
 | 
| -      totalCost +=
 | 
| -          _completeLine(newlines, indent, start, i + 1, flushLeft: flushLeft);
 | 
| -
 | 
| -      // Get ready for the next line.
 | 
| -      newlines = chunk.isDouble ? 2 : 1;
 | 
| -      indent = chunk.indent;
 | 
| -      flushLeft = chunk.flushLeft;
 | 
| -      start = i + 1;
 | 
| -    }
 | 
| -
 | 
| -    if (start < _chunks.length) {
 | 
| -      totalCost += _completeLine(newlines, indent, start, _chunks.length,
 | 
| -          flushLeft: flushLeft);
 | 
| -    }
 | 
| -
 | 
| -    // Be a good citizen, end with a newline.
 | 
| -    if (isCompilationUnit) _buffer.write(_lineEnding);
 | 
| -
 | 
| -    return new FormatResult(
 | 
| -        _buffer.toString(), totalCost, _selectionStart, _selectionEnd);
 | 
| -  }
 | 
| -
 | 
| -  /// Takes the first [length] of the chunks with leading [indent], removes
 | 
| -  /// them, and runs the [LineSplitter] on them.
 | 
| -  int _completeLine(int newlines, int indent, int start, int end,
 | 
| -      {bool flushLeft}) {
 | 
| -    // Write the newlines required by the previous line.
 | 
| -    for (var j = 0; j < newlines; j++) {
 | 
| -      _buffer.write(_lineEnding);
 | 
| -    }
 | 
| -
 | 
| -    var chunks = _chunks.sublist(start, end);
 | 
| -
 | 
| -    if (debug.traceLineWriter) {
 | 
| -      debug.log(debug.green("\nWriting:"));
 | 
| -      debug.dumpChunks(start, chunks);
 | 
| -      debug.log();
 | 
| -    }
 | 
| -
 | 
| -    // Run the line splitter.
 | 
| -    var splitter = new LineSplitter(this, chunks, _blockIndentation, indent,
 | 
| -        flushLeft: flushLeft);
 | 
| -    var splits = splitter.apply();
 | 
| -
 | 
| -    // Write the indentation of the first line.
 | 
| -    if (!flushLeft) {
 | 
| -      _buffer.write(" " * (indent + _blockIndentation));
 | 
| -    }
 | 
| -
 | 
| -    // Write each chunk with the appropriate splits between them.
 | 
| -    for (var i = 0; i < chunks.length; i++) {
 | 
| -      var chunk = chunks[i];
 | 
| -      _writeChunk(chunk);
 | 
| -
 | 
| -      if (chunk.blockChunks.isNotEmpty) {
 | 
| -        if (!splits.shouldSplitAt(i)) {
 | 
| -          // This block didn't split (which implies none of the child blocks
 | 
| -          // of that block split either, recursively), so write them all inline.
 | 
| -          _writeChunksUnsplit(chunk.blockChunks);
 | 
| -        } else {
 | 
| -          // Include the formatted block contents.
 | 
| -          var block = formatBlock(chunk, splits.getColumn(i));
 | 
| -
 | 
| -          // If this block contains one of the selection markers, tell the
 | 
| -          // writer where it ended up in the final output.
 | 
| -          if (block.selectionStart != null) {
 | 
| -            _selectionStart = length + block.selectionStart;
 | 
| -          }
 | 
| -
 | 
| -          if (block.selectionEnd != null) {
 | 
| -            _selectionEnd = length + block.selectionEnd;
 | 
| -          }
 | 
| -
 | 
| -          _buffer.write(block.text);
 | 
| -        }
 | 
| -      }
 | 
| -
 | 
| -      if (i == chunks.length - 1) {
 | 
| -        // Don't write trailing whitespace after the last chunk.
 | 
| -      } else if (splits.shouldSplitAt(i)) {
 | 
| -        _buffer.write(_lineEnding);
 | 
| -        if (chunk.isDouble) _buffer.write(_lineEnding);
 | 
| -
 | 
| -        _buffer.write(" " * (splits.getColumn(i)));
 | 
| -      } else {
 | 
| -        if (chunk.spaceWhenUnsplit) _buffer.write(" ");
 | 
| -      }
 | 
| -    }
 | 
| -
 | 
| -    return splits.cost;
 | 
| -  }
 | 
| -
 | 
| -  /// Writes [chunks] (and any child chunks of them, recursively) without any
 | 
| -  /// splitting.
 | 
| -  void _writeChunksUnsplit(List<Chunk> chunks) {
 | 
| -    for (var chunk in chunks) {
 | 
| -      _writeChunk(chunk);
 | 
| -
 | 
| -      if (chunk.spaceWhenUnsplit) _buffer.write(" ");
 | 
| -
 | 
| -      // Recurse into the block.
 | 
| -      _writeChunksUnsplit(chunk.blockChunks);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  /// Writes [chunk] to the output and updates the selection if the chunk
 | 
| -  /// contains a selection marker.
 | 
| -  void _writeChunk(Chunk chunk) {
 | 
| -    if (chunk.selectionStart != null) {
 | 
| -      _selectionStart = length + chunk.selectionStart;
 | 
| -    }
 | 
| -
 | 
| -    if (chunk.selectionEnd != null) {
 | 
| -      _selectionEnd = length + chunk.selectionEnd;
 | 
| -    }
 | 
| -
 | 
| -    _buffer.write(chunk.text);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/// Key type for the formatted block cache.
 | 
| -///
 | 
| -/// To cache formatted blocks, we just need to know which block it is (the
 | 
| -/// index of its parent chunk) and how far it was indented when we formatted it
 | 
| -/// (the starting column).
 | 
| -class _BlockKey {
 | 
| -  /// The index of the chunk in the surrounding chunk list that contains this
 | 
| -  /// block.
 | 
| -  final Chunk chunk;
 | 
| -
 | 
| -  /// The absolute zero-based column number where the block starts.
 | 
| -  final int column;
 | 
| -
 | 
| -  _BlockKey(this.chunk, this.column);
 | 
| -
 | 
| -  bool operator ==(other) {
 | 
| -    if (other is! _BlockKey) return false;
 | 
| -    return chunk == other.chunk && column == other.column;
 | 
| -  }
 | 
| -
 | 
| -  int get hashCode => chunk.hashCode ^ column.hashCode;
 | 
| -}
 | 
| -
 | 
| -/// The result of formatting a series of chunks.
 | 
| -class FormatResult {
 | 
| -  /// The resulting formatted text, including newlines and leading whitespace
 | 
| -  /// to reach the proper column.
 | 
| -  final String text;
 | 
| -
 | 
| -  /// The numeric cost of the chosen solution.
 | 
| -  final int cost;
 | 
| -
 | 
| -  /// Where in the resulting buffer the selection starting point should appear
 | 
| -  /// if it was contained within this split list of chunks.
 | 
| -  ///
 | 
| -  /// Otherwise, this is `null`.
 | 
| -  final int selectionStart;
 | 
| -
 | 
| -  /// Where in the resulting buffer the selection end point should appear if it
 | 
| -  /// was contained within this split list of chunks.
 | 
| -  ///
 | 
| -  /// Otherwise, this is `null`.
 | 
| -  final int selectionEnd;
 | 
| -
 | 
| -  FormatResult(this.text, this.cost, this.selectionStart, this.selectionEnd);
 | 
| -}
 | 
| 
 |