]> git.r.bdr.sh - rbdr/dotfiles/blobdiff - atom/packages/vim-mode/spec/text-objects-spec.coffee
Update vim plugins
[rbdr/dotfiles] / atom / packages / vim-mode / spec / text-objects-spec.coffee
index 6991dc7e055f1a36a72614ef6206edf218ed7b15..92b4a7a67dea616516b422c3b7c0ff1fe6b4d3e5 100644 (file)
@@ -11,15 +11,23 @@ describe "TextObjects", ->
       editorElement = element
       editor = editorElement.getModel()
       vimState = editorElement.vimState
       editorElement = element
       editor = editorElement.getModel()
       vimState = editorElement.vimState
-      vimState.activateCommandMode()
-      vimState.resetCommandMode()
+      vimState.activateNormalMode()
+      vimState.resetNormalMode()
 
   keydown = (key, options={}) ->
     options.element ?= editorElement
     helpers.keydown(key, options)
 
 
   keydown = (key, options={}) ->
     options.element ?= editorElement
     helpers.keydown(key, options)
 
-  commandModeInputKeydown = (key, opts = {}) ->
-    editor.commandModeInputView.editorElement.getModel().setText(key)
+  describe "Text Object commands in normal mode not preceded by an operator", ->
+    beforeEach ->
+      vimState.activateNormalMode()
+
+    it "selects the appropriate text", ->
+      editor.setText("<html> text </html>")
+      editor.setCursorScreenPosition([0, 7])
+      # Users could dispatch it via the command palette
+      atom.commands.dispatch(editorElement, "vim-mode:select-inside-tags")
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 12]]
 
   describe "the 'iw' text object", ->
     beforeEach ->
 
   describe "the 'iw' text object", ->
     beforeEach ->
@@ -35,7 +43,7 @@ describe "TextObjects", ->
       expect(editor.getCursorScreenPosition()).toEqual [0, 6]
       expect(vimState.getRegister('"').text).toBe "abcde"
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getCursorScreenPosition()).toEqual [0, 6]
       expect(vimState.getRegister('"').text).toBe "abcde"
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "selects inside the current word in visual mode", ->
       keydown('v')
 
     it "selects inside the current word in visual mode", ->
       keydown('v')
@@ -44,6 +52,16 @@ describe "TextObjects", ->
 
       expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 11]]
 
 
       expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 11]]
 
+    it "expands an existing selection in visual mode", ->
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('w')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 9], [0, 17]]
+
     it "works with multiple cursors", ->
       editor.addCursorAtBufferPosition([0, 1])
       keydown("v")
     it "works with multiple cursors", ->
       editor.addCursorAtBufferPosition([0, 1])
       keydown("v")
@@ -54,6 +72,39 @@ describe "TextObjects", ->
         [[0, 0], [0, 5]]
       ]
 
         [[0, 0], [0, 5]]
       ]
 
+  describe "the 'iW' text object", ->
+    beforeEach ->
+      editor.setText("12(45 ab'de ABCDE")
+      editor.setCursorScreenPosition([0, 9])
+
+    it "applies operators inside the current whole word in operator-pending mode", ->
+      keydown('d')
+      keydown('i')
+      keydown('W', shift: true)
+
+      expect(editor.getText()).toBe "12(45  ABCDE"
+      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      expect(vimState.getRegister('"').text).toBe "ab'de"
+      expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "selects inside the current whole word in visual mode", ->
+      keydown('v')
+      keydown('i')
+      keydown('W', shift: true)
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 11]]
+
+    it "expands an existing selection in visual mode", ->
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('W', shift: true)
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 9], [0, 17]]
+
   describe "the 'i(' text object", ->
     beforeEach ->
       editor.setText("( something in here and in (here) )")
   describe "the 'i(' text object", ->
     beforeEach ->
       editor.setText("( something in here and in (here) )")
@@ -66,7 +117,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "()"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "()"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -76,7 +127,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "( something in here and in () )"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "( something in here and in () )"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "works with multiple cursors", ->
       editor.setText("( a b ) cde ( f g h ) ijk")
 
     it "works with multiple cursors", ->
       editor.setText("( a b ) cde ( f g h ) ijk")
@@ -92,6 +143,18 @@ describe "TextObjects", ->
         [[0, 13], [0, 20]]
       ]
 
         [[0, 13], [0, 20]]
       ]
 
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('(')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 32]]
+
   describe "the 'i{' text object", ->
     beforeEach ->
       editor.setText("{ something in here and in {here} }")
   describe "the 'i{' text object", ->
     beforeEach ->
       editor.setText("{ something in here and in {here} }")
@@ -104,7 +167,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "{}"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "{}"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -114,7 +177,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "{ something in here and in {} }"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "{ something in here and in {} }"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('{')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 32]]
 
   describe "the 'i<' text object", ->
     beforeEach ->
 
   describe "the 'i<' text object", ->
     beforeEach ->
@@ -128,7 +203,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "<>"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "<>"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -138,7 +213,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "< something in here and in <> >"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "< something in here and in <> >"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('<')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 32]]
 
   describe "the 'it' text object", ->
     beforeEach ->
 
   describe "the 'it' text object", ->
     beforeEach ->
@@ -152,7 +239,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "<something>here</something><again>"
       expect(editor.getCursorScreenPosition()).toEqual [0, 5]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "<something>here</something><again>"
       expect(editor.getCursorScreenPosition()).toEqual [0, 5]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the current word in operator-pending mode", ->
       editor.setCursorScreenPosition([0, 13])
 
     it "applies operators inside the current word in operator-pending mode", ->
       editor.setCursorScreenPosition([0, 13])
@@ -162,15 +249,24 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "<something></something><again>"
       expect(editor.getCursorScreenPosition()).toEqual [0, 11]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "<something></something><again>"
       expect(editor.getCursorScreenPosition()).toEqual [0, 11]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 7])
+      keydown('v')
+      keydown('6')
+      keydown('l')
+      keydown('i')
+      keydown('t')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 7], [0, 15]]
 
   describe "the 'ip' text object", ->
     beforeEach ->
       editor.setText("\nParagraph-1\nParagraph-1\nParagraph-1\n\n")
 
   describe "the 'ip' text object", ->
     beforeEach ->
       editor.setText("\nParagraph-1\nParagraph-1\nParagraph-1\n\n")
-      editor.setCursorScreenPosition([2, 2])
+      editor.setCursorBufferPosition([2, 2])
 
     it "applies operators inside the current paragraph in operator-pending mode", ->
 
     it "applies operators inside the current paragraph in operator-pending mode", ->
-
       keydown('y')
       keydown('i')
       keydown('p')
       keydown('y')
       keydown('i')
       keydown('p')
@@ -179,7 +275,7 @@ describe "TextObjects", ->
       expect(editor.getCursorScreenPosition()).toEqual [1, 0]
       expect(vimState.getRegister('"').text).toBe "Paragraph-1\nParagraph-1\nParagraph-1\n"
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getCursorScreenPosition()).toEqual [1, 0]
       expect(vimState.getRegister('"').text).toBe "Paragraph-1\nParagraph-1\nParagraph-1\n"
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "selects inside the current paragraph in visual mode", ->
       keydown('v')
 
     it "selects inside the current paragraph in visual mode", ->
       keydown('v')
@@ -188,30 +284,105 @@ describe "TextObjects", ->
 
       expect(editor.getSelectedScreenRange()).toEqual [[1, 0], [4, 0]]
 
 
       expect(editor.getSelectedScreenRange()).toEqual [[1, 0], [4, 0]]
 
+    it "selects between paragraphs in visual mode if invoked on a empty line", ->
+      editor.setText("text\n\n\n\ntext\n")
+      editor.setCursorBufferPosition([1, 0])
+
+      keydown('v')
+      keydown('i')
+      keydown('p')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[1, 0], [4, 0]]
+
+    it "selects all the lines", ->
+      editor.setText("text\ntext\ntext\n")
+      editor.setCursorBufferPosition([0, 0])
+
+      keydown('v')
+      keydown('i')
+      keydown('p')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 0], [3, 0]]
+
+    it "expands an existing selection in visual mode", ->
+      editor.setText("\nParagraph-1\nParagraph-1\nParagraph-1\n\n\nParagraph-2\nParagraph-2\nParagraph-2\n")
+      editor.setCursorBufferPosition([2, 2])
+
+      keydown('v')
+      keydown('i')
+      keydown('p')
+
+      keydown('j')
+      keydown('j')
+      keydown('j')
+      keydown('i')
+      keydown('p')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[1, 0], [9, 0]]
+
   describe "the 'ap' text object", ->
     beforeEach ->
   describe "the 'ap' text object", ->
     beforeEach ->
-      editor.setText("text\n\nParagraph-1\nParagraph-1\nParagraph-1\n\nmoretext")
+      editor.setText("text\n\nParagraph-1\nParagraph-1\nParagraph-1\n\n\nmoretext")
       editor.setCursorScreenPosition([3, 2])
 
     it "applies operators around the current paragraph in operator-pending mode", ->
       editor.setCursorScreenPosition([3, 2])
 
     it "applies operators around the current paragraph in operator-pending mode", ->
-
       keydown('y')
       keydown('a')
       keydown('p')
 
       keydown('y')
       keydown('a')
       keydown('p')
 
-      expect(editor.getText()).toBe "text\n\nParagraph-1\nParagraph-1\nParagraph-1\n\nmoretext"
+      expect(editor.getText()).toBe "text\n\nParagraph-1\nParagraph-1\nParagraph-1\n\n\nmoretext"
       expect(editor.getCursorScreenPosition()).toEqual [2, 0]
       expect(editor.getCursorScreenPosition()).toEqual [2, 0]
-      expect(vimState.getRegister('"').text).toBe "Paragraph-1\nParagraph-1\nParagraph-1\n\n"
+      expect(vimState.getRegister('"').text).toBe "Paragraph-1\nParagraph-1\nParagraph-1\n\n\n"
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "selects around the current paragraph in visual mode", ->
       keydown('v')
       keydown('a')
       keydown('p')
 
 
     it "selects around the current paragraph in visual mode", ->
       keydown('v')
       keydown('a')
       keydown('p')
 
-      expect(editor.getSelectedScreenRange()).toEqual [[2, 0], [6, 0]]
-      
+      expect(editor.getSelectedScreenRange()).toEqual [[2, 0], [7, 0]]
+
+    it "applies operators around the next paragraph in operator-pending mode when started from a blank/only-whitespace line", ->
+      editor.setText("text\n\n\n\nParagraph-1\nParagraph-1\nParagraph-1\n\n\nmoretext")
+      editor.setCursorBufferPosition([1, 0])
+
+      keydown('y')
+      keydown('a')
+      keydown('p')
+
+      expect(editor.getText()).toBe "text\n\n\n\nParagraph-1\nParagraph-1\nParagraph-1\n\n\nmoretext"
+      expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+      expect(vimState.getRegister('"').text).toBe "\n\n\nParagraph-1\nParagraph-1\nParagraph-1\n"
+      expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "selects around the next paragraph in visual mode when started from a blank/only-whitespace line", ->
+      editor.setText("text\n\n\n\nparagraph-1\nparagraph-1\nparagraph-1\n\n\nmoretext")
+      editor.setCursorBufferPosition([1, 0])
+
+      keydown('v')
+      keydown('a')
+      keydown('p')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[1, 0], [7, 0]]
+
+    it "expands an existing selection in visual mode", ->
+      editor.setText("text\n\n\n\nparagraph-1\nparagraph-1\nparagraph-1\n\n\n\nparagraph-2\nparagraph-2\nparagraph-2\n\n\nmoretext")
+      editor.setCursorBufferPosition([5, 0])
+
+      keydown('v')
+      keydown('a')
+      keydown('p')
+
+      keydown('j')
+      keydown('j')
+      keydown('j')
+      keydown('i')
+      keydown('p')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[4, 0], [13, 0]]
+
   describe "the 'i[' text object", ->
     beforeEach ->
       editor.setText("[ something in here and in [here] ]")
   describe "the 'i[' text object", ->
     beforeEach ->
       editor.setText("[ something in here and in [here] ]")
@@ -224,7 +395,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "[]"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "[]"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators inside the current word in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -234,7 +405,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "[ something in here and in [] ]"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "[ something in here and in [] ]"
       expect(editor.getCursorScreenPosition()).toEqual [0, 28]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('[')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 32]]
 
   describe "the 'i\'' text object", ->
     beforeEach ->
 
   describe "the 'i\'' text object", ->
     beforeEach ->
@@ -248,7 +431,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "''here' ' and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "''here' ' and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the next string in operator-pending mode (if not in a string)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators inside the next string in operator-pending mode (if not in a string)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -258,7 +441,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "' something in here and in 'here'' and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 33]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "' something in here and in 'here'' and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 33]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "makes no change if past the last string on a line", ->
       editor.setCursorScreenPosition([0, 39])
 
     it "makes no change if past the last string on a line", ->
       editor.setCursorScreenPosition([0, 39])
@@ -268,7 +451,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "' something in here and in 'here' ' and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 39]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "' something in here and in 'here' ' and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 39]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('\'')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 34]]
 
   describe "the 'i\"' text object", ->
     beforeEach ->
 
   describe "the 'i\"' text object", ->
     beforeEach ->
@@ -282,7 +477,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "\"\"here\" \" and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "\"\"here\" \" and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 1]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators inside the next string in operator-pending mode (if not in a string)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators inside the next string in operator-pending mode (if not in a string)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -292,7 +487,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "\" something in here and in \"here\"\" and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 33]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "\" something in here and in \"here\"\" and over here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 33]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "makes no change if past the last string on a line", ->
       editor.setCursorScreenPosition([0, 39])
 
     it "makes no change if past the last string on a line", ->
       editor.setCursorScreenPosition([0, 39])
@@ -303,6 +498,18 @@ describe "TextObjects", ->
       expect(editor.getCursorScreenPosition()).toEqual [0, 39]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
 
       expect(editor.getCursorScreenPosition()).toEqual [0, 39]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
 
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('i')
+      keydown('"')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 34]]
+
   describe "the 'aw' text object", ->
     beforeEach ->
       editor.setText("12345 abcde ABCDE")
   describe "the 'aw' text object", ->
     beforeEach ->
       editor.setText("12345 abcde ABCDE")
@@ -317,7 +524,7 @@ describe "TextObjects", ->
       expect(editor.getCursorScreenPosition()).toEqual [0, 6]
       expect(vimState.getRegister('"').text).toBe "abcde "
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getCursorScreenPosition()).toEqual [0, 6]
       expect(vimState.getRegister('"').text).toBe "abcde "
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "selects from the start of the current word to the start of the next word in visual mode", ->
       keydown('v')
 
     it "selects from the start of the current word to the start of the next word in visual mode", ->
       keydown('v')
@@ -326,6 +533,17 @@ describe "TextObjects", ->
 
       expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 12]]
 
 
       expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 12]]
 
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 2])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('w')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 2], [0, 12]]
+
     it "doesn't span newlines", ->
       editor.setText("12345\nabcde ABCDE")
       editor.setCursorBufferPosition([0, 3])
     it "doesn't span newlines", ->
       editor.setText("12345\nabcde ABCDE")
       editor.setCursorBufferPosition([0, 3])
@@ -336,6 +554,60 @@ describe "TextObjects", ->
 
       expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 5]]]
 
 
       expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 5]]]
 
+    it "doesn't span special characters", ->
+      editor.setText("1(345\nabcde ABCDE")
+      editor.setCursorBufferPosition([0, 3])
+
+      keydown("v")
+      keydown("a")
+      keydown("w")
+
+      expect(editor.getSelectedBufferRanges()).toEqual [[[0, 2], [0, 5]]]
+
+  describe "the 'aW' text object", ->
+    beforeEach ->
+      editor.setText("12(45 ab'de ABCDE")
+      editor.setCursorScreenPosition([0, 9])
+
+    it "applies operators from the start of the current whole word to the start of the next whole word in operator-pending mode", ->
+      keydown('d')
+      keydown('a')
+      keydown('W', shift: true)
+
+      expect(editor.getText()).toBe "12(45 ABCDE"
+      expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+      expect(vimState.getRegister('"').text).toBe "ab'de "
+      expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "selects from the start of the current whole word to the start of the next whole word in visual mode", ->
+      keydown('v')
+      keydown('a')
+      keydown('W', shift: true)
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 6], [0, 12]]
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 2])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('W', shift: true)
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 2], [0, 12]]
+
+    it "doesn't span newlines", ->
+      editor.setText("12(45\nab'de ABCDE")
+      editor.setCursorBufferPosition([0, 4])
+
+      keydown('v')
+      keydown('a')
+      keydown('W', shift: true)
+
+      expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [0, 5]]]
+
   describe "the 'a(' text object", ->
     beforeEach ->
       editor.setText("( something in here and in (here) )")
   describe "the 'a(' text object", ->
     beforeEach ->
       editor.setText("( something in here and in (here) )")
@@ -348,7 +620,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators around the current parentheses in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators around the current parentheses in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -358,7 +630,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "( something in here and in  )"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "( something in here and in  )"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('(')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 33]]
 
   describe "the 'a{' text object", ->
     beforeEach ->
 
   describe "the 'a{' text object", ->
     beforeEach ->
@@ -372,7 +656,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators around the current curly brackets in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators around the current curly brackets in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -382,7 +666,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "{ something in here and in  }"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "{ something in here and in  }"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('{')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 33]]
 
   describe "the 'a<' text object", ->
     beforeEach ->
 
   describe "the 'a<' text object", ->
     beforeEach ->
@@ -396,7 +692,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators around the current angle brackets in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators around the current angle brackets in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -406,7 +702,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "< something in here and in  >"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "< something in here and in  >"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('<')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 33]]
 
   describe "the 'a[' text object", ->
     beforeEach ->
 
   describe "the 'a[' text object", ->
     beforeEach ->
@@ -420,7 +728,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe ""
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators around the current square brackets in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators around the current square brackets in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -430,7 +738,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "[ something in here and in  ]"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "[ something in here and in  ]"
       expect(editor.getCursorScreenPosition()).toEqual [0, 27]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('[')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 33]]
 
   describe "the 'a\'' text object", ->
     beforeEach ->
 
   describe "the 'a\'' text object", ->
     beforeEach ->
@@ -444,7 +764,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "here' '"
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "here' '"
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators around the current single quotes in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators around the current single quotes in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -454,7 +774,19 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "' something in here and in 'here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 31]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "' something in here and in 'here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 31]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('\'')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 35]]
 
   describe "the 'a\"' text object", ->
     beforeEach ->
 
   describe "the 'a\"' text object", ->
     beforeEach ->
@@ -468,7 +800,7 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe 'here" "'
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe 'here" "'
       expect(editor.getCursorScreenPosition()).toEqual [0, 0]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
 
     it "applies operators around the current double quotes in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
 
     it "applies operators around the current double quotes in operator-pending mode (second test)", ->
       editor.setCursorScreenPosition([0, 29])
@@ -478,4 +810,16 @@ describe "TextObjects", ->
       expect(editor.getText()).toBe "\" something in here and in \"here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 31]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
       expect(editor.getText()).toBe "\" something in here and in \"here"
       expect(editor.getCursorScreenPosition()).toEqual [0, 31]
       expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
-      expect(editorElement.classList.contains('command-mode')).toBe(true)
+      expect(editorElement.classList.contains('normal-mode')).toBe(true)
+
+    it "expands an existing selection in visual mode", ->
+      editor.setCursorScreenPosition([0, 25])
+      keydown('v')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('l')
+      keydown('a')
+      keydown('"')
+
+      expect(editor.getSelectedScreenRange()).toEqual [[0, 25], [0, 35]]