aboutsummaryrefslogtreecommitdiff
path: root/atom/packages/vim-mode/spec/motions-spec.coffee
diff options
context:
space:
mode:
authorBen Beltran <ben@nsovocal.com>2015-07-10 11:12:25 -0500
committerBen Beltran <ben@nsovocal.com>2015-07-10 11:12:25 -0500
commit24c7594d62d8d7fbbcdb64b11ce4adc5d8e6991a (patch)
treeded312222bb108923da1820ba40b04d710d20e5b /atom/packages/vim-mode/spec/motions-spec.coffee
parenteb786e82d170e2abc351a432ade616d6ecdeeb6b (diff)
Adds atom
Diffstat (limited to 'atom/packages/vim-mode/spec/motions-spec.coffee')
-rw-r--r--atom/packages/vim-mode/spec/motions-spec.coffee1865
1 files changed, 1865 insertions, 0 deletions
diff --git a/atom/packages/vim-mode/spec/motions-spec.coffee b/atom/packages/vim-mode/spec/motions-spec.coffee
new file mode 100644
index 0000000..f7114ed
--- /dev/null
+++ b/atom/packages/vim-mode/spec/motions-spec.coffee
@@ -0,0 +1,1865 @@
+helpers = require './spec-helper'
+
+describe "Motions", ->
+ [editor, editorElement, vimState] = []
+
+ beforeEach ->
+ vimMode = atom.packages.loadPackage('vim-mode')
+ vimMode.activateResources()
+
+ helpers.getEditorElement (element) ->
+ editorElement = element
+ editor = editorElement.getModel()
+ vimState = editorElement.vimState
+ vimState.activateCommandMode()
+ vimState.resetCommandMode()
+
+ keydown = (key, options={}) ->
+ options.element ?= editorElement
+ helpers.keydown(key, options)
+
+ commandModeInputKeydown = (key, opts = {}) ->
+ editor.commandModeInputView.editorElement.getModel().setText(key)
+
+ submitCommandModeInputText = (text) ->
+ commandEditor = editor.commandModeInputView.editorElement
+ commandEditor.getModel().setText(text)
+ atom.commands.dispatch(commandEditor, "core:confirm")
+
+ describe "simple motions", ->
+ beforeEach ->
+ editor.setText("12345\nabcd\nABCDE")
+ editor.setCursorScreenPosition([1, 1])
+
+ describe "the h keybinding", ->
+ describe "as a motion", ->
+ it "moves the cursor left, but not to the previous line", ->
+ keydown('h')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ keydown('h')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ it "moves the cursor to the previous line if wrapLeftRightMotion is true", ->
+ atom.config.set('vim-mode.wrapLeftRightMotion', true)
+ keydown('h')
+ keydown('h')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+
+ describe "as a selection", ->
+ it "selects the character to the left", ->
+ keydown('y')
+ keydown('h')
+
+ expect(vimState.getRegister('"').text).toBe 'a'
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "the j keybinding", ->
+ it "moves the cursor down, but not to the end of the last line", ->
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 1]
+
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 1]
+
+ it "moves the cursor to the end of the line, not past it", ->
+ editor.setCursorScreenPosition([0, 4])
+
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ it "remembers the position it column it was in after moving to shorter line", ->
+ editor.setCursorScreenPosition([0, 4])
+
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 4]
+
+ describe "when visual mode", ->
+ beforeEach ->
+ keydown('v')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ it "moves the cursor down", ->
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 2]
+
+ it "doesn't go over after the last line", ->
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 2]
+
+ it "selects the text while moving", ->
+ keydown('j')
+ expect(editor.getSelectedText()).toBe "bcd\nAB"
+
+ describe "the k keybinding", ->
+ it "moves the cursor up, but not to the beginning of the first line", ->
+ keydown('k')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ keydown('k')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ describe "the l keybinding", ->
+ beforeEach -> editor.setCursorScreenPosition([1, 2])
+
+ it "moves the cursor right, but not to the next line", ->
+ keydown('l')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ keydown('l')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ it "moves the cursor to the next line if wrapLeftRightMotion is true", ->
+ atom.config.set('vim-mode.wrapLeftRightMotion', true)
+ keydown('l')
+ keydown('l')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+
+ describe "on a blank line", ->
+ it "doesn't move the cursor", ->
+ editor.setText("\n\n\n")
+ editor.setCursorBufferPosition([1, 0])
+ keydown('l')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ describe "the w keybinding", ->
+ beforeEach -> editor.setText("ab cde1+- \n xyz\n\nzip")
+
+ describe "as a motion", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 0])
+
+ it "moves the cursor to the beginning of the next word", ->
+ keydown('w')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
+ keydown('w')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+
+ keydown('w')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 1]
+
+ 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]
+
+ # After cursor gets to the EOF, it should stay there.
+ keydown('w')
+ expect(editor.getCursorScreenPosition()).toEqual [3, 3]
+
+ 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])
+
+ describe "as a selection", ->
+ describe "within a word", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('y')
+ keydown('w')
+
+ it "selects to the end of the word", ->
+ expect(vimState.getRegister('"').text).toBe 'ab '
+
+ describe "between words", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 2])
+ keydown('y')
+ keydown('w')
+
+ it "selects the whitespace", ->
+ expect(vimState.getRegister('"').text).toBe ' '
+
+ describe "the W keybinding", ->
+ beforeEach -> editor.setText("cde1+- ab \n xyz\n\nzip")
+
+ describe "as a motion", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 0])
+
+ it "moves the cursor to the beginning of the next word", ->
+ keydown('W', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+
+ keydown('W', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [1, 1]
+
+ keydown('W', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+
+ keydown('W', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [3, 0]
+
+ describe "as a selection", ->
+ describe "within a word", ->
+ it "selects to the end of the whole word", ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('y')
+ keydown('W', shift: true)
+ expect(vimState.getRegister('"').text).toBe 'cde1+- '
+
+ it "continues past blank lines", ->
+ editor.setCursorScreenPosition([2, 0])
+
+ keydown('d')
+ keydown('W', shift: true)
+ expect(editor.getText()).toBe "cde1+- ab \n xyz\nzip"
+ expect(vimState.getRegister('"').text).toBe '\n'
+
+ it "doesn't go past the end of the file", ->
+ editor.setCursorScreenPosition([3, 0])
+
+ keydown('d')
+ keydown('W', shift: true)
+ expect(editor.getText()).toBe "cde1+- ab \n xyz\n\n"
+ expect(vimState.getRegister('"').text).toBe 'zip'
+
+ describe "the e keybinding", ->
+ beforeEach -> editor.setText("ab cde1+- \n xyz\n\nzip")
+
+ describe "as a motion", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 0])
+
+ it "moves the cursor to the end of the current word", ->
+ keydown('e')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ keydown('e')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ keydown('e')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+
+ keydown('e')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ keydown('e')
+ expect(editor.getCursorScreenPosition()).toEqual [3, 2]
+
+ describe "as selection", ->
+ describe "within a word", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('y')
+ keydown('e')
+
+ it "selects to the end of the current word", ->
+ expect(vimState.getRegister('"').text).toBe 'ab'
+
+ describe "between words", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 2])
+ keydown('y')
+ keydown('e')
+
+ it "selects to the end of the next word", ->
+ expect(vimState.getRegister('"').text).toBe ' cde1'
+
+ describe "the E keybinding", ->
+ beforeEach -> editor.setText("ab cde1+- \n xyz \n\nzip\n")
+
+ describe "as a motion", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 0])
+
+ it "moves the cursor to the end of the current word", ->
+ keydown('E', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ keydown('E', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 9]
+
+ keydown('E', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ keydown('E', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [3, 2]
+
+ keydown('E', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [4, 0]
+
+ describe "as selection", ->
+ describe "within a word", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('y')
+ keydown('E', shift: true)
+
+ it "selects to the end of the current word", ->
+ expect(vimState.getRegister('"').text).toBe 'ab'
+
+ describe "between words", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 2])
+ keydown('y')
+ keydown('E', shift: true)
+
+ it "selects to the end of the next word", ->
+ expect(vimState.getRegister('"').text).toBe ' cde1+-'
+
+ describe "press more than once", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('v')
+ keydown('E', shift: true)
+ keydown('E', shift: true)
+ keydown('y')
+
+ it "selects to the end of the current word", ->
+ expect(vimState.getRegister('"').text).toBe 'ab cde1+-'
+
+ describe "the } keybinding", ->
+ beforeEach ->
+ editor.setText("abcde\n\nfghij\nhijk\n xyz \n\nzip\n\n \nthe end")
+ editor.setCursorScreenPosition([0, 0])
+
+ describe "as a motion", ->
+ it "moves the cursor to the end of the paragraph", ->
+ keydown('}')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ keydown('}')
+ expect(editor.getCursorScreenPosition()).toEqual [5, 0]
+
+ keydown('}')
+ expect(editor.getCursorScreenPosition()).toEqual [7, 0]
+
+ keydown('}')
+ expect(editor.getCursorScreenPosition()).toEqual [9, 6]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('y')
+ keydown('}')
+
+ it 'selects to the end of the current paragraph', ->
+ expect(vimState.getRegister('"').text).toBe "abcde\n"
+
+ describe "the { keybinding", ->
+ beforeEach ->
+ editor.setText("abcde\n\nfghij\nhijk\n xyz \n\nzip\n\n \nthe end")
+ editor.setCursorScreenPosition([9, 0])
+
+ describe "as a motion", ->
+ it "moves the cursor to the beginning of the paragraph", ->
+ keydown('{')
+ expect(editor.getCursorScreenPosition()).toEqual [7, 0]
+
+ keydown('{')
+ expect(editor.getCursorScreenPosition()).toEqual [5, 0]
+
+ keydown('{')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ keydown('{')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([7, 0])
+ keydown('y')
+ keydown('{')
+
+ it 'selects to the beginning of the current paragraph', ->
+ expect(vimState.getRegister('"').text).toBe "\nzip\n"
+
+ describe "the b keybinding", ->
+ beforeEach -> editor.setText(" ab cde1+- \n xyz\n\nzip }\n last")
+
+ describe "as a motion", ->
+ beforeEach -> editor.setCursorScreenPosition([4, 1])
+
+ it "moves the cursor to the beginning of the previous word", ->
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [3, 4]
+
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [3, 0]
+
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 1]
+
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ # Go to start of the file, after moving past the first word
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ # Stay at the start of the file
+ keydown('b')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "as a selection", ->
+ describe "within a word", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 2])
+ keydown('y')
+ keydown('b')
+
+ it "selects to the beginning of the current word", ->
+ expect(vimState.getRegister('"').text).toBe 'a'
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ describe "between words", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([0, 4])
+ keydown('y')
+ keydown('b')
+
+ it "selects to the beginning of the last word", ->
+ expect(vimState.getRegister('"').text).toBe 'ab '
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ describe "the B keybinding", ->
+ beforeEach -> editor.setText("cde1+- ab \n\t xyz-123\n\n zip")
+
+ describe "as a motion", ->
+ beforeEach -> editor.setCursorScreenPosition([4, 1])
+
+ it "moves the cursor to the beginning of the previous word", ->
+ keydown('B', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [3, 1]
+
+ keydown('B', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+
+ keydown('B', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [1, 3]
+
+ keydown('B', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+
+ keydown('B', shift: true)
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "as a selection", ->
+ it "selects to the beginning of the whole word", ->
+ editor.setCursorScreenPosition([1, 10])
+ keydown('y')
+ keydown('B', shift: true)
+ expect(vimState.getRegister('"').text).toBe 'xyz-123'
+
+ it "doesn't go past the beginning of the file", ->
+ editor.setCursorScreenPosition([0, 0])
+ vimState.setRegister('"', text: 'abc')
+ keydown('y')
+ keydown('B', shift: true)
+ expect(vimState.getRegister('"').text).toBe 'abc'
+
+ describe "the ^ keybinding", ->
+ beforeEach ->
+ editor.setText(" abcde")
+
+ describe "from the beginning of the line", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 0])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('^')
+
+ it "moves the cursor to the first character of the line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('^')
+
+ it 'selects to the first character of the line', ->
+ expect(editor.getText()).toBe 'abcde'
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "from the first character of the line", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 2])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('^')
+
+ it "stays put", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('^')
+
+ it "does nothing", ->
+ expect(editor.getText()).toBe ' abcde'
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "from the middle of a word", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 4])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('^')
+
+ it "moves the cursor to the first character of the line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('^')
+
+ it 'selects to the first character of the line', ->
+ expect(editor.getText()).toBe ' cde'
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "the 0 keybinding", ->
+ beforeEach ->
+ editor.setText(" abcde")
+ editor.setCursorScreenPosition([0, 4])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('0')
+
+ it "moves the cursor to the first column", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('0')
+
+ it 'selects to the first column of the line', ->
+ expect(editor.getText()).toBe 'cde'
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "the $ keybinding", ->
+ beforeEach ->
+ editor.setText(" abcde\n\n1234567890")
+ editor.setCursorScreenPosition([0, 4])
+
+ describe "as a motion from empty line", ->
+ beforeEach -> editor.setCursorScreenPosition([1, 0])
+
+ it "moves the cursor to the end of the line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "as a motion", ->
+ beforeEach -> keydown('$')
+
+ # FIXME: See atom/vim-mode#2
+ it "moves the cursor to the end of the line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it "should remain in the last column when moving down", ->
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ keydown('j')
+ expect(editor.getCursorScreenPosition()).toEqual [2, 9]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('$')
+
+ it "selects to the beginning of the lines", ->
+ expect(editor.getText()).toBe " ab\n\n1234567890"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
+ describe "the 0 keybinding", ->
+ beforeEach ->
+ editor.setText(" a\n")
+ editor.setCursorScreenPosition([0, 2])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('0')
+
+ it "moves the cursor to the beginning of the line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "the - keybinding", ->
+ beforeEach ->
+ editor.setText("abcdefg\n abc\n abc\n")
+
+ describe "from the middle of a line", ->
+ beforeEach -> editor.setCursorScreenPosition([1, 3])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('-')
+
+ it "moves the cursor to the first character of the previous line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('-')
+
+ it "deletes the current and previous line", ->
+ expect(editor.getText()).toBe " abc\n"
+ # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
+ #expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
+ describe "from the first character of a line indented the same as the previous one", ->
+ beforeEach -> editor.setCursorScreenPosition([2, 2])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('-')
+
+ it "moves to the first character of the previous line (directly above)", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('-')
+
+ it "selects to the first character of the previous line (directly above)", ->
+ expect(editor.getText()).toBe "abcdefg\n"
+ # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
+ #expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "from the beginning of a line preceded by an indented line", ->
+ beforeEach -> editor.setCursorScreenPosition([2, 0])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('-')
+
+ it "moves the cursor to the first character of the previous line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('-')
+
+ it "selects to the first character of the previous line", ->
+ expect(editor.getText()).toBe "abcdefg\n"
+ # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
+ #expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "with a count", ->
+ beforeEach ->
+ editor.setText("1\n2\n3\n4\n5\n6\n")
+ editor.setCursorScreenPosition([4, 0])
+
+ describe "as a motion", ->
+ beforeEach ->
+ keydown('3')
+ keydown('-')
+
+ it "moves the cursor to the first character of that many lines previous", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('3')
+ keydown('-')
+
+ it "deletes the current line plus that many previous lines", ->
+ expect(editor.getText()).toBe "1\n6\n"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "the + keybinding", ->
+ beforeEach ->
+ editor.setText(" abc\n abc\nabcdefg\n")
+
+ describe "from the middle of a line", ->
+ beforeEach -> editor.setCursorScreenPosition([1, 3])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('+')
+
+ it "moves the cursor to the first character of the next line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [2, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('+')
+
+ it "deletes the current and next line", ->
+ expect(editor.getText()).toBe " abc\n"
+ # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
+ #expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
+ describe "from the first character of a line indented the same as the next one", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 2])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('+')
+
+ it "moves to the first character of the next line (directly below)", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('+')
+
+ it "selects to the first character of the next line (directly below)", ->
+ expect(editor.getText()).toBe "abcdefg\n"
+ # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
+ #expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe "from the beginning of a line followed by an indented line", ->
+ beforeEach -> editor.setCursorScreenPosition([0, 0])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('+')
+
+ it "moves the cursor to the first character of the next line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('+')
+
+ it "selects to the first character of the next line", ->
+ expect(editor.getText()).toBe "abcdefg\n"
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "with a count", ->
+ beforeEach ->
+ editor.setText("1\n2\n3\n4\n5\n6\n")
+ editor.setCursorScreenPosition([1, 0])
+
+ describe "as a motion", ->
+ beforeEach ->
+ keydown('3')
+ keydown('+')
+
+ it "moves the cursor to the first character of that many lines following", ->
+ expect(editor.getCursorScreenPosition()).toEqual [4, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('3')
+ keydown('+')
+
+ it "deletes the current line plus that many following lines", ->
+ expect(editor.getText()).toBe "1\n6\n"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "the _ keybinding", ->
+ beforeEach ->
+ editor.setText(" abc\n abc\nabcdefg\n")
+
+ describe "from the middle of a line", ->
+ beforeEach -> editor.setCursorScreenPosition([1, 3])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('_')
+
+ it "moves the cursor to the first character of the current line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 2]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('_')
+
+ it "deletes the current line", ->
+ expect(editor.getText()).toBe " abc\nabcdefg\n"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "with a count", ->
+ beforeEach ->
+ editor.setText("1\n2\n3\n4\n5\n6\n")
+ editor.setCursorScreenPosition([1, 0])
+
+ describe "as a motion", ->
+ beforeEach ->
+ keydown('3')
+ keydown('_')
+
+ it "moves the cursor to the first character of that many lines following", ->
+ expect(editor.getCursorScreenPosition()).toEqual [3, 0]
+
+ describe "as a selection", ->
+ beforeEach ->
+ keydown('d')
+ keydown('3')
+ keydown('_')
+
+ it "deletes the current line plus that many following lines", ->
+ expect(editor.getText()).toBe "1\n5\n6\n"
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "the enter keybinding", ->
+ keydownCodeForEnter = '\r' # 'enter' does not work
+ startingText = " abc\n abc\nabcdefg\n"
+
+ describe "from the middle of a line", ->
+ startingCursorPosition = [1, 3]
+
+ describe "as a motion", ->
+ it "acts the same as the + keybinding", ->
+ # do it with + and save the results
+ editor.setText(startingText)
+ editor.setCursorScreenPosition(startingCursorPosition)
+ keydown('+')
+ referenceCursorPosition = editor.getCursorScreenPosition()
+ # do it again with enter and compare the results
+ editor.setText(startingText)
+ editor.setCursorScreenPosition(startingCursorPosition)
+ keydown(keydownCodeForEnter)
+ expect(editor.getCursorScreenPosition()).toEqual referenceCursorPosition
+
+ describe "as a selection", ->
+ it "acts the same as the + keybinding", ->
+ # do it with + and save the results
+ editor.setText(startingText)
+ editor.setCursorScreenPosition(startingCursorPosition)
+ keydown('d')
+ keydown('+')
+ referenceText = editor.getText()
+ referenceCursorPosition = editor.getCursorScreenPosition()
+ # do it again with enter and compare the results
+ editor.setText(startingText)
+ editor.setCursorScreenPosition(startingCursorPosition)
+ keydown('d')
+ keydown(keydownCodeForEnter)
+ expect(editor.getText()).toEqual referenceText
+ expect(editor.getCursorScreenPosition()).toEqual referenceCursorPosition
+
+ describe "the gg keybinding", ->
+ beforeEach ->
+ editor.setText(" 1abc\n 2\n3\n")
+ editor.setCursorScreenPosition([0, 2])
+
+ describe "as a motion", ->
+ describe "in command mode", ->
+ beforeEach ->
+ keydown('g')
+ keydown('g')
+
+ it "moves the cursor to the beginning of the first line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "in linewise visual mode", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([1, 0])
+ vimState.activateVisualMode('linewise')
+ keydown('g')
+ keydown('g')
+
+ it "selects to the first line in the file", ->
+ expect(editor.getSelectedText()).toBe " 1abc\n 2\n"
+
+ it "moves the cursor to a specified line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "in characterwise visual mode", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([1, 1])
+ vimState.activateVisualMode()
+ keydown('g')
+ keydown('g')
+
+ it "selects to the first line in the file", ->
+ expect(editor.getSelectedText()).toBe "1abc\n 2"
+
+ it "moves the cursor to a specified line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ describe "as a repeated motion", ->
+ describe "in command mode", ->
+ beforeEach ->
+ keydown('2')
+ keydown('g')
+ keydown('g')
+
+ it "moves the cursor to a specified line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "in linewise visual motion", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([2, 0])
+ vimState.activateVisualMode('linewise')
+ keydown('2')
+ keydown('g')
+ keydown('g')
+
+ it "selects to a specified line", ->
+ expect(editor.getSelectedText()).toBe " 2\n3\n"
+
+ it "moves the cursor to a specified line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 0]
+
+ describe "in characterwise visual motion", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([2, 0])
+ vimState.activateVisualMode()
+ keydown('2')
+ keydown('g')
+ keydown('g')
+
+ it "selects to a first character of specified line", ->
+ expect(editor.getSelectedText()).toBe "2\n3"
+
+ it "moves the cursor to a specified line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 1]
+
+ describe "the g_ keybinding", ->
+ beforeEach ->
+ editor.setText("1 \n 2 \n 3abc\n ")
+
+ describe "as a motion", ->
+ it "moves the cursor to the last nonblank character", ->
+ editor.setCursorScreenPosition([1, 0])
+ keydown('g')
+ keydown('_')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 4]
+
+ it "will move the cursor to the beginning of the line if necessary", ->
+ editor.setCursorScreenPosition([0, 2])
+ keydown('g')
+ keydown('_')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ describe "as a repeated motion", ->
+ it "moves the cursor downward and outward", ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('2')
+ keydown('g')
+ keydown('_')
+ expect(editor.getCursorScreenPosition()).toEqual [1, 4]
+
+ describe "as a selection", ->
+ it "selects the current line excluding whitespace", ->
+ editor.setCursorScreenPosition([1, 2])
+ vimState.activateVisualMode()
+ keydown('2')
+ keydown('g')
+ keydown('_')
+ expect(editor.getSelectedText()).toEqual " 2 \n 3abc"
+
+ describe "the G keybinding", ->
+ beforeEach ->
+ editor.setText("1\n 2\n 3abc\n ")
+ editor.setCursorScreenPosition([0, 2])
+
+ describe "as a motion", ->
+ beforeEach -> keydown('G', shift: true)
+
+ it "moves the cursor to the last line after whitespace", ->
+ expect(editor.getCursorScreenPosition()).toEqual [3, 1]
+
+ describe "as a repeated motion", ->
+ beforeEach ->
+ keydown('2')
+ keydown('G', shift: true)
+
+ it "moves the cursor to a specified line", ->
+ expect(editor.getCursorScreenPosition()).toEqual [1, 4]
+
+ describe "as a selection", ->
+ beforeEach ->
+ editor.setCursorScreenPosition([1, 0])
+ vimState.activateVisualMode()
+ keydown('G', shift: true)
+
+ it "selects to the last line in the file", ->
+ expect(editor.getSelectedText()).toBe " 2\n 3abc\n "
+
+ it "moves the cursor to the last line after whitespace", ->
+ expect(editor.getCursorScreenPosition()).toEqual [3, 1]
+
+ describe "the / keybinding", ->
+ pane = null
+
+ beforeEach ->
+ pane = {activate: jasmine.createSpy("activate")}
+ spyOn(atom.workspace, 'getActivePane').andReturn(pane)
+
+ editor.setText("abc\ndef\nabc\ndef\n")
+ editor.setCursorBufferPosition([0, 0])
+
+ describe "as a motion", ->
+ it "moves the cursor to the specified search pattern", ->
+ keydown('/')
+
+ submitCommandModeInputText 'def'
+
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ expect(pane.activate).toHaveBeenCalled()
+
+ it "loops back around", ->
+ editor.setCursorBufferPosition([3, 0])
+ keydown('/')
+ submitCommandModeInputText 'def'
+
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ it "uses a valid regex as a regex", ->
+ keydown('/')
+ # Cycle through the 'abc' on the first line with a character pattern
+ submitCommandModeInputText '[abc]'
+ expect(editor.getCursorBufferPosition()).toEqual [0, 1]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [0, 2]
+
+ it "uses an invalid regex as a literal string", ->
+ # Go straight to the literal [abc
+ editor.setText("abc\n[abc]\n")
+ keydown('/')
+ submitCommandModeInputText '[abc'
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ it "uses ? as a literal string", ->
+ editor.setText("abc\n[a?c?\n")
+ keydown('/')
+ submitCommandModeInputText '?'
+ expect(editor.getCursorBufferPosition()).toEqual [1, 2]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 4]
+
+ it 'works with selection in visual mode', ->
+ editor.setText('one two three')
+ keydown('v')
+ keydown('/')
+ submitCommandModeInputText 'th'
+ expect(editor.getCursorBufferPosition()).toEqual [0, 9]
+ keydown('d')
+ expect(editor.getText()).toBe 'hree'
+
+ it 'extends selection when repeating search in visual mode', ->
+ editor.setText('line1\nline2\nline3')
+ keydown('v')
+ keydown('/')
+ submitCommandModeInputText 'line'
+ {start, end} = editor.getSelectedBufferRange()
+ expect(start.row).toEqual 0
+ expect(end.row).toEqual 1
+ keydown('n')
+ {start, end} = editor.getSelectedBufferRange()
+ expect(start.row).toEqual 0
+ expect(end.row).toEqual 2
+
+ describe "case sensitivity", ->
+ beforeEach ->
+ editor.setText("\nabc\nABC\n")
+ editor.setCursorBufferPosition([0, 0])
+ keydown('/')
+
+ it "works in case sensitive mode", ->
+ submitCommandModeInputText 'ABC'
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ it "works in case insensitive mode", ->
+ submitCommandModeInputText '\\cAbC'
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ it "works in case insensitive mode wherever \\c is", ->
+ submitCommandModeInputText 'AbC\\c'
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ it "uses case insensitive search if useSmartcaseForSearch is true and searching lowercase", ->
+ atom.config.set 'vim-mode.useSmartcaseForSearch', true
+ submitCommandModeInputText 'abc'
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ it "uses case sensitive search if useSmartcaseForSearch is true and searching uppercase", ->
+ atom.config.set 'vim-mode.useSmartcaseForSearch', true
+ submitCommandModeInputText 'ABC'
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ describe "repeating", ->
+ it "does nothing with no search history", ->
+ # This tests that no exception is raised
+ keydown('n')
+
+ beforeEach ->
+ keydown('/')
+ submitCommandModeInputText 'def'
+
+ it "repeats previous search with /<enter>", ->
+ keydown('/')
+ submitCommandModeInputText('')
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ it "repeats previous search with //", ->
+ keydown('/')
+ submitCommandModeInputText('/')
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ describe "the n keybinding", ->
+ it "repeats the last search", ->
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ describe "the N keybinding", ->
+ it "repeats the last search backwards", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown('N', shift: true)
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+ keydown('N', shift: true)
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ describe "composing", ->
+ it "composes with operators", ->
+ keydown('d')
+ keydown('/')
+ submitCommandModeInputText('def')
+ expect(editor.getText()).toEqual "def\nabc\ndef\n"
+
+ it "repeats correctly with operators", ->
+ keydown('d')
+ keydown('/')
+ submitCommandModeInputText('def')
+
+ keydown('.')
+ expect(editor.getText()).toEqual "def\n"
+
+ describe "when reversed as ?", ->
+ it "moves the cursor backwards to the specified search pattern", ->
+ keydown('?')
+ submitCommandModeInputText('def')
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ it "accepts / as a literal search pattern", ->
+ editor.setText("abc\nd/f\nabc\nd/f\n")
+ editor.setCursorBufferPosition([0, 0])
+ keydown('?')
+ submitCommandModeInputText('/')
+ expect(editor.getCursorBufferPosition()).toEqual [3, 1]
+ keydown('?')
+ submitCommandModeInputText('/')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+
+ describe "repeating", ->
+ beforeEach ->
+ keydown('?')
+ submitCommandModeInputText('def')
+
+ it "repeats previous search as reversed with ?<enter>", ->
+ keydown('?')
+ submitCommandModeInputText('')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ it "repeats previous search as reversed with ??", ->
+ keydown('?')
+ submitCommandModeInputText('?')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ describe 'the n keybinding', ->
+ it "repeats the last search backwards", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ describe 'the N keybinding', ->
+ it "repeats the last search forwards", ->
+ editor.setCursorBufferPosition([0, 0])
+ keydown('N', shift: true)
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ describe "using search history", ->
+ commandEditor = null
+
+ beforeEach ->
+ keydown('/')
+ submitCommandModeInputText('def')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ keydown('/')
+ submitCommandModeInputText('abc')
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ commandEditor = editor.commandModeInputView.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')
+
+ 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 ''
+
+ describe "the * keybinding", ->
+ beforeEach ->
+ editor.setText("abd\n@def\nabd\ndef\n")
+ editor.setCursorBufferPosition([0, 0])
+
+ describe "as a motion", ->
+ it "moves cursor to next occurence of word under cursor", ->
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ it "repeats with the n key", ->
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+ keydown("n")
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+
+ it "doesn't move cursor unless next occurence is the exact word (no partial matches)", ->
+ editor.setText("abc\ndef\nghiabc\njkl\nabcdef")
+ editor.setCursorBufferPosition([0, 0])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+
+ describe "with words that contain 'non-word' characters", ->
+ it "moves cursor to next occurence of word under cursor", ->
+ editor.setText("abc\n@def\nabc\n@def\n")
+ editor.setCursorBufferPosition([1, 0])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ 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("*")
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ # FIXME: This behavior is different from the one found in
+ # vim. This is because the word boundary match in Javascript
+ # ignores starting 'non-word' characters.
+ # e.g.
+ # in Vim: /\<def\>/.test("@def") => false
+ # in Javascript: /\bdef\b/.test("@def") => true
+ it "moves cursor to the start of valid word char", ->
+ editor.setText("abc\ndef\nabc\n@def\n")
+ editor.setCursorBufferPosition([1, 0])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [3, 1]
+
+ describe "when cursor is on non-word char column", ->
+ it "matches only the non-word char", ->
+ editor.setText("abc\n@def\nabc\n@def\n")
+ editor.setCursorBufferPosition([1, 0])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ describe "when cursor is not on a word", ->
+ it "does a match with the next word", ->
+ editor.setText("abc\na @def\n abc\n @def")
+ editor.setCursorBufferPosition([1, 1])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [3, 1]
+
+ describe "when cursor is at EOF", ->
+ it "doesn't try to do any match", ->
+ editor.setText("abc\n@def\nabc\n ")
+ editor.setCursorBufferPosition([3, 0])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ describe "the hash keybinding", ->
+ describe "as a motion", ->
+ it "moves cursor to previous occurence of word under cursor", ->
+ editor.setText("abc\n@def\nabc\ndef\n")
+ editor.setCursorBufferPosition([2, 1])
+ keydown("#")
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+
+ it "repeats with n", ->
+ editor.setText("abc\n@def\nabc\ndef\nabc\n")
+ editor.setCursorBufferPosition([2, 1])
+ keydown("#")
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+ keydown("n")
+ expect(editor.getCursorBufferPosition()).toEqual [4, 0]
+ keydown("n")
+ expect(editor.getCursorBufferPosition()).toEqual [2, 0]
+
+ it "doesn't move cursor unless next occurence is the exact word (no partial matches)", ->
+ editor.setText("abc\ndef\nghiabc\njkl\nabcdef")
+ editor.setCursorBufferPosition([0, 0])
+ keydown("#")
+ expect(editor.getCursorBufferPosition()).toEqual [0, 0]
+
+ describe "with words that containt 'non-word' characters", ->
+ it "moves cursor to next occurence of word under cursor", ->
+ editor.setText("abc\n@def\nabc\n@def\n")
+ editor.setCursorBufferPosition([3, 0])
+ keydown("#")
+ expect(editor.getCursorBufferPosition()).toEqual [1, 0]
+
+ it "moves cursor to the start of valid word char", ->
+ editor.setText("abc\n@def\nabc\ndef\n")
+ editor.setCursorBufferPosition([3, 0])
+ keydown("#")
+ expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+
+ describe "when cursor is on non-word char column", ->
+ it "matches only the non-word char", ->
+ editor.setText("abc\n@def\nabc\n@def\n")
+ editor.setCursorBufferPosition([1, 0])
+ keydown("*")
+ expect(editor.getCursorBufferPosition()).toEqual [3, 0]
+
+ describe "the H keybinding", ->
+ beforeEach ->
+ editor.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")
+ editor.setCursorScreenPosition([8, 0])
+ spyOn(editor.getLastCursor(), 'setScreenPosition')
+
+ it "moves the cursor to the first row if visible", ->
+ spyOn(editor, 'getFirstVisibleScreenRow').andReturn(0)
+ keydown('H', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([0, 0])
+
+ it "moves the cursor to the first visible row plus offset", ->
+ spyOn(editor, 'getFirstVisibleScreenRow').andReturn(2)
+ keydown('H', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([4, 0])
+
+ it "respects counts", ->
+ spyOn(editor, 'getFirstVisibleScreenRow').andReturn(0)
+ keydown('3')
+ keydown('H', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([2, 0])
+
+ describe "the L keybinding", ->
+ beforeEach ->
+ editor.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")
+ editor.setCursorScreenPosition([8, 0])
+ spyOn(editor.getLastCursor(), 'setScreenPosition')
+
+ it "moves the cursor to the first row if visible", ->
+ spyOn(editor, 'getLastVisibleScreenRow').andReturn(10)
+ keydown('L', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([10, 0])
+
+ it "moves the cursor to the first visible row plus offset", ->
+ spyOn(editor, 'getLastVisibleScreenRow').andReturn(6)
+ keydown('L', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([4, 0])
+
+ it "respects counts", ->
+ spyOn(editor, 'getLastVisibleScreenRow').andReturn(10)
+ keydown('3')
+ keydown('L', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([8, 0])
+
+ describe "the M keybinding", ->
+ beforeEach ->
+ editor.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")
+ editor.setCursorScreenPosition([8, 0])
+ spyOn(editor.getLastCursor(), 'setScreenPosition')
+ spyOn(editor, 'getLastVisibleScreenRow').andReturn(10)
+ spyOn(editor, 'getFirstVisibleScreenRow').andReturn(0)
+
+ it "moves the cursor to the first row if visible", ->
+ keydown('M', shift: true)
+ expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([5, 0])
+
+ describe 'the mark keybindings', ->
+ beforeEach ->
+ editor.setText(' 12\n 34\n56\n')
+ editor.setCursorBufferPosition([0, 1])
+
+ it 'moves to the beginning of the line of a mark', ->
+ editor.setCursorBufferPosition([1, 1])
+ keydown('m')
+ commandModeInputKeydown('a')
+ editor.setCursorBufferPosition([0, 0])
+ keydown('\'')
+ commandModeInputKeydown('a')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 4]
+
+ it 'moves literally to a mark', ->
+ editor.setCursorBufferPosition([1, 1])
+ keydown('m')
+ commandModeInputKeydown('a')
+ editor.setCursorBufferPosition([0, 0])
+ keydown('`')
+ commandModeInputKeydown('a')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 1]
+
+ it 'deletes to a mark by line', ->
+ editor.setCursorBufferPosition([1, 5])
+ keydown('m')
+ commandModeInputKeydown('a')
+ editor.setCursorBufferPosition([0, 0])
+ keydown('d')
+ keydown('\'')
+ commandModeInputKeydown('a')
+ expect(editor.getText()).toEqual '56\n'
+
+ it 'deletes before to a mark literally', ->
+ editor.setCursorBufferPosition([1, 5])
+ keydown('m')
+ commandModeInputKeydown('a')
+ editor.setCursorBufferPosition([0, 1])
+ keydown('d')
+ keydown('`')
+ commandModeInputKeydown('a')
+ expect(editor.getText()).toEqual ' 4\n56\n'
+
+ it 'deletes after to a mark literally', ->
+ editor.setCursorBufferPosition([1, 5])
+ keydown('m')
+ commandModeInputKeydown('a')
+ editor.setCursorBufferPosition([2, 1])
+ keydown('d')
+ keydown('`')
+ commandModeInputKeydown('a')
+ expect(editor.getText()).toEqual ' 12\n 36\n'
+
+ it 'moves back to previous', ->
+ editor.setCursorBufferPosition([1, 5])
+ keydown('`')
+ commandModeInputKeydown('`')
+ editor.setCursorBufferPosition([2, 1])
+ keydown('`')
+ commandModeInputKeydown('`')
+ expect(editor.getCursorBufferPosition()).toEqual [1, 5]
+
+ describe 'the f/F keybindings', ->
+ beforeEach ->
+ editor.setText("abcabcabcabc\n")
+ editor.setCursorScreenPosition([0, 0])
+
+ it 'moves to the first specified character it finds', ->
+ keydown('f')
+ commandModeInputKeydown('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')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ it 'respects count forward', ->
+ keydown('2')
+ keydown('f')
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it 'respects count backward', ->
+ editor.setCursorScreenPosition([0, 6])
+ keydown('2')
+ keydown('F', shift: true)
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ it "doesn't move if the character specified isn't found", ->
+ keydown('f')
+ commandModeInputKeydown('d')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ it "doesn't move if there aren't the specified count of the specified character", ->
+ keydown('1')
+ keydown('0')
+ keydown('f')
+ commandModeInputKeydown('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')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ # and backwards now
+ editor.setCursorScreenPosition([0, 6])
+ keydown('1')
+ keydown('0')
+ keydown('F', shift: true)
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+ keydown('1')
+ keydown('1')
+ keydown('F', shift: true)
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it "composes with d", ->
+ editor.setCursorScreenPosition([0, 3])
+ keydown('d')
+ keydown('2')
+ keydown('f')
+ commandModeInputKeydown('a')
+ expect(editor.getText()).toEqual 'abcbc\n'
+
+ describe 'the t/T keybindings', ->
+ beforeEach ->
+ editor.setText("abcabcabcabc\n")
+ editor.setCursorScreenPosition([0, 0])
+
+ it 'moves to the character previous to the first specified character it finds', ->
+ keydown('t')
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ # or stays put when it's already there
+ keydown('t')
+ commandModeInputKeydown('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')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ it 'respects count forward', ->
+ keydown('2')
+ keydown('t')
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+
+ it 'respects count backward', ->
+ editor.setCursorScreenPosition([0, 6])
+ keydown('2')
+ keydown('T', shift: true)
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+
+ it "doesn't move if the character specified isn't found", ->
+ keydown('t')
+ commandModeInputKeydown('d')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ it "doesn't move if there aren't the specified count of the specified character", ->
+ keydown('1')
+ keydown('0')
+ keydown('t')
+ commandModeInputKeydown('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')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+ # and backwards now
+ editor.setCursorScreenPosition([0, 6])
+ keydown('1')
+ keydown('0')
+ keydown('T', shift: true)
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+ keydown('1')
+ keydown('1')
+ keydown('T', shift: true)
+ commandModeInputKeydown('a')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it "composes with d", ->
+ editor.setCursorScreenPosition([0, 3])
+ keydown('d')
+ keydown('2')
+ keydown('t')
+ commandModeInputKeydown('b')
+ expect(editor.getText()).toBe 'abcbcabc\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', shift: true)
+ keydown('j')
+ keydown('j')
+ expect(editor.getSelectedText()).toBe "002\n0003\n00004\n"
+
+ it "selects up a line", ->
+ keydown('V', shift: true)
+ keydown('k')
+ expect(editor.getSelectedText()).toBe "01\n002\n"
+
+ describe 'the ; and , keybindings', ->
+ beforeEach ->
+ editor.setText("abcabcabcabc\n")
+ editor.setCursorScreenPosition([0, 0])
+
+ it "repeat f in same direction", ->
+ keydown('f')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+
+ it "repeat F in same direction", ->
+ editor.setCursorScreenPosition([0, 10])
+ keydown('F', shift: true)
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ it "repeat f in opposite direction", ->
+ editor.setCursorScreenPosition([0, 6])
+ keydown('f')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ it "repeat F in opposite direction", ->
+ editor.setCursorScreenPosition([0, 4])
+ keydown('F', shift: true)
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+
+ it "alternate repeat f in same direction and reverse", ->
+ keydown('f')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ it "alternate repeat F in same direction and reverse", ->
+ editor.setCursorScreenPosition([0, 10])
+ keydown('F', shift: true)
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 5]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+
+ it "repeat t in same direction", ->
+ keydown('t')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 1]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+
+ it "repeat T in same direction", ->
+ editor.setCursorScreenPosition([0, 10])
+ keydown('T', shift: true)
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 9]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it "repeat t in opposite direction first, and then reverse", ->
+ editor.setCursorScreenPosition([0, 3])
+ keydown('t')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+
+ it "repeat T in opposite direction first, and then reverse", ->
+ editor.setCursorScreenPosition([0, 4])
+ keydown('T', shift: true)
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 4]
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 3]
+
+ it "repeat with count in same direction", ->
+ editor.setCursorScreenPosition([0, 0])
+ keydown('f')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ keydown('2')
+ keydown(';')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+
+ it "repeat with count in reverse direction", ->
+ editor.setCursorScreenPosition([0, 6])
+ keydown('f')
+ commandModeInputKeydown('c')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 8]
+ keydown('2')
+ keydown(',')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+
+ describe 'the % motion', ->
+ beforeEach ->
+ editor.setText("( ( ) )--{ text in here; and a function call(with parameters) }\n")
+ editor.setCursorScreenPosition([0, 0])
+
+ it 'matches the correct parenthesis', ->
+ keydown('%')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 6]
+
+ it 'matches the correct brace', ->
+ editor.setCursorScreenPosition([0, 9])
+ keydown('%')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 62]
+
+ it 'composes correctly with d', ->
+ editor.setCursorScreenPosition([0, 9])
+ keydown('d')
+ keydown('%')
+ expect(editor.getText()).toEqual "( ( ) )--\n"
+
+ it 'moves correctly when composed with v going forward', ->
+ keydown('v')
+ keydown('h')
+ keydown('%')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 7]
+
+ it 'moves correctly when composed with v going backward', ->
+ editor.setCursorScreenPosition([0, 5])
+ keydown('v')
+ keydown('%')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 0]
+
+ it 'it moves appropriately to find the nearest matching action', ->
+ editor.setCursorScreenPosition([0, 3])
+ keydown('%')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 2]
+ expect(editor.getText()).toEqual "( ( ) )--{ text in here; and a function call(with parameters) }\n"
+
+ it 'it moves appropriately to find the nearest matching action', ->
+ editor.setCursorScreenPosition([0, 26])
+ keydown('%')
+ expect(editor.getCursorScreenPosition()).toEqual [0, 60]
+ expect(editor.getText()).toEqual "( ( ) )--{ text in here; and a function call(with parameters) }\n"
+
+ it "finds matches across multiple lines", ->
+ editor.setText("...(\n...)")
+ editor.setCursorScreenPosition([0, 0])
+ keydown("%")
+ expect(editor.getCursorScreenPosition()).toEqual([1, 3])
+
+ it "does not affect search history", ->
+ keydown('/')
+ submitCommandModeInputText 'func'
+ expect(editor.getCursorBufferPosition()).toEqual [0, 31]
+ keydown('%')
+ expect(editor.getCursorBufferPosition()).toEqual [0, 60]
+ keydown('n')
+ expect(editor.getCursorBufferPosition()).toEqual [0, 31]
+
+ describe "scrolling screen and keeping cursor in the same screen position", ->
+ beforeEach ->
+ editor.setText([0...80].join("\n"))
+ editor.setHeight(20 * 10)
+ editor.setLineHeightInPixels(10)
+ editor.setScrollTop(40 * 10)
+ editor.setCursorBufferPosition([42, 0])
+
+ describe "the ctrl-u keybinding", ->
+ it "moves the screen down by half screen size and keeps cursor onscreen", ->
+ keydown('u', ctrl: true)
+ expect(editor.getScrollTop()).toEqual 300
+ expect(editor.getCursorBufferPosition()).toEqual [32, 0]
+
+ it "selects on visual mode", ->
+ editor.setCursorBufferPosition([42, 1])
+ vimState.activateVisualMode()
+ keydown('u', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [32..42].join("\n")
+
+ it "selects on linewise mode", ->
+ vimState.activateVisualMode('linewise')
+ keydown('u', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [32..42].join("\n").concat("\n")
+
+ describe "the ctrl-b keybinding", ->
+ it "moves screen up one page", ->
+ keydown('b', ctrl: true)
+ expect(editor.getScrollTop()).toEqual 200
+ expect(editor.getCursorScreenPosition()).toEqual [22, 0]
+
+ it "selects on visual mode", ->
+ editor.setCursorBufferPosition([42, 1])
+ vimState.activateVisualMode()
+ keydown('b', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [22..42].join("\n")
+
+ it "selects on linewise mode", ->
+ vimState.activateVisualMode('linewise')
+ keydown('b', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [22..42].join("\n").concat("\n")
+
+
+ describe "the ctrl-d keybinding", ->
+ it "moves the screen down by half screen size and keeps cursor onscreen", ->
+ keydown('d', ctrl: true)
+ expect(editor.getScrollTop()).toEqual 500
+ expect(editor.getCursorBufferPosition()).toEqual [52, 0]
+
+ it "selects on visual mode", ->
+ editor.setCursorBufferPosition([42, 1])
+ vimState.activateVisualMode()
+ keydown('d', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [42..52].join("\n").slice(1, -1)
+
+ it "selects on linewise mode", ->
+ vimState.activateVisualMode('linewise')
+ keydown('d', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [42..52].join("\n").concat("\n")
+
+ describe "the ctrl-f keybinding", ->
+ it "moves screen down one page", ->
+ keydown('f', ctrl: true)
+ expect(editor.getScrollTop()).toEqual 600
+ expect(editor.getCursorScreenPosition()).toEqual [62, 0]
+
+ it "selects on visual mode", ->
+ editor.setCursorBufferPosition([42, 1])
+ vimState.activateVisualMode()
+ keydown('f', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [42..62].join("\n").slice(1, -1)
+
+ it "selects on linewise mode", ->
+ vimState.activateVisualMode('linewise')
+ keydown('f', ctrl: true)
+ expect(editor.getSelectedText()).toEqual [42..62].join("\n").concat("\n")