       new Range(first.start, last.end)
     else
       new Range(first.end, last.start).translate([0, -1], [0, +1])
-    #   [first.end, last.start]
     blockwiseSelection.setBufferRange(range)
-
-  duplicateCharacterwise: (blockwiseSelection) ->
-    @duplicateBlockwiseSelection(blockwiseSelection, @direction)
 
 class DuplicateSelectedTextDown extends DuplicateSelectedTextUp
   direction: 'down'
 
 class DuplicateSelectedTextRight extends DuplicateSelectedText
   direction: 'right'
-  duplicateCharacterwise: (selection) ->
-    newText = selection.getText().repeat(@getCount())
+  duplicateCharacterwise: (selection, count) ->
+    newText = selection.getText().repeat(count)
     width = newText.length
     {start, end} = selection.getBufferRange()
     range = switch @direction

# Duplicate
# -------------------------
class DuplicateSelectedText extends MoveSelectedText
  execute: ->
    selections = @editor.getSelectionsOrderedByBufferPosition()
    selections.reverse() if @direction in ['down', 'up']

    @editor.transact =>
      if @isLinewise()
        for selection in selections
          if @vimState.submode is 'linewise'
            @duplicateLinewise(selection)
          else
            swrap(selection).switchToLinewise =>
              @duplicateLinewise(selection)
      else
        switch @direction
          when 'right', 'left'
            for selection in selections
              @duplicateCharacterwise(selection)
          when 'up', 'down'
            for blockwiseSelection in @vimState.getBlockwiseSelections()
              @duplicateCharacterwise(blockwiseSelection)

  # Can move to util
  duplicateLinewiseText: (rows, direction, count) ->
    switch direction
      when 'up', 'down' then _.flatten([1..count].map -> rows)
      when 'left', 'right' then rows.map (text) -> text.repeat(count)

  duplicateLinewise: (selection) ->
    count = @getCount()
    count += 1 if @direction in ['left', 'right']
    {start, end} = selection.getBufferRange()
    rows = swrap(selection).lineTextForBufferRows()
    if @direction is 'up' and @isOverwrite()
      count = Math.min(count, Math.floor(start.row / rows.length))
      return unless count > 0
    lineTexts = @duplicateLinewiseText(rows, @direction, count)
    height = lineTexts.length
    newText = lineTexts.join("\n") + "\n"

    range = switch @direction
      when 'up'
        start = end = start
        start = start.translate([-height, 0]) if @isOverwrite()
        new Range(start, end)
      when 'down'
        start = end = end
        end = end.translate([+height, 0]) if @isOverwrite()
        new Range(start, end)
      when 'left', 'right'
        selection.getBufferRange()
    @setTextInRangeAndSelect(range, newText, selection)

class DuplicateSelectedTextUp extends DuplicateSelectedText
  direction: 'up'
  duplicateBlockwiseSelection: (blockwiseSelection, direction) ->
    {selections} = blockwiseSelection
    height = selections.length

    count = @getCount()
    unless @isOverwrite() # Insert Blank row
      [startRow, endRow] = blockwiseSelection.getBufferRowRange()
      point = switch direction
        when 'up' then [startRow - 1, Infinity]
        when 'down' then [endRow + 1, 0]
      @insertTextAtPoint(point, "\n".repeat(height * count))

        when 'down' then [+height * count, 0]

    ranges = []
    for num in [1..count]
      selections.forEach (selection) =>
        translation = getTranslation(@direction, num)
        range = selection.getBufferRange().translate(translation)
        @complementSpacesToPoint(range.start)
        ranges.push @editor.setTextInBufferRange(range, selection.getText())
