laughing-hipster/.atom/packages/vim-mode/spec/motions-spec.coffee

1411 lines
49 KiB
CoffeeScript

helpers = require './spec-helper'
describe "Motions", ->
[editor, editorView, vimState] = []
beforeEach ->
vimMode = atom.packages.loadPackage('vim-mode')
vimMode.activateResources()
editorView = helpers.cacheEditor(editorView)
editor = editorView.editor
vimState = editorView.vimState
vimState.activateCommandMode()
vimState.resetCommandMode()
keydown = (key, options={}) ->
options.element ?= editorView[0]
helpers.keydown(key, options)
commandModeInputKeydown = (key, opts = {}) ->
opts.element = editor.commandModeInputView.editor.find('input').get(0)
opts.raw = true
keydown(key, opts)
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]
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')
it "moves the cursor down", ->
keydown('j')
expect(editor.getCursorScreenPosition()).toEqual [2, 1]
it "don't go over after the last line", ->
keydown('j')
expect(editor.getCursorScreenPosition()).toEqual [2, 1]
it "selects the text while moving", ->
keydown('j')
expect(editor.getSelectedText()).toBe "bcd\nA"
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]
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 [2, 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 "doesn't go past the end of the file", ->
editor.setCursorScreenPosition([2, 0])
keydown('y')
keydown('W', shift:true)
expect(vimState.getRegister('"').text).toBe ''
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]
# INCOMPATIBILITY: vim doesn't stop at [2, 0] it advances immediately
# to [3, 2]
keydown('e')
expect(editor.getCursorScreenPosition()).toEqual [2, 0]
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 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, 1]
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, 8])
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])
keydown('y')
keydown('B', shift:true)
expect(vimState.getRegister('"').text).toBe ''
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]
# FIXME: this doesn't work as we can't determine if this is a motion
# or part of a repeat prefix.
xdescribe "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"
# commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed
#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"
# commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
#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"
# commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed
#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, 1]
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, 1]
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 ")
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", ->
beforeEach ->
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('/')
editor.commandModeInputView.editor.setText 'def'
editor.commandModeInputView.editor.trigger 'core:confirm'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
it "loops back around", ->
editor.setCursorBufferPosition([3, 0])
keydown('/')
editor.commandModeInputView.editor.setText 'def'
editor.commandModeInputView.editor.trigger 'core:confirm'
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
editor.commandModeInputView.editor.setText '[abc]'
editor.commandModeInputView.editor.trigger 'core:confirm'
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('/')
editor.commandModeInputView.editor.setText '[abc'
editor.commandModeInputView.editor.trigger 'core:confirm'
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('n')
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
it 'works with selection in visual mode', ->
editor.setText('one two three')
keydown('v')
keydown('/')
editor.commandModeInputView.editor.setText 'th'
editor.commandModeInputView.editor.trigger 'core:confirm'
expect(editor.getCursorBufferPosition()).toEqual [0, 8]
keydown('d')
expect(editor.getText()).toBe 'three'
it 'extends selection when repeating search in visual mode', ->
editor.setText('line1\nline2\nline3')
keydown('v')
keydown('/')
editor.commandModeInputView.editor.setText 'line'
editor.commandModeInputView.editor.trigger 'core:confirm'
{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 "repeating", ->
it "does nothing with no search history", ->
# This tests that no exception is raised
keydown('n')
beforeEach ->
keydown('/')
editor.commandModeInputView.editor.setText 'def'
editor.commandModeInputView.editor.trigger 'core:confirm'
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('/')
editor.commandModeInputView.editor.setText('def')
editor.commandModeInputView.editor.trigger('core:confirm')
expect(editor.getText()).toEqual "def\nabc\ndef\n"
it "repeats correctly with operators", ->
keydown('d')
keydown('/')
editor.commandModeInputView.editor.setText('def')
editor.commandModeInputView.editor.trigger('core:confirm')
keydown('.')
expect(editor.getText()).toEqual "def\n"
describe "when reversed as ?", ->
it "moves the cursor backwards to the specified search pattern", ->
keydown('?')
editor.commandModeInputView.editor.setText('def')
editor.commandModeInputView.editor.trigger('core:confirm')
expect(editor.getCursorBufferPosition()).toEqual [3, 0]
describe "repeating", ->
beforeEach ->
keydown('?')
editor.commandModeInputView.editor.setText('def')
editor.commandModeInputView.editor.trigger('core:confirm')
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", ->
beforeEach ->
keydown('/')
editor.commandModeInputView.editor.setText('def')
editor.commandModeInputView.editor.trigger('core:confirm')
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
keydown('/')
editor.commandModeInputView.editor.setText('abc')
editor.commandModeInputView.editor.trigger('core:confirm')
expect(editor.getCursorBufferPosition()).toEqual [2, 0]
it "allows searching history in the search field", ->
keydown('/')
editor.commandModeInputView.editor.trigger('core:move-up')
expect(editor.commandModeInputView.editor.getText()).toEqual('abc')
editor.commandModeInputView.editor.trigger('core:move-up')
expect(editor.commandModeInputView.editor.getText()).toEqual('def')
editor.commandModeInputView.editor.trigger('core:move-up')
expect(editor.commandModeInputView.editor.getText()).toEqual('def')
it "resets the search field to empty when scrolling back", ->
keydown('/')
editor.commandModeInputView.editor.trigger('core:move-up')
expect(editor.commandModeInputView.editor.getText()).toEqual('abc')
editor.commandModeInputView.editor.trigger('core:move-up')
expect(editor.commandModeInputView.editor.getText()).toEqual('def')
editor.commandModeInputView.editor.trigger('core:move-down')
expect(editor.commandModeInputView.editor.getText()).toEqual('abc')
editor.commandModeInputView.editor.trigger('core:move-down')
expect(editor.commandModeInputView.editor.getText()).toEqual ''
describe "the * keybinding", ->
beforeEach ->
editor.setText("abc\n@def\nabc\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 "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\n @def\n abc\n @def")
editor.setCursorBufferPosition([1, 0])
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, 1]
describe "the hash keybinding", ->
describe "as a motion", ->
it "moves cursor to next occurence of word under cursor", ->
editor.setText("abc\n@def\nabc\ndef\n")
editor.setCursorBufferPosition([2, 0])
keydown("#")
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 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, 'setCursorScreenPosition')
it "moves the cursor to the first row if visible", ->
spyOn(editorView, 'getFirstVisibleScreenRow').andReturn(0)
keydown('H', shift: true)
expect(editor.setCursorScreenPosition).toHaveBeenCalledWith([0, 0])
it "moves the cursor to the first visible row plus offset", ->
spyOn(editorView, 'getFirstVisibleScreenRow').andReturn(2)
keydown('H', shift: true)
expect(editor.setCursorScreenPosition).toHaveBeenCalledWith([4, 0])
it "respects counts", ->
spyOn(editorView, 'getFirstVisibleScreenRow').andReturn(0)
keydown('3')
keydown('H', shift: true)
expect(editor.setCursorScreenPosition).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, 'setCursorScreenPosition')
it "moves the cursor to the first row if visible", ->
spyOn(editorView, 'getLastVisibleScreenRow').andReturn(10)
keydown('L', shift: true)
expect(editor.setCursorScreenPosition).toHaveBeenCalledWith([10, 0])
it "moves the cursor to the first visible row plus offset", ->
spyOn(editorView, 'getLastVisibleScreenRow').andReturn(6)
keydown('L', shift: true)
expect(editor.setCursorScreenPosition).toHaveBeenCalledWith([4, 0])
it "respects counts", ->
spyOn(editorView, 'getLastVisibleScreenRow').andReturn(10)
keydown('3')
keydown('L', shift: true)
expect(editor.setCursorScreenPosition).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, 'setCursorScreenPosition')
spyOn(editorView, 'getLastVisibleScreenRow').andReturn(10)
spyOn(editorView, 'getFirstVisibleScreenRow').andReturn(0)
it "moves the cursor to the first row if visible", ->
keydown('M', shift: true)
expect(editor.setCursorScreenPosition).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 '\n56\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]
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]
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]
it "composes with d", ->
editor.setCursorScreenPosition([0,3])
keydown('d')
keydown('2')
keydown('t')
commandModeInputKeydown('a')
expect(editor.getText()).toEqual 'abcabc\n'
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('%')
expect(editor.getCursorScreenPosition()).toEqual [0, 0]
it 'moves correctly when composed with v going backward', ->
editor.setCursorScreenPosition([0, 6])
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"