           unless element.parentNode.firstChild is element
             @appendStringWithAttributes(" ")
 
-
   appendBlockForAttributes: (attributes, element) ->
-    @text = new Trix.Text
-    block = new Trix.Block @text, attributes
+    @blockElements.push(element)
+    block = blockForAttributes(attributes)
     @blocks.push(block)
-    @blockElements.push(element)
     block
 
   appendStringWithAttributes: (string, attributes) ->
-    text = Trix.Text.textForStringWithAttributes(string, attributes)
-    @appendText(text)
-
-  appendAttachmentForAttributes: (attributes, textAttributes) ->
-    attachment = Trix.Attachment.attachmentForAttributes(attributes)
-    text = Trix.Text.textForAttachmentWithAttributes(attachment, textAttributes)
-    @appendText(text)
-
-  appendText: (text) ->
+    @appendPiece(pieceForString(string, attributes))
+
+  appendAttachmentForAttributes: (attachment, attributes) ->
+    @appendPiece(pieceForAttachment(attachment, attributes))
+
+  appendPiece: (piece) ->
     if @blocks.length is 0
       @appendBlockForAttributes({})
-
-    @text = @text.appendText(text)
-    index = @blocks.length - 1
-    @replaceTextForBlockAtIndex(@text, index)
-
-  replaceTextForBlockAtIndex: (text, index) ->
-    block = @blocks[index]
-    @blocks[index] = block.copyWithText(text)
+    @blocks[@blocks.length - 1].text.push(piece)
+
+  appendStringToTextAtIndex: (string, index) ->
+    {text} = @blocks[index]
+    piece = text[text.length - 1]
+
+    if piece?.type is "string"
+      piece.string += string
+    else
+      text.push(pieceForString(string))
+
+  prependStringToTextAtIndex: (string, index) ->
+    {text} = @blocks[index]
+    piece = text[0]
+
+    if piece?.type is "string"
+      piece.string = string + piece.string
+    else
+      text.unshift(pieceForString(string))
 
   getMarginOfBlockElementAtIndex: (index) ->
     if element = @blockElements[index]

  appendBlockForElement: (element) ->
    if @isBlockElement(element) and not @isBlockElement(element.firstChild)
      attributes = getBlockAttributes(element)
      unless elementContainsNode(@currentBlockElement, element) and arraysAreEqual(attributes, @currentBlock.getAttributes())
        @currentBlock = @appendBlockForAttributes(attributes, element)
        @currentBlockElement = element


    @blockElements = []
    @processedElements = []

  getDocument: ->
    Trix.Document.fromJSON(@blocks)

  parse: benchmark "HTMLParser#parse", ->
    try
      @createHiddenContainer()
      html = sanitizeHTML(@html)
