]> git.r.bdr.sh - rbdr/dotfiles/blame - atom/packages/vim-mode/spec/operators-spec.coffee
Remove mc config
[rbdr/dotfiles] / atom / packages / vim-mode / spec / operators-spec.coffee
CommitLineData
24c7594d
BB
1helpers = require './spec-helper'
2settings = require '../lib/settings'
3
4describe "Operators", ->
5 [editor, editorElement, vimState] = []
6
7 beforeEach ->
8 vimMode = atom.packages.loadPackage('vim-mode')
9 vimMode.activateResources()
10
11 helpers.getEditorElement (element) ->
12 editorElement = element
13 editor = editorElement.getModel()
14 vimState = editorElement.vimState
455f099b
BB
15 vimState.activateNormalMode()
16 vimState.resetNormalMode()
24c7594d
BB
17
18 keydown = (key, options={}) ->
19 options.element ?= editorElement
20 helpers.keydown(key, options)
21
455f099b
BB
22 normalModeInputKeydown = (key, opts = {}) ->
23 editor.normalModeInputView.editorElement.getModel().setText(key)
24c7594d
BB
24
25 describe "cancelling operations", ->
455f099b 26 it "throws an error when no operation is pending", ->
24c7594d 27 # cancel operation pushes an empty input operation
455f099b 28 # doing this without a pending operation would throw an exception
24c7594d
BB
29 expect(-> vimState.pushOperations(new Input(''))).toThrow()
30
455f099b
BB
31 it "cancels and cleans up properly", ->
32 # make sure normalModeInputView is created
24c7594d
BB
33 keydown('/')
34 expect(vimState.isOperatorPending()).toBe true
455f099b 35 editor.normalModeInputView.viewModel.cancel()
24c7594d
BB
36
37 expect(vimState.isOperatorPending()).toBe false
455f099b 38 expect(editor.normalModeInputView).toBe undefined
24c7594d
BB
39
40 describe "the x keybinding", ->
41 describe "on a line with content", ->
42 describe "without vim-mode.wrapLeftRightMotion", ->
43 beforeEach ->
44 editor.setText("abc\n012345\n\nxyz")
45 editor.setCursorScreenPosition([1, 4])
46
47 it "deletes a character", ->
48 keydown('x')
49 expect(editor.getText()).toBe 'abc\n01235\n\nxyz'
50 expect(editor.getCursorScreenPosition()).toEqual [1, 4]
51 expect(vimState.getRegister('"').text).toBe '4'
52
53 keydown('x')
54 expect(editor.getText()).toBe 'abc\n0123\n\nxyz'
55 expect(editor.getCursorScreenPosition()).toEqual [1, 3]
56 expect(vimState.getRegister('"').text).toBe '5'
57
58 keydown('x')
59 expect(editor.getText()).toBe 'abc\n012\n\nxyz'
60 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
61 expect(vimState.getRegister('"').text).toBe '3'
62
63 keydown('x')
64 expect(editor.getText()).toBe 'abc\n01\n\nxyz'
65 expect(editor.getCursorScreenPosition()).toEqual [1, 1]
66 expect(vimState.getRegister('"').text).toBe '2'
67
68 keydown('x')
69 expect(editor.getText()).toBe 'abc\n0\n\nxyz'
70 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
71 expect(vimState.getRegister('"').text).toBe '1'
72
73 keydown('x')
74 expect(editor.getText()).toBe 'abc\n\n\nxyz'
75 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
76 expect(vimState.getRegister('"').text).toBe '0'
77
78 it "deletes multiple characters with a count", ->
79 keydown('2')
80 keydown('x')
81 expect(editor.getText()).toBe 'abc\n0123\n\nxyz'
82 expect(editor.getCursorScreenPosition()).toEqual [1, 3]
83 expect(vimState.getRegister('"').text).toBe '45'
84
85 editor.setCursorScreenPosition([0, 1])
86 keydown('3')
87 keydown('x')
88 expect(editor.getText()).toBe 'a\n0123\n\nxyz'
89 expect(editor.getCursorScreenPosition()).toEqual [0, 0]
90 expect(vimState.getRegister('"').text).toBe 'bc'
91
455f099b
BB
92 describe "with multiple cursors", ->
93 beforeEach ->
94 editor.setText "abc\n012345\n\nxyz"
95 editor.setCursorScreenPosition [1, 4]
96 editor.addCursorAtBufferPosition [0, 1]
97
98 it "is undone as one operation", ->
99 keydown('x')
100 expect(editor.getText()).toBe "ac\n01235\n\nxyz"
101 keydown('u')
102 expect(editor.getText()).toBe "abc\n012345\n\nxyz"
103
24c7594d
BB
104 describe "with vim-mode.wrapLeftRightMotion", ->
105 beforeEach ->
106 editor.setText("abc\n012345\n\nxyz")
107 editor.setCursorScreenPosition([1, 4])
108 atom.config.set('vim-mode.wrapLeftRightMotion', true)
109
110 it "deletes a character", ->
111 # copy of the earlier test because wrapLeftRightMotion should not affect it
112 keydown('x')
113 expect(editor.getText()).toBe 'abc\n01235\n\nxyz'
114 expect(editor.getCursorScreenPosition()).toEqual [1, 4]
115 expect(vimState.getRegister('"').text).toBe '4'
116
117 keydown('x')
118 expect(editor.getText()).toBe 'abc\n0123\n\nxyz'
119 expect(editor.getCursorScreenPosition()).toEqual [1, 3]
120 expect(vimState.getRegister('"').text).toBe '5'
121
122 keydown('x')
123 expect(editor.getText()).toBe 'abc\n012\n\nxyz'
124 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
125 expect(vimState.getRegister('"').text).toBe '3'
126
127 keydown('x')
128 expect(editor.getText()).toBe 'abc\n01\n\nxyz'
129 expect(editor.getCursorScreenPosition()).toEqual [1, 1]
130 expect(vimState.getRegister('"').text).toBe '2'
131
132 keydown('x')
133 expect(editor.getText()).toBe 'abc\n0\n\nxyz'
134 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
135 expect(vimState.getRegister('"').text).toBe '1'
136
137 keydown('x')
138 expect(editor.getText()).toBe 'abc\n\n\nxyz'
139 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
140 expect(vimState.getRegister('"').text).toBe '0'
141
142 it "deletes multiple characters and newlines with a count", ->
143 atom.config.set('vim-mode.wrapLeftRightMotion', true)
144 keydown('2')
145 keydown('x')
146 expect(editor.getText()).toBe 'abc\n0123\n\nxyz'
147 expect(editor.getCursorScreenPosition()).toEqual [1, 3]
148 expect(vimState.getRegister('"').text).toBe '45'
149
150 editor.setCursorScreenPosition([0, 1])
151 keydown('3')
152 keydown('x')
153 expect(editor.getText()).toBe 'a0123\n\nxyz'
154 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
155 expect(vimState.getRegister('"').text).toBe 'bc\n'
156
157 keydown('7')
158 keydown('x')
159 expect(editor.getText()).toBe 'ayz'
160 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
161 expect(vimState.getRegister('"').text).toBe '0123\n\nx'
162
24c7594d
BB
163 describe "on an empty line", ->
164 beforeEach ->
165 editor.setText("abc\n012345\n\nxyz")
166 editor.setCursorScreenPosition([2, 0])
167
168 it "deletes nothing on an empty line when vim-mode.wrapLeftRightMotion is false", ->
169 atom.config.set('vim-mode.wrapLeftRightMotion', false)
170 keydown('x')
171 expect(editor.getText()).toBe "abc\n012345\n\nxyz"
172 expect(editor.getCursorScreenPosition()).toEqual [2, 0]
173
174 it "deletes an empty line when vim-mode.wrapLeftRightMotion is true", ->
175 atom.config.set('vim-mode.wrapLeftRightMotion', true)
176 keydown('x')
177 expect(editor.getText()).toBe "abc\n012345\nxyz"
178 expect(editor.getCursorScreenPosition()).toEqual [2, 0]
179
24c7594d
BB
180 describe "the X keybinding", ->
181 describe "on a line with content", ->
182 beforeEach ->
183 editor.setText("ab\n012345")
184 editor.setCursorScreenPosition([1, 2])
185
186 it "deletes a character", ->
187 keydown('X', shift: true)
188 expect(editor.getText()).toBe 'ab\n02345'
189 expect(editor.getCursorScreenPosition()).toEqual [1, 1]
190 expect(vimState.getRegister('"').text).toBe '1'
191
192 keydown('X', shift: true)
193 expect(editor.getText()).toBe 'ab\n2345'
194 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
195 expect(vimState.getRegister('"').text).toBe '0'
196
197 keydown('X', shift: true)
198 expect(editor.getText()).toBe 'ab\n2345'
199 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
200 expect(vimState.getRegister('"').text).toBe '0'
201
202 atom.config.set('vim-mode.wrapLeftRightMotion', true)
203 keydown('X', shift: true)
204 expect(editor.getText()).toBe 'ab2345'
205 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
206 expect(vimState.getRegister('"').text).toBe '\n'
207
24c7594d
BB
208 describe "on an empty line", ->
209 beforeEach ->
210 editor.setText("012345\n\nabcdef")
211 editor.setCursorScreenPosition([1, 0])
212
213 it "deletes nothing when vim-mode.wrapLeftRightMotion is false", ->
214 atom.config.set('vim-mode.wrapLeftRightMotion', false)
215 keydown('X', shift: true)
216 expect(editor.getText()).toBe "012345\n\nabcdef"
217 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
218
219 it "deletes the newline when wrapLeftRightMotion is true", ->
220 atom.config.set('vim-mode.wrapLeftRightMotion', true)
221 keydown('X', shift: true)
222 expect(editor.getText()).toBe "012345\nabcdef"
223 expect(editor.getCursorScreenPosition()).toEqual [0, 5]
224
225 describe "the s keybinding", ->
226 beforeEach ->
227 editor.setText('012345')
228 editor.setCursorScreenPosition([0, 1])
229
230 it "deletes the character to the right and enters insert mode", ->
231 keydown('s')
232 expect(editorElement.classList.contains('insert-mode')).toBe(true)
233 expect(editor.getText()).toBe '02345'
234 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
235 expect(vimState.getRegister('"').text).toBe '1'
236
237 it "is repeatable", ->
238 editor.setCursorScreenPosition([0, 0])
239 keydown('3')
240 keydown('s')
241 editor.insertText("ab")
242 keydown('escape')
243 expect(editor.getText()).toBe 'ab345'
244 editor.setCursorScreenPosition([0, 2])
245 keydown('.')
246 expect(editor.getText()).toBe 'abab'
247
248 it "is undoable", ->
249 editor.setCursorScreenPosition([0, 0])
250 keydown('3')
251 keydown('s')
252 editor.insertText("ab")
253 keydown('escape')
254 expect(editor.getText()).toBe 'ab345'
255 keydown('u')
256 expect(editor.getText()).toBe '012345'
257 expect(editor.getSelectedText()).toBe ''
258
259 describe "in visual mode", ->
260 beforeEach ->
261 keydown('v')
262 editor.selectRight()
263 keydown('s')
264
265 it "deletes the selected characters and enters insert mode", ->
266 expect(editorElement.classList.contains('insert-mode')).toBe(true)
267 expect(editor.getText()).toBe '0345'
268 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
269 expect(vimState.getRegister('"').text).toBe '12'
270
271 describe "the S keybinding", ->
272 beforeEach ->
273 editor.setText("12345\nabcde\nABCDE")
274 editor.setCursorScreenPosition([1, 3])
275
276 it "deletes the entire line and enters insert mode", ->
277 keydown('S', shift: true)
278 expect(editorElement.classList.contains('insert-mode')).toBe(true)
279 expect(editor.getText()).toBe "12345\n\nABCDE"
280 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
281 expect(vimState.getRegister('"').text).toBe "abcde\n"
282 expect(vimState.getRegister('"').type).toBe 'linewise'
283
284 it "is repeatable", ->
285 keydown('S', shift: true)
286 editor.insertText("abc")
287 keydown 'escape'
288 expect(editor.getText()).toBe "12345\nabc\nABCDE"
289 editor.setCursorScreenPosition([2, 3])
290 keydown '.'
291 expect(editor.getText()).toBe "12345\nabc\nabc\n"
292
293 it "is undoable", ->
294 keydown('S', shift: true)
295 editor.insertText("abc")
296 keydown 'escape'
297 expect(editor.getText()).toBe "12345\nabc\nABCDE"
298 keydown 'u'
299 expect(editor.getText()).toBe "12345\nabcde\nABCDE"
300 expect(editor.getSelectedText()).toBe ''
301
302 it "works when the cursor's goal column is greater than its current column", ->
303 editor.setText("\n12345")
304 editor.setCursorBufferPosition([1, Infinity])
305 editor.moveUp()
306 keydown("S", shift: true)
307 expect(editor.getText()).toBe("\n12345")
308
309 # Can't be tested without setting grammar of test buffer
310 xit "respects indentation", ->
311
312 describe "the d keybinding", ->
313 it "enters operator-pending mode", ->
314 keydown('d')
315 expect(editorElement.classList.contains('operator-pending-mode')).toBe(true)
455f099b 316 expect(editorElement.classList.contains('normal-mode')).toBe(false)
24c7594d
BB
317
318 describe "when followed by a d", ->
319 it "deletes the current line and exits operator-pending mode", ->
320 editor.setText("12345\nabcde\n\nABCDE")
321 editor.setCursorScreenPosition([1, 1])
322
323 keydown('d')
324 keydown('d')
325
326 expect(editor.getText()).toBe "12345\n\nABCDE"
327 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
328 expect(vimState.getRegister('"').text).toBe "abcde\n"
329 expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
455f099b 330 expect(editorElement.classList.contains('normal-mode')).toBe(true)
24c7594d
BB
331
332 it "deletes the last line", ->
333 editor.setText("12345\nabcde\nABCDE")
334 editor.setCursorScreenPosition([2, 1])
335
336 keydown('d')
337 keydown('d')
338
339 expect(editor.getText()).toBe "12345\nabcde\n"
340 expect(editor.getCursorScreenPosition()).toEqual [2, 0]
341
342 it "leaves the cursor on the first nonblank character", ->
343 editor.setText("12345\n abcde\n")
344 editor.setCursorScreenPosition([0, 4])
345
346 keydown('d')
347 keydown('d')
348
349 expect(editor.getText()).toBe " abcde\n"
350 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
351
352 describe "undo behavior", ->
353 beforeEach ->
354 editor.setText("12345\nabcde\nABCDE\nQWERT")
355 editor.setCursorScreenPosition([1, 1])
356
455f099b 357 it "undoes both lines", ->
24c7594d
BB
358 keydown('d')
359 keydown('2')
360 keydown('d')
361
362 keydown('u')
363
24c7594d
BB
364 expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT"
365 expect(editor.getSelectedText()).toBe ''
366
455f099b
BB
367 describe "with multiple cursors", ->
368 beforeEach ->
369 editor.setCursorBufferPosition([1, 1])
370 editor.addCursorAtBufferPosition([0, 0])
371
372 it "is undone as one operation", ->
373 keydown('d')
374 keydown('l')
375
376 keydown('u')
377
378 expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT"
379 expect(editor.getSelectedText()).toBe ''
380
24c7594d
BB
381 describe "when followed by a w", ->
382 it "deletes the next word until the end of the line and exits operator-pending mode", ->
383 editor.setText("abcd efg\nabc")
384 editor.setCursorScreenPosition([0, 5])
385
386 keydown('d')
387 keydown('w')
388
389 # Incompatibility with VIM. In vim, `w` behaves differently as an
390 # operator than as a motion; it stops at the end of a line.expect(editor.getText()).toBe "abcd abc"
391 expect(editor.getText()).toBe "abcd abc"
392 expect(editor.getCursorScreenPosition()).toEqual [0, 5]
393
394 expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
455f099b 395 expect(editorElement.classList.contains('normal-mode')).toBe(true)
24c7594d
BB
396
397 it "deletes to the beginning of the next word", ->
398 editor.setText('abcd efg')
399 editor.setCursorScreenPosition([0, 2])
400
401 keydown('d')
402 keydown('w')
403
404 expect(editor.getText()).toBe 'abefg'
405 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
406
407 editor.setText('one two three four')
408 editor.setCursorScreenPosition([0, 0])
409
410 keydown('d')
411 keydown('3')
412 keydown('w')
413
414 expect(editor.getText()).toBe 'four'
415 expect(editor.getCursorScreenPosition()).toEqual [0, 0]
416
417 describe "when followed by an iw", ->
418 it "deletes the containing word", ->
419 editor.setText("12345 abcde ABCDE")
420 editor.setCursorScreenPosition([0, 9])
421
422 keydown('d')
423 expect(editorElement.classList.contains('operator-pending-mode')).toBe(true)
424 keydown('i')
425 keydown('w')
426
427 expect(editor.getText()).toBe "12345 ABCDE"
428 expect(editor.getCursorScreenPosition()).toEqual [0, 6]
429 expect(vimState.getRegister('"').text).toBe "abcde"
430 expect(editorElement.classList.contains('operator-pending-mode')).toBe(false)
455f099b
BB
431 expect(editorElement.classList.contains('normal-mode')).toBe(true)
432
433 describe "when followed by a j", ->
434 originalText = "12345\nabcde\nABCDE\n"
24c7594d 435
24c7594d 436 beforeEach ->
24c7594d
BB
437 editor.setText(originalText)
438
455f099b
BB
439 describe "on the beginning of the file", ->
440 it "deletes the next two lines", ->
24c7594d 441 editor.setCursorScreenPosition([0, 0])
455f099b
BB
442 keydown('d')
443 keydown('j')
444 expect(editor.getText()).toBe("ABCDE\n")
445
446 describe "on the end of the file", ->
447 it "deletes nothing", ->
448 editor.setCursorScreenPosition([4, 0])
449 keydown('d')
450 keydown('j')
451 expect(editor.getText()).toBe(originalText)
452
453 describe "on the middle of second line", ->
454 it "deletes the last two lines", ->
455 editor.setCursorScreenPosition([1, 2])
456 keydown('d')
457 keydown('j')
458 expect(editor.getText()).toBe("12345\n")
24c7594d
BB
459
460 describe "when followed by an k", ->
455f099b
BB
461 originalText = "12345\nabcde\nABCDE"
462
24c7594d 463 beforeEach ->
24c7594d
BB
464 editor.setText(originalText)
465
455f099b
BB
466 describe "on the end of the file", ->
467 it "deletes the bottom two lines", ->
468 editor.setCursorScreenPosition([2, 4])
469 keydown('d')
470 keydown('k')
471 expect(editor.getText()).toBe("12345\n")
24c7594d 472
455f099b
BB
473 describe "on the beginning of the file", ->
474 xit "deletes nothing", ->
24c7594d 475 editor.setCursorScreenPosition([0, 0])
455f099b
BB
476 keydown('d')
477 keydown('k')
478 expect(editor.getText()).toBe(originalText)
24c7594d 479
455f099b
BB
480 describe "when on the middle of second line", ->
481 it "deletes the first two lines", ->
482 editor.setCursorScreenPosition([1, 2])
483 keydown('d')
484 keydown('k')
485 expect(editor.getText()).toBe("ABCDE")
24c7594d
BB
486
487 describe "when followed by a G", ->
488 beforeEach ->
489 originalText = "12345\nabcde\nABCDE"
490 editor.setText(originalText)
491
492 describe "on the beginning of the second line", ->
493 it "deletes the bottom two lines", ->
494 editor.setCursorScreenPosition([1, 0])
495 keydown('d')
496 keydown('G', shift: true)
497 expect(editor.getText()).toBe("12345\n")
498
499 describe "on the middle of the second line", ->
500 it "deletes the bottom two lines", ->
501 editor.setCursorScreenPosition([1, 2])
502 keydown('d')
503 keydown('G', shift: true)
504 expect(editor.getText()).toBe("12345\n")
505
506 describe "when followed by a goto line G", ->
507 beforeEach ->
508 originalText = "12345\nabcde\nABCDE"
509 editor.setText(originalText)
510
511 describe "on the beginning of the second line", ->
512 it "deletes the bottom two lines", ->
513 editor.setCursorScreenPosition([1, 0])
514 keydown('d')
515 keydown('2')
516 keydown('G', shift: true)
517 expect(editor.getText()).toBe("12345\nABCDE")
518
519 describe "on the middle of the second line", ->
520 it "deletes the bottom two lines", ->
521 editor.setCursorScreenPosition([1, 2])
522 keydown('d')
523 keydown('2')
524 keydown('G', shift: true)
525 expect(editor.getText()).toBe("12345\nABCDE")
526
527 describe "when followed by a t)", ->
528 describe "with the entire line yanked before", ->
529 beforeEach ->
530 editor.setText("test (xyz)")
531 editor.setCursorScreenPosition([0, 6])
532
533 it "deletes until the closing parenthesis", ->
534 keydown('y')
535 keydown('y')
536 keydown('d')
537 keydown('t')
455f099b 538 normalModeInputKeydown(')')
24c7594d
BB
539 expect(editor.getText()).toBe("test ()")
540 expect(editor.getCursorScreenPosition()).toEqual [0, 6]
541
542 describe "with multiple cursors", ->
543 it "deletes each selection", ->
544 editor.setText("abcd\n1234\nABCD\n")
545 editor.setCursorBufferPosition([0, 1])
546 editor.addCursorAtBufferPosition([1, 2])
547 editor.addCursorAtBufferPosition([2, 3])
548
549 keydown('d')
550 keydown('e')
551
552 expect(editor.getText()).toBe "a\n12\nABC"
553 expect(editor.getCursorBufferPositions()).toEqual [
554 [0, 0],
555 [1, 1],
556 [2, 2],
557 ]
558
559 it "doesn't delete empty selections", ->
560 editor.setText("abcd\nabc\nabd")
561 editor.setCursorBufferPosition([0, 0])
562 editor.addCursorAtBufferPosition([1, 0])
563 editor.addCursorAtBufferPosition([2, 0])
564
565 keydown('d')
566 keydown('t')
455f099b 567 normalModeInputKeydown('d')
24c7594d
BB
568
569 expect(editor.getText()).toBe "d\nabc\nd"
570 expect(editor.getCursorBufferPositions()).toEqual [
571 [0, 0],
572 [1, 0],
573 [2, 0],
574 ]
575
576 describe "the D keybinding", ->
577 beforeEach ->
578 editor.getBuffer().setText("012\n")
579 editor.setCursorScreenPosition([0, 1])
580 keydown('D', shift: true)
581
582 it "deletes the contents until the end of the line", ->
583 expect(editor.getText()).toBe "0\n"
584
585 describe "the c keybinding", ->
586 beforeEach ->
587 editor.setText("12345\nabcde\nABCDE")
588
589 describe "when followed by a c", ->
455f099b
BB
590 describe "with autoindent", ->
591 beforeEach ->
592 editor.setText("12345\n abcde\nABCDE")
593 editor.setCursorScreenPosition([1, 1])
594 spyOn(editor, 'shouldAutoIndent').andReturn(true)
595 spyOn(editor, 'autoIndentBufferRow').andCallFake (line) ->
596 editor.indent()
597 spyOn(editor.languageMode, 'suggestedIndentForLineAtBufferRow').andCallFake -> 1
24c7594d 598
455f099b
BB
599 it "deletes the current line and enters insert mode", ->
600 editor.setCursorScreenPosition([1, 1])
24c7594d 601
455f099b
BB
602 keydown('c')
603 keydown('c')
604
605 expect(editor.getText()).toBe "12345\n \nABCDE"
606 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
607 expect(editorElement.classList.contains('normal-mode')).toBe(false)
608 expect(editorElement.classList.contains('insert-mode')).toBe(true)
609
610 it "is repeatable", ->
611 keydown('c')
612 keydown('c')
613 editor.insertText("abc")
614 keydown 'escape'
615 expect(editor.getText()).toBe "12345\n abc\nABCDE"
616 editor.setCursorScreenPosition([2, 3])
617 keydown '.'
618 expect(editor.getText()).toBe "12345\n abc\n abc\n"
619
620 it "is undoable", ->
621 keydown('c')
622 keydown('c')
623 editor.insertText("abc")
624 keydown 'escape'
625 expect(editor.getText()).toBe "12345\n abc\nABCDE"
626 keydown 'u'
627 expect(editor.getText()).toBe "12345\n abcde\nABCDE"
628 expect(editor.getSelectedText()).toBe ''
24c7594d
BB
629
630 describe "when the cursor is on the last line", ->
631 it "deletes the line's content and enters insert mode on the last line", ->
632 editor.setCursorScreenPosition([2, 1])
633
634 keydown('c')
635 keydown('c')
636
637 expect(editor.getText()).toBe "12345\nabcde\n\n"
638 expect(editor.getCursorScreenPosition()).toEqual [2, 0]
455f099b 639 expect(editorElement.classList.contains('normal-mode')).toBe(false)
24c7594d
BB
640 expect(editorElement.classList.contains('insert-mode')).toBe(true)
641
642 describe "when the cursor is on the only line", ->
643 it "deletes the line's content and enters insert mode", ->
644 editor.setText("12345")
645 editor.setCursorScreenPosition([0, 2])
646
647 keydown('c')
648 keydown('c')
649
455f099b 650 expect(editor.getText()).toBe ""
24c7594d 651 expect(editor.getCursorScreenPosition()).toEqual [0, 0]
455f099b 652 expect(editorElement.classList.contains('normal-mode')).toBe(false)
24c7594d
BB
653 expect(editorElement.classList.contains('insert-mode')).toBe(true)
654
655 describe "when followed by i w", ->
656 it "undo's and redo's completely", ->
657 editor.setCursorScreenPosition([1, 1])
658
659 keydown('c')
660 keydown('i')
661 keydown('w')
662 expect(editor.getText()).toBe "12345\n\nABCDE"
663 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
664 expect(editorElement.classList.contains('insert-mode')).toBe(true)
665
666 # Just cannot get "typing" to work correctly in test.
667 editor.setText("12345\nfg\nABCDE")
668 keydown('escape')
455f099b 669 expect(editorElement.classList.contains('normal-mode')).toBe(true)
24c7594d
BB
670 expect(editor.getText()).toBe "12345\nfg\nABCDE"
671
672 keydown('u')
673 expect(editor.getText()).toBe "12345\nabcde\nABCDE"
674 keydown('r', ctrl: true)
675 expect(editor.getText()).toBe "12345\nfg\nABCDE"
676
677 describe "when followed by a w", ->
678 it "changes the word", ->
679 editor.setText("word1 word2 word3")
680 editor.setCursorBufferPosition([0, "word1 w".length])
681
682 keydown("c")
683 keydown("w")
684 keydown("escape")
685
686 expect(editor.getText()).toBe "word1 w word3"
687
688 describe "when followed by a G", ->
689 beforeEach ->
690 originalText = "12345\nabcde\nABCDE"
691 editor.setText(originalText)
692
693 describe "on the beginning of the second line", ->
694 it "deletes the bottom two lines", ->
695 editor.setCursorScreenPosition([1, 0])
696 keydown('c')
697 keydown('G', shift: true)
698 keydown('escape')
699 expect(editor.getText()).toBe("12345\n\n")
700
701 describe "on the middle of the second line", ->
702 it "deletes the bottom two lines", ->
703 editor.setCursorScreenPosition([1, 2])
704 keydown('c')
705 keydown('G', shift: true)
706 keydown('escape')
707 expect(editor.getText()).toBe("12345\n\n")
708
455f099b
BB
709 describe "when followed by a %", ->
710 beforeEach ->
711 editor.setText("12345(67)8\nabc(d)e\nA()BCDE")
712
713 describe "before brackets or on the first one", ->
714 beforeEach ->
715 editor.setCursorScreenPosition([0, 1])
716 editor.addCursorAtScreenPosition([1, 1])
717 editor.addCursorAtScreenPosition([2, 1])
718 keydown('c')
719 keydown('%')
720 editor.insertText('x')
721
722 it "replaces inclusively until matching bracket", ->
723 expect(editor.getText()).toBe("1x8\naxe\nAxBCDE")
724 expect(vimState.mode).toBe "insert"
725
726 it "undoes correctly with u", ->
727 keydown('escape')
728 expect(vimState.mode).toBe "normal"
729 keydown 'u'
730 expect(editor.getText()).toBe("12345(67)8\nabc(d)e\nA()BCDE")
731
732 describe "inside brackets or on the ending one", ->
733 it "replaces inclusively backwards until matching bracket", ->
734 editor.setCursorScreenPosition([0, 6])
735 editor.addCursorAtScreenPosition([1, 5])
736 editor.addCursorAtScreenPosition([2, 2])
737 keydown('c')
738 keydown('%')
739 editor.insertText('x')
740 expect(editor.getText()).toBe("12345x7)8\nabcxe\nAxBCDE")
741 expect(vimState.mode).toBe "insert"
742
743 describe "after or without brackets", ->
744 it "deletes nothing", ->
745 editor.setText("12345(67)8\nabc(d)e\nABCDE")
746 editor.setCursorScreenPosition([0, 9])
747 editor.addCursorAtScreenPosition([2, 2])
748 keydown('c')
749 keydown('%')
750 expect(editor.getText()).toBe("12345(67)8\nabc(d)e\nABCDE")
751 expect(vimState.mode).toBe "normal"
752
753 describe "repetition with .", ->
754 beforeEach ->
755 editor.setCursorScreenPosition([0, 1])
756 keydown('c')
757 keydown('%')
758 editor.insertText('x')
759 keydown('escape')
760
761 it "repeats correctly before a bracket", ->
762 editor.setCursorScreenPosition([1, 0])
763 keydown('.')
764 expect(editor.getText()).toBe("1x8\nxe\nA()BCDE")
765 expect(vimState.mode).toBe "normal"
766
767 it "repeats correctly on the opening bracket", ->
768 editor.setCursorScreenPosition([1, 3])
769 keydown('.')
770 expect(editor.getText()).toBe("1x8\nabcxe\nA()BCDE")
771 expect(vimState.mode).toBe "normal"
772
773 it "repeats correctly inside brackets", ->
774 editor.setCursorScreenPosition([1, 4])
775 keydown('.')
776 expect(editor.getText()).toBe("1x8\nabcx)e\nA()BCDE")
777 expect(vimState.mode).toBe "normal"
778
779 it "repeats correctly on the closing bracket", ->
780 editor.setCursorScreenPosition([1, 5])
781 keydown('.')
782 expect(editor.getText()).toBe("1x8\nabcxe\nA()BCDE")
783 expect(vimState.mode).toBe "normal"
784
785 it "does nothing when repeated after a bracket", ->
786 editor.setCursorScreenPosition([2, 3])
787 keydown('.')
788 expect(editor.getText()).toBe("1x8\nabc(d)e\nA()BCDE")
789 expect(vimState.mode).toBe "normal"
790
24c7594d
BB
791 describe "when followed by a goto line G", ->
792 beforeEach ->
793 editor.setText "12345\nabcde\nABCDE"
794
795 describe "on the beginning of the second line", ->
796 it "deletes all the text on the line", ->
797 editor.setCursorScreenPosition([1, 0])
798 keydown('c')
799 keydown('2')
800 keydown('G', shift: true)
801 keydown('escape')
802 expect(editor.getText()).toBe("12345\n\nABCDE")
803
804 describe "on the middle of the second line", ->
805 it "deletes all the text on the line", ->
806 editor.setCursorScreenPosition([1, 2])
807 keydown('c')
808 keydown('2')
809 keydown('G', shift: true)
810 keydown('escape')
811 expect(editor.getText()).toBe("12345\n\nABCDE")
812
455f099b
BB
813 describe "in visual mode", ->
814 beforeEach ->
815 editor.setText "123456789\nabcde\nfghijklmnopq\nuvwxyz"
816 editor.setCursorScreenPosition [1, 1]
817
818 describe "with characterwise selection on a single line", ->
819 it "repeats with .", ->
820 keydown 'v'
821 keydown '2'
822 keydown 'l'
823 keydown 'c'
824 editor.insertText "ab"
825 keydown 'escape'
826 expect(editor.getText()).toBe "123456789\naabe\nfghijklmnopq\nuvwxyz"
827
828 editor.setCursorScreenPosition [0, 1]
829 keydown '.'
830 expect(editor.getText()).toBe "1ab56789\naabe\nfghijklmnopq\nuvwxyz"
831
832 it "repeats shortened with . near the end of the line", ->
833 editor.setCursorScreenPosition [0, 2]
834 keydown 'v'
835 keydown '4'
836 keydown 'l'
837 keydown 'c'
838 editor.insertText "ab"
839 keydown 'escape'
840 expect(editor.getText()).toBe "12ab89\nabcde\nfghijklmnopq\nuvwxyz"
841
842 editor.setCursorScreenPosition [1, 3]
843 keydown '.'
844 expect(editor.getText()).toBe "12ab89\nabcab\nfghijklmnopq\nuvwxyz"
845
846 it "repeats shortened with . near the end of the line regardless of whether motion wrapping is enabled", ->
847 atom.config.set('vim-mode.wrapLeftRightMotion', true)
848 editor.setCursorScreenPosition [0, 2]
849 keydown 'v'
850 keydown '4'
851 keydown 'l'
852 keydown 'c'
853 editor.insertText "ab"
854 keydown 'escape'
855 expect(editor.getText()).toBe "12ab89\nabcde\nfghijklmnopq\nuvwxyz"
856
857 editor.setCursorScreenPosition [1, 3]
858 keydown '.'
859 # this differs from VIM, which would eat the \n before fghij...
860 expect(editor.getText()).toBe "12ab89\nabcab\nfghijklmnopq\nuvwxyz"
861
862 describe "is repeatable with characterwise selection over multiple lines", ->
863 it "repeats with .", ->
864 keydown 'v'
865 keydown 'j'
866 keydown '3'
867 keydown 'l'
868 keydown 'c'
869 editor.insertText "x"
870 keydown 'escape'
871 expect(editor.getText()).toBe "123456789\naxklmnopq\nuvwxyz"
872
873 editor.setCursorScreenPosition [0, 1]
874 keydown '.'
875 expect(editor.getText()).toBe "1xnopq\nuvwxyz"
876
877 it "repeats shortened with . near the end of the line", ->
878 # this behaviour is unlike VIM, see #737
879 keydown 'v'
880 keydown 'j'
881 keydown '6'
882 keydown 'l'
883 keydown 'c'
884 editor.insertText "x"
885 keydown 'escape'
886 expect(editor.getText()).toBe "123456789\naxnopq\nuvwxyz"
887
888 editor.setCursorScreenPosition [0, 1]
889 keydown '.'
890 expect(editor.getText()).toBe "1x\nuvwxyz"
891
892 describe "is repeatable with linewise selection", ->
893 describe "with one line selected", ->
894 it "repeats with .", ->
895 keydown 'V', shift: true
896 keydown 'c'
897 editor.insertText "x"
898 keydown 'escape'
899 expect(editor.getText()).toBe "123456789\nx\nfghijklmnopq\nuvwxyz"
900
901 editor.setCursorScreenPosition [0, 7]
902 keydown '.'
903 expect(editor.getText()).toBe "x\nx\nfghijklmnopq\nuvwxyz"
904
905 editor.setCursorScreenPosition [2, 0]
906 keydown '.'
907 expect(editor.getText()).toBe "x\nx\nx\nuvwxyz"
908
909 describe "with multiple lines selected", ->
910 it "repeats with .", ->
911 keydown 'V', shift: true
912 keydown 'j'
913 keydown 'c'
914 editor.insertText "x"
915 keydown 'escape'
916 expect(editor.getText()).toBe "123456789\nx\nuvwxyz"
917
918 editor.setCursorScreenPosition [0, 7]
919 keydown '.'
920 expect(editor.getText()).toBe "x\nuvwxyz"
921
922 it "repeats shortened with . near the end of the file", ->
923 keydown 'V', shift: true
924 keydown 'j'
925 keydown 'c'
926 editor.insertText "x"
927 keydown 'escape'
928 expect(editor.getText()).toBe "123456789\nx\nuvwxyz"
929
930 editor.setCursorScreenPosition [1, 7]
931 keydown '.'
932 expect(editor.getText()).toBe "123456789\nx\n"
933
934 xdescribe "is repeatable with block selection", ->
935 # there is no block selection yet
936
24c7594d
BB
937 describe "the C keybinding", ->
938 beforeEach ->
939 editor.getBuffer().setText("012\n")
940 editor.setCursorScreenPosition([0, 1])
941 keydown('C', shift: true)
942
943 it "deletes the contents until the end of the line and enters insert mode", ->
944 expect(editor.getText()).toBe "0\n"
945 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
455f099b 946 expect(editorElement.classList.contains('normal-mode')).toBe(false)
24c7594d
BB
947 expect(editorElement.classList.contains('insert-mode')).toBe(true)
948
949 describe "the y keybinding", ->
950 beforeEach ->
455f099b 951 editor.getBuffer().setText("012 345\nabc\ndefg\n")
24c7594d 952 editor.setCursorScreenPosition([0, 4])
455f099b 953 vimState.setRegister('"', text: '345')
24c7594d
BB
954
955 describe "when selected lines in visual linewise mode", ->
956 beforeEach ->
957 keydown('V', shift: true)
958 keydown('j')
959 keydown('y')
960
961 it "is in linewise motion", ->
962 expect(vimState.getRegister('"').type).toEqual "linewise"
963
964 it "saves the lines to the default register", ->
965 expect(vimState.getRegister('"').text).toBe "012 345\nabc\n"
966
967 it "places the cursor at the beginning of the selection", ->
968 expect(editor.getCursorBufferPositions()).toEqual([[0, 0]])
969
970 describe "when followed by a second y ", ->
971 beforeEach ->
972 keydown('y')
973 keydown('y')
974
975 it "saves the line to the default register", ->
976 expect(vimState.getRegister('"').text).toBe "012 345\n"
977
978 it "leaves the cursor at the starting position", ->
979 expect(editor.getCursorScreenPosition()).toEqual [0, 4]
980
981 describe "when useClipboardAsDefaultRegister enabled", ->
982 it "writes to clipboard", ->
983 atom.config.set 'vim-mode.useClipboardAsDefaultRegister', true
984 keydown('y')
985 keydown('y')
986 expect(atom.clipboard.read()).toBe '012 345\n'
987
988 describe "when followed with a repeated y", ->
989 beforeEach ->
990 keydown('y')
991 keydown('2')
992 keydown('y')
993
994 it "copies n lines, starting from the current", ->
995 expect(vimState.getRegister('"').text).toBe "012 345\nabc\n"
996
997 it "leaves the cursor at the starting position", ->
998 expect(editor.getCursorScreenPosition()).toEqual [0, 4]
999
1000 describe "with a register", ->
1001 beforeEach ->
1002 keydown('"')
1003 keydown('a')
1004 keydown('y')
1005 keydown('y')
1006
1007 it "saves the line to the a register", ->
1008 expect(vimState.getRegister('a').text).toBe "012 345\n"
1009
1010 it "appends the line to the A register", ->
1011 keydown('"')
1012 keydown('A', shift: true)
1013 keydown('y')
1014 keydown('y')
1015 expect(vimState.getRegister('a').text).toBe "012 345\n012 345\n"
1016
1017 describe "with a forward motion", ->
1018 beforeEach ->
1019 keydown('y')
1020 keydown('e')
1021
1022 it "saves the selected text to the default register", ->
1023 expect(vimState.getRegister('"').text).toBe '345'
1024
1025 it "leaves the cursor at the starting position", ->
1026 expect(editor.getCursorScreenPosition()).toEqual [0, 4]
1027
1028 it "does not yank when motion fails", ->
1029 keydown('y')
1030 keydown('t')
455f099b 1031 normalModeInputKeydown('x')
24c7594d
BB
1032 expect(vimState.getRegister('"').text).toBe '345'
1033
1034 describe "with a text object", ->
1035 it "moves the cursor to the beginning of the text object", ->
1036 editor.setCursorBufferPosition([0, 5])
1037 keydown("y")
1038 keydown("i")
1039 keydown("w")
1040 expect(editor.getCursorBufferPositions()).toEqual([[0, 4]])
1041
1042 describe "with a left motion", ->
1043 beforeEach ->
1044 keydown('y')
1045 keydown('h')
1046
455f099b
BB
1047 it "saves the left letter to the default register", ->
1048 expect(vimState.getRegister('"').text).toBe " "
24c7594d 1049
455f099b
BB
1050 it "moves the cursor position to the left", ->
1051 expect(editor.getCursorScreenPosition()).toEqual [0, 3]
24c7594d
BB
1052
1053 describe "with a down motion", ->
1054 beforeEach ->
1055 keydown 'y'
1056 keydown 'j'
1057
1058 it "saves both full lines to the default register", ->
1059 expect(vimState.getRegister('"').text).toBe "012 345\nabc\n"
1060
1061 it "leaves the cursor at the starting position", ->
1062 expect(editor.getCursorScreenPosition()).toEqual [0, 4]
1063
455f099b
BB
1064 describe "with an up motion", ->
1065 beforeEach ->
1066 editor.setCursorScreenPosition([2, 2])
1067 keydown 'y'
1068 keydown 'k'
1069
1070 it "saves both full lines to the default register", ->
1071 expect(vimState.getRegister('"').text).toBe "abc\ndefg\n"
1072
1073 it "puts the cursor on the first line and the original column", ->
1074 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
1075
24c7594d
BB
1076 describe "when followed by a G", ->
1077 beforeEach ->
1078 originalText = "12345\nabcde\nABCDE"
1079 editor.setText(originalText)
1080
1081 describe "on the beginning of the second line", ->
1082 it "deletes the bottom two lines", ->
1083 editor.setCursorScreenPosition([1, 0])
1084 keydown('y')
1085 keydown('G', shift: true)
1086 keydown('P', shift: true)
1087 expect(editor.getText()).toBe("12345\nabcde\nABCDE\nabcde\nABCDE")
1088
1089 describe "on the middle of the second line", ->
1090 it "deletes the bottom two lines", ->
1091 editor.setCursorScreenPosition([1, 2])
1092 keydown('y')
1093 keydown('G', shift: true)
1094 keydown('P', shift: true)
1095 expect(editor.getText()).toBe("12345\nabcde\nABCDE\nabcde\nABCDE")
1096
1097 describe "when followed by a goto line G", ->
1098 beforeEach ->
1099 originalText = "12345\nabcde\nABCDE"
1100 editor.setText(originalText)
1101
1102 describe "on the beginning of the second line", ->
1103 it "deletes the bottom two lines", ->
1104 editor.setCursorScreenPosition([1, 0])
1105 keydown('y')
1106 keydown('2')
1107 keydown('G', shift: true)
1108 keydown('P', shift: true)
1109 expect(editor.getText()).toBe("12345\nabcde\nabcde\nABCDE")
1110
1111 describe "on the middle of the second line", ->
1112 it "deletes the bottom two lines", ->
1113 editor.setCursorScreenPosition([1, 2])
1114 keydown('y')
1115 keydown('2')
1116 keydown('G', shift: true)
1117 keydown('P', shift: true)
1118 expect(editor.getText()).toBe("12345\nabcde\nabcde\nABCDE")
1119
1120 describe "with multiple cursors", ->
1121 it "moves each cursor and copies the last selection's text", ->
1122 editor.setText " abcd\n 1234"
1123 editor.setCursorBufferPosition([0, 0])
1124 editor.addCursorAtBufferPosition([1, 5])
1125
1126 keydown("y")
1127 keydown("^")
1128
1129 expect(vimState.getRegister('"').text).toBe '123'
1130 expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 2]]
1131
455f099b
BB
1132 describe "in a long file", ->
1133 beforeEach ->
1134 editor.setHeight(400)
1135 editor.setLineHeightInPixels(10)
1136 editor.setDefaultCharWidth(10)
1137 text = ""
1138 for i in [1..200]
1139 text += "#{i}\n"
1140 editor.setText(text)
1141
1142 describe "yanking many lines forward", ->
1143 it "does not scroll the window", ->
1144 editor.setCursorBufferPosition [40, 1]
1145 previousScrollTop = editor.getScrollTop()
1146
1147 # yank many lines
1148 keydown('y')
1149 keydown('1')
1150 keydown('6')
1151 keydown('0')
1152 keydown('G', shift: true)
1153
1154 expect(editor.getScrollTop()).toEqual(previousScrollTop)
1155 expect(editor.getCursorBufferPosition()).toEqual [40, 1]
1156 expect(vimState.getRegister('"').text.split('\n').length).toBe 121
1157
1158 describe "yanking many lines backwards", ->
1159 it "scrolls the window", ->
1160 editor.setCursorBufferPosition [140, 1]
1161 previousScrollTop = editor.getScrollTop()
1162
1163 # yank many lines
1164 keydown('y')
1165 keydown('6')
1166 keydown('0')
1167 keydown('G', shift: true)
1168
1169 expect(editor.getScrollTop()).toNotEqual previousScrollTop
1170 expect(editor.getCursorBufferPosition()).toEqual [59, 1]
1171 expect(vimState.getRegister('"').text.split('\n').length).toBe 83
1172
24c7594d
BB
1173 describe "the yy keybinding", ->
1174 describe "on a single line file", ->
1175 beforeEach ->
1176 editor.getBuffer().setText "exclamation!\n"
1177 editor.setCursorScreenPosition [0, 0]
1178
1179 it "copies the entire line and pastes it correctly", ->
1180 keydown('y')
1181 keydown('y')
1182 keydown('p')
1183
1184 expect(vimState.getRegister('"').text).toBe "exclamation!\n"
1185 expect(editor.getText()).toBe "exclamation!\nexclamation!\n"
1186
1187 describe "on a single line file with no newline", ->
1188 beforeEach ->
1189 editor.getBuffer().setText "no newline!"
1190 editor.setCursorScreenPosition [0, 0]
1191
1192 it "copies the entire line and pastes it correctly", ->
1193 keydown('y')
1194 keydown('y')
1195 keydown('p')
1196
1197 expect(vimState.getRegister('"').text).toBe "no newline!\n"
1198 expect(editor.getText()).toBe "no newline!\nno newline!"
1199
1200 it "copies the entire line and pastes it respecting count and new lines", ->
1201 keydown('y')
1202 keydown('y')
1203 keydown('2')
1204 keydown('p')
1205
1206 expect(vimState.getRegister('"').text).toBe "no newline!\n"
1207 expect(editor.getText()).toBe "no newline!\nno newline!\nno newline!"
1208
1209 describe "the Y keybinding", ->
1210 beforeEach ->
1211 editor.getBuffer().setText "012 345\nabc\n"
1212 editor.setCursorScreenPosition [0, 4]
1213
1214 it "saves the line to the default register", ->
1215 keydown('Y', shift: true)
1216
1217 expect(vimState.getRegister('"').text).toBe "012 345\n"
1218 expect(editor.getCursorScreenPosition()).toEqual [0, 4]
1219
1220 describe "the p keybinding", ->
1221 describe "with character contents", ->
1222 beforeEach ->
1223 editor.getBuffer().setText "012\n"
1224 editor.setCursorScreenPosition [0, 0]
1225 vimState.setRegister('"', text: '345')
1226 vimState.setRegister('a', text: 'a')
1227 atom.clipboard.write "clip"
1228
1229 describe "from the default register", ->
1230 beforeEach -> keydown('p')
1231
1232 it "inserts the contents", ->
1233 expect(editor.getText()).toBe "034512\n"
1234 expect(editor.getCursorScreenPosition()).toEqual [0, 3]
1235
455f099b
BB
1236 describe "at the end of a line", ->
1237 beforeEach ->
1238 editor.setCursorScreenPosition [0, 2]
1239 keydown('p')
1240
1241 it "positions cursor correctly", ->
1242 expect(editor.getText()).toBe "012345\n"
1243 expect(editor.getCursorScreenPosition()).toEqual [0, 5]
1244
24c7594d
BB
1245 describe "when useClipboardAsDefaultRegister enabled", ->
1246 it "inserts contents from clipboard", ->
1247 atom.config.set 'vim-mode.useClipboardAsDefaultRegister', true
1248 keydown('p')
1249 expect(editor.getText()).toBe "0clip12\n"
1250
1251 describe "from a specified register", ->
1252 beforeEach ->
1253 keydown('"')
1254 keydown('a')
1255 keydown('p')
1256
1257 it "inserts the contents of the 'a' register", ->
1258 expect(editor.getText()).toBe "0a12\n"
1259 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
1260
1261 describe "at the end of a line", ->
1262 it "inserts before the current line's newline", ->
1263 editor.setText("abcde\none two three")
1264 editor.setCursorScreenPosition([1, 4])
1265
1266 keydown 'd'
1267 keydown '$'
1268 keydown 'k'
1269 keydown '$'
1270 keydown 'p'
1271
1272 expect(editor.getText()).toBe "abcdetwo three\none "
1273
1274 describe "with a selection", ->
1275 beforeEach ->
1276 editor.selectRight()
1277 keydown('p')
1278
1279 it "replaces the current selection", ->
1280 expect(editor.getText()).toBe "34512\n"
1281 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1282
1283 describe "with linewise contents", ->
1284 describe "on a single line", ->
1285 beforeEach ->
1286 editor.getBuffer().setText("012")
1287 editor.setCursorScreenPosition([0, 1])
1288 vimState.setRegister('"', text: " 345\n", type: 'linewise')
1289
1290 it "inserts the contents of the default register", ->
1291 keydown('p')
1292
1293 expect(editor.getText()).toBe "012\n 345"
1294 expect(editor.getCursorScreenPosition()).toEqual [1, 1]
1295
1296 it "replaces the current selection", ->
1297 editor.selectRight()
1298 keydown('p')
1299
1300 expect(editor.getText()).toBe "0 345\n2"
1301 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
1302
1303 describe "on multiple lines", ->
1304 beforeEach ->
1305 editor.getBuffer().setText("012\n 345")
1306 vimState.setRegister('"', text: " 456\n", type: 'linewise')
1307
1308 it "inserts the contents of the default register at middle line", ->
1309 editor.setCursorScreenPosition([0, 1])
1310 keydown('p')
1311
1312 expect(editor.getText()).toBe "012\n 456\n 345"
1313 expect(editor.getCursorScreenPosition()).toEqual [1, 1]
1314
1315 it "inserts the contents of the default register at end of line", ->
1316 editor.setCursorScreenPosition([1, 1])
1317 keydown('p')
1318
1319 expect(editor.getText()).toBe "012\n 345\n 456"
1320 expect(editor.getCursorScreenPosition()).toEqual [2, 1]
1321
1322 describe "with multiple linewise contents", ->
1323 beforeEach ->
1324 editor.getBuffer().setText("012\nabc")
1325 editor.setCursorScreenPosition([1, 0])
1326 vimState.setRegister('"', text: " 345\n 678\n", type: 'linewise')
1327 keydown('p')
1328
1329 it "inserts the contents of the default register", ->
1330 expect(editor.getText()).toBe "012\nabc\n 345\n 678"
1331 expect(editor.getCursorScreenPosition()).toEqual [2, 1]
1332
1333 describe "pasting twice", ->
1334 beforeEach ->
1335 editor.setText("12345\nabcde\nABCDE\nQWERT")
1336 editor.setCursorScreenPosition([1, 1])
1337 vimState.setRegister('"', text: '123')
1338 keydown('2')
1339 keydown('p')
1340
1341 it "inserts the same line twice", ->
1342 expect(editor.getText()).toBe "12345\nab123123cde\nABCDE\nQWERT"
1343
1344 describe "when undone", ->
1345 beforeEach ->
1346 keydown('u')
1347
1348 it "removes both lines", ->
1349 expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT"
1350
1351 describe "the P keybinding", ->
1352 describe "with character contents", ->
1353 beforeEach ->
1354 editor.getBuffer().setText("012\n")
1355 editor.setCursorScreenPosition([0, 0])
1356 vimState.setRegister('"', text: '345')
1357 vimState.setRegister('a', text: 'a')
1358 keydown('P', shift: true)
1359
1360 it "inserts the contents of the default register above", ->
1361 expect(editor.getText()).toBe "345012\n"
1362 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1363
1364 describe "the O keybinding", ->
1365 beforeEach ->
1366 spyOn(editor, 'shouldAutoIndent').andReturn(true)
1367 spyOn(editor, 'autoIndentBufferRow').andCallFake (line) ->
1368 editor.indent()
1369
1370 editor.getBuffer().setText(" abc\n 012\n")
1371 editor.setCursorScreenPosition([1, 1])
1372
1373 it "switches to insert and adds a newline above the current one", ->
1374 keydown('O', shift: true)
1375 expect(editor.getText()).toBe " abc\n \n 012\n"
1376 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
1377 expect(editorElement.classList.contains('insert-mode')).toBe(true)
1378
1379 it "is repeatable", ->
1380 editor.getBuffer().setText(" abc\n 012\n 4spaces\n")
1381 editor.setCursorScreenPosition([1, 1])
1382 keydown('O', shift: true)
1383 editor.insertText "def"
1384 keydown 'escape'
1385 expect(editor.getText()).toBe " abc\n def\n 012\n 4spaces\n"
1386 editor.setCursorScreenPosition([1, 1])
1387 keydown '.'
1388 expect(editor.getText()).toBe " abc\n def\n def\n 012\n 4spaces\n"
1389 editor.setCursorScreenPosition([4, 1])
1390 keydown '.'
1391 expect(editor.getText()).toBe " abc\n def\n def\n 012\n def\n 4spaces\n"
1392
1393 it "is undoable", ->
1394 keydown('O', shift: true)
1395 editor.insertText "def"
1396 keydown 'escape'
1397 expect(editor.getText()).toBe " abc\n def\n 012\n"
1398 keydown 'u'
1399 expect(editor.getText()).toBe " abc\n 012\n"
1400
1401 describe "the o keybinding", ->
1402 beforeEach ->
1403 spyOn(editor, 'shouldAutoIndent').andReturn(true)
1404 spyOn(editor, 'autoIndentBufferRow').andCallFake (line) ->
1405 editor.indent()
1406
1407 editor.getBuffer().setText("abc\n 012\n")
1408 editor.setCursorScreenPosition([1, 2])
1409
1410 it "switches to insert and adds a newline above the current one", ->
1411 keydown('o')
1412 expect(editor.getText()).toBe "abc\n 012\n \n"
1413 expect(editorElement.classList.contains('insert-mode')).toBe(true)
1414 expect(editor.getCursorScreenPosition()).toEqual [2, 2]
1415
1416 # This works in practice, but the editor doesn't respect the indentation
1417 # rules without a syntax grammar. Need to set the editor's grammar
1418 # to fix it.
1419 xit "is repeatable", ->
1420 editor.getBuffer().setText(" abc\n 012\n 4spaces\n")
1421 editor.setCursorScreenPosition([1, 1])
1422 keydown('o')
1423 editor.insertText "def"
1424 keydown 'escape'
1425 expect(editor.getText()).toBe " abc\n 012\n def\n 4spaces\n"
1426 keydown '.'
1427 expect(editor.getText()).toBe " abc\n 012\n def\n def\n 4spaces\n"
1428 editor.setCursorScreenPosition([4, 1])
1429 keydown '.'
1430 expect(editor.getText()).toBe " abc\n def\n def\n 012\n 4spaces\n def\n"
1431
1432 it "is undoable", ->
1433 keydown('o')
1434 editor.insertText "def"
1435 keydown 'escape'
1436 expect(editor.getText()).toBe "abc\n 012\n def\n"
1437 keydown 'u'
1438 expect(editor.getText()).toBe "abc\n 012\n"
1439
1440 describe "the a keybinding", ->
1441 beforeEach ->
1442 editor.getBuffer().setText("012\n")
1443
1444 describe "at the beginning of the line", ->
1445 beforeEach ->
1446 editor.setCursorScreenPosition([0, 0])
1447 keydown('a')
1448
1449 it "switches to insert mode and shifts to the right", ->
1450 expect(editor.getCursorScreenPosition()).toEqual [0, 1]
1451 expect(editorElement.classList.contains('insert-mode')).toBe(true)
1452
1453 describe "at the end of the line", ->
1454 beforeEach ->
1455 editor.setCursorScreenPosition([0, 3])
1456 keydown('a')
1457
1458 it "doesn't linewrap", ->
1459 expect(editor.getCursorScreenPosition()).toEqual [0, 3]
1460
1461 describe "the A keybinding", ->
1462 beforeEach ->
1463 editor.getBuffer().setText("11\n22\n")
1464
1465 describe "at the beginning of a line", ->
1466 it "switches to insert mode at the end of the line", ->
1467 editor.setCursorScreenPosition([0, 0])
1468 keydown('A', shift: true)
1469
1470 expect(editorElement.classList.contains('insert-mode')).toBe(true)
1471 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1472
1473 it "repeats always as insert at the end of the line", ->
1474 editor.setCursorScreenPosition([0, 0])
1475 keydown('A', shift: true)
1476 editor.insertText("abc")
1477 keydown 'escape'
1478 editor.setCursorScreenPosition([1, 0])
1479 keydown '.'
1480
1481 expect(editor.getText()).toBe "11abc\n22abc\n"
1482 expect(editorElement.classList.contains('insert-mode')).toBe(false)
1483 expect(editor.getCursorScreenPosition()).toEqual [1, 4]
1484
1485 describe "the I keybinding", ->
1486 beforeEach ->
1487 editor.getBuffer().setText("11\n 22\n")
1488
1489 describe "at the end of a line", ->
1490 it "switches to insert mode at the beginning of the line", ->
1491 editor.setCursorScreenPosition([0, 2])
1492 keydown('I', shift: true)
1493
1494 expect(editorElement.classList.contains('insert-mode')).toBe(true)
1495 expect(editor.getCursorScreenPosition()).toEqual [0, 0]
1496
1497 it "switches to insert mode after leading whitespace", ->
1498 editor.setCursorScreenPosition([1, 4])
1499 keydown('I', shift: true)
1500
1501 expect(editorElement.classList.contains('insert-mode')).toBe(true)
1502 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
1503
1504 it "repeats always as insert at the first character of the line", ->
1505 editor.setCursorScreenPosition([0, 2])
1506 keydown('I', shift: true)
1507 editor.insertText("abc")
1508 keydown 'escape'
1509 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1510 editor.setCursorScreenPosition([1, 4])
1511 keydown '.'
1512
1513 expect(editor.getText()).toBe "abc11\n abc22\n"
1514 expect(editorElement.classList.contains('insert-mode')).toBe(false)
1515 expect(editor.getCursorScreenPosition()).toEqual [1, 4]
1516
1517 describe "the J keybinding", ->
1518 beforeEach ->
1519 editor.getBuffer().setText("012\n 456\n")
1520 editor.setCursorScreenPosition([0, 1])
1521
1522 describe "without repeating", ->
1523 beforeEach -> keydown('J', shift: true)
1524
1525 it "joins the contents of the current line with the one below it", ->
1526 expect(editor.getText()).toBe "012 456\n"
1527
1528 describe "with repeating", ->
1529 beforeEach ->
1530 editor.setText("12345\nabcde\nABCDE\nQWERT")
1531 editor.setCursorScreenPosition([1, 1])
1532 keydown('2')
1533 keydown('J', shift: true)
1534
1535 describe "undo behavior", ->
1536 beforeEach -> keydown('u')
1537
1538 it "handles repeats", ->
1539 expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT"
1540
1541 describe "the > keybinding", ->
1542 beforeEach ->
1543 editor.setText("12345\nabcde\nABCDE")
1544
1545 describe "on the last line", ->
1546 beforeEach ->
1547 editor.setCursorScreenPosition([2, 0])
1548
1549 describe "when followed by a >", ->
1550 beforeEach ->
1551 keydown('>')
1552 keydown('>')
1553
1554 it "indents the current line", ->
1555 expect(editor.getText()).toBe "12345\nabcde\n ABCDE"
1556 expect(editor.getCursorScreenPosition()).toEqual [2, 2]
1557
1558 describe "on the first line", ->
1559 beforeEach ->
1560 editor.setCursorScreenPosition([0, 0])
1561
1562 describe "when followed by a >", ->
1563 beforeEach ->
1564 keydown('>')
1565 keydown('>')
1566
1567 it "indents the current line", ->
1568 expect(editor.getText()).toBe " 12345\nabcde\nABCDE"
1569 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1570
1571 describe "when followed by a repeating >", ->
1572 beforeEach ->
1573 keydown('3')
1574 keydown('>')
1575 keydown('>')
1576
1577 it "indents multiple lines at once", ->
1578 expect(editor.getText()).toBe " 12345\n abcde\n ABCDE"
1579 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1580
1581 describe "undo behavior", ->
1582 beforeEach -> keydown('u')
1583
1584 it "outdents all three lines", ->
1585 expect(editor.getText()).toBe "12345\nabcde\nABCDE"
1586
455f099b 1587 describe "in visual mode linewise", ->
24c7594d
BB
1588 beforeEach ->
1589 editor.setCursorScreenPosition([0, 0])
1590 keydown('v', shift: true)
455f099b
BB
1591 keydown('j')
1592
1593 describe "single indent multiple lines", ->
1594 beforeEach ->
1595 keydown('>')
24c7594d 1596
455f099b
BB
1597 it "indents both lines once and exits visual mode", ->
1598 expect(editorElement.classList.contains('normal-mode')).toBe(true)
1599 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
1600 expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
24c7594d 1601
455f099b
BB
1602 it "allows repeating the operation", ->
1603 keydown('.')
1604 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
1605
1606 describe "multiple indent multiple lines", ->
1607 beforeEach ->
1608 keydown('2')
1609 keydown('>')
1610
1611 it "indents both lines twice and exits visual mode", ->
1612 expect(editorElement.classList.contains('normal-mode')).toBe(true)
1613 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
1614 expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 4], [0, 4]] ]
1615
1616 describe "with multiple selections", ->
1617 beforeEach ->
1618 editor.setCursorScreenPosition([1, 3])
1619 keydown('v')
1620 keydown('j')
1621 editor.addCursorAtScreenPosition([0, 0])
1622
1623 it "indents the lines and keeps the cursors", ->
1624 keydown('>')
1625 expect(editor.getText()).toBe " 12345\n abcde\n ABCDE"
1626 expect(editor.getCursorScreenPositions()).toEqual [[1, 2], [0, 2]]
24c7594d
BB
1627
1628 describe "the < keybinding", ->
1629 beforeEach ->
455f099b 1630 editor.setText(" 12345\n abcde\nABCDE")
24c7594d
BB
1631 editor.setCursorScreenPosition([0, 0])
1632
1633 describe "when followed by a <", ->
1634 beforeEach ->
1635 keydown('<')
1636 keydown('<')
1637
455f099b
BB
1638 it "outdents the current line", ->
1639 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
1640 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
24c7594d
BB
1641
1642 describe "when followed by a repeating <", ->
1643 beforeEach ->
1644 keydown('2')
1645 keydown('<')
1646 keydown('<')
1647
455f099b
BB
1648 it "outdents multiple lines at once", ->
1649 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
1650 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
24c7594d
BB
1651
1652 describe "undo behavior", ->
1653 beforeEach -> keydown('u')
1654
1655 it "indents both lines", ->
455f099b 1656 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
24c7594d 1657
455f099b 1658 describe "in visual mode linewise", ->
24c7594d
BB
1659 beforeEach ->
1660 keydown('v', shift: true)
455f099b 1661 keydown('j')
24c7594d 1662
455f099b
BB
1663 describe "single outdent multiple lines", ->
1664 beforeEach ->
1665 keydown('<')
1666
1667 it "outdents the current line and exits visual mode", ->
1668 expect(editorElement.classList.contains('normal-mode')).toBe(true)
1669 expect(editor.getText()).toBe " 12345\n abcde\nABCDE"
1670 expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 2], [0, 2]] ]
1671
1672 it "allows repeating the operation", ->
1673 keydown('.')
1674 expect(editor.getText()).toBe "12345\nabcde\nABCDE"
1675
1676 describe "multiple outdent multiple lines", ->
1677 beforeEach ->
1678 keydown('2')
1679 keydown('<')
1680
1681 it "outdents both lines twice and exits visual mode", ->
1682 expect(editorElement.classList.contains('normal-mode')).toBe(true)
1683 expect(editor.getText()).toBe "12345\nabcde\nABCDE"
1684 expect(editor.getSelectedBufferRanges()).toEqual [ [[0, 0], [0, 0]] ]
24c7594d
BB
1685
1686 describe "the = keybinding", ->
1687 oldGrammar = []
1688
1689 beforeEach ->
1690 waitsForPromise ->
1691 atom.packages.activatePackage('language-javascript')
1692
1693 oldGrammar = editor.getGrammar()
1694 editor.setText("foo\n bar\n baz")
1695 editor.setCursorScreenPosition([1, 0])
1696
1697 describe "when used in a scope that supports auto-indent", ->
1698 beforeEach ->
1699 jsGrammar = atom.grammars.grammarForScopeName('source.js')
1700 editor.setGrammar(jsGrammar)
1701
1702 afterEach ->
1703 editor.setGrammar(oldGrammar)
1704
1705 describe "when followed by a =", ->
1706 beforeEach ->
1707 keydown('=')
1708 keydown('=')
1709
1710 it "indents the current line", ->
1711 expect(editor.indentationForBufferRow(1)).toBe 0
1712
455f099b
BB
1713 describe "when followed by a G", ->
1714 beforeEach ->
1715 editor.setCursorScreenPosition([0, 0])
1716 keydown('=')
1717 keydown('G', shift: true)
1718
1719 it "uses the default count", ->
1720 expect(editor.indentationForBufferRow(1)).toBe 0
1721 expect(editor.indentationForBufferRow(2)).toBe 0
1722
24c7594d
BB
1723 describe "when followed by a repeating =", ->
1724 beforeEach ->
1725 keydown('2')
1726 keydown('=')
1727 keydown('=')
1728
1729 it "autoindents multiple lines at once", ->
1730 expect(editor.getText()).toBe "foo\nbar\nbaz"
1731 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
1732
1733 describe "undo behavior", ->
1734 beforeEach -> keydown('u')
1735
1736 it "indents both lines", ->
1737 expect(editor.getText()).toBe "foo\n bar\n baz"
1738
1739 describe "the . keybinding", ->
1740 beforeEach ->
1741 editor.setText("12\n34\n56\n78")
1742 editor.setCursorScreenPosition([0, 0])
1743
1744 it "repeats the last operation", ->
1745 keydown '2'
1746 keydown 'd'
1747 keydown 'd'
1748 keydown '.'
1749
1750 expect(editor.getText()).toBe ""
1751
1752 it "composes with motions", ->
1753 keydown 'd'
1754 keydown 'd'
1755 keydown '2'
1756 keydown '.'
1757
1758 expect(editor.getText()).toBe "78"
1759
1760 describe "the r keybinding", ->
1761 beforeEach ->
1762 editor.setText("12\n34\n\n")
1763 editor.setCursorBufferPosition([0, 0])
1764 editor.addCursorAtBufferPosition([1, 0])
1765
1766 it "replaces a single character", ->
1767 keydown('r')
455f099b 1768 normalModeInputKeydown('x')
24c7594d
BB
1769 expect(editor.getText()).toBe 'x2\nx4\n\n'
1770
1771 it "does nothing when cancelled", ->
1772 keydown('r')
1773 expect(editorElement.classList.contains('operator-pending-mode')).toBe(true)
1774 keydown('escape')
1775 expect(editor.getText()).toBe '12\n34\n\n'
455f099b 1776 expect(editorElement.classList.contains('normal-mode')).toBe(true)
24c7594d
BB
1777
1778 it "replaces a single character with a line break", ->
1779 keydown('r')
455f099b 1780 atom.commands.dispatch(editor.normalModeInputView.editorElement, 'core:confirm')
24c7594d
BB
1781 expect(editor.getText()).toBe '\n2\n\n4\n\n'
1782 expect(editor.getCursorBufferPositions()).toEqual [[1, 0], [3, 0]]
1783
1784 it "composes properly with motions", ->
1785 keydown('2')
1786 keydown('r')
455f099b 1787 normalModeInputKeydown('x')
24c7594d
BB
1788 expect(editor.getText()).toBe 'xx\nxx\n\n'
1789
1790 it "does nothing on an empty line", ->
1791 editor.setCursorBufferPosition([2, 0])
1792 keydown('r')
455f099b 1793 normalModeInputKeydown('x')
24c7594d
BB
1794 expect(editor.getText()).toBe '12\n34\n\n'
1795
1796 it "does nothing if asked to replace more characters than there are on a line", ->
1797 keydown('3')
1798 keydown('r')
455f099b 1799 normalModeInputKeydown('x')
24c7594d
BB
1800 expect(editor.getText()).toBe '12\n34\n\n'
1801
1802 describe "when in visual mode", ->
1803 beforeEach ->
1804 keydown('v')
1805 keydown('e')
1806
1807 it "replaces the entire selection with the given character", ->
1808 keydown('r')
455f099b 1809 normalModeInputKeydown('x')
24c7594d
BB
1810 expect(editor.getText()).toBe 'xx\nxx\n\n'
1811
1812 it "leaves the cursor at the beginning of the selection", ->
1813 keydown('r')
455f099b 1814 normalModeInputKeydown('x')
24c7594d
BB
1815 expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]]
1816
455f099b
BB
1817 describe 'with accented characters', ->
1818 buildIMECompositionEvent = (event, {data, target}={}) ->
1819 event = new Event(event)
1820 event.data = data
1821 Object.defineProperty(event, 'target', get: -> target)
1822 event
1823
1824 buildTextInputEvent = ({data, target}) ->
1825 event = new Event('textInput')
1826 event.data = data
1827 Object.defineProperty(event, 'target', get: -> target)
1828 event
1829
1830 it 'works with IME composition', ->
1831 keydown('r')
1832 normalModeEditor = editor.normalModeInputView.editorElement
1833 jasmine.attachToDOM(normalModeEditor)
1834 domNode = normalModeEditor.component.domNode
1835 inputNode = domNode.querySelector('.hidden-input')
1836 domNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode))
1837 domNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 's', target: inputNode))
1838 expect(normalModeEditor.getModel().getText()).toEqual 's'
1839 domNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: 'sd', target: inputNode))
1840 expect(normalModeEditor.getModel().getText()).toEqual 'sd'
1841 domNode.dispatchEvent(buildIMECompositionEvent('compositionend', target: inputNode))
1842 domNode.dispatchEvent(buildTextInputEvent(data: '速度', target: inputNode))
1843 expect(editor.getText()).toBe '速度2\n速度4\n\n'
1844
24c7594d
BB
1845 describe 'the m keybinding', ->
1846 beforeEach ->
1847 editor.setText('12\n34\n56\n')
1848 editor.setCursorBufferPosition([0, 1])
1849
1850 it 'marks a position', ->
1851 keydown('m')
455f099b 1852 normalModeInputKeydown('a')
24c7594d
BB
1853 expect(vimState.getMark('a')).toEqual [0, 1]
1854
1855 describe 'the ~ keybinding', ->
1856 beforeEach ->
1857 editor.setText('aBc\nXyZ')
1858 editor.setCursorBufferPosition([0, 0])
1859 editor.addCursorAtBufferPosition([1, 0])
1860
1861 it 'toggles the case and moves right', ->
1862 keydown('~')
1863 expect(editor.getText()).toBe 'ABc\nxyZ'
1864 expect(editor.getCursorScreenPositions()).toEqual [[0, 1], [1, 1]]
1865
1866 keydown('~')
1867 expect(editor.getText()).toBe 'Abc\nxYZ'
1868 expect(editor.getCursorScreenPositions()).toEqual [[0, 2], [1, 2]]
1869
1870 keydown('~')
1871 expect(editor.getText()).toBe 'AbC\nxYz'
1872 expect(editor.getCursorScreenPositions()).toEqual [[0, 2], [1, 2]]
1873
1874 it 'takes a count', ->
1875 keydown('4')
1876 keydown('~')
1877
1878 expect(editor.getText()).toBe 'AbC\nxYz'
1879 expect(editor.getCursorScreenPositions()).toEqual [[0, 2], [1, 2]]
1880
1881 describe "in visual mode", ->
1882 it "toggles the case of the selected text", ->
1883 editor.setCursorBufferPosition([0, 0])
1884 keydown("V", shift: true)
1885 keydown("~")
1886 expect(editor.getText()).toBe 'AbC\nXyZ'
1887
1888 describe "with g and motion", ->
1889 it "toggles the case of text", ->
1890 editor.setCursorBufferPosition([0, 0])
1891 keydown("g")
1892 keydown("~")
1893 keydown("2")
1894 keydown("l")
1895 expect(editor.getText()).toBe 'Abc\nXyZ'
1896
455f099b
BB
1897 it "uses default count", ->
1898 editor.setCursorBufferPosition([0, 0])
1899 keydown("g")
1900 keydown("~")
1901 keydown("G", shift: true)
1902 expect(editor.getText()).toBe 'AbC\nxYz'
1903
24c7594d
BB
1904 describe 'the U keybinding', ->
1905 beforeEach ->
1906 editor.setText('aBc\nXyZ')
1907 editor.setCursorBufferPosition([0, 0])
1908
1909 it "makes text uppercase with g and motion", ->
1910 keydown("g")
1911 keydown("U", shift: true)
1912 keydown("l")
1913 expect(editor.getText()).toBe 'ABc\nXyZ'
1914
1915 keydown("g")
1916 keydown("U", shift: true)
1917 keydown("e")
1918 expect(editor.getText()).toBe 'ABC\nXyZ'
1919
1920 editor.setCursorBufferPosition([1, 0])
1921 keydown("g")
1922 keydown("U", shift: true)
1923 keydown("$")
1924 expect(editor.getText()).toBe 'ABC\nXYZ'
1925 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
1926
455f099b
BB
1927 it "uses default count", ->
1928 editor.setCursorBufferPosition([0, 0])
1929 keydown("g")
1930 keydown("U", shift: true)
1931 keydown("G", shift: true)
1932 expect(editor.getText()).toBe 'ABC\nXYZ'
1933
24c7594d
BB
1934 it "makes the selected text uppercase in visual mode", ->
1935 keydown("V", shift: true)
1936 keydown("U", shift: true)
1937 expect(editor.getText()).toBe 'ABC\nXyZ'
1938
1939 describe 'the u keybinding', ->
1940 beforeEach ->
1941 editor.setText('aBc\nXyZ')
1942 editor.setCursorBufferPosition([0, 0])
1943
1944 it "makes text lowercase with g and motion", ->
1945 keydown("g")
1946 keydown("u")
1947 keydown("$")
1948 expect(editor.getText()).toBe 'abc\nXyZ'
1949 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
1950
455f099b
BB
1951 it "uses default count", ->
1952 editor.setCursorBufferPosition([0, 0])
1953 keydown("g")
1954 keydown("u")
1955 keydown("G", shift: true)
1956 expect(editor.getText()).toBe 'abc\nxyz'
1957
24c7594d
BB
1958 it "makes the selected text lowercase in visual mode", ->
1959 keydown("V", shift: true)
1960 keydown("u")
1961 expect(editor.getText()).toBe 'abc\nXyZ'
1962
1963 describe "the i keybinding", ->
1964 beforeEach ->
1965 editor.setText('123\n4567')
1966 editor.setCursorBufferPosition([0, 0])
1967 editor.addCursorAtBufferPosition([1, 0])
1968
1969 it "allows undoing an entire batch of typing", ->
1970 keydown 'i'
1971 editor.insertText("abcXX")
1972 editor.backspace()
1973 editor.backspace()
1974 keydown 'escape'
1975 expect(editor.getText()).toBe "abc123\nabc4567"
1976
1977 keydown 'i'
1978 editor.insertText "d"
1979 editor.insertText "e"
1980 editor.insertText "f"
1981 keydown 'escape'
1982 expect(editor.getText()).toBe "abdefc123\nabdefc4567"
1983
1984 keydown 'u'
1985 expect(editor.getText()).toBe "abc123\nabc4567"
1986
1987 keydown 'u'
1988 expect(editor.getText()).toBe "123\n4567"
1989
1990 it "allows repeating typing", ->
1991 keydown 'i'
1992 editor.insertText("abcXX")
1993 editor.backspace()
1994 editor.backspace()
1995 keydown 'escape'
1996 expect(editor.getText()).toBe "abc123\nabc4567"
1997
1998 keydown '.'
1999 expect(editor.getText()).toBe "ababcc123\nababcc4567"
2000
2001 keydown '.'
2002 expect(editor.getText()).toBe "abababccc123\nabababccc4567"
2003
2004 describe 'with nonlinear input', ->
2005 beforeEach ->
2006 editor.setText ''
2007 editor.setCursorBufferPosition [0, 0]
2008
2009 it 'deals with auto-matched brackets', ->
2010 keydown 'i'
2011 # this sequence simulates what the bracket-matcher package does
2012 # when the user types (a)b<enter>
2013 editor.insertText '()'
2014 editor.moveLeft()
2015 editor.insertText 'a'
2016 editor.moveRight()
2017 editor.insertText 'b\n'
2018 keydown 'escape'
2019 expect(editor.getCursorScreenPosition()).toEqual [1, 0]
2020
2021 keydown '.'
2022 expect(editor.getText()).toBe '(a)b\n(a)b\n'
2023 expect(editor.getCursorScreenPosition()).toEqual [2, 0]
2024
2025 it 'deals with autocomplete', ->
2026 keydown 'i'
2027 # this sequence simulates autocompletion of 'add' to 'addFoo'
2028 editor.insertText 'a'
2029 editor.insertText 'd'
2030 editor.insertText 'd'
2031 editor.setTextInBufferRange [[0, 0], [0, 3]], 'addFoo'
2032 keydown 'escape'
2033 expect(editor.getCursorScreenPosition()).toEqual [0, 5]
2034 expect(editor.getText()).toBe 'addFoo'
2035
2036 keydown '.'
2037 expect(editor.getText()).toBe 'addFoaddFooo'
2038 expect(editor.getCursorScreenPosition()).toEqual [0, 10]
2039
2040 describe 'the a keybinding', ->
2041 beforeEach ->
2042 editor.setText('')
2043 editor.setCursorBufferPosition([0, 0])
2044
2045 it "can be undone in one go", ->
2046 keydown 'a'
2047 editor.insertText("abc")
2048 keydown 'escape'
2049 expect(editor.getText()).toBe "abc"
2050 keydown 'u'
2051 expect(editor.getText()).toBe ""
2052
2053 it "repeats correctly", ->
2054 keydown 'a'
2055 editor.insertText("abc")
2056 keydown 'escape'
2057 expect(editor.getText()).toBe "abc"
2058 expect(editor.getCursorScreenPosition()).toEqual [0, 2]
2059 keydown '.'
2060 expect(editor.getText()).toBe "abcabc"
2061 expect(editor.getCursorScreenPosition()).toEqual [0, 5]
2062
2063 describe "the ctrl-a/ctrl-x keybindings", ->
2064 beforeEach ->
2065 atom.config.set 'vim-mode.numberRegex', settings.config.numberRegex.default
2066 editor.setText('123\nab45\ncd-67ef\nab-5\na-bcdef')
2067 editor.setCursorBufferPosition [0, 0]
2068 editor.addCursorAtBufferPosition [1, 0]
2069 editor.addCursorAtBufferPosition [2, 0]
2070 editor.addCursorAtBufferPosition [3, 3]
2071 editor.addCursorAtBufferPosition [4, 0]
2072
2073 describe "increasing numbers", ->
2074 it "increases the next number", ->
2075 keydown('a', ctrl: true)
2076 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
2077 expect(editor.getText()).toBe '124\nab46\ncd-66ef\nab-4\na-bcdef'
455f099b 2078 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2079
2080 it "repeats with .", ->
2081 keydown 'a', ctrl: true
2082 keydown '.'
2083 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
2084 expect(editor.getText()).toBe '125\nab47\ncd-65ef\nab-3\na-bcdef'
455f099b 2085 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2086
2087 it "can have a count", ->
2088 keydown '5'
2089 keydown 'a', ctrl: true
2090 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 2], [4, 0]]
2091 expect(editor.getText()).toBe '128\nab50\ncd-62ef\nab0\na-bcdef'
455f099b 2092 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2093
2094 it "can make a negative number positive, change number of digits", ->
2095 keydown '9'
2096 keydown '9'
2097 keydown 'a', ctrl: true
2098 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 4], [2, 3], [3, 3], [4, 0]]
2099 expect(editor.getText()).toBe '222\nab144\ncd32ef\nab94\na-bcdef'
455f099b 2100 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2101
2102 it "does nothing when cursor is after the number", ->
2103 editor.setCursorBufferPosition [2, 5]
2104 keydown 'a', ctrl: true
2105 expect(editor.getCursorBufferPositions()).toEqual [[2, 5]]
2106 expect(editor.getText()).toBe '123\nab45\ncd-67ef\nab-5\na-bcdef'
455f099b 2107 expect(atom.beep).toHaveBeenCalled()
24c7594d
BB
2108
2109 it "does nothing on an empty line", ->
2110 editor.setText('\n')
2111 editor.setCursorBufferPosition [0, 0]
2112 editor.addCursorAtBufferPosition [1, 0]
2113 keydown 'a', ctrl: true
2114 expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]]
2115 expect(editor.getText()).toBe '\n'
455f099b 2116 expect(atom.beep).toHaveBeenCalled()
24c7594d
BB
2117
2118 it "honours the vim-mode:numberRegex setting", ->
2119 editor.setText('123\nab45\ncd -67ef\nab-5\na-bcdef')
2120 editor.setCursorBufferPosition [0, 0]
2121 editor.addCursorAtBufferPosition [1, 0]
2122 editor.addCursorAtBufferPosition [2, 0]
2123 editor.addCursorAtBufferPosition [3, 3]
2124 editor.addCursorAtBufferPosition [4, 0]
2125 atom.config.set('vim-mode.numberRegex', '(?:\\B-)?[0-9]+')
2126 keydown('a', ctrl: true)
2127 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 5], [3, 3], [4, 0]]
2128 expect(editor.getText()).toBe '124\nab46\ncd -66ef\nab-6\na-bcdef'
455f099b 2129 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2130
2131 describe "decreasing numbers", ->
2132 it "decreases the next number", ->
2133 keydown('x', ctrl: true)
2134 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
2135 expect(editor.getText()).toBe '122\nab44\ncd-68ef\nab-6\na-bcdef'
455f099b 2136 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2137
2138 it "repeats with .", ->
2139 keydown 'x', ctrl: true
2140 keydown '.'
2141 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 3], [4, 0]]
2142 expect(editor.getText()).toBe '121\nab43\ncd-69ef\nab-7\na-bcdef'
455f099b 2143 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2144
2145 it "can have a count", ->
2146 keydown '5'
2147 keydown 'x', ctrl: true
2148 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 4], [3, 4], [4, 0]]
2149 expect(editor.getText()).toBe '118\nab40\ncd-72ef\nab-10\na-bcdef'
455f099b 2150 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2151
2152 it "can make a positive number negative, change number of digits", ->
2153 keydown '9'
2154 keydown '9'
2155 keydown 'x', ctrl: true
2156 expect(editor.getCursorBufferPositions()).toEqual [[0, 1], [1, 4], [2, 5], [3, 5], [4, 0]]
2157 expect(editor.getText()).toBe '24\nab-54\ncd-166ef\nab-104\na-bcdef'
455f099b 2158 expect(atom.beep).not.toHaveBeenCalled()
24c7594d
BB
2159
2160 it "does nothing when cursor is after the number", ->
2161 editor.setCursorBufferPosition [2, 5]
2162 keydown 'x', ctrl: true
2163 expect(editor.getCursorBufferPositions()).toEqual [[2, 5]]
2164 expect(editor.getText()).toBe '123\nab45\ncd-67ef\nab-5\na-bcdef'
455f099b 2165 expect(atom.beep).toHaveBeenCalled()
24c7594d
BB
2166
2167 it "does nothing on an empty line", ->
2168 editor.setText('\n')
2169 editor.setCursorBufferPosition [0, 0]
2170 editor.addCursorAtBufferPosition [1, 0]
2171 keydown 'x', ctrl: true
2172 expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]]
2173 expect(editor.getText()).toBe '\n'
455f099b 2174 expect(atom.beep).toHaveBeenCalled()
24c7594d
BB
2175
2176 it "honours the vim-mode:numberRegex setting", ->
2177 editor.setText('123\nab45\ncd -67ef\nab-5\na-bcdef')
2178 editor.setCursorBufferPosition [0, 0]
2179 editor.addCursorAtBufferPosition [1, 0]
2180 editor.addCursorAtBufferPosition [2, 0]
2181 editor.addCursorAtBufferPosition [3, 3]
2182 editor.addCursorAtBufferPosition [4, 0]
2183 atom.config.set('vim-mode.numberRegex', '(?:\\B-)?[0-9]+')
2184 keydown('x', ctrl: true)
2185 expect(editor.getCursorBufferPositions()).toEqual [[0, 2], [1, 3], [2, 5], [3, 3], [4, 0]]
2186 expect(editor.getText()).toBe '122\nab44\ncd -68ef\nab-4\na-bcdef'
455f099b
BB
2187 expect(atom.beep).not.toHaveBeenCalled()
2188
2189 describe 'the R keybinding', ->
2190 beforeEach ->
2191 editor.setText('12345\n67890')
2192 editor.setCursorBufferPosition([0, 2])
2193
2194 it "enters replace mode and replaces characters", ->
2195 keydown "R", shift: true
2196 expect(editorElement.classList.contains('insert-mode')).toBe true
2197 expect(editorElement.classList.contains('replace-mode')).toBe true
2198
2199 editor.insertText "ab"
2200 keydown 'escape'
2201
2202 expect(editor.getText()).toBe "12ab5\n67890"
2203 expect(editor.getCursorScreenPosition()).toEqual [0, 3]
2204 expect(editorElement.classList.contains('insert-mode')).toBe false
2205 expect(editorElement.classList.contains('replace-mode')).toBe false
2206 expect(editorElement.classList.contains('normal-mode')).toBe true
2207
2208 it "continues beyond end of line as insert", ->
2209 keydown "R", shift: true
2210 expect(editorElement.classList.contains('insert-mode')).toBe true
2211 expect(editorElement.classList.contains('replace-mode')).toBe true
2212
2213 editor.insertText "abcde"
2214 keydown 'escape'
2215
2216 expect(editor.getText()).toBe "12abcde\n67890"
2217
2218 it "treats backspace as undo", ->
2219 editor.insertText "foo"
2220 keydown "R", shift: true
2221
2222 editor.insertText "a"
2223 editor.insertText "b"
2224 expect(editor.getText()).toBe "12fooab5\n67890"
2225
2226 keydown 'backspace', raw: true
2227 expect(editor.getText()).toBe "12fooa45\n67890"
2228
2229 editor.insertText "c"
2230
2231 expect(editor.getText()).toBe "12fooac5\n67890"
2232
2233 keydown 'backspace', raw: true
2234 keydown 'backspace', raw: true
2235
2236 expect(editor.getText()).toBe "12foo345\n67890"
2237 expect(editor.getSelectedText()).toBe ""
2238
2239 keydown 'backspace', raw: true
2240 expect(editor.getText()).toBe "12foo345\n67890"
2241 expect(editor.getSelectedText()).toBe ""
2242
2243 it "can be repeated", ->
2244 keydown "R", shift: true
2245 editor.insertText "ab"
2246 keydown 'escape'
2247 editor.setCursorBufferPosition([1, 2])
2248 keydown '.'
2249 expect(editor.getText()).toBe "12ab5\n67ab0"
2250 expect(editor.getCursorScreenPosition()).toEqual [1, 3]
2251
2252 editor.setCursorBufferPosition([0, 4])
2253 keydown '.'
2254 expect(editor.getText()).toBe "12abab\n67ab0"
2255 expect(editor.getCursorScreenPosition()).toEqual [0, 5]
2256
2257 it "can be interrupted by arrow keys and behave as insert for repeat", ->
2258 # FIXME don't know how to test this (also, depends on PR #568)
2259
2260 it "repeats correctly when backspace was used in the text", ->
2261 keydown "R", shift: true
2262 editor.insertText "a"
2263 keydown 'backspace', raw: true
2264 editor.insertText "b"
2265 keydown 'escape'
2266 editor.setCursorBufferPosition([1, 2])
2267 keydown '.'
2268 expect(editor.getText()).toBe "12b45\n67b90"
2269 expect(editor.getCursorScreenPosition()).toEqual [1, 2]
2270
2271 editor.setCursorBufferPosition([0, 4])
2272 keydown '.'
2273 expect(editor.getText()).toBe "12b4b\n67b90"
2274 expect(editor.getCursorScreenPosition()).toEqual [0, 4]
2275
2276 it "doesn't replace a character if newline is entered", ->
2277 keydown "R", shift: true
2278 expect(editorElement.classList.contains('insert-mode')).toBe true
2279 expect(editorElement.classList.contains('replace-mode')).toBe true
2280
2281 editor.insertText "\n"
2282 keydown 'escape'
2283
2284 expect(editor.getText()).toBe "12\n345\n67890"