anchor.diff:        prevBlock = block;
   
         if (block is Para) {
  -        result.write(writePara(block));
  +        writePara(block);
         } else if (block is Header) {
  -        result.write(writeHeader(block));
  +        writeHeader(block);
         } else if (block is HorizontalRule) {
  -        result.write(writeHorizontalRule(block, unorderedListChar));
  +        writeHorizontalRule(block, unorderedListChar);
         } else if (block is CodeBlock) {
           if (_b is ListBlock) {
  -          result.write('\n');
  +          write('\n');
           }
  -        result.write(writeCodeBlock(block));
  +        writeCodeBlock(block);
         } else if (block is Blockquote) {
  -        result.write(writeBlockquote(block));
  +        writeBlockquote(block);
         } else if (block is RawBlock) {
  -        result.write(block.contents);
  -        result.write("\n");
  +        write(block.contents);
  +        write("\n");
         } else if (block is UnorderedList) {
  -        result.write(writeUnorderedList(block, prevBlock: _b));
  +        writeUnorderedList(block, prevBlock: _b);
         } else if (block is OrderedList) {
  -        result.write(writeOrderedList(block, prevBlock: _b));
  +        writeOrderedList(block, prevBlock: _b);
         } else {
           throw new UnimplementedError(block.toString());
         }
       }
  -
  -    return result.toString();
  -  }
  -
  -  String writeHorizontalRule(HorizontalRule hRule, [String unorderedListChar = "*"]) {
  +  }
  +
  +
  +  void writeHorizontalRule(HorizontalRule hRule, [String unorderedListChar = "*"]) {
       if (unorderedListChar == "-") {
  -      return '*' * 10;
  -    }
  -    return '-' * 10;
  -  }
  -
  -  String writePara(Para para) {
  -    return writeInlines(para.contents) + "\n";
  -  }
  -
  -  String writeBlockquote(Blockquote blockquote) {
  -    String contents = writeBlocks(blockquote.contents);
  +      write('*' * 10);
  +    } else {
  +      write('-' * 10);
  +    }
  +  }
  +
  +
  +  void writePara(Para para) {
  +    writeInlines(para.contents);
  +    write("\n");
  +  }
  +
  +
  +  void writeBlockquote(Blockquote blockquote) {
  +    _MarkdownBuilder inner = new _MarkdownBuilder(_references);
  +    inner.writeBlocks(blockquote.contents);
  +    String contents = inner.toString();
       if (contents.endsWith('\n')) {
         contents = contents.substring(0, contents.length - 1);
       }
  -    return contents.splitMapJoin("\n", onNonMatch: (String str) => "> $str") + "\n";
  -  }
  -
  -  String writeHeader(Header header) {
  -    String inlines = writeInlines(header.contents);
  +    write(contents.splitMapJoin("\n", onNonMatch: (String str) => "> $str") + "\n");
  +  }
  +
  +
  +  void writeHeader(Header header) {
       if (header is SetextHeader && header.level == 2) {
  -      return inlines + "\n" + (header.level == 1 ? '=' : '-') * inlines.length + "\n";
  -    }
  -    return "#" * header.level + " " + inlines + "\n";
  -  }
  -
  -  String writeCodeBlock(CodeBlock codeBlock) {
  +      _MarkdownBuilder inner = new _MarkdownBuilder(_references);
  +      inner.writeInlines(header.contents);
  +      String inlines = inner.toString();
  +      write(inlines);
  +      write("\n");
  +      write((header.level == 1 ? '=' : '-') * inlines.length + "\n");
  +      return;
  +    }
  +    write("#" * header.level + " ");
  +    writeInlines(header.contents);
  +    write("\n");
  +  }
  +
  +
  +  void writeCodeBlock(CodeBlock codeBlock) {
       if (codeBlock is FencedCodeBlock) {
         String fence = (codeBlock.fenceType == FenceType.BacktickFence ? '`' : '~') * codeBlock.fenceSize;
  -      String result = fence;
  +      write(fence);
         if (codeBlock.attributes is InfoString) {
  -        result += ' ${codeBlock.attributes.language}';
  -      }
  -      result += '\n${codeBlock.contents}${fence}\n';
  -      return result;
  -    }
  +        write(' ${codeBlock.attributes.language}');
  +      }
  +      write("\n");
  +      write(codeBlock.contents);
  +      write(fence);
  +      write('\n');
  +      return;
  +    }
  +
       // Indented code block
  -    return codeBlock.contents.splitMapJoin("\n", onNonMatch: (str) => str == "" ? str : "    " + str);
  -  }
  -
  -  String writeUnorderedList(UnorderedList list, {Block prevBlock: null}) {
  -    String result = "";
  +    write(codeBlock.contents.splitMapJoin("\n", onNonMatch: (str) => str == "" ? str : "    " + str));
  +  }
  +
  +
  +  void writeUnorderedList(UnorderedList list, {Block prevBlock: null}) {
       if (prevBlock is UnorderedList && prevBlock.bulletType == list.bulletType) {
  -      result += "\n";
  -    }
  -
  -    Iterable<String> items = list.items.map((ListItem listItem) {
  +      write("\n");
  +    }
  +
  +    Iterator<ListItem> it = list.items.iterator;
  +    bool first = true;
  +    bool tight = list.tight;
  +    while (it.moveNext()) {
  +      if (first) {
  +        first = false;
  +      } else if (!tight) {
  +        write("\n");
  +      }
  +
  +      ListItem listItem = it.current;
  +      _MarkdownBuilder builder = new _MarkdownBuilder(_references);
  +      builder.writeBlocks(listItem.contents, tight: list.tight, unorderedListChar: list.bulletType.char);
  +      String contents = builder.toString();
  +      String marker = list.bulletType.char + " ";
         String pad;
  -      String contents = writeBlocks(listItem.contents, tight: list.tight, unorderedListChar: list.bulletType.char);
  -
  -      return contents.splitMapJoin("\n", onNonMatch: (String str) {
  -        if (pad == null) {
  -          String marker = list.bulletType.char + " ";
  +
  +      write(marker);
  +
  +      write(contents.splitMapJoin("\n", onNonMatch: (String str) {
  +        if (pad == null) { // First
             pad = " " * marker.length;
  -          return marker + str;
  +          return str;
           } else if (str != "") {
             return pad + str;
           }
           return str;
  -      });
  -    });
  -
  -    return result + items.join(list.tight ? "" : "\n");
  -  }
  -
  -  String writeOrderedList(OrderedList list, {Block prevBlock: null}) {
  -    String result = "";
  +      }));
  +    }
  +  }
  +
  +
  +  void writeOrderedList(OrderedList list, {Block prevBlock: null}) {
       if (prevBlock is OrderedList && prevBlock.indexSeparator == list.indexSeparator) {
  -      result += "\n";
  +      write("\n");
       }
       int index = list.startIndex;
  -    Iterable<String> items = list.items.map((ListItem listItem) {
  +    Iterator<ListItem> it = list.items.iterator;
  +    bool first = true;
  +    bool tight = list.tight;
  +    while (it.moveNext()) {
  +      if (first) {
  +        first = false;
  +      } else if (!tight) {
  +        write("\n");
  +      }
  +
  +      ListItem listItem = it.current;
  +      _MarkdownBuilder builder = new _MarkdownBuilder(_references);
  +      builder.writeBlocks(listItem.contents, tight: list.tight);
  +      String contents = builder.toString();
         String pad;
  -      String contents = writeBlocks(listItem.contents, tight: list.tight);
  -      return contents.splitMapJoin("\n", onNonMatch: (String str) {
  +
  +      write(contents.splitMapJoin("\n", onNonMatch: (String str) {
           if (pad == null) {
             String marker = index.toString() + list.indexSeparator.char + " ";
             pad = " " * marker.length;
  
positive.code: 
  import 'definitions.dart';
  
  // TODO make all members private
  class MarkdownWriter {
    Map<String, Target> _references;
    String write(Document document) {
      _references = <String, Target>{};
      var blocks = writeBlocks(document.contents) + "\n\n";
      return blocks + _writeReferences();
    }
  
    String writeBlocks(Iterable<Block> blocks,
                       {bool tight: false, String unorderedListChar: "*"}) {
  
      StringBuffer result = new StringBuffer();
  
      Block prevBlock = null;
      Iterator<Block> it = blocks.iterator;
      bool first = true;
  
negative.code:       if (first) {
          first = false;
        } else if (!tight) {
          write("\n");
        }
  
        Block block = it.current;
  