 helpers = require './spec-helper'
-
-describe "Motions", ->
+_ = require 'underscore-plus'
+
+fdescribe "Motions", ->
   [editor, editorElement, vimState] = []
 
   beforeEach ->

    options.element ?= editorElement
    helpers.keydown(key, options)

  normalModeInputKeydown = (key, opts = {}) ->
    theEditor = opts.editor or editor
    theEditor.normalModeInputView.editorElement.getModel().setText(key)

    inputEditor.getModel().setText(text)
    atom.commands.dispatch(inputEditor, "core:confirm")

  set = (options={}) ->
    if options.keystroke?
      keystroke(options.keystroke)
    if options.text?
      editor.setText(options.text)
    if options.cursor?
      editor.setCursorScreenPosition options.cursor
    if options.addCursor?
      editor.addCursorAtBufferPosition options.addCursor
    if options.register?
      vimState.register.set '"', text: options.register


  selectedScreenRange = ->
    expect editor.getSelectedScreenRange()
  selectedScreenRanges = ->
    expect editor.getSelectedScreenRanges()
  selectedBufferRange = ->
    expect editor.getSelectedBufferRange()
  selectedBufferRanges = ->
    expect editor.getSelectedBufferRanges()

  ensure = (_keystroke, options={}) ->
    unless _.isEmpty(_keystroke)
      keystroke(_keystroke)
    if options.text?
      expect(editor.getText()).toBe options.text
    if options.cursor?
      expect(editor.getCursorScreenPosition()).toEqual options.cursor
    if options.register?
      expect(vimState.register.get('"').text).toBe options.register
    if options.selectedText?
      expect(editor.getSelectedText()).toBe options.selectedText

    if options.selectedBufferRange?
      selectedBufferRange().toEqual options.selectedBufferRange
    if options.selectedBufferRanges?
      selectedBufferRanges().toEqual options.selectedBufferRanges

    if options.selectedScreenRange?
      selectedScreenRange().toEqual options.selectedScreenRange
    if options.selectedScreenRanges?
      selectedScreenRanges().toEqual options.selectedScreenRanges

  describe "simple motions", ->
    beforeEach ->
      set
        text: "12345\nabcd\nABCDE"
        cursor: [1, 1]

    describe "the h keybinding", ->
      describe "as a motion", ->
        it "moves the cursor left, but not to the previous line", ->
          ensure 'h', cursor: [1, 0]
          ensure 'h', cursor: [1, 0]

        it "moves the cursor to the previous line if wrapLeftRightMotion is true", ->
          atom.config.set('vim-mode.wrapLeftRightMotion', true)
          ensure 'hh', cursor: [0, 4]

      describe "as a selection", ->
        it "selects the character to the left", ->
          ensure 'yh',
            register: 'a'
            cursor: [1, 0]

    describe "the j keybinding", ->
      it "moves the cursor down, but not to the end of the last line", ->
        ensure 'j', cursor: [2, 1]
        ensure 'j', cursor: [2, 1]

      it "moves the cursor to the end of the line, not past it", ->
        set
          cursor: [0, 4]
        ensure 'j',
          cursor: [1, 3]

      it "remembers the position it column it was in after moving to shorter line", ->
        set cursor: [0, 4]
        ensure 'j', cursor: [1, 3]
        ensure 'j', cursor: [2, 4]

      describe "when visual mode", ->
        beforeEach ->
          ensure 'v', cursor: [1, 2]

        it "moves the cursor down", ->
          ensure 'j', cursor: [2, 2]

        it "doesn't go over after the last line", ->
          ensure 'j', cursor: [2, 2]

        it "selects the text while moving", ->
          ensure 'j',
            selectedText: "bcd\nAB"

    describe "the k keybinding", ->
      it "moves the cursor up, but not to the beginning of the first line", ->
        ensure 'k', cursor: [0, 1]
        ensure 'k', cursor: [0, 1]

    describe "the l keybinding", ->
      beforeEach ->
        set cursor: [1, 2]

      it "moves the cursor right, but not to the next line", ->
        ensure 'l', cursor: [1, 3]
        ensure 'l', cursor: [1, 3]

      it "moves the cursor to the next line if wrapLeftRightMotion is true", ->
        atom.config.set('vim-mode.wrapLeftRightMotion', true)
        ensure 'll', cursor: [2, 0]

      describe "on a blank line", ->
        it "doesn't move the cursor", ->
          set
            text: "\n\n\n"
            cursor: [1, 0]
          ensure 'l',
            cursor: [1, 0]

  describe "the w keybinding", ->
    beforeEach ->
      set text: "ab cde1+- \n xyz\n\nzip"

    describe "as a motion", ->
      beforeEach ->
        set cursor: [0, 0]

      it "moves the cursor to the beginning of the next word", ->
        ensure 'w', cursor: [0, 3]
        ensure 'w', cursor: [0, 7]
        ensure 'w', cursor: [1, 1]
        ensure 'w', cursor: [2, 0]
        ensure 'w', cursor: [3, 0]
        ensure 'w', cursor: [3, 2]
        # When the cursor gets to the EOF, it should stay there.
        ensure 'w', cursor: [3, 2]

      it "moves the cursor to the end of the word if last word in file", ->
        set
          text: 'abc'
          cursor: [0, 0]
        ensure 'w',
          cursor: [0, 2]

    describe "as a selection", ->
      describe "within a word", ->
        it "selects to the end of the word", ->
          set
            cursor: [0, 0]
          ensure 'yw',
            register: 'ab '

      describe "between words", ->
        it "selects the whitespace", ->
          set cursor: [0, 2]
          ensure 'yw', register: ' '

  describe "the W keybinding", ->
    beforeEach ->
      set text: "cde1+- ab \n xyz\n\nzip"

    describe "as a motion", ->
      beforeEach ->
        set cursor: [0, 0]

      it "moves the cursor to the beginning of the next word", ->
        ensure 'W', cursor: [0, 7]
        ensure 'W', cursor: [1, 1]
        ensure 'W', cursor: [2, 0]
        ensure 'W', cursor: [3, 0]

    describe "as a selection", ->
      describe "within a word", ->
        it "selects to the end of the whole word", ->
          set cursor: [0, 0]
          ensure 'yW', register: 'cde1+- '

      it "continues past blank lines", ->
        set
          cursor: [2, 0]
        ensure 'dW',
          text: "cde1+- ab \n xyz\nzip"
          register: "\n"

      it "doesn't go past the end of the file", ->
        set
          cursor: [3, 0]
        ensure 'dW',
          text: "cde1+- ab \n xyz\n\n"
          register: 'zip'

  describe "the e keybinding", ->
    beforeEach ->
      set text: "ab cde1+- \n xyz\n\nzip"

    describe "as a motion", ->
      beforeEach ->
        set cursor: [0, 0]

      it "moves the cursor to the end of the current word", ->
        ensure 'e', cursor: [0, 1]
        ensure 'e', cursor: [0, 6]
        ensure 'e', cursor: [0, 8]
        ensure 'e', cursor: [1, 3]
        ensure 'e', cursor: [3, 2]

    describe "as selection", ->
      describe "within a word", ->
        it "selects to the end of the current word", ->
          set cursor: [0, 0]
          ensure 'ye', register: 'ab'

      describe "between words", ->
        it "selects to the end of the next word", ->
          set cursor: [0, 2]
          ensure 'ye', register: ' cde1'

  describe "the E keybinding", ->
    beforeEach ->
      set text: "ab  cde1+- \n xyz \n\nzip\n"

    describe "as a motion", ->
      beforeEach ->
        set cursor: [0, 0]

      it "moves the cursor to the end of the current word", ->
        ensure 'E', cursor: [0, 1]
        ensure 'E', cursor: [0, 9]
        ensure 'E', cursor: [1, 3]
        ensure 'E', cursor: [3, 2]
        ensure 'E', cursor: [4, 0]

    describe "as selection", ->
      describe "within a word", ->
        it "selects to the end of the current word", ->
          set cursor: [0, 0]
          ensure 'yE', register: 'ab'

      describe "between words", ->
        it "selects to the end of the next word", ->
          set cursor: [0, 2]
          ensure 'yE', register: '  cde1+-'

      describe "press more than once", ->
        it "selects to the end of the current word", ->
          set cursor: [0, 0]
          ensure 'vEEy', register: 'ab  cde1+-'

  describe "the } keybinding", ->
    beforeEach ->
      set
        text: "abcde\n\nfghij\nhijk\n  xyz  \n\nzip\n\n  \nthe end"
        cursor: [0, 0]

    describe "as a motion", ->
      it "moves the cursor to the end of the paragraph", ->
        ensure '}', cursor: [1, 0]
        ensure '}', cursor: [5, 0]
        ensure '}', cursor: [7, 0]
        ensure '}', cursor: [9, 6]

    describe "as a selection", ->
      it 'selects to the end of the current paragraph', ->
        ensure 'y}', register: "abcde\n"

  describe "the { keybinding", ->
    beforeEach ->
      set
        text: "abcde\n\nfghij\nhijk\n  xyz  \n\nzip\n\n  \nthe end"
        cursor: [9, 0]

    describe "as a motion", ->
      it "moves the cursor to the beginning of the paragraph", ->
        ensure '{', cursor: [7, 0]
        ensure '{', cursor: [5, 0]
        ensure '{', cursor: [1, 0]
        ensure '{', cursor: [0, 0]

    describe "as a selection", ->
      it 'selects to the beginning of the current paragraph', ->
        set cursor: [7, 0]
        ensure 'y{', register: "\nzip\n"

  describe "the b keybinding", ->
    beforeEach ->
      set text: " ab cde1+- \n xyz\n\nzip }\n last"

    describe "as a motion", ->
      beforeEach ->
        set cursor: [4, 1]

      it "moves the cursor to the beginning of the previous word", ->
        ensure 'b', cursor: [3, 4]
        ensure 'b', cursor: [3, 0]
        ensure 'b', cursor: [2, 0]
        ensure 'b', cursor: [1, 1]
        ensure 'b', cursor: [0, 8]
        ensure 'b', cursor: [0, 4]
        ensure 'b', cursor: [0, 1]

        # Go to start of the file, after moving past the first word
        ensure 'b', cursor: [0, 0]
        # Stay at the start of the file
        ensure 'b', cursor: [0, 0]

    describe "as a selection", ->
      describe "within a word", ->
        it "selects to the beginning of the current word", ->
          set
            cursor: [0, 2]
          ensure 'yb',
            register: 'a'
            cursor: [0, 1]

      describe "between words", ->
        it "selects to the beginning of the last word", ->
          set cursor: [0, 4]
          ensure 'yb',
            register: 'ab '
            cursor: [0, 1]

  describe "the B keybinding", ->
    beforeEach ->
      set text: "cde1+- ab \n\t xyz-123\n\n zip"

    describe "as a motion", ->
      beforeEach ->
        set cursor: [4, 1]

      it "moves the cursor to the beginning of the previous word", ->
        ensure 'B', cursor: [3, 1]
        ensure 'B', cursor: [2, 0]
        ensure 'B', cursor: [1, 3]
        ensure 'B', cursor: [0, 7]
        ensure 'B', cursor: [0, 0]

    describe "as a selection", ->
      it "selects to the beginning of the whole word", ->
        set cursor: [1, 10]
        ensure 'yB', register: 'xyz-12' # because cursor is on the `3`

      it "doesn't go past the beginning of the file", ->
        set
          cursor: [0, 0]
          register: 'abc'
        ensure 'yB',
          register: 'abc'

  describe "the ^ keybinding", ->
    beforeEach ->
      set text: "  abcde"

    describe "from the beginning of the line", ->
      beforeEach ->
        set cursor: [0, 0]

      describe "as a motion", ->
        it "moves the cursor to the first character of the line", ->
          ensure '^', cursor: [0, 2]

      describe "as a selection", ->
        it 'selects to the first character of the line', ->
          ensure 'd^',
            text: 'abcde'
            cursor: [0, 0]

    describe "from the first character of the line", ->
      beforeEach ->
        set cursor: [0, 2]

      describe "as a motion", ->
        it "stays put", ->
          ensure '^', cursor: [0, 2]

      describe "as a selection", ->
        it "does nothing", ->
          ensure 'd^',
            text: '  abcde'
            cursor: [0, 2]

    describe "from the middle of a word", ->
      beforeEach ->
        set cursor: [0, 4]

      describe "as a motion", ->
        it "moves the cursor to the first character of the line", ->
          ensure '^', cursor: [0, 2]

      describe "as a selection", ->
        beforeEach ->
