]>
Commit | Line | Data |
---|---|---|
1 | helpers = require './spec-helper' | |
2 | settings = require '../lib/settings' | |
3 | ||
4 | describe "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 | |
15 | vimState.activateNormalMode() | |
16 | vimState.resetNormalMode() | |
17 | ||
18 | keydown = (key, options={}) -> | |
19 | options.element ?= editorElement | |
20 | helpers.keydown(key, options) | |
21 | ||
22 | normalModeInputKeydown = (key, opts = {}) -> | |
23 | editor.normalModeInputView.editorElement.getModel().setText(key) | |
24 | ||
25 | describe "cancelling operations", -> | |
26 | it "throws an error when no operation is pending", -> | |
27 | # cancel operation pushes an empty input operation | |
28 | # doing this without a pending operation would throw an exception | |
29 | expect(-> vimState.pushOperations(new Input(''))).toThrow() | |
30 | ||
31 | it "cancels and cleans up properly", -> | |
32 | # make sure normalModeInputView is created | |
33 | keydown('/') | |
34 | expect(vimState.isOperatorPending()).toBe true | |
35 | editor.normalModeInputView.viewModel.cancel() | |
36 | ||
37 | expect(vimState.isOperatorPending()).toBe false | |
38 | expect(editor.normalModeInputView).toBe undefined | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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) | |
316 | expect(editorElement.classList.contains('normal-mode')).toBe(false) | |
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) | |
330 | expect(editorElement.classList.contains('normal-mode')).toBe(true) | |
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 | ||
357 | it "undoes both lines", -> | |
358 | keydown('d') | |
359 | keydown('2') | |
360 | keydown('d') | |
361 | ||
362 | keydown('u') | |
363 | ||
364 | expect(editor.getText()).toBe "12345\nabcde\nABCDE\nQWERT" | |
365 | expect(editor.getSelectedText()).toBe '' | |
366 | ||
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 | ||
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) | |
395 | expect(editorElement.classList.contains('normal-mode')).toBe(true) | |
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) | |
431 | expect(editorElement.classList.contains('normal-mode')).toBe(true) | |
432 | ||
433 | describe "when followed by a j", -> | |
434 | originalText = "12345\nabcde\nABCDE\n" | |
435 | ||
436 | beforeEach -> | |
437 | editor.setText(originalText) | |
438 | ||
439 | describe "on the beginning of the file", -> | |
440 | it "deletes the next two lines", -> | |
441 | editor.setCursorScreenPosition([0, 0]) | |
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") | |
459 | ||
460 | describe "when followed by an k", -> | |
461 | originalText = "12345\nabcde\nABCDE" | |
462 | ||
463 | beforeEach -> | |
464 | editor.setText(originalText) | |
465 | ||
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") | |
472 | ||
473 | describe "on the beginning of the file", -> | |
474 | xit "deletes nothing", -> | |
475 | editor.setCursorScreenPosition([0, 0]) | |
476 | keydown('d') | |
477 | keydown('k') | |
478 | expect(editor.getText()).toBe(originalText) | |
479 | ||
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") | |
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') | |
538 | normalModeInputKeydown(')') | |
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') | |
567 | normalModeInputKeydown('d') | |
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", -> | |
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 | |
598 | ||
599 | it "deletes the current line and enters insert mode", -> | |
600 | editor.setCursorScreenPosition([1, 1]) | |
601 | ||
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 '' | |
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] | |
639 | expect(editorElement.classList.contains('normal-mode')).toBe(false) | |
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 | ||
650 | expect(editor.getText()).toBe "" | |
651 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
652 | expect(editorElement.classList.contains('normal-mode')).toBe(false) | |
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') | |
669 | expect(editorElement.classList.contains('normal-mode')).toBe(true) | |
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 | ||
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 | ||
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 | ||
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 | ||
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] | |
946 | expect(editorElement.classList.contains('normal-mode')).toBe(false) | |
947 | expect(editorElement.classList.contains('insert-mode')).toBe(true) | |
948 | ||
949 | describe "the y keybinding", -> | |
950 | beforeEach -> | |
951 | editor.getBuffer().setText("012 345\nabc\ndefg\n") | |
952 | editor.setCursorScreenPosition([0, 4]) | |
953 | vimState.setRegister('"', text: '345') | |
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') | |
1031 | normalModeInputKeydown('x') | |
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 | ||
1047 | it "saves the left letter to the default register", -> | |
1048 | expect(vimState.getRegister('"').text).toBe " " | |
1049 | ||
1050 | it "moves the cursor position to the left", -> | |
1051 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
1587 | describe "in visual mode linewise", -> | |
1588 | beforeEach -> | |
1589 | editor.setCursorScreenPosition([0, 0]) | |
1590 | keydown('v', shift: true) | |
1591 | keydown('j') | |
1592 | ||
1593 | describe "single indent multiple lines", -> | |
1594 | beforeEach -> | |
1595 | keydown('>') | |
1596 | ||
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]] ] | |
1601 | ||
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]] | |
1627 | ||
1628 | describe "the < keybinding", -> | |
1629 | beforeEach -> | |
1630 | editor.setText(" 12345\n abcde\nABCDE") | |
1631 | editor.setCursorScreenPosition([0, 0]) | |
1632 | ||
1633 | describe "when followed by a <", -> | |
1634 | beforeEach -> | |
1635 | keydown('<') | |
1636 | keydown('<') | |
1637 | ||
1638 | it "outdents the current line", -> | |
1639 | expect(editor.getText()).toBe " 12345\n abcde\nABCDE" | |
1640 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1641 | ||
1642 | describe "when followed by a repeating <", -> | |
1643 | beforeEach -> | |
1644 | keydown('2') | |
1645 | keydown('<') | |
1646 | keydown('<') | |
1647 | ||
1648 | it "outdents multiple lines at once", -> | |
1649 | expect(editor.getText()).toBe " 12345\n abcde\nABCDE" | |
1650 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1651 | ||
1652 | describe "undo behavior", -> | |
1653 | beforeEach -> keydown('u') | |
1654 | ||
1655 | it "indents both lines", -> | |
1656 | expect(editor.getText()).toBe " 12345\n abcde\nABCDE" | |
1657 | ||
1658 | describe "in visual mode linewise", -> | |
1659 | beforeEach -> | |
1660 | keydown('v', shift: true) | |
1661 | keydown('j') | |
1662 | ||
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]] ] | |
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 | ||
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 | ||
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') | |
1768 | normalModeInputKeydown('x') | |
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' | |
1776 | expect(editorElement.classList.contains('normal-mode')).toBe(true) | |
1777 | ||
1778 | it "replaces a single character with a line break", -> | |
1779 | keydown('r') | |
1780 | atom.commands.dispatch(editor.normalModeInputView.editorElement, 'core:confirm') | |
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') | |
1787 | normalModeInputKeydown('x') | |
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') | |
1793 | normalModeInputKeydown('x') | |
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') | |
1799 | normalModeInputKeydown('x') | |
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') | |
1809 | normalModeInputKeydown('x') | |
1810 | expect(editor.getText()).toBe 'xx\nxx\n\n' | |
1811 | ||
1812 | it "leaves the cursor at the beginning of the selection", -> | |
1813 | keydown('r') | |
1814 | normalModeInputKeydown('x') | |
1815 | expect(editor.getCursorBufferPositions()).toEqual [[0, 0], [1, 0]] | |
1816 | ||
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 | ||
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') | |
1852 | normalModeInputKeydown('a') | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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' | |
2078 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2085 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2092 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2100 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2107 | expect(atom.beep).toHaveBeenCalled() | |
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' | |
2116 | expect(atom.beep).toHaveBeenCalled() | |
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' | |
2129 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2136 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2143 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2150 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2158 | expect(atom.beep).not.toHaveBeenCalled() | |
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' | |
2165 | expect(atom.beep).toHaveBeenCalled() | |
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' | |
2174 | expect(atom.beep).toHaveBeenCalled() | |
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' | |
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" |