]>
Commit | Line | Data |
---|---|---|
1 | helpers = require './spec-helper' | |
2 | ||
3 | describe "Motions", -> | |
4 | [editor, editorElement, vimState] = [] | |
5 | ||
6 | beforeEach -> | |
7 | vimMode = atom.packages.loadPackage('vim-mode') | |
8 | vimMode.activateResources() | |
9 | ||
10 | helpers.getEditorElement (element) -> | |
11 | editorElement = element | |
12 | editor = editorElement.getModel() | |
13 | vimState = editorElement.vimState | |
14 | vimState.activateNormalMode() | |
15 | vimState.resetNormalMode() | |
16 | ||
17 | keydown = (key, options={}) -> | |
18 | options.element ?= editorElement | |
19 | helpers.keydown(key, options) | |
20 | ||
21 | normalModeInputKeydown = (key, opts = {}) -> | |
22 | theEditor = opts.editor or editor | |
23 | theEditor.normalModeInputView.editorElement.getModel().setText(key) | |
24 | ||
25 | submitNormalModeInputText = (text) -> | |
26 | inputEditor = editor.normalModeInputView.editorElement | |
27 | inputEditor.getModel().setText(text) | |
28 | atom.commands.dispatch(inputEditor, "core:confirm") | |
29 | ||
30 | describe "simple motions", -> | |
31 | beforeEach -> | |
32 | editor.setText("12345\nabcd\nABCDE") | |
33 | editor.setCursorScreenPosition([1, 1]) | |
34 | ||
35 | describe "the h keybinding", -> | |
36 | describe "as a motion", -> | |
37 | it "moves the cursor left, but not to the previous line", -> | |
38 | keydown('h') | |
39 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
40 | ||
41 | keydown('h') | |
42 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
43 | ||
44 | it "moves the cursor to the previous line if wrapLeftRightMotion is true", -> | |
45 | atom.config.set('vim-mode.wrapLeftRightMotion', true) | |
46 | keydown('h') | |
47 | keydown('h') | |
48 | expect(editor.getCursorScreenPosition()).toEqual [0, 4] | |
49 | ||
50 | describe "as a selection", -> | |
51 | it "selects the character to the left", -> | |
52 | keydown('y') | |
53 | keydown('h') | |
54 | ||
55 | expect(vimState.getRegister('"').text).toBe 'a' | |
56 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
57 | ||
58 | describe "the j keybinding", -> | |
59 | it "moves the cursor down, but not to the end of the last line", -> | |
60 | keydown('j') | |
61 | expect(editor.getCursorScreenPosition()).toEqual [2, 1] | |
62 | ||
63 | keydown('j') | |
64 | expect(editor.getCursorScreenPosition()).toEqual [2, 1] | |
65 | ||
66 | it "moves the cursor to the end of the line, not past it", -> | |
67 | editor.setCursorScreenPosition([0, 4]) | |
68 | ||
69 | keydown('j') | |
70 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
71 | ||
72 | it "remembers the position it column it was in after moving to shorter line", -> | |
73 | editor.setCursorScreenPosition([0, 4]) | |
74 | ||
75 | keydown('j') | |
76 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
77 | ||
78 | keydown('j') | |
79 | expect(editor.getCursorScreenPosition()).toEqual [2, 4] | |
80 | ||
81 | describe "when visual mode", -> | |
82 | beforeEach -> | |
83 | keydown('v') | |
84 | expect(editor.getCursorScreenPosition()).toEqual [1, 2] | |
85 | ||
86 | it "moves the cursor down", -> | |
87 | keydown('j') | |
88 | expect(editor.getCursorScreenPosition()).toEqual [2, 2] | |
89 | ||
90 | it "doesn't go over after the last line", -> | |
91 | keydown('j') | |
92 | expect(editor.getCursorScreenPosition()).toEqual [2, 2] | |
93 | ||
94 | it "selects the text while moving", -> | |
95 | keydown('j') | |
96 | expect(editor.getSelectedText()).toBe "bcd\nAB" | |
97 | ||
98 | describe "the k keybinding", -> | |
99 | it "moves the cursor up, but not to the beginning of the first line", -> | |
100 | keydown('k') | |
101 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
102 | ||
103 | keydown('k') | |
104 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
105 | ||
106 | describe "the l keybinding", -> | |
107 | beforeEach -> editor.setCursorScreenPosition([1, 2]) | |
108 | ||
109 | it "moves the cursor right, but not to the next line", -> | |
110 | keydown('l') | |
111 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
112 | ||
113 | keydown('l') | |
114 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
115 | ||
116 | it "moves the cursor to the next line if wrapLeftRightMotion is true", -> | |
117 | atom.config.set('vim-mode.wrapLeftRightMotion', true) | |
118 | keydown('l') | |
119 | keydown('l') | |
120 | expect(editor.getCursorScreenPosition()).toEqual [2, 0] | |
121 | ||
122 | describe "on a blank line", -> | |
123 | it "doesn't move the cursor", -> | |
124 | editor.setText("\n\n\n") | |
125 | editor.setCursorBufferPosition([1, 0]) | |
126 | keydown('l') | |
127 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
128 | ||
129 | describe "the w keybinding", -> | |
130 | beforeEach -> editor.setText("ab cde1+- \n xyz\n\nzip") | |
131 | ||
132 | describe "as a motion", -> | |
133 | beforeEach -> editor.setCursorScreenPosition([0, 0]) | |
134 | ||
135 | it "moves the cursor to the beginning of the next word", -> | |
136 | keydown('w') | |
137 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
138 | ||
139 | keydown('w') | |
140 | expect(editor.getCursorScreenPosition()).toEqual [0, 7] | |
141 | ||
142 | keydown('w') | |
143 | expect(editor.getCursorScreenPosition()).toEqual [1, 1] | |
144 | ||
145 | keydown('w') | |
146 | expect(editor.getCursorScreenPosition()).toEqual [2, 0] | |
147 | ||
148 | keydown('w') | |
149 | expect(editor.getCursorScreenPosition()).toEqual [3, 0] | |
150 | ||
151 | keydown('w') | |
152 | expect(editor.getCursorScreenPosition()).toEqual [3, 2] | |
153 | ||
154 | # When the cursor gets to the EOF, it should stay there. | |
155 | keydown('w') | |
156 | expect(editor.getCursorScreenPosition()).toEqual [3, 2] | |
157 | ||
158 | it "moves the cursor to the end of the word if last word in file", -> | |
159 | editor.setText("abc") | |
160 | editor.setCursorScreenPosition([0, 0]) | |
161 | keydown('w') | |
162 | expect(editor.getCursorScreenPosition()).toEqual([0, 2]) | |
163 | ||
164 | describe "as a selection", -> | |
165 | describe "within a word", -> | |
166 | beforeEach -> | |
167 | editor.setCursorScreenPosition([0, 0]) | |
168 | keydown('y') | |
169 | keydown('w') | |
170 | ||
171 | it "selects to the end of the word", -> | |
172 | expect(vimState.getRegister('"').text).toBe 'ab ' | |
173 | ||
174 | describe "between words", -> | |
175 | beforeEach -> | |
176 | editor.setCursorScreenPosition([0, 2]) | |
177 | keydown('y') | |
178 | keydown('w') | |
179 | ||
180 | it "selects the whitespace", -> | |
181 | expect(vimState.getRegister('"').text).toBe ' ' | |
182 | ||
183 | describe "the W keybinding", -> | |
184 | beforeEach -> editor.setText("cde1+- ab \n xyz\n\nzip") | |
185 | ||
186 | describe "as a motion", -> | |
187 | beforeEach -> editor.setCursorScreenPosition([0, 0]) | |
188 | ||
189 | it "moves the cursor to the beginning of the next word", -> | |
190 | keydown('W', shift: true) | |
191 | expect(editor.getCursorScreenPosition()).toEqual [0, 7] | |
192 | ||
193 | keydown('W', shift: true) | |
194 | expect(editor.getCursorScreenPosition()).toEqual [1, 1] | |
195 | ||
196 | keydown('W', shift: true) | |
197 | expect(editor.getCursorScreenPosition()).toEqual [2, 0] | |
198 | ||
199 | keydown('W', shift: true) | |
200 | expect(editor.getCursorScreenPosition()).toEqual [3, 0] | |
201 | ||
202 | describe "as a selection", -> | |
203 | describe "within a word", -> | |
204 | it "selects to the end of the whole word", -> | |
205 | editor.setCursorScreenPosition([0, 0]) | |
206 | keydown('y') | |
207 | keydown('W', shift: true) | |
208 | expect(vimState.getRegister('"').text).toBe 'cde1+- ' | |
209 | ||
210 | it "continues past blank lines", -> | |
211 | editor.setCursorScreenPosition([2, 0]) | |
212 | ||
213 | keydown('d') | |
214 | keydown('W', shift: true) | |
215 | expect(editor.getText()).toBe "cde1+- ab \n xyz\nzip" | |
216 | expect(vimState.getRegister('"').text).toBe '\n' | |
217 | ||
218 | it "doesn't go past the end of the file", -> | |
219 | editor.setCursorScreenPosition([3, 0]) | |
220 | ||
221 | keydown('d') | |
222 | keydown('W', shift: true) | |
223 | expect(editor.getText()).toBe "cde1+- ab \n xyz\n\n" | |
224 | expect(vimState.getRegister('"').text).toBe 'zip' | |
225 | ||
226 | describe "the e keybinding", -> | |
227 | beforeEach -> editor.setText("ab cde1+- \n xyz\n\nzip") | |
228 | ||
229 | describe "as a motion", -> | |
230 | beforeEach -> editor.setCursorScreenPosition([0, 0]) | |
231 | ||
232 | it "moves the cursor to the end of the current word", -> | |
233 | keydown('e') | |
234 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
235 | ||
236 | keydown('e') | |
237 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
238 | ||
239 | keydown('e') | |
240 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
241 | ||
242 | keydown('e') | |
243 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
244 | ||
245 | keydown('e') | |
246 | expect(editor.getCursorScreenPosition()).toEqual [3, 2] | |
247 | ||
248 | describe "as selection", -> | |
249 | describe "within a word", -> | |
250 | beforeEach -> | |
251 | editor.setCursorScreenPosition([0, 0]) | |
252 | keydown('y') | |
253 | keydown('e') | |
254 | ||
255 | it "selects to the end of the current word", -> | |
256 | expect(vimState.getRegister('"').text).toBe 'ab' | |
257 | ||
258 | describe "between words", -> | |
259 | beforeEach -> | |
260 | editor.setCursorScreenPosition([0, 2]) | |
261 | keydown('y') | |
262 | keydown('e') | |
263 | ||
264 | it "selects to the end of the next word", -> | |
265 | expect(vimState.getRegister('"').text).toBe ' cde1' | |
266 | ||
267 | describe "the E keybinding", -> | |
268 | beforeEach -> editor.setText("ab cde1+- \n xyz \n\nzip\n") | |
269 | ||
270 | describe "as a motion", -> | |
271 | beforeEach -> editor.setCursorScreenPosition([0, 0]) | |
272 | ||
273 | it "moves the cursor to the end of the current word", -> | |
274 | keydown('E', shift: true) | |
275 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
276 | ||
277 | keydown('E', shift: true) | |
278 | expect(editor.getCursorScreenPosition()).toEqual [0, 9] | |
279 | ||
280 | keydown('E', shift: true) | |
281 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
282 | ||
283 | keydown('E', shift: true) | |
284 | expect(editor.getCursorScreenPosition()).toEqual [3, 2] | |
285 | ||
286 | keydown('E', shift: true) | |
287 | expect(editor.getCursorScreenPosition()).toEqual [4, 0] | |
288 | ||
289 | describe "as selection", -> | |
290 | describe "within a word", -> | |
291 | beforeEach -> | |
292 | editor.setCursorScreenPosition([0, 0]) | |
293 | keydown('y') | |
294 | keydown('E', shift: true) | |
295 | ||
296 | it "selects to the end of the current word", -> | |
297 | expect(vimState.getRegister('"').text).toBe 'ab' | |
298 | ||
299 | describe "between words", -> | |
300 | beforeEach -> | |
301 | editor.setCursorScreenPosition([0, 2]) | |
302 | keydown('y') | |
303 | keydown('E', shift: true) | |
304 | ||
305 | it "selects to the end of the next word", -> | |
306 | expect(vimState.getRegister('"').text).toBe ' cde1+-' | |
307 | ||
308 | describe "press more than once", -> | |
309 | beforeEach -> | |
310 | editor.setCursorScreenPosition([0, 0]) | |
311 | keydown('v') | |
312 | keydown('E', shift: true) | |
313 | keydown('E', shift: true) | |
314 | keydown('y') | |
315 | ||
316 | it "selects to the end of the current word", -> | |
317 | expect(vimState.getRegister('"').text).toBe 'ab cde1+-' | |
318 | ||
319 | describe "the } keybinding", -> | |
320 | beforeEach -> | |
321 | editor.setText("abcde\n\nfghij\nhijk\n xyz \n\nzip\n\n \nthe end") | |
322 | editor.setCursorScreenPosition([0, 0]) | |
323 | ||
324 | describe "as a motion", -> | |
325 | it "moves the cursor to the end of the paragraph", -> | |
326 | keydown('}') | |
327 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
328 | ||
329 | keydown('}') | |
330 | expect(editor.getCursorScreenPosition()).toEqual [5, 0] | |
331 | ||
332 | keydown('}') | |
333 | expect(editor.getCursorScreenPosition()).toEqual [7, 0] | |
334 | ||
335 | keydown('}') | |
336 | expect(editor.getCursorScreenPosition()).toEqual [9, 6] | |
337 | ||
338 | describe "as a selection", -> | |
339 | beforeEach -> | |
340 | keydown('y') | |
341 | keydown('}') | |
342 | ||
343 | it 'selects to the end of the current paragraph', -> | |
344 | expect(vimState.getRegister('"').text).toBe "abcde\n" | |
345 | ||
346 | describe "the { keybinding", -> | |
347 | beforeEach -> | |
348 | editor.setText("abcde\n\nfghij\nhijk\n xyz \n\nzip\n\n \nthe end") | |
349 | editor.setCursorScreenPosition([9, 0]) | |
350 | ||
351 | describe "as a motion", -> | |
352 | it "moves the cursor to the beginning of the paragraph", -> | |
353 | keydown('{') | |
354 | expect(editor.getCursorScreenPosition()).toEqual [7, 0] | |
355 | ||
356 | keydown('{') | |
357 | expect(editor.getCursorScreenPosition()).toEqual [5, 0] | |
358 | ||
359 | keydown('{') | |
360 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
361 | ||
362 | keydown('{') | |
363 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
364 | ||
365 | describe "as a selection", -> | |
366 | beforeEach -> | |
367 | editor.setCursorScreenPosition([7, 0]) | |
368 | keydown('y') | |
369 | keydown('{') | |
370 | ||
371 | it 'selects to the beginning of the current paragraph', -> | |
372 | expect(vimState.getRegister('"').text).toBe "\nzip\n" | |
373 | ||
374 | describe "the b keybinding", -> | |
375 | beforeEach -> editor.setText(" ab cde1+- \n xyz\n\nzip }\n last") | |
376 | ||
377 | describe "as a motion", -> | |
378 | beforeEach -> editor.setCursorScreenPosition([4, 1]) | |
379 | ||
380 | it "moves the cursor to the beginning of the previous word", -> | |
381 | keydown('b') | |
382 | expect(editor.getCursorScreenPosition()).toEqual [3, 4] | |
383 | ||
384 | keydown('b') | |
385 | expect(editor.getCursorScreenPosition()).toEqual [3, 0] | |
386 | ||
387 | keydown('b') | |
388 | expect(editor.getCursorScreenPosition()).toEqual [2, 0] | |
389 | ||
390 | keydown('b') | |
391 | expect(editor.getCursorScreenPosition()).toEqual [1, 1] | |
392 | ||
393 | keydown('b') | |
394 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
395 | ||
396 | keydown('b') | |
397 | expect(editor.getCursorScreenPosition()).toEqual [0, 4] | |
398 | ||
399 | keydown('b') | |
400 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
401 | ||
402 | # Go to start of the file, after moving past the first word | |
403 | keydown('b') | |
404 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
405 | ||
406 | # Stay at the start of the file | |
407 | keydown('b') | |
408 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
409 | ||
410 | describe "as a selection", -> | |
411 | describe "within a word", -> | |
412 | beforeEach -> | |
413 | editor.setCursorScreenPosition([0, 2]) | |
414 | keydown('y') | |
415 | keydown('b') | |
416 | ||
417 | it "selects to the beginning of the current word", -> | |
418 | expect(vimState.getRegister('"').text).toBe 'a' | |
419 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
420 | ||
421 | describe "between words", -> | |
422 | beforeEach -> | |
423 | editor.setCursorScreenPosition([0, 4]) | |
424 | keydown('y') | |
425 | keydown('b') | |
426 | ||
427 | it "selects to the beginning of the last word", -> | |
428 | expect(vimState.getRegister('"').text).toBe 'ab ' | |
429 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
430 | ||
431 | describe "the B keybinding", -> | |
432 | beforeEach -> editor.setText("cde1+- ab \n\t xyz-123\n\n zip") | |
433 | ||
434 | describe "as a motion", -> | |
435 | beforeEach -> editor.setCursorScreenPosition([4, 1]) | |
436 | ||
437 | it "moves the cursor to the beginning of the previous word", -> | |
438 | keydown('B', shift: true) | |
439 | expect(editor.getCursorScreenPosition()).toEqual [3, 1] | |
440 | ||
441 | keydown('B', shift: true) | |
442 | expect(editor.getCursorScreenPosition()).toEqual [2, 0] | |
443 | ||
444 | keydown('B', shift: true) | |
445 | expect(editor.getCursorScreenPosition()).toEqual [1, 3] | |
446 | ||
447 | keydown('B', shift: true) | |
448 | expect(editor.getCursorScreenPosition()).toEqual [0, 7] | |
449 | ||
450 | keydown('B', shift: true) | |
451 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
452 | ||
453 | describe "as a selection", -> | |
454 | it "selects to the beginning of the whole word", -> | |
455 | editor.setCursorScreenPosition([1, 9]) | |
456 | keydown('y') | |
457 | keydown('B', shift: true) | |
458 | expect(vimState.getRegister('"').text).toBe 'xyz-12' | |
459 | ||
460 | it "doesn't go past the beginning of the file", -> | |
461 | editor.setCursorScreenPosition([0, 0]) | |
462 | vimState.setRegister('"', text: 'abc') | |
463 | keydown('y') | |
464 | keydown('B', shift: true) | |
465 | expect(vimState.getRegister('"').text).toBe 'abc' | |
466 | ||
467 | describe "the ^ keybinding", -> | |
468 | beforeEach -> | |
469 | editor.setText(" abcde") | |
470 | ||
471 | describe "from the beginning of the line", -> | |
472 | beforeEach -> editor.setCursorScreenPosition([0, 0]) | |
473 | ||
474 | describe "as a motion", -> | |
475 | beforeEach -> keydown('^') | |
476 | ||
477 | it "moves the cursor to the first character of the line", -> | |
478 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
479 | ||
480 | describe "as a selection", -> | |
481 | beforeEach -> | |
482 | keydown('d') | |
483 | keydown('^') | |
484 | ||
485 | it 'selects to the first character of the line', -> | |
486 | expect(editor.getText()).toBe 'abcde' | |
487 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
488 | ||
489 | describe "from the first character of the line", -> | |
490 | beforeEach -> editor.setCursorScreenPosition([0, 2]) | |
491 | ||
492 | describe "as a motion", -> | |
493 | beforeEach -> keydown('^') | |
494 | ||
495 | it "stays put", -> | |
496 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
497 | ||
498 | describe "as a selection", -> | |
499 | beforeEach -> | |
500 | keydown('d') | |
501 | keydown('^') | |
502 | ||
503 | it "does nothing", -> | |
504 | expect(editor.getText()).toBe ' abcde' | |
505 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
506 | ||
507 | describe "from the middle of a word", -> | |
508 | beforeEach -> editor.setCursorScreenPosition([0, 4]) | |
509 | ||
510 | describe "as a motion", -> | |
511 | beforeEach -> keydown('^') | |
512 | ||
513 | it "moves the cursor to the first character of the line", -> | |
514 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
515 | ||
516 | describe "as a selection", -> | |
517 | beforeEach -> | |
518 | keydown('d') | |
519 | keydown('^') | |
520 | ||
521 | it 'selects to the first character of the line', -> | |
522 | expect(editor.getText()).toBe ' cde' | |
523 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
524 | ||
525 | describe "the 0 keybinding", -> | |
526 | beforeEach -> | |
527 | editor.setText(" abcde") | |
528 | editor.setCursorScreenPosition([0, 4]) | |
529 | ||
530 | describe "as a motion", -> | |
531 | beforeEach -> keydown('0') | |
532 | ||
533 | it "moves the cursor to the first column", -> | |
534 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
535 | ||
536 | describe "as a selection", -> | |
537 | beforeEach -> | |
538 | keydown('d') | |
539 | keydown('0') | |
540 | ||
541 | it 'selects to the first column of the line', -> | |
542 | expect(editor.getText()).toBe 'cde' | |
543 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
544 | ||
545 | describe "the $ keybinding", -> | |
546 | beforeEach -> | |
547 | editor.setText(" abcde\n\n1234567890") | |
548 | editor.setCursorScreenPosition([0, 4]) | |
549 | ||
550 | describe "as a motion from empty line", -> | |
551 | beforeEach -> editor.setCursorScreenPosition([1, 0]) | |
552 | ||
553 | it "moves the cursor to the end of the line", -> | |
554 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
555 | ||
556 | describe "as a motion", -> | |
557 | beforeEach -> keydown('$') | |
558 | ||
559 | # FIXME: See atom/vim-mode#2 | |
560 | it "moves the cursor to the end of the line", -> | |
561 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
562 | ||
563 | it "should remain in the last column when moving down", -> | |
564 | keydown('j') | |
565 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
566 | ||
567 | keydown('j') | |
568 | expect(editor.getCursorScreenPosition()).toEqual [2, 9] | |
569 | ||
570 | describe "as a selection", -> | |
571 | beforeEach -> | |
572 | keydown('d') | |
573 | keydown('$') | |
574 | ||
575 | it "selects to the beginning of the lines", -> | |
576 | expect(editor.getText()).toBe " ab\n\n1234567890" | |
577 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
578 | ||
579 | describe "the 0 keybinding", -> | |
580 | beforeEach -> | |
581 | editor.setText(" a\n") | |
582 | editor.setCursorScreenPosition([0, 2]) | |
583 | ||
584 | describe "as a motion", -> | |
585 | beforeEach -> keydown('0') | |
586 | ||
587 | it "moves the cursor to the beginning of the line", -> | |
588 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
589 | ||
590 | describe "the - keybinding", -> | |
591 | beforeEach -> | |
592 | editor.setText("abcdefg\n abc\n abc\n") | |
593 | ||
594 | describe "from the middle of a line", -> | |
595 | beforeEach -> editor.setCursorScreenPosition([1, 3]) | |
596 | ||
597 | describe "as a motion", -> | |
598 | beforeEach -> keydown('-') | |
599 | ||
600 | it "moves the cursor to the first character of the previous line", -> | |
601 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
602 | ||
603 | describe "as a selection", -> | |
604 | beforeEach -> | |
605 | keydown('d') | |
606 | keydown('-') | |
607 | ||
608 | it "deletes the current and previous line", -> | |
609 | expect(editor.getText()).toBe " abc\n" | |
610 | # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed | |
611 | #expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
612 | ||
613 | describe "from the first character of a line indented the same as the previous one", -> | |
614 | beforeEach -> editor.setCursorScreenPosition([2, 2]) | |
615 | ||
616 | describe "as a motion", -> | |
617 | beforeEach -> keydown('-') | |
618 | ||
619 | it "moves to the first character of the previous line (directly above)", -> | |
620 | expect(editor.getCursorScreenPosition()).toEqual [1, 2] | |
621 | ||
622 | describe "as a selection", -> | |
623 | beforeEach -> | |
624 | keydown('d') | |
625 | keydown('-') | |
626 | ||
627 | it "selects to the first character of the previous line (directly above)", -> | |
628 | expect(editor.getText()).toBe "abcdefg\n" | |
629 | # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed | |
630 | #expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
631 | ||
632 | describe "from the beginning of a line preceded by an indented line", -> | |
633 | beforeEach -> editor.setCursorScreenPosition([2, 0]) | |
634 | ||
635 | describe "as a motion", -> | |
636 | beforeEach -> keydown('-') | |
637 | ||
638 | it "moves the cursor to the first character of the previous line", -> | |
639 | expect(editor.getCursorScreenPosition()).toEqual [1, 2] | |
640 | ||
641 | describe "as a selection", -> | |
642 | beforeEach -> | |
643 | keydown('d') | |
644 | keydown('-') | |
645 | ||
646 | it "selects to the first character of the previous line", -> | |
647 | expect(editor.getText()).toBe "abcdefg\n" | |
648 | # commented out because the column is wrong due to a bug in `k`; re-enable when `k` is fixed | |
649 | #expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
650 | ||
651 | describe "with a count", -> | |
652 | beforeEach -> | |
653 | editor.setText("1\n2\n3\n4\n5\n6\n") | |
654 | editor.setCursorScreenPosition([4, 0]) | |
655 | ||
656 | describe "as a motion", -> | |
657 | beforeEach -> | |
658 | keydown('3') | |
659 | keydown('-') | |
660 | ||
661 | it "moves the cursor to the first character of that many lines previous", -> | |
662 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
663 | ||
664 | describe "as a selection", -> | |
665 | beforeEach -> | |
666 | keydown('d') | |
667 | keydown('3') | |
668 | keydown('-') | |
669 | ||
670 | it "deletes the current line plus that many previous lines", -> | |
671 | expect(editor.getText()).toBe "1\n6\n" | |
672 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
673 | ||
674 | describe "the + keybinding", -> | |
675 | beforeEach -> | |
676 | editor.setText(" abc\n abc\nabcdefg\n") | |
677 | ||
678 | describe "from the middle of a line", -> | |
679 | beforeEach -> editor.setCursorScreenPosition([1, 3]) | |
680 | ||
681 | describe "as a motion", -> | |
682 | beforeEach -> keydown('+') | |
683 | ||
684 | it "moves the cursor to the first character of the next line", -> | |
685 | expect(editor.getCursorScreenPosition()).toEqual [2, 0] | |
686 | ||
687 | describe "as a selection", -> | |
688 | beforeEach -> | |
689 | keydown('d') | |
690 | keydown('+') | |
691 | ||
692 | it "deletes the current and next line", -> | |
693 | expect(editor.getText()).toBe " abc\n" | |
694 | # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed | |
695 | #expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
696 | ||
697 | describe "from the first character of a line indented the same as the next one", -> | |
698 | beforeEach -> editor.setCursorScreenPosition([0, 2]) | |
699 | ||
700 | describe "as a motion", -> | |
701 | beforeEach -> keydown('+') | |
702 | ||
703 | it "moves to the first character of the next line (directly below)", -> | |
704 | expect(editor.getCursorScreenPosition()).toEqual [1, 2] | |
705 | ||
706 | describe "as a selection", -> | |
707 | beforeEach -> | |
708 | keydown('d') | |
709 | keydown('+') | |
710 | ||
711 | it "selects to the first character of the next line (directly below)", -> | |
712 | expect(editor.getText()).toBe "abcdefg\n" | |
713 | # commented out because the column is wrong due to a bug in `j`; re-enable when `j` is fixed | |
714 | #expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
715 | ||
716 | describe "from the beginning of a line followed by an indented line", -> | |
717 | beforeEach -> editor.setCursorScreenPosition([0, 0]) | |
718 | ||
719 | describe "as a motion", -> | |
720 | beforeEach -> keydown('+') | |
721 | ||
722 | it "moves the cursor to the first character of the next line", -> | |
723 | expect(editor.getCursorScreenPosition()).toEqual [1, 2] | |
724 | ||
725 | describe "as a selection", -> | |
726 | beforeEach -> | |
727 | keydown('d') | |
728 | keydown('+') | |
729 | ||
730 | it "selects to the first character of the next line", -> | |
731 | expect(editor.getText()).toBe "abcdefg\n" | |
732 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
733 | ||
734 | describe "with a count", -> | |
735 | beforeEach -> | |
736 | editor.setText("1\n2\n3\n4\n5\n6\n") | |
737 | editor.setCursorScreenPosition([1, 0]) | |
738 | ||
739 | describe "as a motion", -> | |
740 | beforeEach -> | |
741 | keydown('3') | |
742 | keydown('+') | |
743 | ||
744 | it "moves the cursor to the first character of that many lines following", -> | |
745 | expect(editor.getCursorScreenPosition()).toEqual [4, 0] | |
746 | ||
747 | describe "as a selection", -> | |
748 | beforeEach -> | |
749 | keydown('d') | |
750 | keydown('3') | |
751 | keydown('+') | |
752 | ||
753 | it "deletes the current line plus that many following lines", -> | |
754 | expect(editor.getText()).toBe "1\n6\n" | |
755 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
756 | ||
757 | describe "the _ keybinding", -> | |
758 | beforeEach -> | |
759 | editor.setText(" abc\n abc\nabcdefg\n") | |
760 | ||
761 | describe "from the middle of a line", -> | |
762 | beforeEach -> editor.setCursorScreenPosition([1, 3]) | |
763 | ||
764 | describe "as a motion", -> | |
765 | beforeEach -> keydown('_') | |
766 | ||
767 | it "moves the cursor to the first character of the current line", -> | |
768 | expect(editor.getCursorScreenPosition()).toEqual [1, 2] | |
769 | ||
770 | describe "as a selection", -> | |
771 | beforeEach -> | |
772 | keydown('d') | |
773 | keydown('_') | |
774 | ||
775 | it "deletes the current line", -> | |
776 | expect(editor.getText()).toBe " abc\nabcdefg\n" | |
777 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
778 | ||
779 | describe "with a count", -> | |
780 | beforeEach -> | |
781 | editor.setText("1\n2\n3\n4\n5\n6\n") | |
782 | editor.setCursorScreenPosition([1, 0]) | |
783 | ||
784 | describe "as a motion", -> | |
785 | beforeEach -> | |
786 | keydown('3') | |
787 | keydown('_') | |
788 | ||
789 | it "moves the cursor to the first character of that many lines following", -> | |
790 | expect(editor.getCursorScreenPosition()).toEqual [3, 0] | |
791 | ||
792 | describe "as a selection", -> | |
793 | beforeEach -> | |
794 | keydown('d') | |
795 | keydown('3') | |
796 | keydown('_') | |
797 | ||
798 | it "deletes the current line plus that many following lines", -> | |
799 | expect(editor.getText()).toBe "1\n5\n6\n" | |
800 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
801 | ||
802 | describe "the enter keybinding", -> | |
803 | keydownCodeForEnter = '\r' # 'enter' does not work | |
804 | startingText = " abc\n abc\nabcdefg\n" | |
805 | ||
806 | describe "from the middle of a line", -> | |
807 | startingCursorPosition = [1, 3] | |
808 | ||
809 | describe "as a motion", -> | |
810 | it "acts the same as the + keybinding", -> | |
811 | # do it with + and save the results | |
812 | editor.setText(startingText) | |
813 | editor.setCursorScreenPosition(startingCursorPosition) | |
814 | keydown('+') | |
815 | referenceCursorPosition = editor.getCursorScreenPosition() | |
816 | # do it again with enter and compare the results | |
817 | editor.setText(startingText) | |
818 | editor.setCursorScreenPosition(startingCursorPosition) | |
819 | keydown(keydownCodeForEnter) | |
820 | expect(editor.getCursorScreenPosition()).toEqual referenceCursorPosition | |
821 | ||
822 | describe "as a selection", -> | |
823 | it "acts the same as the + keybinding", -> | |
824 | # do it with + and save the results | |
825 | editor.setText(startingText) | |
826 | editor.setCursorScreenPosition(startingCursorPosition) | |
827 | keydown('d') | |
828 | keydown('+') | |
829 | referenceText = editor.getText() | |
830 | referenceCursorPosition = editor.getCursorScreenPosition() | |
831 | # do it again with enter and compare the results | |
832 | editor.setText(startingText) | |
833 | editor.setCursorScreenPosition(startingCursorPosition) | |
834 | keydown('d') | |
835 | keydown(keydownCodeForEnter) | |
836 | expect(editor.getText()).toEqual referenceText | |
837 | expect(editor.getCursorScreenPosition()).toEqual referenceCursorPosition | |
838 | ||
839 | describe "the gg keybinding", -> | |
840 | beforeEach -> | |
841 | editor.setText(" 1abc\n 2\n3\n") | |
842 | editor.setCursorScreenPosition([0, 2]) | |
843 | ||
844 | describe "as a motion", -> | |
845 | describe "in normal mode", -> | |
846 | beforeEach -> | |
847 | keydown('g') | |
848 | keydown('g') | |
849 | ||
850 | it "moves the cursor to the beginning of the first line", -> | |
851 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
852 | ||
853 | describe "in linewise visual mode", -> | |
854 | beforeEach -> | |
855 | editor.setCursorScreenPosition([1, 0]) | |
856 | vimState.activateVisualMode('linewise') | |
857 | keydown('g') | |
858 | keydown('g') | |
859 | ||
860 | it "selects to the first line in the file", -> | |
861 | expect(editor.getSelectedText()).toBe " 1abc\n 2\n" | |
862 | ||
863 | it "moves the cursor to a specified line", -> | |
864 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
865 | ||
866 | describe "in characterwise visual mode", -> | |
867 | beforeEach -> | |
868 | editor.setCursorScreenPosition([1, 1]) | |
869 | vimState.activateVisualMode() | |
870 | keydown('g') | |
871 | keydown('g') | |
872 | ||
873 | it "selects to the first line in the file", -> | |
874 | expect(editor.getSelectedText()).toBe "1abc\n 2" | |
875 | ||
876 | it "moves the cursor to a specified line", -> | |
877 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
878 | ||
879 | describe "as a repeated motion", -> | |
880 | describe "in normal mode", -> | |
881 | beforeEach -> | |
882 | keydown('2') | |
883 | keydown('g') | |
884 | keydown('g') | |
885 | ||
886 | it "moves the cursor to a specified line", -> | |
887 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
888 | ||
889 | describe "in linewise visual motion", -> | |
890 | beforeEach -> | |
891 | editor.setCursorScreenPosition([2, 0]) | |
892 | vimState.activateVisualMode('linewise') | |
893 | keydown('2') | |
894 | keydown('g') | |
895 | keydown('g') | |
896 | ||
897 | it "selects to a specified line", -> | |
898 | expect(editor.getSelectedText()).toBe " 2\n3\n" | |
899 | ||
900 | it "moves the cursor to a specified line", -> | |
901 | expect(editor.getCursorScreenPosition()).toEqual [1, 0] | |
902 | ||
903 | describe "in characterwise visual motion", -> | |
904 | beforeEach -> | |
905 | editor.setCursorScreenPosition([2, 0]) | |
906 | vimState.activateVisualMode() | |
907 | keydown('2') | |
908 | keydown('g') | |
909 | keydown('g') | |
910 | ||
911 | it "selects to a first character of specified line", -> | |
912 | expect(editor.getSelectedText()).toBe "2\n3" | |
913 | ||
914 | it "moves the cursor to a specified line", -> | |
915 | expect(editor.getCursorScreenPosition()).toEqual [1, 1] | |
916 | ||
917 | describe "the g_ keybinding", -> | |
918 | beforeEach -> | |
919 | editor.setText("1 \n 2 \n 3abc\n ") | |
920 | ||
921 | describe "as a motion", -> | |
922 | it "moves the cursor to the last nonblank character", -> | |
923 | editor.setCursorScreenPosition([1, 0]) | |
924 | keydown('g') | |
925 | keydown('_') | |
926 | expect(editor.getCursorScreenPosition()).toEqual [1, 4] | |
927 | ||
928 | it "will move the cursor to the beginning of the line if necessary", -> | |
929 | editor.setCursorScreenPosition([0, 2]) | |
930 | keydown('g') | |
931 | keydown('_') | |
932 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
933 | ||
934 | describe "as a repeated motion", -> | |
935 | it "moves the cursor downward and outward", -> | |
936 | editor.setCursorScreenPosition([0, 0]) | |
937 | keydown('2') | |
938 | keydown('g') | |
939 | keydown('_') | |
940 | expect(editor.getCursorScreenPosition()).toEqual [1, 4] | |
941 | ||
942 | describe "as a selection", -> | |
943 | it "selects the current line excluding whitespace", -> | |
944 | editor.setCursorScreenPosition([1, 2]) | |
945 | vimState.activateVisualMode() | |
946 | keydown('2') | |
947 | keydown('g') | |
948 | keydown('_') | |
949 | expect(editor.getSelectedText()).toEqual " 2 \n 3abc" | |
950 | ||
951 | describe "the G keybinding", -> | |
952 | beforeEach -> | |
953 | editor.setText("1\n 2\n 3abc\n ") | |
954 | editor.setCursorScreenPosition([0, 2]) | |
955 | ||
956 | describe "as a motion", -> | |
957 | beforeEach -> keydown('G', shift: true) | |
958 | ||
959 | it "moves the cursor to the last line after whitespace", -> | |
960 | expect(editor.getCursorScreenPosition()).toEqual [3, 0] | |
961 | ||
962 | describe "as a repeated motion", -> | |
963 | beforeEach -> | |
964 | keydown('2') | |
965 | keydown('G', shift: true) | |
966 | ||
967 | it "moves the cursor to a specified line", -> | |
968 | expect(editor.getCursorScreenPosition()).toEqual [1, 4] | |
969 | ||
970 | describe "as a selection", -> | |
971 | beforeEach -> | |
972 | editor.setCursorScreenPosition([1, 0]) | |
973 | vimState.activateVisualMode() | |
974 | keydown('G', shift: true) | |
975 | ||
976 | it "selects to the last line in the file", -> | |
977 | expect(editor.getSelectedText()).toBe " 2\n 3abc\n " | |
978 | ||
979 | it "moves the cursor to the last line after whitespace", -> | |
980 | expect(editor.getCursorScreenPosition()).toEqual [3, 1] | |
981 | ||
982 | describe "the / keybinding", -> | |
983 | pane = null | |
984 | ||
985 | beforeEach -> | |
986 | pane = {activate: jasmine.createSpy("activate")} | |
987 | spyOn(atom.workspace, 'getActivePane').andReturn(pane) | |
988 | ||
989 | editor.setText("abc\ndef\nabc\ndef\n") | |
990 | editor.setCursorBufferPosition([0, 0]) | |
991 | ||
992 | # clear search history | |
993 | vimState.globalVimState.searchHistory = [] | |
994 | vimState.globalVimState.currentSearch = {} | |
995 | ||
996 | describe "as a motion", -> | |
997 | it "beeps when repeating nonexistent last search", -> | |
998 | keydown '/' | |
999 | submitNormalModeInputText '' | |
1000 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1001 | expect(atom.beep).toHaveBeenCalled() | |
1002 | ||
1003 | it "moves the cursor to the specified search pattern", -> | |
1004 | keydown('/') | |
1005 | ||
1006 | submitNormalModeInputText 'def' | |
1007 | ||
1008 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1009 | expect(pane.activate).toHaveBeenCalled() | |
1010 | expect(atom.beep).not.toHaveBeenCalled() | |
1011 | ||
1012 | it "loops back around", -> | |
1013 | editor.setCursorBufferPosition([3, 0]) | |
1014 | keydown('/') | |
1015 | submitNormalModeInputText 'def' | |
1016 | ||
1017 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1018 | expect(atom.beep).not.toHaveBeenCalled() | |
1019 | ||
1020 | it "uses a valid regex as a regex", -> | |
1021 | keydown('/') | |
1022 | # Cycle through the 'abc' on the first line with a character pattern | |
1023 | submitNormalModeInputText '[abc]' | |
1024 | expect(editor.getCursorBufferPosition()).toEqual [0, 1] | |
1025 | keydown('n') | |
1026 | expect(editor.getCursorBufferPosition()).toEqual [0, 2] | |
1027 | expect(atom.beep).not.toHaveBeenCalled() | |
1028 | ||
1029 | it "uses an invalid regex as a literal string", -> | |
1030 | # Go straight to the literal [abc | |
1031 | editor.setText("abc\n[abc]\n") | |
1032 | keydown('/') | |
1033 | submitNormalModeInputText '[abc' | |
1034 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1035 | keydown('n') | |
1036 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1037 | expect(atom.beep).not.toHaveBeenCalled() | |
1038 | ||
1039 | it "uses ? as a literal string", -> | |
1040 | editor.setText("abc\n[a?c?\n") | |
1041 | keydown('/') | |
1042 | submitNormalModeInputText '?' | |
1043 | expect(editor.getCursorBufferPosition()).toEqual [1, 2] | |
1044 | keydown('n') | |
1045 | expect(editor.getCursorBufferPosition()).toEqual [1, 4] | |
1046 | expect(atom.beep).not.toHaveBeenCalled() | |
1047 | ||
1048 | it 'works with selection in visual mode', -> | |
1049 | editor.setText('one two three') | |
1050 | keydown('v') | |
1051 | keydown('/') | |
1052 | submitNormalModeInputText 'th' | |
1053 | expect(editor.getCursorBufferPosition()).toEqual [0, 9] | |
1054 | keydown('d') | |
1055 | expect(editor.getText()).toBe 'hree' | |
1056 | expect(atom.beep).not.toHaveBeenCalled() | |
1057 | ||
1058 | it 'extends selection when repeating search in visual mode', -> | |
1059 | editor.setText('line1\nline2\nline3') | |
1060 | keydown('v') | |
1061 | keydown('/') | |
1062 | submitNormalModeInputText 'line' | |
1063 | {start, end} = editor.getSelectedBufferRange() | |
1064 | expect(start.row).toEqual 0 | |
1065 | expect(end.row).toEqual 1 | |
1066 | keydown('n') | |
1067 | {start, end} = editor.getSelectedBufferRange() | |
1068 | expect(start.row).toEqual 0 | |
1069 | expect(end.row).toEqual 2 | |
1070 | expect(atom.beep).not.toHaveBeenCalled() | |
1071 | ||
1072 | describe "case sensitivity", -> | |
1073 | beforeEach -> | |
1074 | editor.setText("\nabc\nABC\n") | |
1075 | editor.setCursorBufferPosition([0, 0]) | |
1076 | keydown('/') | |
1077 | ||
1078 | it "works in case sensitive mode", -> | |
1079 | submitNormalModeInputText 'ABC' | |
1080 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1081 | keydown('n') | |
1082 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1083 | expect(atom.beep).not.toHaveBeenCalled() | |
1084 | ||
1085 | it "works in case insensitive mode", -> | |
1086 | submitNormalModeInputText '\\cAbC' | |
1087 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1088 | keydown('n') | |
1089 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1090 | expect(atom.beep).not.toHaveBeenCalled() | |
1091 | ||
1092 | it "works in case insensitive mode wherever \\c is", -> | |
1093 | submitNormalModeInputText 'AbC\\c' | |
1094 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1095 | keydown('n') | |
1096 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1097 | expect(atom.beep).not.toHaveBeenCalled() | |
1098 | ||
1099 | it "uses case insensitive search if useSmartcaseForSearch is true and searching lowercase", -> | |
1100 | atom.config.set 'vim-mode.useSmartcaseForSearch', true | |
1101 | submitNormalModeInputText 'abc' | |
1102 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1103 | keydown('n') | |
1104 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1105 | expect(atom.beep).not.toHaveBeenCalled() | |
1106 | ||
1107 | it "uses case sensitive search if useSmartcaseForSearch is true and searching uppercase", -> | |
1108 | atom.config.set 'vim-mode.useSmartcaseForSearch', true | |
1109 | submitNormalModeInputText 'ABC' | |
1110 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1111 | keydown('n') | |
1112 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1113 | expect(atom.beep).not.toHaveBeenCalled() | |
1114 | ||
1115 | describe "repeating", -> | |
1116 | it "does nothing with no search history", -> | |
1117 | editor.setCursorBufferPosition([0, 0]) | |
1118 | keydown('n') | |
1119 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1120 | expect(atom.beep).toHaveBeenCalled() | |
1121 | ||
1122 | editor.setCursorBufferPosition([1, 1]) | |
1123 | keydown('n') | |
1124 | expect(editor.getCursorBufferPosition()).toEqual [1, 1] | |
1125 | expect(atom.beep.callCount).toBe 2 | |
1126 | ||
1127 | describe "repeating with search history", -> | |
1128 | beforeEach -> | |
1129 | keydown('/') | |
1130 | submitNormalModeInputText 'def' | |
1131 | ||
1132 | it "repeats previous search with /<enter>", -> | |
1133 | keydown('/') | |
1134 | submitNormalModeInputText('') | |
1135 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1136 | expect(atom.beep).not.toHaveBeenCalled() | |
1137 | ||
1138 | it "repeats previous search with //", -> | |
1139 | keydown('/') | |
1140 | submitNormalModeInputText('/') | |
1141 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1142 | expect(atom.beep).not.toHaveBeenCalled() | |
1143 | ||
1144 | describe "the n keybinding", -> | |
1145 | it "repeats the last search", -> | |
1146 | keydown('n') | |
1147 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1148 | expect(atom.beep).not.toHaveBeenCalled() | |
1149 | ||
1150 | describe "the N keybinding", -> | |
1151 | it "repeats the last search backwards", -> | |
1152 | editor.setCursorBufferPosition([0, 0]) | |
1153 | keydown('N', shift: true) | |
1154 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1155 | keydown('N', shift: true) | |
1156 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1157 | expect(atom.beep).not.toHaveBeenCalled() | |
1158 | ||
1159 | describe "composing", -> | |
1160 | it "composes with operators", -> | |
1161 | keydown('d') | |
1162 | keydown('/') | |
1163 | submitNormalModeInputText('def') | |
1164 | expect(editor.getText()).toEqual "def\nabc\ndef\n" | |
1165 | expect(atom.beep).not.toHaveBeenCalled() | |
1166 | ||
1167 | it "repeats correctly with operators", -> | |
1168 | keydown('d') | |
1169 | keydown('/') | |
1170 | submitNormalModeInputText('def') | |
1171 | ||
1172 | keydown('.') | |
1173 | expect(editor.getText()).toEqual "def\n" | |
1174 | expect(atom.beep).not.toHaveBeenCalled() | |
1175 | ||
1176 | describe "when reversed as ?", -> | |
1177 | it "moves the cursor backwards to the specified search pattern", -> | |
1178 | keydown('?') | |
1179 | submitNormalModeInputText('def') | |
1180 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1181 | expect(atom.beep).not.toHaveBeenCalled() | |
1182 | ||
1183 | it "accepts / as a literal search pattern", -> | |
1184 | editor.setText("abc\nd/f\nabc\nd/f\n") | |
1185 | editor.setCursorBufferPosition([0, 0]) | |
1186 | keydown('?') | |
1187 | submitNormalModeInputText('/') | |
1188 | expect(editor.getCursorBufferPosition()).toEqual [3, 1] | |
1189 | keydown('?') | |
1190 | submitNormalModeInputText('/') | |
1191 | expect(editor.getCursorBufferPosition()).toEqual [1, 1] | |
1192 | expect(atom.beep).not.toHaveBeenCalled() | |
1193 | ||
1194 | describe "repeating", -> | |
1195 | beforeEach -> | |
1196 | keydown('?') | |
1197 | submitNormalModeInputText('def') | |
1198 | ||
1199 | it "repeats previous search as reversed with ?<enter>", -> | |
1200 | keydown('?') | |
1201 | submitNormalModeInputText('') | |
1202 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1203 | expect(atom.beep).not.toHaveBeenCalled() | |
1204 | ||
1205 | it "repeats previous search as reversed with ??", -> | |
1206 | keydown('?') | |
1207 | submitNormalModeInputText('?') | |
1208 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1209 | expect(atom.beep).not.toHaveBeenCalled() | |
1210 | ||
1211 | describe 'the n keybinding', -> | |
1212 | it "repeats the last search backwards", -> | |
1213 | editor.setCursorBufferPosition([0, 0]) | |
1214 | keydown('n') | |
1215 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1216 | expect(atom.beep).not.toHaveBeenCalled() | |
1217 | ||
1218 | describe 'the N keybinding', -> | |
1219 | it "repeats the last search forwards", -> | |
1220 | editor.setCursorBufferPosition([0, 0]) | |
1221 | keydown('N', shift: true) | |
1222 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1223 | expect(atom.beep).not.toHaveBeenCalled() | |
1224 | ||
1225 | describe "using search history", -> | |
1226 | inputEditor = null | |
1227 | ||
1228 | beforeEach -> | |
1229 | keydown('/') | |
1230 | submitNormalModeInputText('def') | |
1231 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1232 | ||
1233 | keydown('/') | |
1234 | submitNormalModeInputText('abc') | |
1235 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1236 | ||
1237 | inputEditor = editor.normalModeInputView.editorElement | |
1238 | ||
1239 | it "allows searching history in the search field", -> | |
1240 | keydown('/') | |
1241 | atom.commands.dispatch(inputEditor, 'core:move-up') | |
1242 | expect(inputEditor.getModel().getText()).toEqual('abc') | |
1243 | atom.commands.dispatch(inputEditor, 'core:move-up') | |
1244 | expect(inputEditor.getModel().getText()).toEqual('def') | |
1245 | atom.commands.dispatch(inputEditor, 'core:move-up') | |
1246 | expect(inputEditor.getModel().getText()).toEqual('def') | |
1247 | expect(atom.beep).not.toHaveBeenCalled() | |
1248 | ||
1249 | it "resets the search field to empty when scrolling back", -> | |
1250 | keydown('/') | |
1251 | atom.commands.dispatch(inputEditor, 'core:move-up') | |
1252 | expect(inputEditor.getModel().getText()).toEqual('abc') | |
1253 | atom.commands.dispatch(inputEditor, 'core:move-up') | |
1254 | expect(inputEditor.getModel().getText()).toEqual('def') | |
1255 | atom.commands.dispatch(inputEditor, 'core:move-down') | |
1256 | expect(inputEditor.getModel().getText()).toEqual('abc') | |
1257 | atom.commands.dispatch(inputEditor, 'core:move-down') | |
1258 | expect(inputEditor.getModel().getText()).toEqual '' | |
1259 | expect(atom.beep).not.toHaveBeenCalled() | |
1260 | ||
1261 | describe "the * keybinding", -> | |
1262 | beforeEach -> | |
1263 | editor.setText("abd\n@def\nabd\ndef\n") | |
1264 | editor.setCursorBufferPosition([0, 0]) | |
1265 | ||
1266 | describe "as a motion", -> | |
1267 | it "moves cursor to next occurence of word under cursor", -> | |
1268 | keydown("*") | |
1269 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1270 | ||
1271 | it "repeats with the n key", -> | |
1272 | keydown("*") | |
1273 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1274 | keydown("n") | |
1275 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1276 | ||
1277 | it "doesn't move cursor unless next occurence is the exact word (no partial matches)", -> | |
1278 | editor.setText("abc\ndef\nghiabc\njkl\nabcdef") | |
1279 | editor.setCursorBufferPosition([0, 0]) | |
1280 | keydown("*") | |
1281 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1282 | ||
1283 | describe "with words that contain 'non-word' characters", -> | |
1284 | it "moves cursor to next occurence of word under cursor", -> | |
1285 | editor.setText("abc\n@def\nabc\n@def\n") | |
1286 | editor.setCursorBufferPosition([1, 0]) | |
1287 | keydown("*") | |
1288 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1289 | ||
1290 | it "doesn't move cursor unless next match has exact word ending", -> | |
1291 | editor.setText("abc\n@def\nabc\n@def1\n") | |
1292 | editor.setCursorBufferPosition([1, 1]) | |
1293 | keydown("*") | |
1294 | # this is because of the default isKeyword value of vim-mode that includes @ | |
1295 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1296 | ||
1297 | # FIXME: This behavior is different from the one found in | |
1298 | # vim. This is because the word boundary match in Javascript | |
1299 | # ignores starting 'non-word' characters. | |
1300 | # e.g. | |
1301 | # in Vim: /\<def\>/.test("@def") => false | |
1302 | # in Javascript: /\bdef\b/.test("@def") => true | |
1303 | it "moves cursor to the start of valid word char", -> | |
1304 | editor.setText("abc\ndef\nabc\n@def\n") | |
1305 | editor.setCursorBufferPosition([1, 0]) | |
1306 | keydown("*") | |
1307 | expect(editor.getCursorBufferPosition()).toEqual [3, 1] | |
1308 | ||
1309 | describe "when cursor is on non-word char column", -> | |
1310 | it "matches only the non-word char", -> | |
1311 | editor.setText("abc\n@def\nabc\n@def\n") | |
1312 | editor.setCursorBufferPosition([1, 0]) | |
1313 | keydown("*") | |
1314 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1315 | ||
1316 | describe "when cursor is not on a word", -> | |
1317 | it "does a match with the next word", -> | |
1318 | editor.setText("abc\na @def\n abc\n @def") | |
1319 | editor.setCursorBufferPosition([1, 1]) | |
1320 | keydown("*") | |
1321 | expect(editor.getCursorBufferPosition()).toEqual [3, 1] | |
1322 | ||
1323 | describe "when cursor is at EOF", -> | |
1324 | it "doesn't try to do any match", -> | |
1325 | editor.setText("abc\n@def\nabc\n ") | |
1326 | editor.setCursorBufferPosition([3, 0]) | |
1327 | keydown("*") | |
1328 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1329 | ||
1330 | describe "the hash keybinding", -> | |
1331 | describe "as a motion", -> | |
1332 | it "moves cursor to previous occurence of word under cursor", -> | |
1333 | editor.setText("abc\n@def\nabc\ndef\n") | |
1334 | editor.setCursorBufferPosition([2, 1]) | |
1335 | keydown("#") | |
1336 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1337 | ||
1338 | it "repeats with n", -> | |
1339 | editor.setText("abc\n@def\nabc\ndef\nabc\n") | |
1340 | editor.setCursorBufferPosition([2, 1]) | |
1341 | keydown("#") | |
1342 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1343 | keydown("n") | |
1344 | expect(editor.getCursorBufferPosition()).toEqual [4, 0] | |
1345 | keydown("n") | |
1346 | expect(editor.getCursorBufferPosition()).toEqual [2, 0] | |
1347 | ||
1348 | it "doesn't move cursor unless next occurence is the exact word (no partial matches)", -> | |
1349 | editor.setText("abc\ndef\nghiabc\njkl\nabcdef") | |
1350 | editor.setCursorBufferPosition([0, 0]) | |
1351 | keydown("#") | |
1352 | expect(editor.getCursorBufferPosition()).toEqual [0, 0] | |
1353 | ||
1354 | describe "with words that containt 'non-word' characters", -> | |
1355 | it "moves cursor to next occurence of word under cursor", -> | |
1356 | editor.setText("abc\n@def\nabc\n@def\n") | |
1357 | editor.setCursorBufferPosition([3, 0]) | |
1358 | keydown("#") | |
1359 | expect(editor.getCursorBufferPosition()).toEqual [1, 0] | |
1360 | ||
1361 | it "moves cursor to the start of valid word char", -> | |
1362 | editor.setText("abc\n@def\nabc\ndef\n") | |
1363 | editor.setCursorBufferPosition([3, 0]) | |
1364 | keydown("#") | |
1365 | expect(editor.getCursorBufferPosition()).toEqual [1, 1] | |
1366 | ||
1367 | describe "when cursor is on non-word char column", -> | |
1368 | it "matches only the non-word char", -> | |
1369 | editor.setText("abc\n@def\nabc\n@def\n") | |
1370 | editor.setCursorBufferPosition([1, 0]) | |
1371 | keydown("*") | |
1372 | expect(editor.getCursorBufferPosition()).toEqual [3, 0] | |
1373 | ||
1374 | describe "the H keybinding", -> | |
1375 | beforeEach -> | |
1376 | editor.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n") | |
1377 | editor.setCursorScreenPosition([8, 0]) | |
1378 | spyOn(editor.getLastCursor(), 'setScreenPosition') | |
1379 | ||
1380 | it "moves the cursor to the first row if visible", -> | |
1381 | spyOn(editor, 'getFirstVisibleScreenRow').andReturn(0) | |
1382 | keydown('H', shift: true) | |
1383 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([0, 0]) | |
1384 | ||
1385 | it "moves the cursor to the first visible row plus offset", -> | |
1386 | spyOn(editor, 'getFirstVisibleScreenRow').andReturn(2) | |
1387 | keydown('H', shift: true) | |
1388 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([4, 0]) | |
1389 | ||
1390 | it "respects counts", -> | |
1391 | spyOn(editor, 'getFirstVisibleScreenRow').andReturn(0) | |
1392 | keydown('3') | |
1393 | keydown('H', shift: true) | |
1394 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([2, 0]) | |
1395 | ||
1396 | describe "the L keybinding", -> | |
1397 | beforeEach -> | |
1398 | editor.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n") | |
1399 | editor.setCursorScreenPosition([8, 0]) | |
1400 | spyOn(editor.getLastCursor(), 'setScreenPosition') | |
1401 | ||
1402 | it "moves the cursor to the first row if visible", -> | |
1403 | spyOn(editor, 'getLastVisibleScreenRow').andReturn(10) | |
1404 | keydown('L', shift: true) | |
1405 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([10, 0]) | |
1406 | ||
1407 | it "moves the cursor to the first visible row plus offset", -> | |
1408 | spyOn(editor, 'getLastVisibleScreenRow').andReturn(6) | |
1409 | keydown('L', shift: true) | |
1410 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([4, 0]) | |
1411 | ||
1412 | it "respects counts", -> | |
1413 | spyOn(editor, 'getLastVisibleScreenRow').andReturn(10) | |
1414 | keydown('3') | |
1415 | keydown('L', shift: true) | |
1416 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([8, 0]) | |
1417 | ||
1418 | describe "the M keybinding", -> | |
1419 | beforeEach -> | |
1420 | editor.setText("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n") | |
1421 | editor.setCursorScreenPosition([8, 0]) | |
1422 | spyOn(editor.getLastCursor(), 'setScreenPosition') | |
1423 | spyOn(editor, 'getLastVisibleScreenRow').andReturn(10) | |
1424 | spyOn(editor, 'getFirstVisibleScreenRow').andReturn(0) | |
1425 | ||
1426 | it "moves the cursor to the first row if visible", -> | |
1427 | keydown('M', shift: true) | |
1428 | expect(editor.getLastCursor().setScreenPosition).toHaveBeenCalledWith([5, 0]) | |
1429 | ||
1430 | describe 'the mark keybindings', -> | |
1431 | beforeEach -> | |
1432 | editor.setText(' 12\n 34\n56\n') | |
1433 | editor.setCursorBufferPosition([0, 1]) | |
1434 | ||
1435 | it 'moves to the beginning of the line of a mark', -> | |
1436 | editor.setCursorBufferPosition([1, 1]) | |
1437 | keydown('m') | |
1438 | normalModeInputKeydown('a') | |
1439 | editor.setCursorBufferPosition([0, 0]) | |
1440 | keydown('\'') | |
1441 | normalModeInputKeydown('a') | |
1442 | expect(editor.getCursorBufferPosition()).toEqual [1, 4] | |
1443 | ||
1444 | it 'moves literally to a mark', -> | |
1445 | editor.setCursorBufferPosition([1, 1]) | |
1446 | keydown('m') | |
1447 | normalModeInputKeydown('a') | |
1448 | editor.setCursorBufferPosition([0, 0]) | |
1449 | keydown('`') | |
1450 | normalModeInputKeydown('a') | |
1451 | expect(editor.getCursorBufferPosition()).toEqual [1, 1] | |
1452 | ||
1453 | it 'deletes to a mark by line', -> | |
1454 | editor.setCursorBufferPosition([1, 5]) | |
1455 | keydown('m') | |
1456 | normalModeInputKeydown('a') | |
1457 | editor.setCursorBufferPosition([0, 0]) | |
1458 | keydown('d') | |
1459 | keydown('\'') | |
1460 | normalModeInputKeydown('a') | |
1461 | expect(editor.getText()).toEqual '56\n' | |
1462 | ||
1463 | it 'deletes before to a mark literally', -> | |
1464 | editor.setCursorBufferPosition([1, 5]) | |
1465 | keydown('m') | |
1466 | normalModeInputKeydown('a') | |
1467 | editor.setCursorBufferPosition([0, 1]) | |
1468 | keydown('d') | |
1469 | keydown('`') | |
1470 | normalModeInputKeydown('a') | |
1471 | expect(editor.getText()).toEqual ' 4\n56\n' | |
1472 | ||
1473 | it 'deletes after to a mark literally', -> | |
1474 | editor.setCursorBufferPosition([1, 5]) | |
1475 | keydown('m') | |
1476 | normalModeInputKeydown('a') | |
1477 | editor.setCursorBufferPosition([2, 1]) | |
1478 | keydown('d') | |
1479 | keydown('`') | |
1480 | normalModeInputKeydown('a') | |
1481 | expect(editor.getText()).toEqual ' 12\n 36\n' | |
1482 | ||
1483 | it 'moves back to previous', -> | |
1484 | editor.setCursorBufferPosition([1, 5]) | |
1485 | keydown('`') | |
1486 | normalModeInputKeydown('`') | |
1487 | editor.setCursorBufferPosition([2, 1]) | |
1488 | keydown('`') | |
1489 | normalModeInputKeydown('`') | |
1490 | expect(editor.getCursorBufferPosition()).toEqual [1, 5] | |
1491 | ||
1492 | describe 'the f/F keybindings', -> | |
1493 | beforeEach -> | |
1494 | editor.setText("abcabcabcabc\n") | |
1495 | editor.setCursorScreenPosition([0, 0]) | |
1496 | ||
1497 | it 'moves to the first specified character it finds', -> | |
1498 | keydown('f') | |
1499 | normalModeInputKeydown('c') | |
1500 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1501 | ||
1502 | it 'moves backwards to the first specified character it finds', -> | |
1503 | editor.setCursorScreenPosition([0, 2]) | |
1504 | keydown('F', shift: true) | |
1505 | normalModeInputKeydown('a') | |
1506 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1507 | ||
1508 | it 'respects count forward', -> | |
1509 | keydown('2') | |
1510 | keydown('f') | |
1511 | normalModeInputKeydown('a') | |
1512 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1513 | ||
1514 | it 'respects count backward', -> | |
1515 | editor.setCursorScreenPosition([0, 6]) | |
1516 | keydown('2') | |
1517 | keydown('F', shift: true) | |
1518 | normalModeInputKeydown('a') | |
1519 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1520 | ||
1521 | it "doesn't move if the character specified isn't found", -> | |
1522 | keydown('f') | |
1523 | normalModeInputKeydown('d') | |
1524 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1525 | expect(atom.beep).not.toHaveBeenCalled() | |
1526 | ||
1527 | it "doesn't move if there aren't the specified count of the specified character", -> | |
1528 | keydown('1') | |
1529 | keydown('0') | |
1530 | keydown('f') | |
1531 | normalModeInputKeydown('a') | |
1532 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1533 | # a bug was making this behaviour depend on the count | |
1534 | keydown('1') | |
1535 | keydown('1') | |
1536 | keydown('f') | |
1537 | normalModeInputKeydown('a') | |
1538 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1539 | # and backwards now | |
1540 | editor.setCursorScreenPosition([0, 6]) | |
1541 | keydown('1') | |
1542 | keydown('0') | |
1543 | keydown('F', shift: true) | |
1544 | normalModeInputKeydown('a') | |
1545 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1546 | keydown('1') | |
1547 | keydown('1') | |
1548 | keydown('F', shift: true) | |
1549 | normalModeInputKeydown('a') | |
1550 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1551 | ||
1552 | it "composes with d", -> | |
1553 | editor.setCursorScreenPosition([0, 3]) | |
1554 | keydown('d') | |
1555 | keydown('2') | |
1556 | keydown('f') | |
1557 | normalModeInputKeydown('a') | |
1558 | expect(editor.getText()).toEqual 'abcbc\n' | |
1559 | ||
1560 | it "cancels c when no match found", -> | |
1561 | keydown('c') | |
1562 | keydown('f') | |
1563 | normalModeInputKeydown('d') | |
1564 | expect(editor.getText()).toBe("abcabcabcabc\n") | |
1565 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1566 | expect(vimState.mode).toBe "normal" | |
1567 | ||
1568 | describe 'with accented characters', -> | |
1569 | buildIMECompositionEvent = (event, {data, target}={}) -> | |
1570 | event = new Event(event) | |
1571 | event.data = data | |
1572 | Object.defineProperty(event, 'target', get: -> target) | |
1573 | event | |
1574 | ||
1575 | buildTextInputEvent = ({data, target}) -> | |
1576 | event = new Event('textInput') | |
1577 | event.data = data | |
1578 | Object.defineProperty(event, 'target', get: -> target) | |
1579 | event | |
1580 | ||
1581 | beforeEach -> | |
1582 | editor.setText("abcébcabcébc\n") | |
1583 | editor.setCursorScreenPosition([0, 0]) | |
1584 | ||
1585 | it 'works with IME composition', -> | |
1586 | keydown('f') | |
1587 | normalModeEditor = editor.normalModeInputView.editorElement | |
1588 | jasmine.attachToDOM(normalModeEditor) | |
1589 | domNode = normalModeEditor.component.domNode | |
1590 | inputNode = domNode.querySelector('.hidden-input') | |
1591 | domNode.dispatchEvent(buildIMECompositionEvent('compositionstart', target: inputNode)) | |
1592 | domNode.dispatchEvent(buildIMECompositionEvent('compositionupdate', data: "´", target: inputNode)) | |
1593 | expect(normalModeEditor.getModel().getText()).toEqual '´' | |
1594 | domNode.dispatchEvent(buildIMECompositionEvent('compositionend', data: "é", target: inputNode)) | |
1595 | domNode.dispatchEvent(buildTextInputEvent(data: 'é', target: inputNode)) | |
1596 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
1597 | ||
1598 | describe 'the t/T keybindings', -> | |
1599 | beforeEach -> | |
1600 | editor.setText("abcabcabcabc\n") | |
1601 | editor.setCursorScreenPosition([0, 0]) | |
1602 | ||
1603 | it 'moves to the character previous to the first specified character it finds', -> | |
1604 | keydown('t') | |
1605 | normalModeInputKeydown('a') | |
1606 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1607 | # or stays put when it's already there | |
1608 | keydown('t') | |
1609 | normalModeInputKeydown('a') | |
1610 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1611 | ||
1612 | it 'moves backwards to the character after the first specified character it finds', -> | |
1613 | editor.setCursorScreenPosition([0, 2]) | |
1614 | keydown('T', shift: true) | |
1615 | normalModeInputKeydown('a') | |
1616 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
1617 | ||
1618 | it 'respects count forward', -> | |
1619 | keydown('2') | |
1620 | keydown('t') | |
1621 | normalModeInputKeydown('a') | |
1622 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1623 | ||
1624 | it 'respects count backward', -> | |
1625 | editor.setCursorScreenPosition([0, 6]) | |
1626 | keydown('2') | |
1627 | keydown('T', shift: true) | |
1628 | normalModeInputKeydown('a') | |
1629 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
1630 | ||
1631 | it "doesn't move if the character specified isn't found", -> | |
1632 | keydown('t') | |
1633 | normalModeInputKeydown('d') | |
1634 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1635 | expect(atom.beep).not.toHaveBeenCalled() | |
1636 | ||
1637 | it "doesn't move if there aren't the specified count of the specified character", -> | |
1638 | keydown('1') | |
1639 | keydown('0') | |
1640 | keydown('t') | |
1641 | normalModeInputKeydown('a') | |
1642 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1643 | # a bug was making this behaviour depend on the count | |
1644 | keydown('1') | |
1645 | keydown('1') | |
1646 | keydown('t') | |
1647 | normalModeInputKeydown('a') | |
1648 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1649 | # and backwards now | |
1650 | editor.setCursorScreenPosition([0, 6]) | |
1651 | keydown('1') | |
1652 | keydown('0') | |
1653 | keydown('T', shift: true) | |
1654 | normalModeInputKeydown('a') | |
1655 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1656 | keydown('1') | |
1657 | keydown('1') | |
1658 | keydown('T', shift: true) | |
1659 | normalModeInputKeydown('a') | |
1660 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1661 | ||
1662 | it "composes with d", -> | |
1663 | editor.setCursorScreenPosition([0, 3]) | |
1664 | keydown('d') | |
1665 | keydown('2') | |
1666 | keydown('t') | |
1667 | normalModeInputKeydown('b') | |
1668 | expect(editor.getText()).toBe 'abcbcabc\n' | |
1669 | ||
1670 | it "selects character under cursor even when no movement happens", -> | |
1671 | editor.setCursorBufferPosition([0, 0]) | |
1672 | keydown('d') | |
1673 | keydown('t') | |
1674 | normalModeInputKeydown('b') | |
1675 | expect(editor.getText()).toBe 'bcabcabcabc\n' | |
1676 | ||
1677 | describe 'the v keybinding', -> | |
1678 | beforeEach -> | |
1679 | editor.setText("01\n002\n0003\n00004\n000005\n") | |
1680 | editor.setCursorScreenPosition([1, 1]) | |
1681 | ||
1682 | it "selects down a line", -> | |
1683 | keydown('v') | |
1684 | keydown('j') | |
1685 | keydown('j') | |
1686 | expect(editor.getSelectedText()).toBe "02\n0003\n00" | |
1687 | expect(editor.getSelectedBufferRange().isSingleLine()).toBeFalsy() | |
1688 | ||
1689 | it "selects right", -> | |
1690 | keydown('v') | |
1691 | keydown('l') | |
1692 | expect(editor.getSelectedText()).toBe "02" | |
1693 | expect(editor.getSelectedBufferRange().isSingleLine()).toBeTruthy() | |
1694 | ||
1695 | describe 'the V keybinding', -> | |
1696 | beforeEach -> | |
1697 | editor.setText("01\n002\n0003\n00004\n000005\n") | |
1698 | editor.setCursorScreenPosition([1, 1]) | |
1699 | ||
1700 | it "selects down a line", -> | |
1701 | keydown('V', shift: true) | |
1702 | expect(editor.getSelectedBufferRange().isSingleLine()).toBeFalsy() | |
1703 | keydown('j') | |
1704 | keydown('j') | |
1705 | expect(editor.getSelectedText()).toBe "002\n0003\n00004\n" | |
1706 | expect(editor.getSelectedBufferRange().isSingleLine()).toBeFalsy() | |
1707 | ||
1708 | it "selects up a line", -> | |
1709 | keydown('V', shift: true) | |
1710 | keydown('k') | |
1711 | expect(editor.getSelectedText()).toBe "01\n002\n" | |
1712 | ||
1713 | describe 'the ; and , keybindings', -> | |
1714 | beforeEach -> | |
1715 | editor.setText("abcabcabcabc\n") | |
1716 | editor.setCursorScreenPosition([0, 0]) | |
1717 | ||
1718 | it "repeat f in same direction", -> | |
1719 | keydown('f') | |
1720 | normalModeInputKeydown('c') | |
1721 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1722 | keydown(';') | |
1723 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1724 | keydown(';') | |
1725 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1726 | ||
1727 | it "repeat F in same direction", -> | |
1728 | editor.setCursorScreenPosition([0, 10]) | |
1729 | keydown('F', shift: true) | |
1730 | normalModeInputKeydown('c') | |
1731 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1732 | keydown(';') | |
1733 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1734 | keydown(';') | |
1735 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1736 | ||
1737 | it "repeat f in opposite direction", -> | |
1738 | editor.setCursorScreenPosition([0, 6]) | |
1739 | keydown('f') | |
1740 | normalModeInputKeydown('c') | |
1741 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1742 | keydown(',') | |
1743 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1744 | keydown(',') | |
1745 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1746 | ||
1747 | it "repeat F in opposite direction", -> | |
1748 | editor.setCursorScreenPosition([0, 4]) | |
1749 | keydown('F', shift: true) | |
1750 | normalModeInputKeydown('c') | |
1751 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1752 | keydown(',') | |
1753 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1754 | keydown(',') | |
1755 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1756 | ||
1757 | it "alternate repeat f in same direction and reverse", -> | |
1758 | keydown('f') | |
1759 | normalModeInputKeydown('c') | |
1760 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1761 | keydown(';') | |
1762 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1763 | keydown(',') | |
1764 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1765 | ||
1766 | it "alternate repeat F in same direction and reverse", -> | |
1767 | editor.setCursorScreenPosition([0, 10]) | |
1768 | keydown('F', shift: true) | |
1769 | normalModeInputKeydown('c') | |
1770 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1771 | keydown(';') | |
1772 | expect(editor.getCursorScreenPosition()).toEqual [0, 5] | |
1773 | keydown(',') | |
1774 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1775 | ||
1776 | it "repeat t in same direction", -> | |
1777 | keydown('t') | |
1778 | normalModeInputKeydown('c') | |
1779 | expect(editor.getCursorScreenPosition()).toEqual [0, 1] | |
1780 | keydown(';') | |
1781 | expect(editor.getCursorScreenPosition()).toEqual [0, 4] | |
1782 | ||
1783 | it "repeat T in same direction", -> | |
1784 | editor.setCursorScreenPosition([0, 10]) | |
1785 | keydown('T', shift: true) | |
1786 | normalModeInputKeydown('c') | |
1787 | expect(editor.getCursorScreenPosition()).toEqual [0, 9] | |
1788 | keydown(';') | |
1789 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1790 | ||
1791 | it "repeat t in opposite direction first, and then reverse", -> | |
1792 | editor.setCursorScreenPosition([0, 3]) | |
1793 | keydown('t') | |
1794 | normalModeInputKeydown('c') | |
1795 | expect(editor.getCursorScreenPosition()).toEqual [0, 4] | |
1796 | keydown(',') | |
1797 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
1798 | keydown(';') | |
1799 | expect(editor.getCursorScreenPosition()).toEqual [0, 4] | |
1800 | ||
1801 | it "repeat T in opposite direction first, and then reverse", -> | |
1802 | editor.setCursorScreenPosition([0, 4]) | |
1803 | keydown('T', shift: true) | |
1804 | normalModeInputKeydown('c') | |
1805 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
1806 | keydown(',') | |
1807 | expect(editor.getCursorScreenPosition()).toEqual [0, 4] | |
1808 | keydown(';') | |
1809 | expect(editor.getCursorScreenPosition()).toEqual [0, 3] | |
1810 | ||
1811 | it "repeat with count in same direction", -> | |
1812 | editor.setCursorScreenPosition([0, 0]) | |
1813 | keydown('f') | |
1814 | normalModeInputKeydown('c') | |
1815 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1816 | keydown('2') | |
1817 | keydown(';') | |
1818 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1819 | ||
1820 | it "repeat with count in reverse direction", -> | |
1821 | editor.setCursorScreenPosition([0, 6]) | |
1822 | keydown('f') | |
1823 | normalModeInputKeydown('c') | |
1824 | expect(editor.getCursorScreenPosition()).toEqual [0, 8] | |
1825 | keydown('2') | |
1826 | keydown(',') | |
1827 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1828 | ||
1829 | it "shares the most recent find/till command with other editors", -> | |
1830 | helpers.getEditorElement (otherEditorElement) -> | |
1831 | otherEditor = otherEditorElement.getModel() | |
1832 | ||
1833 | editor.setText("a baz bar\n") | |
1834 | editor.setCursorScreenPosition([0, 0]) | |
1835 | ||
1836 | otherEditor.setText("foo bar baz") | |
1837 | otherEditor.setCursorScreenPosition([0, 0]) | |
1838 | ||
1839 | # by default keyDown and such go in the usual editor | |
1840 | keydown('f') | |
1841 | normalModeInputKeydown('b') | |
1842 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1843 | expect(otherEditor.getCursorScreenPosition()).toEqual [0, 0] | |
1844 | ||
1845 | # replay same find in the other editor | |
1846 | keydown(';', element: otherEditorElement) | |
1847 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1848 | expect(otherEditor.getCursorScreenPosition()).toEqual [0, 4] | |
1849 | ||
1850 | # do a till in the other editor | |
1851 | keydown('t', element: otherEditorElement) | |
1852 | normalModeInputKeydown('r', editor: otherEditor) | |
1853 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1854 | expect(otherEditor.getCursorScreenPosition()).toEqual [0, 5] | |
1855 | ||
1856 | # and replay in the normal editor | |
1857 | keydown(';') | |
1858 | expect(editor.getCursorScreenPosition()).toEqual [0, 7] | |
1859 | expect(otherEditor.getCursorScreenPosition()).toEqual [0, 5] | |
1860 | expect(atom.beep).not.toHaveBeenCalled() | |
1861 | ||
1862 | describe 'the % motion', -> | |
1863 | beforeEach -> | |
1864 | editor.setText("( ( ) )--{ text in here; and a function call(with parameters) }\n") | |
1865 | editor.setCursorScreenPosition([0, 0]) | |
1866 | ||
1867 | it 'matches the correct parenthesis', -> | |
1868 | keydown('%') | |
1869 | expect(editor.getCursorScreenPosition()).toEqual [0, 6] | |
1870 | ||
1871 | it 'matches the correct brace', -> | |
1872 | editor.setCursorScreenPosition([0, 9]) | |
1873 | keydown('%') | |
1874 | expect(editor.getCursorScreenPosition()).toEqual [0, 62] | |
1875 | ||
1876 | it 'composes correctly with d', -> | |
1877 | editor.setCursorScreenPosition([0, 9]) | |
1878 | keydown('d') | |
1879 | keydown('%') | |
1880 | expect(editor.getText()).toEqual "( ( ) )--\n" | |
1881 | ||
1882 | it 'moves correctly when composed with v going forward', -> | |
1883 | keydown('v') | |
1884 | keydown('h') | |
1885 | keydown('%') | |
1886 | expect(editor.getCursorScreenPosition()).toEqual [0, 7] | |
1887 | ||
1888 | it 'moves correctly when composed with v going backward', -> | |
1889 | editor.setCursorScreenPosition([0, 5]) | |
1890 | keydown('v') | |
1891 | keydown('%') | |
1892 | expect(editor.getCursorScreenPosition()).toEqual [0, 0] | |
1893 | ||
1894 | it 'it moves appropriately to find the nearest matching action', -> | |
1895 | editor.setCursorScreenPosition([0, 3]) | |
1896 | keydown('%') | |
1897 | expect(editor.getCursorScreenPosition()).toEqual [0, 2] | |
1898 | expect(editor.getText()).toEqual "( ( ) )--{ text in here; and a function call(with parameters) }\n" | |
1899 | ||
1900 | it 'it moves appropriately to find the nearest matching action', -> | |
1901 | editor.setCursorScreenPosition([0, 26]) | |
1902 | keydown('%') | |
1903 | expect(editor.getCursorScreenPosition()).toEqual [0, 60] | |
1904 | expect(editor.getText()).toEqual "( ( ) )--{ text in here; and a function call(with parameters) }\n" | |
1905 | ||
1906 | it "finds matches across multiple lines", -> | |
1907 | editor.setText("...(\n...)") | |
1908 | editor.setCursorScreenPosition([0, 0]) | |
1909 | keydown("%") | |
1910 | expect(editor.getCursorScreenPosition()).toEqual([1, 3]) | |
1911 | ||
1912 | it "does not affect search history", -> | |
1913 | keydown('/') | |
1914 | submitNormalModeInputText 'func' | |
1915 | expect(editor.getCursorBufferPosition()).toEqual [0, 31] | |
1916 | keydown('%') | |
1917 | expect(editor.getCursorBufferPosition()).toEqual [0, 60] | |
1918 | keydown('n') | |
1919 | expect(editor.getCursorBufferPosition()).toEqual [0, 31] | |
1920 | ||
1921 | describe "scrolling screen and keeping cursor in the same screen position", -> | |
1922 | beforeEach -> | |
1923 | editor.setText([0...80].join("\n")) | |
1924 | editor.setHeight(20 * 10) | |
1925 | editor.setLineHeightInPixels(10) | |
1926 | editor.setScrollTop(40 * 10) | |
1927 | editor.setCursorBufferPosition([42, 0]) | |
1928 | ||
1929 | describe "the ctrl-u keybinding", -> | |
1930 | it "moves the screen down by half screen size and keeps cursor onscreen", -> | |
1931 | keydown('u', ctrl: true) | |
1932 | expect(editor.getScrollTop()).toEqual 300 | |
1933 | expect(editor.getCursorBufferPosition()).toEqual [32, 0] | |
1934 | ||
1935 | it "selects on visual mode", -> | |
1936 | editor.setCursorBufferPosition([42, 1]) | |
1937 | vimState.activateVisualMode() | |
1938 | keydown('u', ctrl: true) | |
1939 | expect(editor.getSelectedText()).toEqual [32..42].join("\n") | |
1940 | ||
1941 | it "selects on linewise mode", -> | |
1942 | vimState.activateVisualMode('linewise') | |
1943 | keydown('u', ctrl: true) | |
1944 | expect(editor.getSelectedText()).toEqual [32..42].join("\n").concat("\n") | |
1945 | ||
1946 | describe "the ctrl-b keybinding", -> | |
1947 | it "moves screen up one page", -> | |
1948 | keydown('b', ctrl: true) | |
1949 | expect(editor.getScrollTop()).toEqual 200 | |
1950 | expect(editor.getCursorScreenPosition()).toEqual [22, 0] | |
1951 | ||
1952 | it "selects on visual mode", -> | |
1953 | editor.setCursorBufferPosition([42, 1]) | |
1954 | vimState.activateVisualMode() | |
1955 | keydown('b', ctrl: true) | |
1956 | expect(editor.getSelectedText()).toEqual [22..42].join("\n") | |
1957 | ||
1958 | it "selects on linewise mode", -> | |
1959 | vimState.activateVisualMode('linewise') | |
1960 | keydown('b', ctrl: true) | |
1961 | expect(editor.getSelectedText()).toEqual [22..42].join("\n").concat("\n") | |
1962 | ||
1963 | ||
1964 | describe "the ctrl-d keybinding", -> | |
1965 | it "moves the screen down by half screen size and keeps cursor onscreen", -> | |
1966 | keydown('d', ctrl: true) | |
1967 | expect(editor.getScrollTop()).toEqual 500 | |
1968 | expect(editor.getCursorBufferPosition()).toEqual [52, 0] | |
1969 | ||
1970 | it "selects on visual mode", -> | |
1971 | editor.setCursorBufferPosition([42, 1]) | |
1972 | vimState.activateVisualMode() | |
1973 | keydown('d', ctrl: true) | |
1974 | expect(editor.getSelectedText()).toEqual [42..52].join("\n").slice(1, -1) | |
1975 | ||
1976 | it "selects on linewise mode", -> | |
1977 | vimState.activateVisualMode('linewise') | |
1978 | keydown('d', ctrl: true) | |
1979 | expect(editor.getSelectedText()).toEqual [42..52].join("\n").concat("\n") | |
1980 | ||
1981 | describe "the ctrl-f keybinding", -> | |
1982 | it "moves screen down one page", -> | |
1983 | keydown('f', ctrl: true) | |
1984 | expect(editor.getScrollTop()).toEqual 600 | |
1985 | expect(editor.getCursorScreenPosition()).toEqual [62, 0] | |
1986 | ||
1987 | it "selects on visual mode", -> | |
1988 | editor.setCursorBufferPosition([42, 1]) | |
1989 | vimState.activateVisualMode() | |
1990 | keydown('f', ctrl: true) | |
1991 | expect(editor.getSelectedText()).toEqual [42..62].join("\n").slice(1, -1) | |
1992 | ||
1993 | it "selects on linewise mode", -> | |
1994 | vimState.activateVisualMode('linewise') | |
1995 | keydown('f', ctrl: true) | |
1996 | expect(editor.getSelectedText()).toEqual [42..62].join("\n").concat("\n") |