aboutsummaryrefslogtreecommitdiff
path: root/atom/packages/vim-mode/spec
diff options
context:
space:
mode:
Diffstat (limited to 'atom/packages/vim-mode/spec')
-rw-r--r--atom/packages/vim-mode/spec/insert-mode-spec.coffee73
-rw-r--r--atom/packages/vim-mode/spec/motions-spec.coffee371
-rw-r--r--atom/packages/vim-mode/spec/operators-spec.coffee754
-rw-r--r--atom/packages/vim-mode/spec/prefixes-spec.coffee38
-rw-r--r--atom/packages/vim-mode/spec/scroll-spec.coffee112
-rw-r--r--atom/packages/vim-mode/spec/spec-helper.coffee12
-rw-r--r--atom/packages/vim-mode/spec/text-objects-spec.coffee430
-rw-r--r--atom/packages/vim-mode/spec/vim-mode-spec.coffee19
-rw-r--r--atom/packages/vim-mode/spec/vim-state-spec.coffee231
9 files changed, 1690 insertions, 350 deletions
diff --git a/atom/packages/vim-mode/spec/insert-mode-spec.coffee b/atom/packages/vim-mode/spec/insert-mode-spec.coffee
new file mode 100644
index 0000000..061cb50
--- /dev/null
+++ b/atom/packages/vim-mode/spec/insert-mode-spec.coffee
@@ -0,0 +1,73 @@
+helpers = require './spec-helper'
+
+describe "Insert mode commands", ->
+ [editor, editorElement, vimState] = []
+
+ beforeEach ->
+ vimMode = atom.packages.loadPackage('vim-mode')
+ vimMode.activateResources()
+
+ helpers.getEditorElement (element) ->
+ editorElement = element
+ editor = editorElement.getModel()
+ vimState = editorElement.vimState
+ vimState.activateNormalMode()
+ vimState.resetNormalMode()
+
+ keydown = (key, options={}) ->
+ options.element ?= editorElement
+ helpers.keydown(key, options)
+
+ describe "Copy from line above/below", ->
+ beforeEach ->
+ editor.setText("12345\n\nabcd\nefghi")
+ editor.setCursorBufferPosition([1, 0])
+ editor.addCursorAtBufferPosition([3, 0])
+ keydown 'i'
+
+ describe "the ctrl-y command", ->
+ it "copies from the line above", ->
+ keydown 'y', ctrl: true
+ expect(editor.getText()).toBe '12345\n1\nabcd\naefghi'
+
+ editor.insertText ' '
+ keydown 'y', ctrl: true
+ expect(editor.getText()).toBe '12345\n1 3\nabcd\na cefghi'
+
+ it "does nothing if there's nothing above the cursor", ->
+ editor.insertText 'fill'
+ keydown 'y', ctrl: true
+ expect(editor.getText()).toBe '12345\nfill5\nabcd\nfillefghi'
+
+ keydown 'y', ctrl: true
+ expect(editor.getText()).toBe '12345\nfill5\nabcd\nfillefghi'
+
+ it "does nothing on the first line", ->
+ editor.setCursorBufferPosition([0, 2])
+ editor.addCursorAtBufferPosition([3, 2])
+ editor.insertText 'a'
+ expect(editor.getText()).toBe '12a345\n\nabcd\nefaghi'
+ keydown 'y', ctrl: true
+ expect(editor.getText()).toBe '12a345\n\nabcd\nefadghi'
+
+ describe "the ctrl-e command", ->
+ beforeEach ->
+ atom.keymaps.add "test",
+ 'atom-text-editor.vim-mode.insert-mode':
+ 'ctrl-e': 'vim-mode:copy-from-line-below'
+
+ it "copies from the line below", ->
+ keydown 'e', ctrl: true
+ expect(editor.getText()).toBe '12345\na\nabcd\nefghi'
+
+ editor.insertText ' '
+ keydown 'e', ctrl: true
+ expect(editor.getText()).toBe '12345\na c\nabcd\n efghi'
+
+ it "does nothing if there's nothing below the cursor", ->
+ editor.insertText 'foo'
+ keydown 'e', ctrl: true
+ expect(editor.getText()).toBe '12345\nfood\nabcd\nfooefghi'
+
+ keydown 'e', ctrl: true
+ expect(editor.getText()).toBe '12345\nfood\nabcd\nfooefghi'
diff --git a/atom/packages/vim-mode/spec/motions-spec.coffee b/atom/packages/vim-mode/spec/motions-spec.coffee
index f7114ed..9c205ec 100644
--- a/atom/packages/vim-mode/spec/motions-spec.coffee
+++ b/atom/packages/vim-mode/spec/motions-spec.coffee
@@ -11,20 +11,21 @@ describe "Motions", ->
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)
- commandModeInputKeydown = (key, opts = {}) ->
- editor.commandModeInputView.editorElement.getModel().setText(key)
+ normalModeInputKeydown = (key, opts = {}) ->
+ theEditor = opts.editor or editor
+ theEditor.normalModeInputView.editorElement.getModel().setText(key)
- submitCommandModeInputText = (text) ->
- commandEditor = editor.commandModeInputView.editorElement
- commandEditor.getModel().setText(text)
- atom.commands.dispatch(commandEditor, "core:confirm")
+ submitNormalModeInputText = (text) ->
+ inputEditor = editor.normalModeInputView.editorElement
+ inputEditor.getModel().setText(text)
+ atom.commands.dispatch(inputEditor, "core:confirm")
describe "simple motions", ->
beforeEach ->
@@ -144,30 +145,21 @@ describe "Motions", ->
keydown('w')
expect(editor.getCursorScreenPosition()).toEqual [2, 0]
- # FIXME: The definition of Cursor#getEndOfCurrentWordBufferPosition,
- # means that the end of the word can't be the current cursor
- # position (even though it is when your cursor is on a new line).
- #
- # Therefore it picks the end of the next word here (which is [3,3])
- # to start looking for the next word, which is also the end of the
- # buffer so the cursor never advances.
- #
- # See atom/vim-mode#3
keydown('w')
expect(editor.getCursorScreenPosition()).toEqual [3, 0]
keydown('w')
- expect(editor.getCursorScreenPosition()).toEqual [3, 3]
+ expect(editor.getCursorScreenPosition()).toEqual [3, 2]
- # After cursor gets to the EOF, it should stay there.
+ # When the cursor gets to the EOF, it should stay there.
keydown('w')
- expect(editor.getCursorScreenPosition()).toEqual [3, 3]
+ expect(editor.getCursorScreenPosition()).toEqual [3, 2]
it "moves the cursor to the end of the word if last word in file", ->
editor.setText("abc")
editor.setCursorScreenPosition([0, 0])
keydown('w')
- expect(editor.getCursorScreenPosition()).toEqual([0, 3])
+ expect(editor.getCursorScreenPosition()).toEqual([0, 2])
describe "as a selection", ->
describe "within a word", ->
@@ -460,10 +452,10 @@ describe "Motions", ->
describe "as a selection", ->
it "selects to the beginning of the whole word", ->
- editor.setCursorScreenPosition([1, 10])
+ editor.setCursorScreenPosition([1, 9])
keydown('y')
keydown('B', shift: true)
- expect(vimState.getRegister('"').text).toBe 'xyz-123'
+ expect(vimState.getRegister('"').text).toBe 'xyz-12'
it "doesn't go past the beginning of the file", ->
editor.setCursorScreenPosition([0, 0])
@@ -850,7 +842,7 @@ describe "Motions", ->
editor.setCursorScreenPosition([0, 2])
describe "as a motion", ->
- describe "in command mode", ->
+ describe "in normal mode", ->
beforeEach ->
keydown('g')
keydown('g')
@@ -885,7 +877,7 @@ describe "Motions", ->
expect(editor.getCursorScreenPosition()).toEqual [0, 1]
describe "as a repeated motion", ->
- describe "in command mode", ->
+ describe "in normal mode", ->
beforeEach ->
keydown('2')
keydown('g')
@@ -965,7 +957,7 @@ describe "Motions", ->
beforeEach -> keydown('G', shift: true)
it "moves the cursor to the last line after whitespace", ->
- expect(editor.getCursorScreenPosition()).toEqual [3, 1]
+ expect(editor.getCursorScreenPosition()).toEqual [3, 0]
describe "as a repeated motion", ->
beforeEach ->
@@ -997,61 +989,77 @@ describe "Motions", ->
editor.setText("abc\ndef\nabc\ndef\n")
editor.setCursorBufferPosition([0, 0])
+ # clear search history
+ vimState.globalVimState.searchHistory = []
+ vimState.globalVimState.currentSearch = {}
+
describe "as a motion", ->
+ it "beeps when repeating nonexistent last search", ->
+ keydown '/'
+ submitNormalModeInputText ''
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+ expect(atom.beep).toHaveBeenCalled()
+
it "moves the cursor to the specified search pattern", ->
keydown('/')
- submitCommandModeInputText 'def'
+ submitNormalModeInputText 'def'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
expect(pane.activate).toHaveBeenCalled()
+ expect(atom.beep).not.toHaveBeenCalled()
it "loops back around", ->
editor.setCursorBufferPosition([3, 0])
keydown('/')
- submitCommandModeInputText 'def'
+ submitNormalModeInputText 'def'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "uses a valid regex as a regex", ->
keydown('/')
# Cycle through the 'abc' on the first line with a character pattern
- submitCommandModeInputText '[abc]'
+ submitNormalModeInputText '[abc]'
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [0, 2]
+ expect(atom.beep).not.toHaveBeenCalled()
it "uses an invalid regex as a literal string", ->
# Go straight to the literal [abc
editor.setText("abc\n[abc]\n")
keydown('/')
- submitCommandModeInputText '[abc'
+ submitNormalModeInputText '[abc'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "uses ? as a literal string", ->
editor.setText("abc\n[a?c?\n")
keydown('/')
- submitCommandModeInputText '?'
+ submitNormalModeInputText '?'
expect(editor.getCursorBufferPosition()).toEqual [1, 2]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [1, 4]
+ expect(atom.beep).not.toHaveBeenCalled()
it 'works with selection in visual mode', ->
editor.setText('one two three')
keydown('v')
keydown('/')
- submitCommandModeInputText 'th'
+ submitNormalModeInputText 'th'
expect(editor.getCursorBufferPosition()).toEqual [0, 9]
keydown('d')
expect(editor.getText()).toBe 'hree'
+ expect(atom.beep).not.toHaveBeenCalled()
it 'extends selection when repeating search in visual mode', ->
editor.setText('line1\nline2\nline3')
keydown('v')
keydown('/')
- submitCommandModeInputText 'line'
+ submitNormalModeInputText 'line'
{start, end} = editor.getSelectedBufferRange()
expect(start.row).toEqual 0
expect(end.row).toEqual 1
@@ -1059,6 +1067,7 @@ describe "Motions", ->
{start, end} = editor.getSelectedBufferRange()
expect(start.row).toEqual 0
expect(end.row).toEqual 2
+ expect(atom.beep).not.toHaveBeenCalled()
describe "case sensitivity", ->
beforeEach ->
@@ -1067,60 +1076,76 @@ describe "Motions", ->
keydown('/')
it "works in case sensitive mode", ->
- submitCommandModeInputText 'ABC'
+ submitNormalModeInputText 'ABC'
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "works in case insensitive mode", ->
- submitCommandModeInputText '\\cAbC'
+ submitNormalModeInputText '\\cAbC'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "works in case insensitive mode wherever \\c is", ->
- submitCommandModeInputText 'AbC\\c'
+ submitNormalModeInputText 'AbC\\c'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "uses case insensitive search if useSmartcaseForSearch is true and searching lowercase", ->
atom.config.set 'vim-mode.useSmartcaseForSearch', true
- submitCommandModeInputText 'abc'
+ submitNormalModeInputText 'abc'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "uses case sensitive search if useSmartcaseForSearch is true and searching uppercase", ->
atom.config.set 'vim-mode.useSmartcaseForSearch', true
- submitCommandModeInputText 'ABC'
+ submitNormalModeInputText 'ABC'
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe "repeating", ->
it "does nothing with no search history", ->
- # This tests that no exception is raised
+ editor.setCursorBufferPosition([0, 0])
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+ expect(atom.beep).toHaveBeenCalled()
+
+ editor.setCursorBufferPosition([1, 1])
keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+ expect(atom.beep.callCount).toBe 2
+ describe "repeating with search history", ->
beforeEach ->
keydown('/')
- submitCommandModeInputText 'def'
+ submitNormalModeInputText 'def'
it "repeats previous search with /<enter>", ->
keydown('/')
- submitCommandModeInputText('')
+ submitNormalModeInputText('')
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "repeats previous search with //", ->
keydown('/')
- submitCommandModeInputText('/')
+ submitNormalModeInputText('/')
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe "the n keybinding", ->
it "repeats the last search", ->
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe "the N keybinding", ->
it "repeats the last search backwards", ->
@@ -1129,98 +1154,109 @@ describe "Motions", ->
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
keydown('N', shift: true)
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe "composing", ->
it "composes with operators", ->
keydown('d')
keydown('/')
- submitCommandModeInputText('def')
+ submitNormalModeInputText('def')
expect(editor.getText()).toEqual "def\nabc\ndef\n"
+ expect(atom.beep).not.toHaveBeenCalled()
it "repeats correctly with operators", ->
keydown('d')
keydown('/')
- submitCommandModeInputText('def')
+ submitNormalModeInputText('def')
keydown('.')
expect(editor.getText()).toEqual "def\n"
+ expect(atom.beep).not.toHaveBeenCalled()
describe "when reversed as ?", ->
it "moves the cursor backwards to the specified search pattern", ->
keydown('?')
- submitCommandModeInputText('def')
+ submitNormalModeInputText('def')
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "accepts / as a literal search pattern", ->
editor.setText("abc\nd/f\nabc\nd/f\n")
editor.setCursorBufferPosition([0, 0])
keydown('?')
- submitCommandModeInputText('/')
+ submitNormalModeInputText('/')
expect(editor.getCursorBufferPosition()).toEqual [3, 1]
keydown('?')
- submitCommandModeInputText('/')
+ submitNormalModeInputText('/')
expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+ expect(atom.beep).not.toHaveBeenCalled()
describe "repeating", ->
beforeEach ->
keydown('?')
- submitCommandModeInputText('def')
+ submitNormalModeInputText('def')
it "repeats previous search as reversed with ?<enter>", ->
keydown('?')
- submitCommandModeInputText('')
+ submitNormalModeInputText('')
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "repeats previous search as reversed with ??", ->
keydown('?')
- submitCommandModeInputText('?')
+ submitNormalModeInputText('?')
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe 'the n keybinding', ->
it "repeats the last search backwards", ->
editor.setCursorBufferPosition([0, 0])
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe 'the N keybinding', ->
it "repeats the last search forwards", ->
editor.setCursorBufferPosition([0, 0])
keydown('N', shift: true)
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
describe "using search history", ->
- commandEditor = null
+ inputEditor = null
beforeEach ->
keydown('/')
- submitCommandModeInputText('def')
+ submitNormalModeInputText('def')
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('/')
- submitCommandModeInputText('abc')
+ submitNormalModeInputText('abc')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
- commandEditor = editor.commandModeInputView.editorElement
+ inputEditor = editor.normalModeInputView.editorElement
it "allows searching history in the search field", ->
keydown('/')
- atom.commands.dispatch(commandEditor, 'core:move-up')
- expect(commandEditor.getModel().getText()).toEqual('abc')
- atom.commands.dispatch(commandEditor, 'core:move-up')
- expect(commandEditor.getModel().getText()).toEqual('def')
- atom.commands.dispatch(commandEditor, 'core:move-up')
- expect(commandEditor.getModel().getText()).toEqual('def')
+ atom.commands.dispatch(inputEditor, 'core:move-up')
+ expect(inputEditor.getModel().getText()).toEqual('abc')
+ atom.commands.dispatch(inputEditor, 'core:move-up')
+ expect(inputEditor.getModel().getText()).toEqual('def')
+ atom.commands.dispatch(inputEditor, 'core:move-up')
+ expect(inputEditor.getModel().getText()).toEqual('def')
+ expect(atom.beep).not.toHaveBeenCalled()
it "resets the search field to empty when scrolling back", ->
keydown('/')
- atom.commands.dispatch(commandEditor, 'core:move-up')
- expect(commandEditor.getModel().getText()).toEqual('abc')
- atom.commands.dispatch(commandEditor, 'core:move-up')
- expect(commandEditor.getModel().getText()).toEqual('def')
- atom.commands.dispatch(commandEditor, 'core:move-down')
- expect(commandEditor.getModel().getText()).toEqual('abc')
- atom.commands.dispatch(commandEditor, 'core:move-down')
- expect(commandEditor.getModel().getText()).toEqual ''
+ atom.commands.dispatch(inputEditor, 'core:move-up')
+ expect(inputEditor.getModel().getText()).toEqual('abc')
+ atom.commands.dispatch(inputEditor, 'core:move-up')
+ expect(inputEditor.getModel().getText()).toEqual('def')
+ atom.commands.dispatch(inputEditor, 'core:move-down')
+ expect(inputEditor.getModel().getText()).toEqual('abc')
+ atom.commands.dispatch(inputEditor, 'core:move-down')
+ expect(inputEditor.getModel().getText()).toEqual ''
+ expect(atom.beep).not.toHaveBeenCalled()
describe "the * keybinding", ->
beforeEach ->
@@ -1253,14 +1289,9 @@ describe "Motions", ->
it "doesn't move cursor unless next match has exact word ending", ->
editor.setText("abc\n@def\nabc\n@def1\n")
- # FIXME: I suspect there is a bug laying around
- # Cursor#getEndOfCurrentWordBufferPosition, this function
- # is returning '@' as a word, instead of returning the whole
- # word '@def', this behavior is avoided in this test, when we
- # execute the '*' command when cursor is on character after '@'
- # (in this particular example, the 'd' char)
editor.setCursorBufferPosition([1, 1])
keydown("*")
+ # this is because of the default isKeyword value of vim-mode that includes @
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
# FIXME: This behavior is different from the one found in
@@ -1404,58 +1435,58 @@ describe "Motions", ->
it 'moves to the beginning of the line of a mark', ->
editor.setCursorBufferPosition([1, 1])
keydown('m')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
editor.setCursorBufferPosition([0, 0])
keydown('\'')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorBufferPosition()).toEqual [1, 4]
it 'moves literally to a mark', ->
editor.setCursorBufferPosition([1, 1])
keydown('m')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
editor.setCursorBufferPosition([0, 0])
keydown('`')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorBufferPosition()).toEqual [1, 1]
it 'deletes to a mark by line', ->
editor.setCursorBufferPosition([1, 5])
keydown('m')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
editor.setCursorBufferPosition([0, 0])
keydown('d')
keydown('\'')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getText()).toEqual '56\n'
it 'deletes before to a mark literally', ->
editor.setCursorBufferPosition([1, 5])
keydown('m')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
editor.setCursorBufferPosition([0, 1])
keydown('d')
keydown('`')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getText()).toEqual ' 4\n56\n'
it 'deletes after to a mark literally', ->
editor.setCursorBufferPosition([1, 5])
keydown('m')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
editor.setCursorBufferPosition([2, 1])
keydown('d')
keydown('`')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getText()).toEqual ' 12\n 36\n'
it 'moves back to previous', ->
editor.setCursorBufferPosition([1, 5])
keydown('`')
- commandModeInputKeydown('`')
+ normalModeInputKeydown('`')
editor.setCursorBufferPosition([2, 1])
keydown('`')
- commandModeInputKeydown('`')
+ normalModeInputKeydown('`')
expect(editor.getCursorBufferPosition()).toEqual [1, 5]
describe 'the f/F keybindings', ->
@@ -1465,56 +1496,57 @@ describe "Motions", ->
it 'moves to the first specified character it finds', ->
keydown('f')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
it 'moves backwards to the first specified character it finds', ->
editor.setCursorScreenPosition([0, 2])
keydown('F', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
it 'respects count forward', ->
keydown('2')
keydown('f')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
it 'respects count backward', ->
editor.setCursorScreenPosition([0, 6])
keydown('2')
keydown('F', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
it "doesn't move if the character specified isn't found", ->
keydown('f')
- commandModeInputKeydown('d')
+ normalModeInputKeydown('d')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "doesn't move if there aren't the specified count of the specified character", ->
keydown('1')
keydown('0')
keydown('f')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
# a bug was making this behaviour depend on the count
keydown('1')
keydown('1')
keydown('f')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
# and backwards now
editor.setCursorScreenPosition([0, 6])
keydown('1')
keydown('0')
keydown('F', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
keydown('1')
keydown('1')
keydown('F', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
it "composes with d", ->
@@ -1522,9 +1554,47 @@ describe "Motions", ->
keydown('d')
keydown('2')
keydown('f')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getText()).toEqual 'abcbc\n'
+ it "cancels c when no match found", ->
+ keydown('c')
+ keydown('f')
+ normalModeInputKeydown('d')
+ expect(editor.getText()).toBe("abcabcabcabc\n")
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ expect(vimState.mode).toBe "normal"
+
+ describe 'with accented characters', ->
+ buildIMECompositionEvent = (event, {data, target}={}) ->
+ event = new Event(event)
+ event.data = data
+ Object.defineProperty(event, 'target', get: -> target)
+ event
+
+ buildTextInputEvent = ({data, target}) ->
+ event = new Event('textInput')
+ event.data = data
+ Object.defineProperty(event, 'target', get: -> target)
+ event
+
+ beforeEach ->
+ editor.setText("abcébcabcébc\n")
+ editor.setCursorScreenPosition([0, 0])
+
+ it 'works with IME composition', ->
+ keydown('f')
+ normalModeEditor = editor.normalModeInputView.editorElement
+ jasmine.attachToDOM(normalModeEditor)
+ domNode = normalModeEditor.component.domNode
+ inputNode = domNode.querySelector('.hidden-input')
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "´", target: inputNode))
+ expect(normalModeEditor.getModel().getText()).toEqual '´'
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionend', data: "é", target: inputNode))
+ domNode.dispatchEvent(buildTextInputEvent(data: 'é', target: inputNode))
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
describe 'the t/T keybindings', ->
beforeEach ->
editor.setText("abcabcabcabc\n")
@@ -1532,60 +1602,61 @@ describe "Motions", ->
it 'moves to the character previous to the first specified character it finds', ->
keydown('t')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
# or stays put when it's already there
keydown('t')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
it 'moves backwards to the character after the first specified character it finds', ->
editor.setCursorScreenPosition([0, 2])
keydown('T', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 1]
it 'respects count forward', ->
keydown('2')
keydown('t')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
it 'respects count backward', ->
editor.setCursorScreenPosition([0, 6])
keydown('2')
keydown('T', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 1]
it "doesn't move if the character specified isn't found", ->
keydown('t')
- commandModeInputKeydown('d')
+ normalModeInputKeydown('d')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ expect(atom.beep).not.toHaveBeenCalled()
it "doesn't move if there aren't the specified count of the specified character", ->
keydown('1')
keydown('0')
keydown('t')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
# a bug was making this behaviour depend on the count
keydown('1')
keydown('1')
keydown('t')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
# and backwards now
editor.setCursorScreenPosition([0, 6])
keydown('1')
keydown('0')
keydown('T', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
keydown('1')
keydown('1')
keydown('T', shift: true)
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
it "composes with d", ->
@@ -1593,9 +1664,34 @@ describe "Motions", ->
keydown('d')
keydown('2')
keydown('t')
- commandModeInputKeydown('b')
+ normalModeInputKeydown('b')
expect(editor.getText()).toBe 'abcbcabc\n'
+ it "selects character under cursor even when no movement happens", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown('d')
+ keydown('t')
+ normalModeInputKeydown('b')
+ expect(editor.getText()).toBe 'bcabcabcabc\n'
+
+ describe 'the v keybinding', ->
+ beforeEach ->
+ editor.setText("01\n002\n0003\n00004\n000005\n")
+ editor.setCursorScreenPosition([1, 1])
+
+ it "selects down a line", ->
+ keydown('v')
+ keydown('j')
+ keydown('j')
+ expect(editor.getSelectedText()).toBe "02\n0003\n00"
+ expect(editor.getSelectedBufferRange().isSingleLine()).toBeFalsy()
+
+ it "selects right", ->
+ keydown('v')
+ keydown('l')
+ expect(editor.getSelectedText()).toBe "02"
+ expect(editor.getSelectedBufferRange().isSingleLine()).toBeTruthy()
+
describe 'the V keybinding', ->
beforeEach ->
editor.setText("01\n002\n0003\n00004\n000005\n")
@@ -1603,9 +1699,11 @@ describe "Motions", ->
it "selects down a line", ->
keydown('V', shift: true)
+ expect(editor.getSelectedBufferRange().isSingleLine()).toBeFalsy()
keydown('j')
keydown('j')
expect(editor.getSelectedText()).toBe "002\n0003\n00004\n"
+ expect(editor.getSelectedBufferRange().isSingleLine()).toBeFalsy()
it "selects up a line", ->
keydown('V', shift: true)
@@ -1619,7 +1717,7 @@ describe "Motions", ->
it "repeat f in same direction", ->
keydown('f')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
keydown(';')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
@@ -1629,7 +1727,7 @@ describe "Motions", ->
it "repeat F in same direction", ->
editor.setCursorScreenPosition([0, 10])
keydown('F', shift: true)
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 8]
keydown(';')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
@@ -1639,7 +1737,7 @@ describe "Motions", ->
it "repeat f in opposite direction", ->
editor.setCursorScreenPosition([0, 6])
keydown('f')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 8]
keydown(',')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
@@ -1649,7 +1747,7 @@ describe "Motions", ->
it "repeat F in opposite direction", ->
editor.setCursorScreenPosition([0, 4])
keydown('F', shift: true)
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
keydown(',')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
@@ -1658,7 +1756,7 @@ describe "Motions", ->
it "alternate repeat f in same direction and reverse", ->
keydown('f')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
keydown(';')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
@@ -1668,7 +1766,7 @@ describe "Motions", ->
it "alternate repeat F in same direction and reverse", ->
editor.setCursorScreenPosition([0, 10])
keydown('F', shift: true)
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 8]
keydown(';')
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
@@ -1677,7 +1775,7 @@ describe "Motions", ->
it "repeat t in same direction", ->
keydown('t')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 1]
keydown(';')
expect(editor.getCursorScreenPosition()).toEqual [0, 4]
@@ -1685,7 +1783,7 @@ describe "Motions", ->
it "repeat T in same direction", ->
editor.setCursorScreenPosition([0, 10])
keydown('T', shift: true)
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 9]
keydown(';')
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
@@ -1693,7 +1791,7 @@ describe "Motions", ->
it "repeat t in opposite direction first, and then reverse", ->
editor.setCursorScreenPosition([0, 3])
keydown('t')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 4]
keydown(',')
expect(editor.getCursorScreenPosition()).toEqual [0, 3]
@@ -1703,7 +1801,7 @@ describe "Motions", ->
it "repeat T in opposite direction first, and then reverse", ->
editor.setCursorScreenPosition([0, 4])
keydown('T', shift: true)
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 3]
keydown(',')
expect(editor.getCursorScreenPosition()).toEqual [0, 4]
@@ -1713,7 +1811,7 @@ describe "Motions", ->
it "repeat with count in same direction", ->
editor.setCursorScreenPosition([0, 0])
keydown('f')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
keydown('2')
keydown(';')
@@ -1722,12 +1820,45 @@ describe "Motions", ->
it "repeat with count in reverse direction", ->
editor.setCursorScreenPosition([0, 6])
keydown('f')
- commandModeInputKeydown('c')
+ normalModeInputKeydown('c')
expect(editor.getCursorScreenPosition()).toEqual [0, 8]
keydown('2')
keydown(',')
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ it "shares the most recent find/till command with other editors", ->
+ helpers.getEditorElement (otherEditorElement) ->
+ otherEditor = otherEditorElement.getModel()
+
+ editor.setText("a baz bar\n")
+ editor.setCursorScreenPosition([0, 0])
+
+ otherEditor.setText("foo bar baz")
+ otherEditor.setCursorScreenPosition([0, 0])
+
+ # by default keyDown and such go in the usual editor
+ keydown('f')
+ normalModeInputKeydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ expect(otherEditor.getCursorScreenPosition()).toEqual [0, 0]
+
+ # replay same find in the other editor
+ keydown(';', element: otherEditorElement)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ expect(otherEditor.getCursorScreenPosition()).toEqual [0, 4]
+
+ # do a till in the other editor
+ keydown('t', element: otherEditorElement)
+ normalModeInputKeydown('r', editor: otherEditor)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ expect(otherEditor.getCursorScreenPosition()).toEqual [0, 5]
+
+ # and replay in the normal editor
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+ expect(otherEditor.getCursorScreenPosition()).toEqual [0, 5]
+ expect(atom.beep).not.toHaveBeenCalled()
+
describe 'the % motion', ->
beforeEach ->
editor.setText("( ( ) )--{ text in here; and a function call(with parameters) }\n")
@@ -1780,7 +1911,7 @@ describe "Motions", ->
it "does not affect search history", ->
keydown('/')
- submitCommandModeInputText 'func'
+ submitNormalModeInputText 'func'
expect(editor.getCursorBufferPosition()).toEqual [0, 31]
keydown('%')
expect(editor.getCursorBufferPosition()).toEqual [0, 60]
diff --git a/atom/packages/vim-mode/spec/operators-spec.coffee b/atom/packages/vim-mode/spec/operators-spec.coffee
index a41edb3..0dff120 100644
--- a/atom/packages/vim-mode/spec/operators-spec.coffee
+++ b/atom/packages/vim-mode/spec/operators-spec.coffee
@@ -12,29 +12,30 @@ describe "Operators", ->
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)
- commandModeInputKeydown = (key, opts = {}) ->
- editor.commandModeInputView.editorElement.getModel().setText(key)
+ normalModeInputKeydown = (key, opts = {}) ->
+ editor.normalModeInputView.editorElement.getModel().setText(key)
describe "cancelling operations", ->
- it "does not throw an error even if no operation is pending", ->
+ it "throws an error when no operation is pending", ->
# cancel operation pushes an empty input operation
- # doing this without a pending operation throws an exception
+ # doing this without a pending operation would throw an exception
expect(-> vimState.pushOperations(new Input(''))).toThrow()
- # make sure commandModeInputView is created
+ it "cancels and cleans up properly", ->
+ # make sure normalModeInputView is created
keydown('/')
expect(vimState.isOperatorPending()).toBe true
- editor.commandModeInputView.viewModel.cancel()
+ editor.normalModeInputView.viewModel.cancel()
expect(vimState.isOperatorPending()).toBe false
- expect(-> editor.commandModeInputView.viewModel.cancel()).not.toThrow()
+ expect(editor.normalModeInputView).toBe undefined
describe "the x keybinding", ->
describe "on a line with content", ->
@@ -88,6 +89,18 @@ describe "Operators", ->
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
expect(vimState.getRegister('"').text).toBe 'bc'
+ describe "with multiple cursors", ->
+ beforeEach ->
+ editor.setText "abc\n012345\n\nxyz"
+ editor.setCursorScreenPosition [1, 4]
+ editor.addCursorAtBufferPosition [0, 1]
+
+ it "is undone as one operation", ->
+ keydown('x')
+ expect(editor.getText()).toBe "ac\n01235\n\nxyz"
+ keydown('u')
+ expect(editor.getText()).toBe "abc\n012345\n\nxyz"
+
describe "with vim-mode.wrapLeftRightMotion", ->
beforeEach ->
editor.setText("abc\n012345\n\nxyz")
@@ -147,7 +160,6 @@ describe "Operators", ->
expect(editor.getCursorScreenPosition()).toEqual [0, 1]
expect(vimState.getRegister('"').text).toBe '0123\n\nx'
-
describe "on an empty line", ->
beforeEach ->
editor.setText("abc\n012345\n\nxyz")
@@ -165,7 +177,6 @@ describe "Operators", ->
expect(editor.getText()).toBe "abc\n012345\nxyz"
expect(editor.getCursorScreenPosition()).toEqual [2, 0]
-
describe "the X keybinding", ->
describe "on a line with content", ->
beforeEach ->
@@ -194,7 +205,6 @@ describe "Operators", ->
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
expect(vimState.getRegister('"').text).toBe '\n'
-
describe "on an empty line", ->
beforeEach ->
editor.setText("012345\n\nabcdef")
@@ -303,7 +313,7 @@ describe "Operators", ->
it "enters operator-pending mode", ->
keydown('d')
expect(editorElement.classList.contains('operator-pending-mode')).toBe(true)
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
describe "when followed by a d", ->
it "deletes the current line and exits operator-pending mode", ->
@@ -317,7 +327,7 @@ describe "Operators", ->
expect(editor.getCursorScreenPosition()).toEqual [1, 0]
expect(vimState.getRegister('"').text).toBe "abcde\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 "deletes the last line", ->
editor.setText("12345\nabcde\nABCDE")
@@ -344,16 +354,30 @@ describe "Operators", ->
editor.setText("12345\nabcde\nABCDE\nQWERT")
editor.setCursorScreenPosition([1, 1])
+ it "undoes both lines", ->
keydown('d')
keydown('2')
keydown('d')
keydown('u')
- it "undoes both lines", ->
expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT"
expect(editor.getSelectedText()).toBe ''
+ describe "with multiple cursors", ->
+ beforeEach ->
+ editor.setCursorBufferPosition([1, 1])
+ editor.addCursorAtBufferPosition([0, 0])
+
+ it "is undone as one operation", ->
+ keydown('d')
+ keydown('l')
+
+ keydown('u')
+
+ expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT"
+ expect(editor.getSelectedText()).toBe ''
+
describe "when followed by a w", ->
it "deletes the next word until the end of the line and exits operator-pending mode", ->
editor.setText("abcd efg\nabc")
@@ -368,7 +392,7 @@ describe "Operators", ->
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 "deletes to the beginning of the next word", ->
editor.setText('abcd efg')
@@ -404,59 +428,61 @@ describe "Operators", ->
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)
+
+ describe "when followed by a j", ->
+ originalText = "12345\nabcde\nABCDE\n"
- describe "when followed by an j", ->
beforeEach ->
- originalText = "12345\nabcde\nABCDE"
editor.setText(originalText)
- describe "on the beginning of the file", ->
+ describe "on the beginning of the file", ->
+ it "deletes the next two lines", ->
editor.setCursorScreenPosition([0, 0])
- it "deletes the next two lines", ->
- keydown('d')
- keydown('j')
- expect(editor.getText()).toBe("ABCDE")
+ keydown('d')
+ keydown('j')
+ expect(editor.getText()).toBe("ABCDE\n")
- describe "on the end of the file", ->
- editor.setCursorScreenPosition([4, 2])
- it "deletes nothing", ->
- keydown('d')
- keydown('j')
- expect(editor.getText()).toBe(originalText)
+ describe "on the end of the file", ->
+ it "deletes nothing", ->
+ editor.setCursorScreenPosition([4, 0])
+ keydown('d')
+ keydown('j')
+ expect(editor.getText()).toBe(originalText)
- describe "on the middle of second line", ->
- editor.setCursorScreenPosition([2, 1])
- it "deletes the last two lines", ->
- keydown('d')
- keydown('j')
- expect(editor.getText()).toBe("12345")
+ describe "on the middle of second line", ->
+ it "deletes the last two lines", ->
+ editor.setCursorScreenPosition([1, 2])
+ keydown('d')
+ keydown('j')
+ expect(editor.getText()).toBe("12345\n")
describe "when followed by an k", ->
+ originalText = "12345\nabcde\nABCDE"
+
beforeEach ->
- originalText = "12345\nabcde\nABCDE"
editor.setText(originalText)
- describe "on the end of the file", ->
- editor.setCursorScreenPosition([4, 2])
- it "deletes the bottom two lines", ->
- keydown('d')
- keydown('k')
- expect(editor.getText()).toBe("ABCDE")
+ describe "on the end of the file", ->
+ it "deletes the bottom two lines", ->
+ editor.setCursorScreenPosition([2, 4])
+ keydown('d')
+ keydown('k')
+ expect(editor.getText()).toBe("12345\n")
- describe "on the beginning of the file", ->
+ describe "on the beginning of the file", ->
+ xit "deletes nothing", ->
editor.setCursorScreenPosition([0, 0])
- it "deletes nothing", ->
- keydown('d')
- keydown('k')
- expect(editor.getText()).toBe(originalText)
+ keydown('d')
+ keydown('k')
+ expect(editor.getText()).toBe(originalText)
- describe "when on the middle of second line", ->
- editor.setCursorScreenPosition([2, 1])
- it "deletes the first two lines", ->
- keydown('d')
- keydown('k')
- expect(editor.getText()).toBe("12345")
+ describe "when on the middle of second line", ->
+ it "deletes the first two lines", ->
+ editor.setCursorScreenPosition([1, 2])
+ keydown('d')
+ keydown('k')
+ expect(editor.getText()).toBe("ABCDE")
describe "when followed by a G", ->
beforeEach ->
@@ -509,7 +535,7 @@ describe "Operators", ->
keydown('y')
keydown('d')
keydown('t')
- commandModeInputKeydown(')')
+ normalModeInputKeydown(')')
expect(editor.getText()).toBe("test ()")
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
@@ -538,7 +564,7 @@ describe "Operators", ->
keydown('d')
keydown('t')
- commandModeInputKeydown('d')
+ normalModeInputKeydown('d')
expect(editor.getText()).toBe "d\nabc\nd"
expect(editor.getCursorBufferPositions()).toEqual [
@@ -561,16 +587,45 @@ describe "Operators", ->
editor.setText("12345\nabcde\nABCDE")
describe "when followed by a c", ->
- it "deletes the current line and enters insert mode", ->
- editor.setCursorScreenPosition([1, 1])
+ describe "with autoindent", ->
+ beforeEach ->
+ editor.setText("12345\n abcde\nABCDE")
+ editor.setCursorScreenPosition([1, 1])
+ spyOn(editor, 'shouldAutoIndent').andReturn(true)
+ spyOn(editor, 'autoIndentBufferRow').andCallFake (line) ->
+ editor.indent()
+ spyOn(editor.languageMode, 'suggestedIndentForLineAtBufferRow').andCallFake -> 1
- keydown('c')
- keydown('c')
+ it "deletes the current line and enters insert mode", ->
+ editor.setCursorScreenPosition([1, 1])
- expect(editor.getText()).toBe "12345\n\nABCDE"
- expect(editor.getCursorScreenPosition()).toEqual [1, 0]
- expect(editorElement.classList.contains('command-mode')).toBe(false)
- expect(editorElement.classList.contains('insert-mode')).toBe(true)
+ keydown('c')
+ keydown('c')
+
+ expect(editor.getText()).toBe "12345\n \nABCDE"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
+ expect(editorElement.classList.contains('insert-mode')).toBe(true)
+
+ it "is repeatable", ->
+ keydown('c')
+ keydown('c')
+ editor.insertText("abc")
+ keydown 'escape'
+ expect(editor.getText()).toBe "12345\n abc\nABCDE"
+ editor.setCursorScreenPosition([2, 3])
+ keydown '.'
+ expect(editor.getText()).toBe "12345\n abc\n abc\n"
+
+ it "is undoable", ->
+ keydown('c')
+ keydown('c')
+ editor.insertText("abc")
+ keydown 'escape'
+ expect(editor.getText()).toBe "12345\n abc\nABCDE"
+ keydown 'u'
+ expect(editor.getText()).toBe "12345\n abcde\nABCDE"
+ expect(editor.getSelectedText()).toBe ''
describe "when the cursor is on the last line", ->
it "deletes the line's content and enters insert mode on the last line", ->
@@ -581,7 +636,7 @@ describe "Operators", ->
expect(editor.getText()).toBe "12345\nabcde\n\n"
expect(editor.getCursorScreenPosition()).toEqual [2, 0]
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
expect(editorElement.classList.contains('insert-mode')).toBe(true)
describe "when the cursor is on the only line", ->
@@ -592,9 +647,9 @@ describe "Operators", ->
keydown('c')
keydown('c')
- expect(editor.getText()).toBe "\n"
+ expect(editor.getText()).toBe ""
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
expect(editorElement.classList.contains('insert-mode')).toBe(true)
describe "when followed by i w", ->
@@ -611,7 +666,7 @@ describe "Operators", ->
# Just cannot get "typing" to work correctly in test.
editor.setText("12345\nfg\nABCDE")
keydown('escape')
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
expect(editor.getText()).toBe "12345\nfg\nABCDE"
keydown('u')
@@ -651,6 +706,88 @@ describe "Operators", ->
keydown('escape')
expect(editor.getText()).toBe("12345\n\n")
+ describe "when followed by a %", ->
+ beforeEach ->
+ editor.setText("12345(67)8\nabc(d)e\nA()BCDE")
+
+ describe "before brackets or on the first one", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 1])
+ editor.addCursorAtScreenPosition([1, 1])
+ editor.addCursorAtScreenPosition([2, 1])
+ keydown('c')
+ keydown('%')
+ editor.insertText('x')
+
+ it "replaces inclusively until matching bracket", ->
+ expect(editor.getText()).toBe("1x8\naxe\nAxBCDE")
+ expect(vimState.mode).toBe "insert"
+
+ it "undoes correctly with u", ->
+ keydown('escape')
+ expect(vimState.mode).toBe "normal"
+ keydown 'u'
+ expect(editor.getText()).toBe("12345(67)8\nabc(d)e\nA()BCDE")
+
+ describe "inside brackets or on the ending one", ->
+ it "replaces inclusively backwards until matching bracket", ->
+ editor.setCursorScreenPosition([0, 6])
+ editor.addCursorAtScreenPosition([1, 5])
+ editor.addCursorAtScreenPosition([2, 2])
+ keydown('c')
+ keydown('%')
+ editor.insertText('x')
+ expect(editor.getText()).toBe("12345x7)8\nabcxe\nAxBCDE")
+ expect(vimState.mode).toBe "insert"
+
+ describe "after or without brackets", ->
+ it "deletes nothing", ->
+ editor.setText("12345(67)8\nabc(d)e\nABCDE")
+ editor.setCursorScreenPosition([0, 9])
+ editor.addCursorAtScreenPosition([2, 2])
+ keydown('c')
+ keydown('%')
+ expect(editor.getText()).toBe("12345(67)8\nabc(d)e\nABCDE")
+ expect(vimState.mode).toBe "normal"
+
+ describe "repetition with .", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 1])
+ keydown('c')
+ keydown('%')
+ editor.insertText('x')
+ keydown('escape')
+
+ it "repeats correctly before a bracket", ->
+ editor.setCursorScreenPosition([1, 0])
+ keydown('.')
+ expect(editor.getText()).toBe("1x8\nxe\nA()BCDE")
+ expect(vimState.mode).toBe "normal"
+
+ it "repeats correctly on the opening bracket", ->
+ editor.setCursorScreenPosition([1, 3])
+ keydown('.')
+ expect(editor.getText()).toBe("1x8\nabcxe\nA()BCDE")
+ expect(vimState.mode).toBe "normal"
+
+ it "repeats correctly inside brackets", ->
+ editor.setCursorScreenPosition([1, 4])
+ keydown('.')
+ expect(editor.getText()).toBe("1x8\nabcx)e\nA()BCDE")
+ expect(vimState.mode).toBe "normal"
+
+ it "repeats correctly on the closing bracket", ->
+ editor.setCursorScreenPosition([1, 5])
+ keydown('.')
+ expect(editor.getText()).toBe("1x8\nabcxe\nA()BCDE")
+ expect(vimState.mode).toBe "normal"
+
+ it "does nothing when repeated after a bracket", ->
+ editor.setCursorScreenPosition([2, 3])
+ keydown('.')
+ expect(editor.getText()).toBe("1x8\nabc(d)e\nA()BCDE")
+ expect(vimState.mode).toBe "normal"
+
describe "when followed by a goto line G", ->
beforeEach ->
editor.setText "12345\nabcde\nABCDE"
@@ -673,6 +810,130 @@ describe "Operators", ->
keydown('escape')
expect(editor.getText()).toBe("12345\n\nABCDE")
+ describe "in visual mode", ->
+ beforeEach ->
+ editor.setText "123456789\nabcde\nfghijklmnopq\nuvwxyz"
+ editor.setCursorScreenPosition [1, 1]
+
+ describe "with characterwise selection on a single line", ->
+ it "repeats with .", ->
+ keydown 'v'
+ keydown '2'
+ keydown 'l'
+ keydown 'c'
+ editor.insertText "ab"
+ keydown 'escape'
+ expect(editor.getText()).toBe "123456789\naabe\nfghijklmnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [0, 1]
+ keydown '.'
+ expect(editor.getText()).toBe "1ab56789\naabe\nfghijklmnopq\nuvwxyz"
+
+ it "repeats shortened with . near the end of the line", ->
+ editor.setCursorScreenPosition [0, 2]
+ keydown 'v'
+ keydown '4'
+ keydown 'l'
+ keydown 'c'
+ editor.insertText "ab"
+ keydown 'escape'
+ expect(editor.getText()).toBe "12ab89\nabcde\nfghijklmnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [1, 3]
+ keydown '.'
+ expect(editor.getText()).toBe "12ab89\nabcab\nfghijklmnopq\nuvwxyz"
+
+ it "repeats shortened with . near the end of the line regardless of whether motion wrapping is enabled", ->
+ atom.config.set('vim-mode.wrapLeftRightMotion', true)
+ editor.setCursorScreenPosition [0, 2]
+ keydown 'v'
+ keydown '4'
+ keydown 'l'
+ keydown 'c'
+ editor.insertText "ab"
+ keydown 'escape'
+ expect(editor.getText()).toBe "12ab89\nabcde\nfghijklmnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [1, 3]
+ keydown '.'
+ # this differs from VIM, which would eat the \n before fghij...
+ expect(editor.getText()).toBe "12ab89\nabcab\nfghijklmnopq\nuvwxyz"
+
+ describe "is repeatable with characterwise selection over multiple lines", ->
+ it "repeats with .", ->
+ keydown 'v'
+ keydown 'j'
+ keydown '3'
+ keydown 'l'
+ keydown 'c'
+ editor.insertText "x"
+ keydown 'escape'
+ expect(editor.getText()).toBe "123456789\naxklmnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [0, 1]
+ keydown '.'
+ expect(editor.getText()).toBe "1xnopq\nuvwxyz"
+
+ it "repeats shortened with . near the end of the line", ->
+ # this behaviour is unlike VIM, see #737
+ keydown 'v'
+ keydown 'j'
+ keydown '6'
+ keydown 'l'
+ keydown 'c'
+ editor.insertText "x"
+ keydown 'escape'
+ expect(editor.getText()).toBe "123456789\naxnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [0, 1]
+ keydown '.'
+ expect(editor.getText()).toBe "1x\nuvwxyz"
+
+ describe "is repeatable with linewise selection", ->
+ describe "with one line selected", ->
+ it "repeats with .", ->
+ keydown 'V', shift: true
+ keydown 'c'
+ editor.insertText "x"
+ keydown 'escape'
+ expect(editor.getText()).toBe "123456789\nx\nfghijklmnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [0, 7]
+ keydown '.'
+ expect(editor.getText()).toBe "x\nx\nfghijklmnopq\nuvwxyz"
+
+ editor.setCursorScreenPosition [2, 0]
+ keydown '.'
+ expect(editor.getText()).toBe "x\nx\nx\nuvwxyz"
+
+ describe "with multiple lines selected", ->
+ it "repeats with .", ->
+ keydown 'V', shift: true
+ keydown 'j'
+ keydown 'c'
+ editor.insertText "x"
+ keydown 'escape'
+ expect(editor.getText()).toBe "123456789\nx\nuvwxyz"
+
+ editor.setCursorScreenPosition [0, 7]
+ keydown '.'
+ expect(editor.getText()).toBe "x\nuvwxyz"
+
+ it "repeats shortened with . near the end of the file", ->
+ keydown 'V', shift: true
+ keydown 'j'
+ keydown 'c'
+ editor.insertText "x"
+ keydown 'escape'
+ expect(editor.getText()).toBe "123456789\nx\nuvwxyz"
+
+ editor.setCursorScreenPosition [1, 7]
+ keydown '.'
+ expect(editor.getText()).toBe "123456789\nx\n"
+
+ xdescribe "is repeatable with block selection", ->
+ # there is no block selection yet
+
describe "the C keybinding", ->
beforeEach ->
editor.getBuffer().setText("012\n")
@@ -682,13 +943,14 @@ describe "Operators", ->
it "deletes the contents until the end of the line and enters insert mode", ->
expect(editor.getText()).toBe "0\n"
expect(editor.getCursorScreenPosition()).toEqual [0, 1]
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
expect(editorElement.classList.contains('insert-mode')).toBe(true)
describe "the y keybinding", ->
beforeEach ->
- editor.getBuffer().setText("012 345\nabc\n")
+ editor.getBuffer().setText("012 345\nabc\ndefg\n")
editor.setCursorScreenPosition([0, 4])
+ vimState.setRegister('"', text: '345')
describe "when selected lines in visual linewise mode", ->
beforeEach ->
@@ -766,7 +1028,7 @@ describe "Operators", ->
it "does not yank when motion fails", ->
keydown('y')
keydown('t')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(vimState.getRegister('"').text).toBe '345'
describe "with a text object", ->
@@ -782,11 +1044,11 @@ describe "Operators", ->
keydown('y')
keydown('h')
- it "saves the left letter to the default register", ->
- expect(vimState.getRegister('"').text).toBe " "
+ it "saves the left letter to the default register", ->
+ expect(vimState.getRegister('"').text).toBe " "
- it "moves the cursor position to the left", ->
- expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+ it "moves the cursor position to the left", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
describe "with a down motion", ->
beforeEach ->
@@ -799,6 +1061,18 @@ describe "Operators", ->
it "leaves the cursor at the starting position", ->
expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+ describe "with an up motion", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([2, 2])
+ keydown 'y'
+ keydown 'k'
+
+ it "saves both full lines to the default register", ->
+ expect(vimState.getRegister('"').text).toBe "abc\ndefg\n"
+
+ it "puts the cursor on the first line and the original column", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
describe "when followed by a G", ->
beforeEach ->
originalText = "12345\nabcde\nABCDE"
@@ -855,6 +1129,47 @@ describe "Operators", ->
expect(vimState.getRegister('"').text).toBe '123'
expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 2]]
+ describe "in a long file", ->
+ beforeEach ->
+ editor.setHeight(400)
+ editor.setLineHeightInPixels(10)
+ editor.setDefaultCharWidth(10)
+ text = ""
+ for i in [1..200]
+ text += "#{i}\n"
+ editor.setText(text)
+
+ describe "yanking many lines forward", ->
+ it "does not scroll the window", ->
+ editor.setCursorBufferPosition [40, 1]
+ previousScrollTop = editor.getScrollTop()
+
+ # yank many lines
+ keydown('y')
+ keydown('1')
+ keydown('6')
+ keydown('0')
+ keydown('G', shift: true)
+
+ expect(editor.getScrollTop()).toEqual(previousScrollTop)
+ expect(editor.getCursorBufferPosition()).toEqual [40, 1]
+ expect(vimState.getRegister('"').text.split('\n').length).toBe 121
+
+ describe "yanking many lines backwards", ->
+ it "scrolls the window", ->
+ editor.setCursorBufferPosition [140, 1]
+ previousScrollTop = editor.getScrollTop()
+
+ # yank many lines
+ keydown('y')
+ keydown('6')
+ keydown('0')
+ keydown('G', shift: true)
+
+ expect(editor.getScrollTop()).toNotEqual previousScrollTop
+ expect(editor.getCursorBufferPosition()).toEqual [59, 1]
+ expect(vimState.getRegister('"').text.split('\n').length).toBe 83
+
describe "the yy keybinding", ->
describe "on a single line file", ->
beforeEach ->
@@ -918,6 +1233,15 @@ describe "Operators", ->
expect(editor.getText()).toBe "034512\n"
expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+ describe "at the end of a line", ->
+ beforeEach ->
+ editor.setCursorScreenPosition [0, 2]
+ keydown('p')
+
+ it "positions cursor correctly", ->
+ expect(editor.getText()).toBe "012345\n"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+
describe "when useClipboardAsDefaultRegister enabled", ->
it "inserts contents from clipboard", ->
atom.config.set 'vim-mode.useClipboardAsDefaultRegister', true
@@ -1260,26 +1584,50 @@ describe "Operators", ->
it "outdents all three lines", ->
expect(editor.getText()).toBe "12345\nabcde\nABCDE"
- describe "in visual mode", ->
+ describe "in visual mode linewise", ->
beforeEach ->
editor.setCursorScreenPosition([0, 0])
keydown('v', shift: true)
- keydown('>')
+ keydown('j')
+
+ describe "single indent multiple lines", ->
+ beforeEach ->
+ keydown('>')
+
+ it "indents both lines once and exits visual mode", ->
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
+ expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
- it "indents the current line and remains in visual mode", ->
- expect(editorElement.classList.contains('visual-mode')).toBe(true)
- expect(editor.getText()).toBe " 12345\nabcde\nABCDE"
- expect(editor.getSelectedText()).toBe " 12345\n"
+ it "allows repeating the operation", ->
+ keydown('.')
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
- it "allows repeating the operation", ->
- keydown("escape")
- keydown(".")
- expect(editorElement.classList.contains('command-mode')).toBe(true)
- expect(editor.getText()).toBe " 12345\nabcde\nABCDE"
+ describe "multiple indent multiple lines", ->
+ beforeEach ->
+ keydown('2')
+ keydown('>')
+
+ it "indents both lines twice and exits visual mode", ->
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
+ expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 4], [0, 4]] ]
+
+ describe "with multiple selections", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([1, 3])
+ keydown('v')
+ keydown('j')
+ editor.addCursorAtScreenPosition([0, 0])
+
+ it "indents the lines and keeps the cursors", ->
+ keydown('>')
+ expect(editor.getText()).toBe " 12345\n abcde\n ABCDE"
+ expect(editor.getCursorScreenPositions()).toEqual [[1, 2], [0, 2]]
describe "the < keybinding", ->
beforeEach ->
- editor.setText(" 12345\n abcde\nABCDE")
+ editor.setText(" 12345\n abcde\nABCDE")
editor.setCursorScreenPosition([0, 0])
describe "when followed by a <", ->
@@ -1287,9 +1635,9 @@ describe "Operators", ->
keydown('<')
keydown('<')
- it "indents the current line", ->
- expect(editor.getText()).toBe "12345\n abcde\nABCDE"
- expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ it "outdents the current line", ->
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
describe "when followed by a repeating <", ->
beforeEach ->
@@ -1297,25 +1645,43 @@ describe "Operators", ->
keydown('<')
keydown('<')
- it "indents multiple lines at once", ->
- expect(editor.getText()).toBe "12345\nabcde\nABCDE"
- expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ it "outdents multiple lines at once", ->
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
describe "undo behavior", ->
beforeEach -> keydown('u')
it "indents both lines", ->
- expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
- describe "in visual mode", ->
+ describe "in visual mode linewise", ->
beforeEach ->
keydown('v', shift: true)
- keydown('<')
+ keydown('j')
+
+ describe "single outdent multiple lines", ->
+ beforeEach ->
+ keydown('<')
+
+ it "outdents the current line and exits visual mode", ->
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
+ expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
+ expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
+
+ it "allows repeating the operation", ->
+ keydown('.')
+ expect(editor.getText()).toBe "12345\nabcde\nABCDE"
- it "indents the current line and remains in visual mode", ->
- expect(editorElement.classList.contains('visual-mode')).toBe(true)
- expect(editor.getText()).toBe "12345\n abcde\nABCDE"
- expect(editor.getSelectedText()).toBe "12345\n"
+ describe "multiple outdent multiple lines", ->
+ beforeEach ->
+ keydown('2')
+ keydown('<')
+
+ it "outdents both lines twice and exits visual mode", ->
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
+ expect(editor.getText()).toBe "12345\nabcde\nABCDE"
+ expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 0], [0, 0]] ]
describe "the = keybinding", ->
oldGrammar = []
@@ -1344,6 +1710,16 @@ describe "Operators", ->
it "indents the current line", ->
expect(editor.indentationForBufferRow(1)).toBe 0
+ describe "when followed by a G", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('=')
+ keydown('G', shift: true)
+
+ it "uses the default count", ->
+ expect(editor.indentationForBufferRow(1)).toBe 0
+ expect(editor.indentationForBufferRow(2)).toBe 0
+
describe "when followed by a repeating =", ->
beforeEach ->
keydown('2')
@@ -1389,7 +1765,7 @@ describe "Operators", ->
it "replaces a single character", ->
keydown('r')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(editor.getText()).toBe 'x2\nx4\n\n'
it "does nothing when cancelled", ->
@@ -1397,30 +1773,30 @@ describe "Operators", ->
expect(editorElement.classList.contains('operator-pending-mode')).toBe(true)
keydown('escape')
expect(editor.getText()).toBe '12\n34\n\n'
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
it "replaces a single character with a line break", ->
keydown('r')
- atom.commands.dispatch(editor.commandModeInputView.editorElement, 'core:confirm')
+ atom.commands.dispatch(editor.normalModeInputView.editorElement, 'core:confirm')
expect(editor.getText()).toBe '\n2\n\n4\n\n'
expect(editor.getCursorBufferPositions()).toEqual [[1, 0], [3, 0]]
it "composes properly with motions", ->
keydown('2')
keydown('r')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(editor.getText()).toBe 'xx\nxx\n\n'
it "does nothing on an empty line", ->
editor.setCursorBufferPosition([2, 0])
keydown('r')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(editor.getText()).toBe '12\n34\n\n'
it "does nothing if asked to replace more characters than there are on a line", ->
keydown('3')
keydown('r')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(editor.getText()).toBe '12\n34\n\n'
describe "when in visual mode", ->
@@ -1430,14 +1806,42 @@ describe "Operators", ->
it "replaces the entire selection with the given character", ->
keydown('r')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(editor.getText()).toBe 'xx\nxx\n\n'
it "leaves the cursor at the beginning of the selection", ->
keydown('r')
- commandModeInputKeydown('x')
+ normalModeInputKeydown('x')
expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]]
+ describe 'with accented characters', ->
+ buildIMECompositionEvent = (event, {data, target}={}) ->
+ event = new Event(event)
+ event.data = data
+ Object.defineProperty(event, 'target', get: -> target)
+ event
+
+ buildTextInputEvent = ({data, target}) ->
+ event = new Event('textInput')
+ event.data = data
+ Object.defineProperty(event, 'target', get: -> target)
+ event
+
+ it 'works with IME composition', ->
+ keydown('r')
+ normalModeEditor = editor.normalModeInputView.editorElement
+ jasmine.attachToDOM(normalModeEditor)
+ domNode = normalModeEditor.component.domNode
+ inputNode = domNode.querySelector('.hidden-input')
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
+ expect(normalModeEditor.getModel().getText()).toEqual 's'
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
+ expect(normalModeEditor.getModel().getText()).toEqual 'sd'
+ domNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
+ domNode.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode))
+ expect(editor.getText()).toBe '速度2\n速度4\n\n'
+
describe 'the m keybinding', ->
beforeEach ->
editor.setText('12\n34\n56\n')
@@ -1445,7 +1849,7 @@ describe "Operators", ->
it 'marks a position', ->
keydown('m')
- commandModeInputKeydown('a')
+ normalModeInputKeydown('a')
expect(vimState.getMark('a')).toEqual [0, 1]
describe 'the ~ keybinding', ->
@@ -1490,6 +1894,13 @@ describe "Operators", ->
keydown("l")
expect(editor.getText()).toBe 'Abc\nXyZ'
+ it "uses default count", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown("g")
+ keydown("~")
+ keydown("G", shift: true)
+ expect(editor.getText()).toBe 'AbC\nxYz'
+
describe 'the U keybinding', ->
beforeEach ->
editor.setText('aBc\nXyZ')
@@ -1513,6 +1924,13 @@ describe "Operators", ->
expect(editor.getText()).toBe 'ABC\nXYZ'
expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+ it "uses default count", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown("g")
+ keydown("U", shift: true)
+ keydown("G", shift: true)
+ expect(editor.getText()).toBe 'ABC\nXYZ'
+
it "makes the selected text uppercase in visual mode", ->
keydown("V", shift: true)
keydown("U", shift: true)
@@ -1530,6 +1948,13 @@ describe "Operators", ->
expect(editor.getText()).toBe 'abc\nXyZ'
expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ it "uses default count", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown("g")
+ keydown("u")
+ keydown("G", shift: true)
+ expect(editor.getText()).toBe 'abc\nxyz'
+
it "makes the selected text lowercase in visual mode", ->
keydown("V", shift: true)
keydown("u")
@@ -1650,18 +2075,21 @@ describe "Operators", ->
keydown('a', ctrl: true)
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
expect(editor.getText()).toBe '124\nab46\ncd-66ef\nab-4\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "repeats with .", ->
keydown 'a', ctrl: true
keydown '.'
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
expect(editor.getText()).toBe '125\nab47\ncd-65ef\nab-3\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "can have a count", ->
keydown '5'
keydown 'a', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 2], [4, 0]]
expect(editor.getText()).toBe '128\nab50\ncd-62ef\nab0\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "can make a negative number positive, change number of digits", ->
keydown '9'
@@ -1669,12 +2097,14 @@ describe "Operators", ->
keydown 'a', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 4], [2, 3], [3, 3], [4, 0]]
expect(editor.getText()).toBe '222\nab144\ncd32ef\nab94\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "does nothing when cursor is after the number", ->
editor.setCursorBufferPosition [2, 5]
keydown 'a', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[2, 5]]
expect(editor.getText()).toBe '123\nab45\ncd-67ef\nab-5\na-bcdef'
+ expect(atom.beep).toHaveBeenCalled()
it "does nothing on an empty line", ->
editor.setText('\n')
@@ -1683,6 +2113,7 @@ describe "Operators", ->
keydown 'a', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]]
expect(editor.getText()).toBe '\n'
+ expect(atom.beep).toHaveBeenCalled()
it "honours the vim-mode:numberRegex setting", ->
editor.setText('123\nab45\ncd -67ef\nab-5\na-bcdef')
@@ -1695,24 +2126,28 @@ describe "Operators", ->
keydown('a', ctrl: true)
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 5], [3, 3], [4, 0]]
expect(editor.getText()).toBe '124\nab46\ncd -66ef\nab-6\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
describe "decreasing numbers", ->
it "decreases the next number", ->
keydown('x', ctrl: true)
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
expect(editor.getText()).toBe '122\nab44\ncd-68ef\nab-6\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "repeats with .", ->
keydown 'x', ctrl: true
keydown '.'
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
expect(editor.getText()).toBe '121\nab43\ncd-69ef\nab-7\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "can have a count", ->
keydown '5'
keydown 'x', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 4], [4, 0]]
expect(editor.getText()).toBe '118\nab40\ncd-72ef\nab-10\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "can make a positive number negative, change number of digits", ->
keydown '9'
@@ -1720,12 +2155,14 @@ describe "Operators", ->
keydown 'x', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[0, 1], [1, 4], [2, 5], [3, 5], [4, 0]]
expect(editor.getText()).toBe '24\nab-54\ncd-166ef\nab-104\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
it "does nothing when cursor is after the number", ->
editor.setCursorBufferPosition [2, 5]
keydown 'x', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[2, 5]]
expect(editor.getText()).toBe '123\nab45\ncd-67ef\nab-5\na-bcdef'
+ expect(atom.beep).toHaveBeenCalled()
it "does nothing on an empty line", ->
editor.setText('\n')
@@ -1734,6 +2171,7 @@ describe "Operators", ->
keydown 'x', ctrl: true
expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]]
expect(editor.getText()).toBe '\n'
+ expect(atom.beep).toHaveBeenCalled()
it "honours the vim-mode:numberRegex setting", ->
editor.setText('123\nab45\ncd -67ef\nab-5\na-bcdef')
@@ -1746,3 +2184,101 @@ describe "Operators", ->
keydown('x', ctrl: true)
expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 5], [3, 3], [4, 0]]
expect(editor.getText()).toBe '122\nab44\ncd -68ef\nab-4\na-bcdef'
+ expect(atom.beep).not.toHaveBeenCalled()
+
+ describe 'the R keybinding', ->
+ beforeEach ->
+ editor.setText('12345\n67890')
+ editor.setCursorBufferPosition([0, 2])
+
+ it "enters replace mode and replaces characters", ->
+ keydown "R", shift: true
+ expect(editorElement.classList.contains('insert-mode')).toBe true
+ expect(editorElement.classList.contains('replace-mode')).toBe true
+
+ editor.insertText "ab"
+ keydown 'escape'
+
+ expect(editor.getText()).toBe "12ab5\n67890"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+ expect(editorElement.classList.contains('insert-mode')).toBe false
+ expect(editorElement.classList.contains('replace-mode')).toBe false
+ expect(editorElement.classList.contains('normal-mode')).toBe true
+
+ it "continues beyond end of line as insert", ->
+ keydown "R", shift: true
+ expect(editorElement.classList.contains('insert-mode')).toBe true
+ expect(editorElement.classList.contains('replace-mode')).toBe true
+
+ editor.insertText "abcde"
+ keydown 'escape'
+
+ expect(editor.getText()).toBe "12abcde\n67890"
+
+ it "treats backspace as undo", ->
+ editor.insertText "foo"
+ keydown "R", shift: true
+
+ editor.insertText "a"
+ editor.insertText "b"
+ expect(editor.getText()).toBe "12fooab5\n67890"
+
+ keydown 'backspace', raw: true
+ expect(editor.getText()).toBe "12fooa45\n67890"
+
+ editor.insertText "c"
+
+ expect(editor.getText()).toBe "12fooac5\n67890"
+
+ keydown 'backspace', raw: true
+ keydown 'backspace', raw: true
+
+ expect(editor.getText()).toBe "12foo345\n67890"
+ expect(editor.getSelectedText()).toBe ""
+
+ keydown 'backspace', raw: true
+ expect(editor.getText()).toBe "12foo345\n67890"
+ expect(editor.getSelectedText()).toBe ""
+
+ it "can be repeated", ->
+ keydown "R", shift: true
+ editor.insertText "ab"
+ keydown 'escape'
+ editor.setCursorBufferPosition([1, 2])
+ keydown '.'
+ expect(editor.getText()).toBe "12ab5\n67ab0"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ editor.setCursorBufferPosition([0, 4])
+ keydown '.'
+ expect(editor.getText()).toBe "12abab\n67ab0"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+
+ it "can be interrupted by arrow keys and behave as insert for repeat", ->
+ # FIXME don't know how to test this (also, depends on PR #568)
+
+ it "repeats correctly when backspace was used in the text", ->
+ keydown "R", shift: true
+ editor.insertText "a"
+ keydown 'backspace', raw: true
+ editor.insertText "b"
+ keydown 'escape'
+ editor.setCursorBufferPosition([1, 2])
+ keydown '.'
+ expect(editor.getText()).toBe "12b45\n67b90"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ editor.setCursorBufferPosition([0, 4])
+ keydown '.'
+ expect(editor.getText()).toBe "12b4b\n67b90"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+
+ it "doesn't replace a character if newline is entered", ->
+ keydown "R", shift: true
+ expect(editorElement.classList.contains('insert-mode')).toBe true
+ expect(editorElement.classList.contains('replace-mode')).toBe true
+
+ editor.insertText "\n"
+ keydown 'escape'
+
+ expect(editor.getText()).toBe "12\n345\n67890"
diff --git a/atom/packages/vim-mode/spec/prefixes-spec.coffee b/atom/packages/vim-mode/spec/prefixes-spec.coffee
index e782d20..71c4a12 100644
--- a/atom/packages/vim-mode/spec/prefixes-spec.coffee
+++ b/atom/packages/vim-mode/spec/prefixes-spec.coffee
@@ -11,8 +11,8 @@ describe "Prefixes", ->
editorElement = element
editor = editorElement.getModel()
vimState = editorElement.vimState
- vimState.activateCommandMode()
- vimState.resetCommandMode()
+ vimState.activateNormalMode()
+ vimState.resetNormalMode()
keydown = (key, options={}) ->
options.element ?= editorElement
@@ -146,3 +146,37 @@ describe "Prefixes", ->
it "throws away anything written to it", ->
vimState.setRegister('%', "new content")
expect(vimState.getRegister('%').text).toEqual '/Users/atom/known_value.txt'
+
+ describe "the ctrl-r command in insert mode", ->
+ beforeEach ->
+ editor.setText "02\n"
+ editor.setCursorScreenPosition [0, 0]
+ vimState.setRegister('"', text: '345')
+ vimState.setRegister('a', text: 'abc')
+ atom.clipboard.write "clip"
+ keydown 'a'
+ editor.insertText '1'
+
+ it "inserts contents of the unnamed register with \"", ->
+ keydown 'r', ctrl: true
+ keydown '"'
+ expect(editor.getText()).toBe '013452\n'
+
+ describe "when useClipboardAsDefaultRegister enabled", ->
+ it "inserts contents from clipboard with \"", ->
+ atom.config.set 'vim-mode.useClipboardAsDefaultRegister', true
+ keydown 'r', ctrl: true
+ keydown '"'
+ expect(editor.getText()).toBe '01clip2\n'
+
+ it "inserts contents of the 'a' register", ->
+ keydown 'r', ctrl: true
+ keydown 'a'
+ expect(editor.getText()).toBe '01abc2\n'
+
+ it "is cancelled with the escape key", ->
+ keydown 'r', ctrl: true
+ keydown 'escape'
+ expect(editor.getText()).toBe '012\n'
+ expect(vimState.mode).toBe "insert"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
diff --git a/atom/packages/vim-mode/spec/scroll-spec.coffee b/atom/packages/vim-mode/spec/scroll-spec.coffee
index 9473193..ebe400a 100644
--- a/atom/packages/vim-mode/spec/scroll-spec.coffee
+++ b/atom/packages/vim-mode/spec/scroll-spec.coffee
@@ -11,8 +11,8 @@ describe "Scrolling", ->
editorElement = element
editor = editorElement.getModel()
vimState = editorElement.vimState
- vimState.activateCommandMode()
- vimState.resetCommandMode()
+ vimState.activateNormalMode()
+ vimState.resetNormalMode()
keydown = (key, options={}) ->
options.element ?= editorElement
@@ -120,3 +120,111 @@ describe "Scrolling", ->
keydown('b')
expect(editor.setScrollTop).toHaveBeenCalledWith(860)
expect(editor.moveToFirstCharacterOfLine).not.toHaveBeenCalled()
+
+ describe "horizontal scroll cursor keybindings", ->
+ beforeEach ->
+ editor.setWidth(600)
+ editor.setLineHeightInPixels(10)
+ editor.setDefaultCharWidth(10)
+ text = ""
+ for i in [100..199]
+ text += "#{i} "
+ editor.setText(text)
+ editor.setCursorBufferPosition([0, 0])
+
+ describe "the zs keybinding", ->
+ zsPos = (pos) ->
+ editor.setCursorBufferPosition([0, pos])
+ keydown('z')
+ keydown('s')
+ editor.getScrollLeft()
+
+ startPosition = NaN
+
+ beforeEach ->
+ startPosition = editor.getScrollLeft()
+
+ it "does nothing near the start of the line", ->
+ pos1 = zsPos(1)
+ expect(pos1).toEqual(startPosition)
+
+ it "moves the cursor the nearest it can to the left edge of the editor", ->
+ pos10 = zsPos(10)
+ expect(pos10).toBeGreaterThan(startPosition)
+
+ pos11 = zsPos(11)
+ expect(pos11 - pos10).toEqual(10)
+
+ it "does nothing near the end of the line", ->
+ posEnd = zsPos(399)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 399]
+
+ pos390 = zsPos(390)
+ expect(pos390).toEqual(posEnd)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 390]
+
+ pos340 = zsPos(340)
+ expect(pos340).toBeLessThan(posEnd)
+ pos342 = zsPos(342)
+ expect(pos342 - pos340).toEqual(20)
+
+ it "does nothing if all lines are short", ->
+ editor.setText('short')
+ startPosition = editor.getScrollLeft()
+ pos1 = zsPos(1)
+ expect(pos1).toEqual(startPosition)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 1]
+ pos10 = zsPos(10)
+ expect(pos10).toEqual(startPosition)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 4]
+
+
+ describe "the ze keybinding", ->
+ zePos = (pos) ->
+ editor.setCursorBufferPosition([0, pos])
+ keydown('z')
+ keydown('e')
+ editor.getScrollLeft()
+
+ startPosition = NaN
+
+ beforeEach ->
+ startPosition = editor.getScrollLeft()
+
+ it "does nothing near the start of the line", ->
+ pos1 = zePos(1)
+ expect(pos1).toEqual(startPosition)
+
+ pos40 = zePos(40)
+ expect(pos40).toEqual(startPosition)
+
+ it "moves the cursor the nearest it can to the right edge of the editor", ->
+ pos110 = zePos(110)
+ expect(pos110).toBeGreaterThan(startPosition)
+
+ pos109 = zePos(109)
+ expect(pos110 - pos109).toEqual(10)
+
+ it "does nothing when very near the end of the line", ->
+ posEnd = zePos(399)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 399]
+
+ pos397 = zePos(397)
+ expect(pos397).toEqual(posEnd)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 397]
+
+ pos380 = zePos(380)
+ expect(pos380).toBeLessThan(posEnd)
+
+ pos382 = zePos(382)
+ expect(pos382 - pos380).toEqual(20)
+
+ it "does nothing if all lines are short", ->
+ editor.setText('short')
+ startPosition = editor.getScrollLeft()
+ pos1 = zePos(1)
+ expect(pos1).toEqual(startPosition)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 1]
+ pos10 = zePos(10)
+ expect(pos10).toEqual(startPosition)
+ expect(editor.getCursorBufferPosition()).toEqual [0, 4]
diff --git a/atom/packages/vim-mode/spec/spec-helper.coffee b/atom/packages/vim-mode/spec/spec-helper.coffee
index 88ba4b2..7cff2fc 100644
--- a/atom/packages/vim-mode/spec/spec-helper.coffee
+++ b/atom/packages/vim-mode/spec/spec-helper.coffee
@@ -3,8 +3,13 @@ GlobalVimState = require '../lib/global-vim-state'
VimMode = require '../lib/vim-mode'
StatusBarManager = require '../lib/status-bar-manager'
+[globalVimState, statusBarManager] = []
+
beforeEach ->
atom.workspace ||= {}
+ statusBarManager = null
+ globalVimState = null
+ spyOn(atom, 'beep')
getEditorElement = (callback) ->
textEditor = null
@@ -17,11 +22,16 @@ getEditorElement = (callback) ->
element = document.createElement("atom-text-editor")
element.setModel(textEditor)
element.classList.add('vim-mode')
- element.vimState = new VimState(element, new StatusBarManager, new GlobalVimState)
+ statusBarManager ?= new StatusBarManager
+ globalVimState ?= new GlobalVimState
+ element.vimState = new VimState(element, statusBarManager, globalVimState)
element.addEventListener "keydown", (e) ->
atom.keymaps.handleKeyboardEvent(e)
+ # mock parent element for the text editor
+ document.createElement('html').appendChild(atom.views.getView(textEditor))
+
callback(element)
mockPlatform = (editorElement, platform) ->
diff --git a/atom/packages/vim-mode/spec/text-objects-spec.coffee b/atom/packages/vim-mode/spec/text-objects-spec.coffee
index 6991dc7..92b4a7a 100644
--- a/atom/packages/vim-mode/spec/text-objects-spec.coffee
+++ b/atom/packages/vim-mode/spec/text-objects-spec.coffee
@@ -11,15 +11,23 @@ describe "TextObjects", ->
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)
- 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 ->
@@ -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(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')
@@ -44,6 +52,16 @@ describe "TextObjects", ->
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")
@@ -54,6 +72,39 @@ describe "TextObjects", ->
[[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) )")
@@ -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(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])
@@ -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(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")
@@ -92,6 +143,18 @@ describe "TextObjects", ->
[[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} }")
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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")
- editor.setCursorScreenPosition([2, 2])
+ editor.setCursorBufferPosition([2, 2])
it "applies operators inside the current paragraph in operator-pending mode", ->
-
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(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')
@@ -188,30 +284,105 @@ describe "TextObjects", ->
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 ->
- 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", ->
-
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(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('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')
- 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] ]")
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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])
@@ -303,6 +498,18 @@ describe "TextObjects", ->
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")
@@ -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(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')
@@ -326,6 +533,17 @@ describe "TextObjects", ->
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])
@@ -336,6 +554,60 @@ describe "TextObjects", ->
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) )")
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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 ->
@@ -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(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])
@@ -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(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]]
diff --git a/atom/packages/vim-mode/spec/vim-mode-spec.coffee b/atom/packages/vim-mode/spec/vim-mode-spec.coffee
index 0f4d8b8..280e545 100644
--- a/atom/packages/vim-mode/spec/vim-mode-spec.coffee
+++ b/atom/packages/vim-mode/spec/vim-mode-spec.coffee
@@ -18,15 +18,20 @@ describe "VimMode", ->
editorElement = atom.views.getView(editor)
describe ".activate", ->
- it "puts the editor in command-mode initially by default", ->
+ it "puts the editor in normal-mode initially by default", ->
expect(editorElement.classList.contains('vim-mode')).toBe(true)
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
it "shows the current vim mode in the status bar", ->
- statusBarTile = workspaceElement.querySelector("#status-bar-vim-mode")
- expect(statusBarTile.textContent).toBe("Command")
- atom.commands.dispatch(editorElement, "vim-mode:activate-insert-mode")
- expect(statusBarTile.textContent).toBe("Insert")
+ statusBarTile = null
+
+ waitsFor ->
+ statusBarTile = workspaceElement.querySelector("#status-bar-vim-mode")
+
+ runs ->
+ expect(statusBarTile.textContent).toBe("Normal")
+ atom.commands.dispatch(editorElement, "vim-mode:activate-insert-mode")
+ expect(statusBarTile.textContent).toBe("Insert")
it "doesn't register duplicate command listeners for editors", ->
editor.setText("12345")
@@ -44,7 +49,7 @@ describe "VimMode", ->
it "removes the vim classes from the editor", ->
atom.packages.deactivatePackage('vim-mode')
expect(editorElement.classList.contains("vim-mode")).toBe(false)
- expect(editorElement.classList.contains("command-mode")).toBe(false)
+ expect(editorElement.classList.contains("normal-mode")).toBe(false)
it "removes the vim commands from the editor element", ->
vimCommands = ->
diff --git a/atom/packages/vim-mode/spec/vim-state-spec.coffee b/atom/packages/vim-mode/spec/vim-state-spec.coffee
index 741c371..8fd3fb0 100644
--- a/atom/packages/vim-mode/spec/vim-state-spec.coffee
+++ b/atom/packages/vim-mode/spec/vim-state-spec.coffee
@@ -14,20 +14,20 @@ describe "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)
- commandModeInputKeydown = (key, opts = {}) ->
- editor.commandModeInputView.editorElement.getModel().setText(key)
+ normalModeInputKeydown = (key, opts = {}) ->
+ editor.normalModeInputView.editorElement.getModel().setText(key)
describe "initialization", ->
- it "puts the editor in command-mode initially by default", ->
+ it "puts the editor in normal-mode initially by default", ->
expect(editorElement.classList.contains('vim-mode')).toBe(true)
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
it "puts the editor in insert-mode if startInInsertMode is true", ->
atom.config.set 'vim-mode.startInInsertMode', true
@@ -41,15 +41,15 @@ describe "VimState", ->
expect(editorElement.component.isInputEnabled()).toBeTruthy()
it "removes the mode classes from the editor", ->
- expect(editorElement.classList.contains("command-mode")).toBeTruthy()
+ expect(editorElement.classList.contains("normal-mode")).toBeTruthy()
vimState.destroy()
- expect(editorElement.classList.contains("command-mode")).toBeFalsy()
+ expect(editorElement.classList.contains("normal-mode")).toBeFalsy()
it "is a noop when the editor is already destroyed", ->
editorElement.getModel().destroy()
vimState.destroy()
- describe "command-mode", ->
+ describe "normal-mode", ->
describe "when entering an insertable character", ->
beforeEach -> keydown('\\')
@@ -86,12 +86,18 @@ describe "VimState", ->
expect(editor.getCursors().length).toBe 1
describe "the v keybinding", ->
- beforeEach -> keydown('v')
+ beforeEach ->
+ editor.setText("012345\nabcdef")
+ editor.setCursorScreenPosition([0, 0])
+ keydown('v')
it "puts the editor into visual characterwise mode", ->
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'characterwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
+
+ it "selects the current character", ->
+ expect(editor.getLastSelection().getText()).toEqual '0'
describe "the V keybinding", ->
beforeEach ->
@@ -102,33 +108,34 @@ describe "VimState", ->
it "puts the editor into visual linewise mode", ->
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'linewise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
it "selects the current line", ->
expect(editor.getLastSelection().getText()).toEqual '012345\n'
describe "the ctrl-v keybinding", ->
- beforeEach -> keydown('v', ctrl: true)
+ beforeEach ->
+ editor.setText("012345\nabcdef")
+ editor.setCursorScreenPosition([0, 0])
+ keydown('v', ctrl: true)
- it "puts the editor into visual characterwise mode", ->
+ it "puts the editor into visual blockwise mode", ->
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'blockwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
describe "selecting text", ->
beforeEach ->
- spyOn(_._, "now").andCallFake -> window.now
editor.setText("abc def")
+ editor.setCursorScreenPosition([0, 0])
it "puts the editor into visual mode", ->
- expect(vimState.mode).toEqual 'command'
- editor.setSelectedBufferRanges([[[0, 0], [0, 3]]])
-
- advanceClock(100)
+ expect(vimState.mode).toEqual 'normal'
+ atom.commands.dispatch(editorElement, "core:select-right")
expect(vimState.mode).toEqual 'visual'
expect(vimState.submode).toEqual 'characterwise'
- expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 3]]])
+ expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 1]]])
it "handles the editor being destroyed shortly after selecting text", ->
editor.setSelectedBufferRanges([[[0, 0], [0, 3]]])
@@ -136,27 +143,41 @@ describe "VimState", ->
vimState.destroy()
advanceClock(100)
+ it "handles native selection such as core:select-all", ->
+ atom.commands.dispatch(editorElement, "core:select-all")
+ expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 7]]])
+
describe "the i keybinding", ->
beforeEach -> keydown('i')
it "puts the editor into insert mode", ->
expect(editorElement.classList.contains('insert-mode')).toBe(true)
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
- describe "with content", ->
- beforeEach -> editor.setText("012345\n\nabcdef")
+ describe "the R keybinding", ->
+ beforeEach -> keydown('R', shift: true)
- # FIXME: See atom/vim-mode#2
- xdescribe "on a line with content", ->
- beforeEach -> editor.setCursorScreenPosition([0, 6])
+ it "puts the editor into replace mode", ->
+ expect(editorElement.classList.contains('insert-mode')).toBe(true)
+ expect(editorElement.classList.contains('replace-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
- it "does not allow the cursor to be placed on the \n character", ->
+ describe "with content", ->
+ beforeEach ->
+ editor.setText("012345\n\nabcdef")
+ editor.setCursorScreenPosition([0, 0])
+
+ describe "on a line with content", ->
+ it "does not allow atom commands to place the cursor on the \\n character", ->
+ atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
describe "on an empty line", ->
- beforeEach -> editor.setCursorScreenPosition([1, 0])
+ beforeEach ->
+ editor.setCursorScreenPosition([1, 0])
+ atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
- it "allows the cursor to be placed on the \n character", ->
+ it "allows the cursor to be placed on the \\n character", ->
expect(editor.getCursorScreenPosition()).toEqual [1, 0]
describe 'with character-input operations', ->
@@ -165,9 +186,9 @@ describe "VimState", ->
it 'properly clears the opStack', ->
keydown('d')
keydown('r')
- expect(vimState.mode).toBe 'command'
+ expect(vimState.mode).toBe 'normal'
expect(vimState.opStack.length).toBe 0
- atom.commands.dispatch(editor.commandModeInputView.editorElement, "core:cancel")
+ atom.commands.dispatch(editor.normalModeInputView.editorElement, "core:cancel")
keydown('d')
expect(editor.getText()).toBe '012345\nabcdef'
@@ -193,25 +214,78 @@ describe "VimState", ->
expect(editor.getCursorScreenPosition()).toEqual [1, 0]
describe "on a line with content", ->
- beforeEach -> editor.setCursorScreenPosition([0, 6])
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 0])
+ atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
+
+ it "allows the cursor to be placed on the \\n character", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it "puts the editor into normal mode when <escape> is pressed", ->
+ keydown('escape')
+
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
+ expect(editorElement.classList.contains('insert-mode')).toBe(false)
+ expect(editorElement.classList.contains('visual-mode')).toBe(false)
+
+ it "puts the editor into normal mode when <ctrl-c> is pressed", ->
+ helpers.mockPlatform(editorElement, 'platform-darwin')
+ keydown('c', ctrl: true)
+ helpers.unmockPlatform(editorElement)
+
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
+ expect(editorElement.classList.contains('insert-mode')).toBe(false)
+ expect(editorElement.classList.contains('visual-mode')).toBe(false)
+
+ describe "replace-mode", ->
+ describe "with content", ->
+ beforeEach -> editor.setText("012345\n\nabcdef")
+
+ describe "when cursor is in the middle of the line", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 3])
+ keydown('R', shift: true)
+
+ it "moves the cursor to the left when exiting replace mode", ->
+ keydown('escape')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "when cursor is at the beginning of line", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([1, 0])
+ keydown('R', shift: true)
+
+ it "leaves the cursor at the beginning of line", ->
+ keydown('escape')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "on a line with content", ->
+ beforeEach ->
+ keydown('R', shift: true)
+ editor.setCursorScreenPosition([0, 0])
+ atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
- it "allows the cursor to be placed on the \n character", ->
+ it "allows the cursor to be placed on the \\n character", ->
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
- it "puts the editor into command mode when <escape> is pressed", ->
+ it "puts the editor into normal mode when <escape> is pressed", ->
+ keydown('R', shift: true)
keydown('escape')
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
expect(editorElement.classList.contains('insert-mode')).toBe(false)
+ expect(editorElement.classList.contains('replace-mode')).toBe(false)
expect(editorElement.classList.contains('visual-mode')).toBe(false)
- it "puts the editor into command mode when <ctrl-c> is pressed", ->
+ it "puts the editor into normal mode when <ctrl-c> is pressed", ->
+ keydown('R', shift: true)
helpers.mockPlatform(editorElement, 'platform-darwin')
keydown('c', ctrl: true)
helpers.unmockPlatform(editorElement)
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
expect(editorElement.classList.contains('insert-mode')).toBe(false)
+ expect(editorElement.classList.contains('replace-mode')).toBe(false)
expect(editorElement.classList.contains('visual-mode')).toBe(false)
describe "visual-mode", ->
@@ -224,21 +298,21 @@ describe "VimState", ->
expect(editor.getSelectedBufferRanges()).toEqual [[[0, 4], [0, 5]]]
expect(editor.getSelectedText()).toBe("t")
- it "puts the editor into command mode when <escape> is pressed", ->
+ it "puts the editor into normal mode when <escape> is pressed", ->
keydown('escape')
expect(editor.getCursorBufferPositions()).toEqual [[0, 4]]
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
expect(editorElement.classList.contains('visual-mode')).toBe(false)
- it "puts the editor into command mode when <escape> is pressed on selection is reversed", ->
+ it "puts the editor into normal mode when <escape> is pressed on selection is reversed", ->
expect(editor.getSelectedText()).toBe("t")
keydown("h")
keydown("h")
expect(editor.getSelectedText()).toBe("e t")
expect(editor.getLastSelection().isReversed()).toBe(true)
keydown('escape')
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
expect(editor.getCursorBufferPositions()).toEqual [[0, 2]]
describe "motions", ->
@@ -254,7 +328,6 @@ describe "VimState", ->
expect(editor.getSelectedText()).toBe("t")
keydown("l")
- keydown("l")
expect(editor.getSelectedText()).toBe("tw")
describe "operators", ->
@@ -267,7 +340,7 @@ describe "VimState", ->
it "operate on the current selection", ->
expect(editor.getText()).toEqual "\nabcdef"
- describe "returning to command-mode", ->
+ describe "returning to normal-mode", ->
beforeEach ->
editor.setText("012345\n\nabcdef")
editor.selectLinesContainingCursors()
@@ -302,39 +375,65 @@ describe "VimState", ->
[0, 8]
])
+ it "harmonizes selection directions", ->
+ keydown("e")
+ editor.addCursorAtBufferPosition([0, Infinity])
+ keydown("h")
+ keydown("h")
+
+ expect(editor.getSelectedBufferRanges()).toEqual([
+ [[0, 4], [0, 5]],
+ [[0, 11], [0, 13]]
+ ])
+ expect(editor.getCursorBufferPositions()).toEqual([
+ [0, 5]
+ [0, 11]
+ ])
+
+ keydown("o")
+
+ expect(editor.getSelectedBufferRanges()).toEqual([
+ [[0, 4], [0, 5]],
+ [[0, 11], [0, 13]]
+ ])
+ expect(editor.getCursorBufferPositions()).toEqual([
+ [0, 5]
+ [0, 13]
+ ])
+
describe "activate visualmode witin visualmode", ->
beforeEach ->
keydown('escape')
- expect(vimState.mode).toEqual 'command'
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(vimState.mode).toEqual 'normal'
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
- it "activateVisualMode with same type puts the editor into command mode", ->
+ it "activateVisualMode with same type puts the editor into normal mode", ->
keydown('v')
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'characterwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
keydown('v')
- expect(vimState.mode).toEqual 'command'
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(vimState.mode).toEqual 'normal'
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
keydown('V', shift: true)
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'linewise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
keydown('V', shift: true)
- expect(vimState.mode).toEqual 'command'
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(vimState.mode).toEqual 'normal'
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
keydown('v', ctrl: true)
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'blockwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
keydown('v', ctrl: true)
- expect(vimState.mode).toEqual 'command'
- expect(editorElement.classList.contains('command-mode')).toBe(true)
+ expect(vimState.mode).toEqual 'normal'
+ expect(editorElement.classList.contains('normal-mode')).toBe(true)
describe "change submode within visualmode", ->
beforeEach ->
@@ -346,22 +445,22 @@ describe "VimState", ->
keydown('v')
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'characterwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
keydown('V', shift: true)
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'linewise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
keydown('v', ctrl: true)
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'blockwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
keydown('v')
expect(editorElement.classList.contains('visual-mode')).toBe(true)
expect(vimState.submode).toEqual 'characterwise'
- expect(editorElement.classList.contains('command-mode')).toBe(false)
+ expect(editorElement.classList.contains('normal-mode')).toBe(false)
it "recover original range when shift from linewse to characterwise", ->
@@ -389,32 +488,32 @@ describe "VimState", ->
it "basic marking functionality", ->
editor.setCursorScreenPosition([1, 1])
keydown('m')
- commandModeInputKeydown('t')
+ normalModeInputKeydown('t')
expect(editor.getText()).toEqual "text in line 1\ntext in line 2\ntext in line 3"
editor.setCursorScreenPosition([2, 2])
keydown('`')
- commandModeInputKeydown('t')
+ normalModeInputKeydown('t')
expect(editor.getCursorScreenPosition()).toEqual [1, 1]
it "real (tracking) marking functionality", ->
editor.setCursorScreenPosition([2, 2])
keydown('m')
- commandModeInputKeydown('q')
+ normalModeInputKeydown('q')
editor.setCursorScreenPosition([1, 2])
keydown('o')
keydown('escape')
keydown('`')
- commandModeInputKeydown('q')
+ normalModeInputKeydown('q')
expect(editor.getCursorScreenPosition()).toEqual [3, 2]
it "real (tracking) marking functionality", ->
editor.setCursorScreenPosition([2, 2])
keydown('m')
- commandModeInputKeydown('q')
+ normalModeInputKeydown('q')
editor.setCursorScreenPosition([1, 2])
keydown('d')
keydown('d')
keydown('escape')
keydown('`')
- commandModeInputKeydown('q')
+ normalModeInputKeydown('q')
expect(editor.getCursorScreenPosition()).toEqual [1, 2]