helpers = require './spec-helper' settings = require '../lib/settings' describe "Operators", -> [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) describe "cancelling operations", -> it "does not throw an error even if no operation is pending", -> # cancel operation pushes an empty input operation # doing this without a pending operation throws an exception expect(-> vimState.pushOperations(new Input(''))).toThrow() # make sure commandModeInputView is created keydown('/') expect(vimState.isOperatorPending()).toBe true editor.commandModeInputView.viewModel.cancel() expect(vimState.isOperatorPending()).toBe false expect(-> editor.commandModeInputView.viewModel.cancel()).not.toThrow() describe "the x keybinding", -> describe "on a line with content", -> describe "without vim-mode.wrapLeftRightMotion", -> beforeEach -> editor.setText("abc\n012345\n\nxyz") editor.setCursorScreenPosition([1, 4]) it "deletes a character", -> keydown('x') expect(editor.getText()).toBe 'abc\n01235\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 4] expect(vimState.getRegister('"').text).toBe '4' keydown('x') expect(editor.getText()).toBe 'abc\n0123\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 3] expect(vimState.getRegister('"').text).toBe '5' keydown('x') expect(editor.getText()).toBe 'abc\n012\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 2] expect(vimState.getRegister('"').text).toBe '3' keydown('x') expect(editor.getText()).toBe 'abc\n01\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 1] expect(vimState.getRegister('"').text).toBe '2' keydown('x') expect(editor.getText()).toBe 'abc\n0\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe '1' keydown('x') expect(editor.getText()).toBe 'abc\n\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe '0' it "deletes multiple characters with a count", -> keydown('2') keydown('x') expect(editor.getText()).toBe 'abc\n0123\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 3] expect(vimState.getRegister('"').text).toBe '45' editor.setCursorScreenPosition([0, 1]) keydown('3') keydown('x') expect(editor.getText()).toBe 'a\n0123\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [0, 0] expect(vimState.getRegister('"').text).toBe 'bc' describe "with vim-mode.wrapLeftRightMotion", -> beforeEach -> editor.setText("abc\n012345\n\nxyz") editor.setCursorScreenPosition([1, 4]) atom.config.set('vim-mode.wrapLeftRightMotion', true) it "deletes a character", -> # copy of the earlier test because wrapLeftRightMotion should not affect it keydown('x') expect(editor.getText()).toBe 'abc\n01235\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 4] expect(vimState.getRegister('"').text).toBe '4' keydown('x') expect(editor.getText()).toBe 'abc\n0123\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 3] expect(vimState.getRegister('"').text).toBe '5' keydown('x') expect(editor.getText()).toBe 'abc\n012\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 2] expect(vimState.getRegister('"').text).toBe '3' keydown('x') expect(editor.getText()).toBe 'abc\n01\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 1] expect(vimState.getRegister('"').text).toBe '2' keydown('x') expect(editor.getText()).toBe 'abc\n0\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe '1' keydown('x') expect(editor.getText()).toBe 'abc\n\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe '0' it "deletes multiple characters and newlines with a count", -> atom.config.set('vim-mode.wrapLeftRightMotion', true) keydown('2') keydown('x') expect(editor.getText()).toBe 'abc\n0123\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [1, 3] expect(vimState.getRegister('"').text).toBe '45' editor.setCursorScreenPosition([0, 1]) keydown('3') keydown('x') expect(editor.getText()).toBe 'a0123\n\nxyz' expect(editor.getCursorScreenPosition()).toEqual [0, 1] expect(vimState.getRegister('"').text).toBe 'bc\n' keydown('7') keydown('x') expect(editor.getText()).toBe 'ayz' expect(editor.getCursorScreenPosition()).toEqual [0, 1] expect(vimState.getRegister('"').text).toBe '0123\n\nx' describe "on an empty line", -> beforeEach -> editor.setText("abc\n012345\n\nxyz") editor.setCursorScreenPosition([2, 0]) it "deletes nothing on an empty line when vim-mode.wrapLeftRightMotion is false", -> atom.config.set('vim-mode.wrapLeftRightMotion', false) keydown('x') expect(editor.getText()).toBe "abc\n012345\n\nxyz" expect(editor.getCursorScreenPosition()).toEqual [2, 0] it "deletes an empty line when vim-mode.wrapLeftRightMotion is true", -> atom.config.set('vim-mode.wrapLeftRightMotion', true) keydown('x') expect(editor.getText()).toBe "abc\n012345\nxyz" expect(editor.getCursorScreenPosition()).toEqual [2, 0] describe "the X keybinding", -> describe "on a line with content", -> beforeEach -> editor.setText("ab\n012345") editor.setCursorScreenPosition([1, 2]) it "deletes a character", -> keydown('X', shift: true) expect(editor.getText()).toBe 'ab\n02345' expect(editor.getCursorScreenPosition()).toEqual [1, 1] expect(vimState.getRegister('"').text).toBe '1' keydown('X', shift: true) expect(editor.getText()).toBe 'ab\n2345' expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe '0' keydown('X', shift: true) expect(editor.getText()).toBe 'ab\n2345' expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe '0' atom.config.set('vim-mode.wrapLeftRightMotion', true) keydown('X', shift: true) expect(editor.getText()).toBe 'ab2345' expect(editor.getCursorScreenPosition()).toEqual [0, 2] expect(vimState.getRegister('"').text).toBe '\n' describe "on an empty line", -> beforeEach -> editor.setText("012345\n\nabcdef") editor.setCursorScreenPosition([1, 0]) it "deletes nothing when vim-mode.wrapLeftRightMotion is false", -> atom.config.set('vim-mode.wrapLeftRightMotion', false) keydown('X', shift: true) expect(editor.getText()).toBe "012345\n\nabcdef" expect(editor.getCursorScreenPosition()).toEqual [1, 0] it "deletes the newline when wrapLeftRightMotion is true", -> atom.config.set('vim-mode.wrapLeftRightMotion', true) keydown('X', shift: true) expect(editor.getText()).toBe "012345\nabcdef" expect(editor.getCursorScreenPosition()).toEqual [0, 5] describe "the s keybinding", -> beforeEach -> editor.setText('012345') editor.setCursorScreenPosition([0, 1]) it "deletes the character to the right and enters insert mode", -> keydown('s') expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getText()).toBe '02345' expect(editor.getCursorScreenPosition()).toEqual [0, 1] expect(vimState.getRegister('"').text).toBe '1' it "is repeatable", -> editor.setCursorScreenPosition([0, 0]) keydown('3') keydown('s') editor.insertText("ab") keydown('escape') expect(editor.getText()).toBe 'ab345' editor.setCursorScreenPosition([0, 2]) keydown('.') expect(editor.getText()).toBe 'abab' it "is undoable", -> editor.setCursorScreenPosition([0, 0]) keydown('3') keydown('s') editor.insertText("ab") keydown('escape') expect(editor.getText()).toBe 'ab345' keydown('u') expect(editor.getText()).toBe '012345' expect(editor.getSelectedText()).toBe '' describe "in visual mode", -> beforeEach -> keydown('v') editor.selectRight() keydown('s') it "deletes the selected characters and enters insert mode", -> expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getText()).toBe '0345' expect(editor.getCursorScreenPosition()).toEqual [0, 1] expect(vimState.getRegister('"').text).toBe '12' describe "the S keybinding", -> beforeEach -> editor.setText("12345\nabcde\nABCDE") editor.setCursorScreenPosition([1, 3]) it "deletes the entire line and enters insert mode", -> keydown('S', shift: true) expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getText()).toBe "12345\n\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe "abcde\n" expect(vimState.getRegister('"').type).toBe 'linewise' it "is repeatable", -> keydown('S', shift: true) editor.insertText("abc") keydown 'escape' expect(editor.getText()).toBe "12345\nabc\nABCDE" editor.setCursorScreenPosition([2, 3]) keydown '.' expect(editor.getText()).toBe "12345\nabc\nabc\n" it "is undoable", -> keydown('S', shift: true) editor.insertText("abc") keydown 'escape' expect(editor.getText()).toBe "12345\nabc\nABCDE" keydown 'u' expect(editor.getText()).toBe "12345\nabcde\nABCDE" expect(editor.getSelectedText()).toBe '' it "works when the cursor's goal column is greater than its current column", -> editor.setText("\n12345") editor.setCursorBufferPosition([1, Infinity]) editor.moveUp() keydown("S", shift: true) expect(editor.getText()).toBe("\n12345") # Can't be tested without setting grammar of test buffer xit "respects indentation", -> describe "the d keybinding", -> it "enters operator-pending mode", -> keydown('d') expect(editorElement.classList.contains('operator-pending-mode')).toBe(true) expect(editorElement.classList.contains('command-mode')).toBe(false) describe "when followed by a d", -> it "deletes the current line and exits operator-pending mode", -> editor.setText("12345\nabcde\n\nABCDE") editor.setCursorScreenPosition([1, 1]) keydown('d') keydown('d') expect(editor.getText()).toBe "12345\n\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(vimState.getRegister('"').text).toBe "abcde\n" expect(editorElement.classList.contains('operator-pending-mode')).toBe(false) expect(editorElement.classList.contains('command-mode')).toBe(true) it "deletes the last line", -> editor.setText("12345\nabcde\nABCDE") editor.setCursorScreenPosition([2, 1]) keydown('d') keydown('d') expect(editor.getText()).toBe "12345\nabcde\n" expect(editor.getCursorScreenPosition()).toEqual [2, 0] it "leaves the cursor on the first nonblank character", -> editor.setText("12345\n abcde\n") editor.setCursorScreenPosition([0, 4]) keydown('d') keydown('d') expect(editor.getText()).toBe " abcde\n" expect(editor.getCursorScreenPosition()).toEqual [0, 2] describe "undo behavior", -> beforeEach -> editor.setText("12345\nabcde\nABCDE\nQWERT") editor.setCursorScreenPosition([1, 1]) keydown('d') keydown('2') keydown('d') keydown('u') it "undoes both lines", -> expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT" expect(editor.getSelectedText()).toBe '' describe "when followed by a w", -> it "deletes the next word until the end of the line and exits operator-pending mode", -> editor.setText("abcd efg\nabc") editor.setCursorScreenPosition([0, 5]) keydown('d') keydown('w') # Incompatibility with VIM. In vim, `w` behaves differently as an # operator than as a motion; it stops at the end of a line.expect(editor.getText()).toBe "abcd abc" expect(editor.getText()).toBe "abcd abc" expect(editor.getCursorScreenPosition()).toEqual [0, 5] expect(editorElement.classList.contains('operator-pending-mode')).toBe(false) expect(editorElement.classList.contains('command-mode')).toBe(true) it "deletes to the beginning of the next word", -> editor.setText('abcd efg') editor.setCursorScreenPosition([0, 2]) keydown('d') keydown('w') expect(editor.getText()).toBe 'abefg' expect(editor.getCursorScreenPosition()).toEqual [0, 2] editor.setText('one two three four') editor.setCursorScreenPosition([0, 0]) keydown('d') keydown('3') keydown('w') expect(editor.getText()).toBe 'four' expect(editor.getCursorScreenPosition()).toEqual [0, 0] describe "when followed by an iw", -> it "deletes the containing word", -> editor.setText("12345 abcde ABCDE") editor.setCursorScreenPosition([0, 9]) keydown('d') expect(editorElement.classList.contains('operator-pending-mode')).toBe(true) keydown('i') keydown('w') expect(editor.getText()).toBe "12345 ABCDE" expect(editor.getCursorScreenPosition()).toEqual [0, 6] expect(vimState.getRegister('"').text).toBe "abcde" expect(editorElement.classList.contains('operator-pending-mode')).toBe(false) expect(editorElement.classList.contains('command-mode')).toBe(true) describe "when followed by an j", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the beginning of the file", -> editor.setCursorScreenPosition([0, 0]) it "deletes the next two lines", -> keydown('d') keydown('j') expect(editor.getText()).toBe("ABCDE") describe "on the end of the file", -> editor.setCursorScreenPosition([4, 2]) it "deletes nothing", -> keydown('d') keydown('j') expect(editor.getText()).toBe(originalText) describe "on the middle of second line", -> editor.setCursorScreenPosition([2, 1]) it "deletes the last two lines", -> keydown('d') keydown('j') expect(editor.getText()).toBe("12345") describe "when followed by an k", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the end of the file", -> editor.setCursorScreenPosition([4, 2]) it "deletes the bottom two lines", -> keydown('d') keydown('k') expect(editor.getText()).toBe("ABCDE") describe "on the beginning of the file", -> editor.setCursorScreenPosition([0, 0]) it "deletes nothing", -> keydown('d') keydown('k') expect(editor.getText()).toBe(originalText) describe "when on the middle of second line", -> editor.setCursorScreenPosition([2, 1]) it "deletes the first two lines", -> keydown('d') keydown('k') expect(editor.getText()).toBe("12345") describe "when followed by a G", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the beginning of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 0]) keydown('d') keydown('G', shift: true) expect(editor.getText()).toBe("12345\n") describe "on the middle of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 2]) keydown('d') keydown('G', shift: true) expect(editor.getText()).toBe("12345\n") describe "when followed by a goto line G", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the beginning of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 0]) keydown('d') keydown('2') keydown('G', shift: true) expect(editor.getText()).toBe("12345\nABCDE") describe "on the middle of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 2]) keydown('d') keydown('2') keydown('G', shift: true) expect(editor.getText()).toBe("12345\nABCDE") describe "when followed by a t)", -> describe "with the entire line yanked before", -> beforeEach -> editor.setText("test (xyz)") editor.setCursorScreenPosition([0, 6]) it "deletes until the closing parenthesis", -> keydown('y') keydown('y') keydown('d') keydown('t') commandModeInputKeydown(')') expect(editor.getText()).toBe("test ()") expect(editor.getCursorScreenPosition()).toEqual [0, 6] describe "with multiple cursors", -> it "deletes each selection", -> editor.setText("abcd\n1234\nABCD\n") editor.setCursorBufferPosition([0, 1]) editor.addCursorAtBufferPosition([1, 2]) editor.addCursorAtBufferPosition([2, 3]) keydown('d') keydown('e') expect(editor.getText()).toBe "a\n12\nABC" expect(editor.getCursorBufferPositions()).toEqual [ [0, 0], [1, 1], [2, 2], ] it "doesn't delete empty selections", -> editor.setText("abcd\nabc\nabd") editor.setCursorBufferPosition([0, 0]) editor.addCursorAtBufferPosition([1, 0]) editor.addCursorAtBufferPosition([2, 0]) keydown('d') keydown('t') commandModeInputKeydown('d') expect(editor.getText()).toBe "d\nabc\nd" expect(editor.getCursorBufferPositions()).toEqual [ [0, 0], [1, 0], [2, 0], ] describe "the D keybinding", -> beforeEach -> editor.getBuffer().setText("012\n") editor.setCursorScreenPosition([0, 1]) keydown('D', shift: true) it "deletes the contents until the end of the line", -> expect(editor.getText()).toBe "0\n" describe "the c keybinding", -> beforeEach -> editor.setText("12345\nabcde\nABCDE") describe "when followed by a c", -> it "deletes the current line and enters insert mode", -> editor.setCursorScreenPosition([1, 1]) keydown('c') keydown('c') expect(editor.getText()).toBe "12345\n\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(editorElement.classList.contains('command-mode')).toBe(false) expect(editorElement.classList.contains('insert-mode')).toBe(true) describe "when the cursor is on the last line", -> it "deletes the line's content and enters insert mode on the last line", -> editor.setCursorScreenPosition([2, 1]) keydown('c') keydown('c') expect(editor.getText()).toBe "12345\nabcde\n\n" expect(editor.getCursorScreenPosition()).toEqual [2, 0] expect(editorElement.classList.contains('command-mode')).toBe(false) expect(editorElement.classList.contains('insert-mode')).toBe(true) describe "when the cursor is on the only line", -> it "deletes the line's content and enters insert mode", -> editor.setText("12345") editor.setCursorScreenPosition([0, 2]) keydown('c') keydown('c') expect(editor.getText()).toBe "\n" expect(editor.getCursorScreenPosition()).toEqual [0, 0] expect(editorElement.classList.contains('command-mode')).toBe(false) expect(editorElement.classList.contains('insert-mode')).toBe(true) describe "when followed by i w", -> it "undo's and redo's completely", -> editor.setCursorScreenPosition([1, 1]) keydown('c') keydown('i') keydown('w') expect(editor.getText()).toBe "12345\n\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [1, 0] expect(editorElement.classList.contains('insert-mode')).toBe(true) # Just cannot get "typing" to work correctly in test. editor.setText("12345\nfg\nABCDE") keydown('escape') expect(editorElement.classList.contains('command-mode')).toBe(true) expect(editor.getText()).toBe "12345\nfg\nABCDE" keydown('u') expect(editor.getText()).toBe "12345\nabcde\nABCDE" keydown('r', ctrl: true) expect(editor.getText()).toBe "12345\nfg\nABCDE" describe "when followed by a w", -> it "changes the word", -> editor.setText("word1 word2 word3") editor.setCursorBufferPosition([0, "word1 w".length]) keydown("c") keydown("w") keydown("escape") expect(editor.getText()).toBe "word1 w word3" describe "when followed by a G", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the beginning of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 0]) keydown('c') keydown('G', shift: true) keydown('escape') expect(editor.getText()).toBe("12345\n\n") describe "on the middle of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 2]) keydown('c') keydown('G', shift: true) keydown('escape') expect(editor.getText()).toBe("12345\n\n") describe "when followed by a goto line G", -> beforeEach -> editor.setText "12345\nabcde\nABCDE" describe "on the beginning of the second line", -> it "deletes all the text on the line", -> editor.setCursorScreenPosition([1, 0]) keydown('c') keydown('2') keydown('G', shift: true) keydown('escape') expect(editor.getText()).toBe("12345\n\nABCDE") describe "on the middle of the second line", -> it "deletes all the text on the line", -> editor.setCursorScreenPosition([1, 2]) keydown('c') keydown('2') keydown('G', shift: true) keydown('escape') expect(editor.getText()).toBe("12345\n\nABCDE") describe "the C keybinding", -> beforeEach -> editor.getBuffer().setText("012\n") editor.setCursorScreenPosition([0, 1]) keydown('C', shift: true) it "deletes the contents until the end of the line and enters insert mode", -> expect(editor.getText()).toBe "0\n" expect(editor.getCursorScreenPosition()).toEqual [0, 1] expect(editorElement.classList.contains('command-mode')).toBe(false) expect(editorElement.classList.contains('insert-mode')).toBe(true) describe "the y keybinding", -> beforeEach -> editor.getBuffer().setText("012 345\nabc\n") editor.setCursorScreenPosition([0, 4]) describe "when selected lines in visual linewise mode", -> beforeEach -> keydown('V', shift: true) keydown('j') keydown('y') it "is in linewise motion", -> expect(vimState.getRegister('"').type).toEqual "linewise" it "saves the lines to the default register", -> expect(vimState.getRegister('"').text).toBe "012 345\nabc\n" it "places the cursor at the beginning of the selection", -> expect(editor.getCursorBufferPositions()).toEqual([[0, 0]]) describe "when followed by a second y ", -> beforeEach -> keydown('y') keydown('y') it "saves the line to the default register", -> expect(vimState.getRegister('"').text).toBe "012 345\n" it "leaves the cursor at the starting position", -> expect(editor.getCursorScreenPosition()).toEqual [0, 4] describe "when useClipboardAsDefaultRegister enabled", -> it "writes to clipboard", -> atom.config.set 'vim-mode.useClipboardAsDefaultRegister', true keydown('y') keydown('y') expect(atom.clipboard.read()).toBe '012 345\n' describe "when followed with a repeated y", -> beforeEach -> keydown('y') keydown('2') keydown('y') it "copies n lines, starting from the current", -> expect(vimState.getRegister('"').text).toBe "012 345\nabc\n" it "leaves the cursor at the starting position", -> expect(editor.getCursorScreenPosition()).toEqual [0, 4] describe "with a register", -> beforeEach -> keydown('"') keydown('a') keydown('y') keydown('y') it "saves the line to the a register", -> expect(vimState.getRegister('a').text).toBe "012 345\n" it "appends the line to the A register", -> keydown('"') keydown('A', shift: true) keydown('y') keydown('y') expect(vimState.getRegister('a').text).toBe "012 345\n012 345\n" describe "with a forward motion", -> beforeEach -> keydown('y') keydown('e') it "saves the selected text to the default register", -> expect(vimState.getRegister('"').text).toBe '345' it "leaves the cursor at the starting position", -> expect(editor.getCursorScreenPosition()).toEqual [0, 4] it "does not yank when motion fails", -> keydown('y') keydown('t') commandModeInputKeydown('x') expect(vimState.getRegister('"').text).toBe '345' describe "with a text object", -> it "moves the cursor to the beginning of the text object", -> editor.setCursorBufferPosition([0, 5]) keydown("y") keydown("i") keydown("w") expect(editor.getCursorBufferPositions()).toEqual([[0, 4]]) describe "with a left motion", -> beforeEach -> keydown('y') keydown('h') it "saves the left letter to the default register", -> expect(vimState.getRegister('"').text).toBe " " it "moves the cursor position to the left", -> expect(editor.getCursorScreenPosition()).toEqual [0, 3] describe "with a down motion", -> beforeEach -> keydown 'y' keydown 'j' it "saves both full lines to the default register", -> expect(vimState.getRegister('"').text).toBe "012 345\nabc\n" it "leaves the cursor at the starting position", -> expect(editor.getCursorScreenPosition()).toEqual [0, 4] describe "when followed by a G", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the beginning of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 0]) keydown('y') keydown('G', shift: true) keydown('P', shift: true) expect(editor.getText()).toBe("12345\nabcde\nABCDE\nabcde\nABCDE") describe "on the middle of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 2]) keydown('y') keydown('G', shift: true) keydown('P', shift: true) expect(editor.getText()).toBe("12345\nabcde\nABCDE\nabcde\nABCDE") describe "when followed by a goto line G", -> beforeEach -> originalText = "12345\nabcde\nABCDE" editor.setText(originalText) describe "on the beginning of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 0]) keydown('y') keydown('2') keydown('G', shift: true) keydown('P', shift: true) expect(editor.getText()).toBe("12345\nabcde\nabcde\nABCDE") describe "on the middle of the second line", -> it "deletes the bottom two lines", -> editor.setCursorScreenPosition([1, 2]) keydown('y') keydown('2') keydown('G', shift: true) keydown('P', shift: true) expect(editor.getText()).toBe("12345\nabcde\nabcde\nABCDE") describe "with multiple cursors", -> it "moves each cursor and copies the last selection's text", -> editor.setText " abcd\n 1234" editor.setCursorBufferPosition([0, 0]) editor.addCursorAtBufferPosition([1, 5]) keydown("y") keydown("^") expect(vimState.getRegister('"').text).toBe '123' expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 2]] describe "the yy keybinding", -> describe "on a single line file", -> beforeEach -> editor.getBuffer().setText "exclamation!\n" editor.setCursorScreenPosition [0, 0] it "copies the entire line and pastes it correctly", -> keydown('y') keydown('y') keydown('p') expect(vimState.getRegister('"').text).toBe "exclamation!\n" expect(editor.getText()).toBe "exclamation!\nexclamation!\n" describe "on a single line file with no newline", -> beforeEach -> editor.getBuffer().setText "no newline!" editor.setCursorScreenPosition [0, 0] it "copies the entire line and pastes it correctly", -> keydown('y') keydown('y') keydown('p') expect(vimState.getRegister('"').text).toBe "no newline!\n" expect(editor.getText()).toBe "no newline!\nno newline!" it "copies the entire line and pastes it respecting count and new lines", -> keydown('y') keydown('y') keydown('2') keydown('p') expect(vimState.getRegister('"').text).toBe "no newline!\n" expect(editor.getText()).toBe "no newline!\nno newline!\nno newline!" describe "the Y keybinding", -> beforeEach -> editor.getBuffer().setText "012 345\nabc\n" editor.setCursorScreenPosition [0, 4] it "saves the line to the default register", -> keydown('Y', shift: true) expect(vimState.getRegister('"').text).toBe "012 345\n" expect(editor.getCursorScreenPosition()).toEqual [0, 4] describe "the p keybinding", -> describe "with character contents", -> beforeEach -> editor.getBuffer().setText "012\n" editor.setCursorScreenPosition [0, 0] vimState.setRegister('"', text: '345') vimState.setRegister('a', text: 'a') atom.clipboard.write "clip" describe "from the default register", -> beforeEach -> keydown('p') it "inserts the contents", -> expect(editor.getText()).toBe "034512\n" expect(editor.getCursorScreenPosition()).toEqual [0, 3] describe "when useClipboardAsDefaultRegister enabled", -> it "inserts contents from clipboard", -> atom.config.set 'vim-mode.useClipboardAsDefaultRegister', true keydown('p') expect(editor.getText()).toBe "0clip12\n" describe "from a specified register", -> beforeEach -> keydown('"') keydown('a') keydown('p') it "inserts the contents of the 'a' register", -> expect(editor.getText()).toBe "0a12\n" expect(editor.getCursorScreenPosition()).toEqual [0, 1] describe "at the end of a line", -> it "inserts before the current line's newline", -> editor.setText("abcde\none two three") editor.setCursorScreenPosition([1, 4]) keydown 'd' keydown '$' keydown 'k' keydown '$' keydown 'p' expect(editor.getText()).toBe "abcdetwo three\none " describe "with a selection", -> beforeEach -> editor.selectRight() keydown('p') it "replaces the current selection", -> expect(editor.getText()).toBe "34512\n" expect(editor.getCursorScreenPosition()).toEqual [0, 2] describe "with linewise contents", -> describe "on a single line", -> beforeEach -> editor.getBuffer().setText("012") editor.setCursorScreenPosition([0, 1]) vimState.setRegister('"', text: " 345\n", type: 'linewise') it "inserts the contents of the default register", -> keydown('p') expect(editor.getText()).toBe "012\n 345" expect(editor.getCursorScreenPosition()).toEqual [1, 1] it "replaces the current selection", -> editor.selectRight() keydown('p') expect(editor.getText()).toBe "0 345\n2" expect(editor.getCursorScreenPosition()).toEqual [1, 0] describe "on multiple lines", -> beforeEach -> editor.getBuffer().setText("012\n 345") vimState.setRegister('"', text: " 456\n", type: 'linewise') it "inserts the contents of the default register at middle line", -> editor.setCursorScreenPosition([0, 1]) keydown('p') expect(editor.getText()).toBe "012\n 456\n 345" expect(editor.getCursorScreenPosition()).toEqual [1, 1] it "inserts the contents of the default register at end of line", -> editor.setCursorScreenPosition([1, 1]) keydown('p') expect(editor.getText()).toBe "012\n 345\n 456" expect(editor.getCursorScreenPosition()).toEqual [2, 1] describe "with multiple linewise contents", -> beforeEach -> editor.getBuffer().setText("012\nabc") editor.setCursorScreenPosition([1, 0]) vimState.setRegister('"', text: " 345\n 678\n", type: 'linewise') keydown('p') it "inserts the contents of the default register", -> expect(editor.getText()).toBe "012\nabc\n 345\n 678" expect(editor.getCursorScreenPosition()).toEqual [2, 1] describe "pasting twice", -> beforeEach -> editor.setText("12345\nabcde\nABCDE\nQWERT") editor.setCursorScreenPosition([1, 1]) vimState.setRegister('"', text: '123') keydown('2') keydown('p') it "inserts the same line twice", -> expect(editor.getText()).toBe "12345\nab123123cde\nABCDE\nQWERT" describe "when undone", -> beforeEach -> keydown('u') it "removes both lines", -> expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT" describe "the P keybinding", -> describe "with character contents", -> beforeEach -> editor.getBuffer().setText("012\n") editor.setCursorScreenPosition([0, 0]) vimState.setRegister('"', text: '345') vimState.setRegister('a', text: 'a') keydown('P', shift: true) it "inserts the contents of the default register above", -> expect(editor.getText()).toBe "345012\n" expect(editor.getCursorScreenPosition()).toEqual [0, 2] describe "the O keybinding", -> beforeEach -> spyOn(editor, 'shouldAutoIndent').andReturn(true) spyOn(editor, 'autoIndentBufferRow').andCallFake (line) -> editor.indent() editor.getBuffer().setText(" abc\n 012\n") editor.setCursorScreenPosition([1, 1]) it "switches to insert and adds a newline above the current one", -> keydown('O', shift: true) expect(editor.getText()).toBe " abc\n \n 012\n" expect(editor.getCursorScreenPosition()).toEqual [1, 2] expect(editorElement.classList.contains('insert-mode')).toBe(true) it "is repeatable", -> editor.getBuffer().setText(" abc\n 012\n 4spaces\n") editor.setCursorScreenPosition([1, 1]) keydown('O', shift: true) editor.insertText "def" keydown 'escape' expect(editor.getText()).toBe " abc\n def\n 012\n 4spaces\n" editor.setCursorScreenPosition([1, 1]) keydown '.' expect(editor.getText()).toBe " abc\n def\n def\n 012\n 4spaces\n" editor.setCursorScreenPosition([4, 1]) keydown '.' expect(editor.getText()).toBe " abc\n def\n def\n 012\n def\n 4spaces\n" it "is undoable", -> keydown('O', shift: true) editor.insertText "def" keydown 'escape' expect(editor.getText()).toBe " abc\n def\n 012\n" keydown 'u' expect(editor.getText()).toBe " abc\n 012\n" describe "the o keybinding", -> beforeEach -> spyOn(editor, 'shouldAutoIndent').andReturn(true) spyOn(editor, 'autoIndentBufferRow').andCallFake (line) -> editor.indent() editor.getBuffer().setText("abc\n 012\n") editor.setCursorScreenPosition([1, 2]) it "switches to insert and adds a newline above the current one", -> keydown('o') expect(editor.getText()).toBe "abc\n 012\n \n" expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getCursorScreenPosition()).toEqual [2, 2] # This works in practice, but the editor doesn't respect the indentation # rules without a syntax grammar. Need to set the editor's grammar # to fix it. xit "is repeatable", -> editor.getBuffer().setText(" abc\n 012\n 4spaces\n") editor.setCursorScreenPosition([1, 1]) keydown('o') editor.insertText "def" keydown 'escape' expect(editor.getText()).toBe " abc\n 012\n def\n 4spaces\n" keydown '.' expect(editor.getText()).toBe " abc\n 012\n def\n def\n 4spaces\n" editor.setCursorScreenPosition([4, 1]) keydown '.' expect(editor.getText()).toBe " abc\n def\n def\n 012\n 4spaces\n def\n" it "is undoable", -> keydown('o') editor.insertText "def" keydown 'escape' expect(editor.getText()).toBe "abc\n 012\n def\n" keydown 'u' expect(editor.getText()).toBe "abc\n 012\n" describe "the a keybinding", -> beforeEach -> editor.getBuffer().setText("012\n") describe "at the beginning of the line", -> beforeEach -> editor.setCursorScreenPosition([0, 0]) keydown('a') it "switches to insert mode and shifts to the right", -> expect(editor.getCursorScreenPosition()).toEqual [0, 1] expect(editorElement.classList.contains('insert-mode')).toBe(true) describe "at the end of the line", -> beforeEach -> editor.setCursorScreenPosition([0, 3]) keydown('a') it "doesn't linewrap", -> expect(editor.getCursorScreenPosition()).toEqual [0, 3] describe "the A keybinding", -> beforeEach -> editor.getBuffer().setText("11\n22\n") describe "at the beginning of a line", -> it "switches to insert mode at the end of the line", -> editor.setCursorScreenPosition([0, 0]) keydown('A', shift: true) expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getCursorScreenPosition()).toEqual [0, 2] it "repeats always as insert at the end of the line", -> editor.setCursorScreenPosition([0, 0]) keydown('A', shift: true) editor.insertText("abc") keydown 'escape' editor.setCursorScreenPosition([1, 0]) keydown '.' expect(editor.getText()).toBe "11abc\n22abc\n" expect(editorElement.classList.contains('insert-mode')).toBe(false) expect(editor.getCursorScreenPosition()).toEqual [1, 4] describe "the I keybinding", -> beforeEach -> editor.getBuffer().setText("11\n 22\n") describe "at the end of a line", -> it "switches to insert mode at the beginning of the line", -> editor.setCursorScreenPosition([0, 2]) keydown('I', shift: true) expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getCursorScreenPosition()).toEqual [0, 0] it "switches to insert mode after leading whitespace", -> editor.setCursorScreenPosition([1, 4]) keydown('I', shift: true) expect(editorElement.classList.contains('insert-mode')).toBe(true) expect(editor.getCursorScreenPosition()).toEqual [1, 2] it "repeats always as insert at the first character of the line", -> editor.setCursorScreenPosition([0, 2]) keydown('I', shift: true) editor.insertText("abc") keydown 'escape' expect(editor.getCursorScreenPosition()).toEqual [0, 2] editor.setCursorScreenPosition([1, 4]) keydown '.' expect(editor.getText()).toBe "abc11\n abc22\n" expect(editorElement.classList.contains('insert-mode')).toBe(false) expect(editor.getCursorScreenPosition()).toEqual [1, 4] describe "the J keybinding", -> beforeEach -> editor.getBuffer().setText("012\n 456\n") editor.setCursorScreenPosition([0, 1]) describe "without repeating", -> beforeEach -> keydown('J', shift: true) it "joins the contents of the current line with the one below it", -> expect(editor.getText()).toBe "012 456\n" describe "with repeating", -> beforeEach -> editor.setText("12345\nabcde\nABCDE\nQWERT") editor.setCursorScreenPosition([1, 1]) keydown('2') keydown('J', shift: true) describe "undo behavior", -> beforeEach -> keydown('u') it "handles repeats", -> expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT" describe "the > keybinding", -> beforeEach -> editor.setText("12345\nabcde\nABCDE") describe "on the last line", -> beforeEach -> editor.setCursorScreenPosition([2, 0]) describe "when followed by a >", -> beforeEach -> keydown('>') keydown('>') it "indents the current line", -> expect(editor.getText()).toBe "12345\nabcde\n ABCDE" expect(editor.getCursorScreenPosition()).toEqual [2, 2] describe "on the first line", -> beforeEach -> editor.setCursorScreenPosition([0, 0]) describe "when followed by a >", -> beforeEach -> keydown('>') keydown('>') it "indents the current line", -> expect(editor.getText()).toBe " 12345\nabcde\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [0, 2] describe "when followed by a repeating >", -> beforeEach -> keydown('3') keydown('>') keydown('>') it "indents multiple lines at once", -> expect(editor.getText()).toBe " 12345\n abcde\n ABCDE" expect(editor.getCursorScreenPosition()).toEqual [0, 2] describe "undo behavior", -> beforeEach -> keydown('u') it "outdents all three lines", -> expect(editor.getText()).toBe "12345\nabcde\nABCDE" describe "in visual mode", -> beforeEach -> editor.setCursorScreenPosition([0, 0]) keydown('v', shift: true) keydown('>') it "indents the current line and remains in visual mode", -> expect(editorElement.classList.contains('visual-mode')).toBe(true) expect(editor.getText()).toBe " 12345\nabcde\nABCDE" expect(editor.getSelectedText()).toBe " 12345\n" it "allows repeating the operation", -> keydown("escape") keydown(".") expect(editorElement.classList.contains('command-mode')).toBe(true) expect(editor.getText()).toBe " 12345\nabcde\nABCDE" describe "the < keybinding", -> beforeEach -> editor.setText(" 12345\n abcde\nABCDE") editor.setCursorScreenPosition([0, 0]) describe "when followed by a <", -> beforeEach -> keydown('<') keydown('<') it "indents the current line", -> expect(editor.getText()).toBe "12345\n abcde\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [0, 0] describe "when followed by a repeating <", -> beforeEach -> keydown('2') keydown('<') keydown('<') it "indents multiple lines at once", -> expect(editor.getText()).toBe "12345\nabcde\nABCDE" expect(editor.getCursorScreenPosition()).toEqual [0, 0] describe "undo behavior", -> beforeEach -> keydown('u') it "indents both lines", -> expect(editor.getText()).toBe " 12345\n abcde\nABCDE" describe "in visual mode", -> beforeEach -> keydown('v', shift: true) keydown('<') it "indents the current line and remains in visual mode", -> expect(editorElement.classList.contains('visual-mode')).toBe(true) expect(editor.getText()).toBe "12345\n abcde\nABCDE" expect(editor.getSelectedText()).toBe "12345\n" describe "the = keybinding", -> oldGrammar = [] beforeEach -> waitsForPromise -> atom.packages.activatePackage('language-javascript') oldGrammar = editor.getGrammar() editor.setText("foo\n bar\n baz") editor.setCursorScreenPosition([1, 0]) describe "when used in a scope that supports auto-indent", -> beforeEach -> jsGrammar = atom.grammars.grammarForScopeName('source.js') editor.setGrammar(jsGrammar) afterEach -> editor.setGrammar(oldGrammar) describe "when followed by a =", -> beforeEach -> keydown('=') keydown('=') it "indents the current line", -> expect(editor.indentationForBufferRow(1)).toBe 0 describe "when followed by a repeating =", -> beforeEach -> keydown('2') keydown('=') keydown('=') it "autoindents multiple lines at once", -> expect(editor.getText()).toBe "foo\nbar\nbaz" expect(editor.getCursorScreenPosition()).toEqual [1, 0] describe "undo behavior", -> beforeEach -> keydown('u') it "indents both lines", -> expect(editor.getText()).toBe "foo\n bar\n baz" describe "the . keybinding", -> beforeEach -> editor.setText("12\n34\n56\n78") editor.setCursorScreenPosition([0, 0]) it "repeats the last operation", -> keydown '2' keydown 'd' keydown 'd' keydown '.' expect(editor.getText()).toBe "" it "composes with motions", -> keydown 'd' keydown 'd' keydown '2' keydown '.' expect(editor.getText()).toBe "78" describe "the r keybinding", -> beforeEach -> editor.setText("12\n34\n\n") editor.setCursorBufferPosition([0, 0]) editor.addCursorAtBufferPosition([1, 0]) it "replaces a single character", -> keydown('r') commandModeInputKeydown('x') expect(editor.getText()).toBe 'x2\nx4\n\n' it "does nothing when cancelled", -> keydown('r') expect(editorElement.classList.contains('operator-pending-mode')).toBe(true) keydown('escape') expect(editor.getText()).toBe '12\n34\n\n' expect(editorElement.classList.contains('command-mode')).toBe(true) it "replaces a single character with a line break", -> keydown('r') atom.commands.dispatch(editor.commandModeInputView.editorElement, 'core:confirm') expect(editor.getText()).toBe '\n2\n\n4\n\n' expect(editor.getCursorBufferPositions()).toEqual [[1, 0], [3, 0]] it "composes properly with motions", -> keydown('2') keydown('r') commandModeInputKeydown('x') expect(editor.getText()).toBe 'xx\nxx\n\n' it "does nothing on an empty line", -> editor.setCursorBufferPosition([2, 0]) keydown('r') commandModeInputKeydown('x') expect(editor.getText()).toBe '12\n34\n\n' it "does nothing if asked to replace more characters than there are on a line", -> keydown('3') keydown('r') commandModeInputKeydown('x') expect(editor.getText()).toBe '12\n34\n\n' describe "when in visual mode", -> beforeEach -> keydown('v') keydown('e') it "replaces the entire selection with the given character", -> keydown('r') commandModeInputKeydown('x') expect(editor.getText()).toBe 'xx\nxx\n\n' it "leaves the cursor at the beginning of the selection", -> keydown('r') commandModeInputKeydown('x') expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]] describe 'the m keybinding', -> beforeEach -> editor.setText('12\n34\n56\n') editor.setCursorBufferPosition([0, 1]) it 'marks a position', -> keydown('m') commandModeInputKeydown('a') expect(vimState.getMark('a')).toEqual [0, 1] describe 'the ~ keybinding', -> beforeEach -> editor.setText('aBc\nXyZ') editor.setCursorBufferPosition([0, 0]) editor.addCursorAtBufferPosition([1, 0]) it 'toggles the case and moves right', -> keydown('~') expect(editor.getText()).toBe 'ABc\nxyZ' expect(editor.getCursorScreenPositions()).toEqual [[0, 1], [1, 1]] keydown('~') expect(editor.getText()).toBe 'Abc\nxYZ' expect(editor.getCursorScreenPositions()).toEqual [[0, 2], [1, 2]] keydown('~') expect(editor.getText()).toBe 'AbC\nxYz' expect(editor.getCursorScreenPositions()).toEqual [[0, 2], [1, 2]] it 'takes a count', -> keydown('4') keydown('~') expect(editor.getText()).toBe 'AbC\nxYz' expect(editor.getCursorScreenPositions()).toEqual [[0, 2], [1, 2]] describe "in visual mode", -> it "toggles the case of the selected text", -> editor.setCursorBufferPosition([0, 0]) keydown("V", shift: true) keydown("~") expect(editor.getText()).toBe 'AbC\nXyZ' describe "with g and motion", -> it "toggles the case of text", -> editor.setCursorBufferPosition([0, 0]) keydown("g") keydown("~") keydown("2") keydown("l") expect(editor.getText()).toBe 'Abc\nXyZ' describe 'the U keybinding', -> beforeEach -> editor.setText('aBc\nXyZ') editor.setCursorBufferPosition([0, 0]) it "makes text uppercase with g and motion", -> keydown("g") keydown("U", shift: true) keydown("l") expect(editor.getText()).toBe 'ABc\nXyZ' keydown("g") keydown("U", shift: true) keydown("e") expect(editor.getText()).toBe 'ABC\nXyZ' editor.setCursorBufferPosition([1, 0]) keydown("g") keydown("U", shift: true) keydown("$") expect(editor.getText()).toBe 'ABC\nXYZ' expect(editor.getCursorScreenPosition()).toEqual [1, 2] it "makes the selected text uppercase in visual mode", -> keydown("V", shift: true) keydown("U", shift: true) expect(editor.getText()).toBe 'ABC\nXyZ' describe 'the u keybinding', -> beforeEach -> editor.setText('aBc\nXyZ') editor.setCursorBufferPosition([0, 0]) it "makes text lowercase with g and motion", -> keydown("g") keydown("u") keydown("$") expect(editor.getText()).toBe 'abc\nXyZ' expect(editor.getCursorScreenPosition()).toEqual [0, 2] it "makes the selected text lowercase in visual mode", -> keydown("V", shift: true) keydown("u") expect(editor.getText()).toBe 'abc\nXyZ' describe "the i keybinding", -> beforeEach -> editor.setText('123\n4567') editor.setCursorBufferPosition([0, 0]) editor.addCursorAtBufferPosition([1, 0]) it "allows undoing an entire batch of typing", -> keydown 'i' editor.insertText("abcXX") editor.backspace() editor.backspace() keydown 'escape' expect(editor.getText()).toBe "abc123\nabc4567" keydown 'i' editor.insertText "d" editor.insertText "e" editor.insertText "f" keydown 'escape' expect(editor.getText()).toBe "abdefc123\nabdefc4567" keydown 'u' expect(editor.getText()).toBe "abc123\nabc4567" keydown 'u' expect(editor.getText()).toBe "123\n4567" it "allows repeating typing", -> keydown 'i' editor.insertText("abcXX") editor.backspace() editor.backspace() keydown 'escape' expect(editor.getText()).toBe "abc123\nabc4567" keydown '.' expect(editor.getText()).toBe "ababcc123\nababcc4567" keydown '.' expect(editor.getText()).toBe "abababccc123\nabababccc4567" describe 'with nonlinear input', -> beforeEach -> editor.setText '' editor.setCursorBufferPosition [0, 0] it 'deals with auto-matched brackets', -> keydown 'i' # this sequence simulates what the bracket-matcher package does # when the user types (a)b editor.insertText '()' editor.moveLeft() editor.insertText 'a' editor.moveRight() editor.insertText 'b\n' keydown 'escape' expect(editor.getCursorScreenPosition()).toEqual [1, 0] keydown '.' expect(editor.getText()).toBe '(a)b\n(a)b\n' expect(editor.getCursorScreenPosition()).toEqual [2, 0] it 'deals with autocomplete', -> keydown 'i' # this sequence simulates autocompletion of 'add' to 'addFoo' editor.insertText 'a' editor.insertText 'd' editor.insertText 'd' editor.setTextInBufferRange [[0, 0], [0, 3]], 'addFoo' keydown 'escape' expect(editor.getCursorScreenPosition()).toEqual [0, 5] expect(editor.getText()).toBe 'addFoo' keydown '.' expect(editor.getText()).toBe 'addFoaddFooo' expect(editor.getCursorScreenPosition()).toEqual [0, 10] describe 'the a keybinding', -> beforeEach -> editor.setText('') editor.setCursorBufferPosition([0, 0]) it "can be undone in one go", -> keydown 'a' editor.insertText("abc") keydown 'escape' expect(editor.getText()).toBe "abc" keydown 'u' expect(editor.getText()).toBe "" it "repeats correctly", -> keydown 'a' editor.insertText("abc") keydown 'escape' expect(editor.getText()).toBe "abc" expect(editor.getCursorScreenPosition()).toEqual [0, 2] keydown '.' expect(editor.getText()).toBe "abcabc" expect(editor.getCursorScreenPosition()).toEqual [0, 5] describe "the ctrl-a/ctrl-x keybindings", -> beforeEach -> atom.config.set 'vim-mode.numberRegex', settings.config.numberRegex.default editor.setText('123\nab45\ncd-67ef\nab-5\na-bcdef') editor.setCursorBufferPosition [0, 0] editor.addCursorAtBufferPosition [1, 0] editor.addCursorAtBufferPosition [2, 0] editor.addCursorAtBufferPosition [3, 3] editor.addCursorAtBufferPosition [4, 0] describe "increasing numbers", -> it "increases the next number", -> keydown('a', ctrl: true) expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]] expect(editor.getText()).toBe '124\nab46\ncd-66ef\nab-4\na-bcdef' it "repeats with .", -> keydown 'a', ctrl: true keydown '.' expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]] expect(editor.getText()).toBe '125\nab47\ncd-65ef\nab-3\na-bcdef' it "can have a count", -> keydown '5' keydown 'a', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 2], [4, 0]] expect(editor.getText()).toBe '128\nab50\ncd-62ef\nab0\na-bcdef' it "can make a negative number positive, change number of digits", -> keydown '9' keydown '9' keydown 'a', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 4], [2, 3], [3, 3], [4, 0]] expect(editor.getText()).toBe '222\nab144\ncd32ef\nab94\na-bcdef' it "does nothing when cursor is after the number", -> editor.setCursorBufferPosition [2, 5] keydown 'a', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[2, 5]] expect(editor.getText()).toBe '123\nab45\ncd-67ef\nab-5\na-bcdef' it "does nothing on an empty line", -> editor.setText('\n') editor.setCursorBufferPosition [0, 0] editor.addCursorAtBufferPosition [1, 0] keydown 'a', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]] expect(editor.getText()).toBe '\n' it "honours the vim-mode:numberRegex setting", -> editor.setText('123\nab45\ncd -67ef\nab-5\na-bcdef') editor.setCursorBufferPosition [0, 0] editor.addCursorAtBufferPosition [1, 0] editor.addCursorAtBufferPosition [2, 0] editor.addCursorAtBufferPosition [3, 3] editor.addCursorAtBufferPosition [4, 0] atom.config.set('vim-mode.numberRegex', '(?:\\B-)?[0-9]+') keydown('a', ctrl: true) expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 5], [3, 3], [4, 0]] expect(editor.getText()).toBe '124\nab46\ncd -66ef\nab-6\na-bcdef' describe "decreasing numbers", -> it "decreases the next number", -> keydown('x', ctrl: true) expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]] expect(editor.getText()).toBe '122\nab44\ncd-68ef\nab-6\na-bcdef' it "repeats with .", -> keydown 'x', ctrl: true keydown '.' expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]] expect(editor.getText()).toBe '121\nab43\ncd-69ef\nab-7\na-bcdef' it "can have a count", -> keydown '5' keydown 'x', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 4], [4, 0]] expect(editor.getText()).toBe '118\nab40\ncd-72ef\nab-10\na-bcdef' it "can make a positive number negative, change number of digits", -> keydown '9' keydown '9' keydown 'x', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[0, 1], [1, 4], [2, 5], [3, 5], [4, 0]] expect(editor.getText()).toBe '24\nab-54\ncd-166ef\nab-104\na-bcdef' it "does nothing when cursor is after the number", -> editor.setCursorBufferPosition [2, 5] keydown 'x', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[2, 5]] expect(editor.getText()).toBe '123\nab45\ncd-67ef\nab-5\na-bcdef' it "does nothing on an empty line", -> editor.setText('\n') editor.setCursorBufferPosition [0, 0] editor.addCursorAtBufferPosition [1, 0] keydown 'x', ctrl: true expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]] expect(editor.getText()).toBe '\n' it "honours the vim-mode:numberRegex setting", -> editor.setText('123\nab45\ncd -67ef\nab-5\na-bcdef') editor.setCursorBufferPosition [0, 0] editor.addCursorAtBufferPosition [1, 0] editor.addCursorAtBufferPosition [2, 0] editor.addCursorAtBufferPosition [3, 3] editor.addCursorAtBufferPosition [4, 0] atom.config.set('vim-mode.numberRegex', '(?:\\B-)?[0-9]+') keydown('x', ctrl: true) expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 5], [3, 3], [4, 0]] expect(editor.getText()).toBe '122\nab44\ncd -68ef\nab-4\na-bcdef'