   isOverwrite: ->
     atom.config.get('vim-mode-plus-move-selected-text.overwrite')
 
+  isLinewise: ->
+    switch @vimState.submode
+      when 'linewise' then true
+      when 'characterwise', 'blockwise'
+        @editor.getSelections().some (selection) ->
+          not swrap(selection).isSingleRow()
+
+  isCharacterwise: ->
+    not @isLinewise()
+
+  isMovable: (selection) ->
+    {start} = selection.getBufferRange()
+    switch @direction
+      when 'down', 'right' then true
+      when 'up' then start.row isnt 0
+      when 'left'
+        if @isLinewise() then true else start.column isnt 0
+
   execute: ->
     @withUndoJoin =>
       selections = @editor.getSelectionsOrderedByBufferPosition()
-      topSelection = selections[0]
+      return if @isCharacterwise() and (not @isMovable(selections[0]))
       selections.reverse() if @direction is 'down'
       @editor.transact =>
         @countTimes =>
-          return if (not @isLinewise()) and (not @isMovable(topSelection))
-          for selection in selections
-            @mutate(selection) if @isMovable(selection)
-
-  getOverwrittenBySelection: ->
+          @mutateSelections(selections)
+
+  mutateSelections: (selections) ->
+    for selection in selections when @isMovable(selection)
+      switch @direction
+        when 'down' # auto insert new linew at last row
+          endRow = selection.getBufferRange().end.row
+          if endRow >= getVimLastBufferRow(@editor)
+            eof = @editor.getEofBufferPosition()
+            @editor.setTextInBufferRange([eof, eof], "\n")
+        when 'right' # automatically append space at EOL
+          if @isCharacterwise()
+            eol = selection.getBufferRange().end
+            if pointIsAtEndOfLine(@editor, eol)
+              @editor.setTextInBufferRange([eol, eol], " ")
+
+      if @isLinewise()
+        @moveLinewise(selection)
+      else
+        @moveCharacterwise(selection)
+
+  getInitialOverwrittenBySelection: ->
     overwrittenBySelection = new Map
     isLinewise = @isLinewise()
     @editor.getSelections().forEach (selection) ->


  # Return [rotatedText, overwrittenText]
  rotateText: (text, selection, considerOverwrite=false) ->
    switch @direction
      when 'up', 'left'
        [overwritten, rest...] = text
        overwritten = @getOverwrittenForSelection(selection, overwritten) if considerOverwrite
        [[rest..., overwritten], overwritten]
      when 'down', 'right'
        [rest..., overwritten] = text
        overwritten = @getOverwrittenForSelection(selection, overwritten) if considerOverwrite
        [[overwritten, rest...], overwritten]

class MoveSelectedTextUp extends MoveSelectedText
  direction: 'up'
  flashTarget: false

  mutate: (selection) ->
    if @direction is 'down'
      endRow = selection.getBufferRange().end.row
      if endRow >= getVimLastBufferRow(@editor)
        eof = @editor.getEofBufferPosition()
        @editor.setTextInBufferRange([eof, eof], "\n")

    if @isLinewise()
      if @vimState.submode is 'linewise'
        @rotateTextForSelection(selection)
      else
        swrap(selection).switchToLinewise => @rotateTextForSelection(selection)
      @editor.scrollToCursorPosition({center: true})
    else
      @moveCharacterwise(selection)

  # Characterwise
  # -------------------------
  moveCharacterwise: (selection) ->
    reversed = selection.isReversed()
    # Pre mutate

  direction: 'right'
  flashTarget: false

  moveLinewise: (selection) ->
    # console.log @direction, "HELLO"
    switch @direction
      when 'right' then selection.indentSelectedRows()
      when 'left' then selection.outdentSelectedRows()

  moveCharacterwise: (selection) ->
    @rotateTextForSelection(selection)
    @editor.scrollToCursorPosition({center: true})

class MoveSelectedTextLeft extends MoveSelectedTextRight
  direction: 'left'
