]> git.madduck.net Git - etc/vim.git/blob - spec/indent/indent_spec.rb

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Revert "Improve s:find_start_of_multiline_statement: only look for round parens"...
[etc/vim.git] / spec / indent / indent_spec.rb
1 require "spec_helper"
2
3 shared_examples_for "vim" do
4
5   before(:each) {
6     # clear buffer
7     vim.normal 'gg"_dG'
8
9     # Insert two blank lines.
10     # The first line is a corner case in this plugin that would shadow the
11     # correct behaviour of other tests. Thus we explicitly jump to the first
12     # line when we require so.
13     vim.feedkeys 'i\<CR>\<CR>\<ESC>'
14   }
15
16   describe "when using the indent plugin" do
17     it "sets the indentexpr and indentkeys options" do
18       vim.command("set indentexpr?").should include "GetPythonPEPIndent("
19       vim.command("set indentkeys?").should include "=elif"
20     end
21
22     it "sets autoindent and expandtab" do
23       vim.command("set autoindent?").should match(/\s*autoindent/)
24       vim.command("set expandtab?").should match(/\s*expandtab/)
25     end
26   end
27
28   describe "when entering the first line" do
29     before { vim.feedkeys '0ggipass' }
30
31     it "does not indent" do
32       indent.should == 0
33       proposed_indent.should == 0
34     end
35
36     it "does not indent when using '=='" do
37       vim.normal "=="
38       indent.should == 0
39     end
40   end
41
42   describe "when after a '(' that is at the end of its line" do
43     before { vim.feedkeys 'itest(\<CR>' }
44
45     it "indents by one level" do
46       proposed_indent.should == shiftwidth
47       vim.feedkeys 'something'
48       indent.should == shiftwidth
49       vim.normal '=='
50       indent.should == shiftwidth
51     end
52
53     it "puts the closing parenthesis at the same level" do
54       vim.feedkeys ')'
55       indent.should == 0
56     end
57   end
58
59   describe "when after an '(' that is followed by something" do
60     before { vim.feedkeys 'itest(something,\<CR>' }
61
62     it "lines up on following lines" do
63       indent.should == 5
64       vim.feedkeys 'more,\<CR>'
65       indent.should == 5
66     end
67
68     it "lines up the closing parenthesis" do
69       vim.feedkeys ')'
70       indent.should == 5
71     end
72
73     it "does not touch the closing parenthesis if it is already indented further" do
74       vim.feedkeys '  )'
75       indent.should == 7
76     end
77   end
78
79   describe "when after an '{' that is followed by a comment" do
80     before { vim.feedkeys 'imydict = {  # comment\<CR>' }
81
82     it "indent by one level" do
83       indent.should == shiftwidth
84       vim.feedkeys '1: 1,\<CR>'
85       indent.should == shiftwidth
86     end
87
88     it "lines up the closing parenthesis" do
89       vim.feedkeys '}'
90       indent.should == 0
91     end
92   end
93
94   describe "when using gq to reindent a '(' that is" do
95     before { vim.feedkeys 'itest(' }
96     it "something and has a string without spaces at the end" do
97       vim.feedkeys 'something_very_long_blaaaaaaaaa, "some_very_long_string_blaaaaaaaaaaaaaaaaaaaa"\<esc>gqq'
98       indent.should == 5
99     end
100   end
101
102   describe "when after multiple parens of different types" do
103     it "indents by one level" do
104       vim.feedkeys 'if({\<CR>'
105       indent.should == shiftwidth
106     end
107
108     it "lines up with the last paren" do
109       vim.feedkeys 'ifff({123: 456,\<CR>'
110       indent.should == 5
111     end
112   end
113
114   describe "when '#' is contained in a string that is followed by a colon" do
115     it "indents by one level" do
116         vim.feedkeys 'iif "some#thing" == "test":#test\<CR>pass'
117         indent.should == shiftwidth
118     end
119   end
120
121   describe "when '#' is not contained in a string and is followed by a colon" do
122     it "does not indent" do
123         vim.feedkeys 'iif "some#thing" == "test"#:test\<CR>'
124         indent.should == 0
125     end
126   end
127
128   describe "when inside an unfinished string" do
129     it "does not indent" do
130       vim.feedkeys 'i"test:\<ESC>'
131       vim.echo('synIDattr(synID(line("."), col("."), 0), "name")'
132               ).downcase.should include 'string'
133       vim.feedkeys 'a\<CR>'
134       proposed_indent.should == 0
135       indent.should == 0
136     end
137
138     it "does not dedent" do
139       vim.feedkeys 'iif True:\<CR>"test:\<ESC>'
140       vim.echo('synIDattr(synID(line("."), col("."), 0), "name")'
141               ).downcase.should include 'string'
142       proposed_indent.should == shiftwidth
143       indent.should == shiftwidth
144     end
145   end
146
147   describe "when the previous line has a colon in a string" do
148     before { vim.feedkeys 'itest(":".join(["1","2"]))\<CR>' }
149     it "does not indent" do
150       vim.feedkeys 'if True:'
151       indent.should == 0
152       proposed_indent.should == 0
153     end
154   end
155
156   describe "when the previous line has a list slice" do
157     it "does not indent" do
158       vim.feedkeys 'ib = a[2:]\<CR>'
159       indent.should == 0
160       proposed_indent.should == 0
161     end
162   end
163
164   describe "when line is empty inside a block" do
165     it "is indented like the previous line" do
166       vim.feedkeys 'idef a():\<CR>1\<CR>\<CR>2\<ESC>kcc'
167       indent.should == shiftwidth
168     end
169   end
170
171   describe "when an empty line is after empty line / before non-empty" do
172     it "is indented like the next line" do
173       vim.feedkeys 'idef a():\<CR>1\<CR>\<CR>\<CR>2\<ESC><<kcc'
174       indent.should == 0
175     end
176   end
177
178   describe "when an empty line is after empty line / before non-empty (nested)" do
179     it "is indented like the next line" do
180       vim.feedkeys 'idef a():\<CR>1\<CR>\<CR>\<CR>\<ESC>0i\<TAB>2\<ESC>kcc'
181       indent.should == shiftwidth
182     end
183   end
184
185   describe "when line is empty inside a block following multi-line statement" do
186     it "is indented like the previous line" do
187       vim.feedkeys 'idef a():\<CR>x = (1 +\<CR>2)\<CR>\<CR>y\<ESC>kcc'
188       indent.should == shiftwidth
189     end
190   end
191
192   describe "when line is empty inside a block following stop statement" do
193     it "is indented like the previous line minus shiftwidth" do
194       vim.feedkeys 'iif x:\<CR>if y:\<CR>pass\<CR>\<CR>z\<ESC>kcc'
195       indent.should == shiftwidth
196     end
197   end
198
199   describe "when using simple control structures" do
200       it "indents shiftwidth spaces" do
201           vim.feedkeys 'iwhile True:\<CR>pass'
202           indent.should == shiftwidth
203       end
204   end
205
206   describe "when using a function definition" do
207       it "indents shiftwidth spaces" do
208           vim.feedkeys 'idef long_function_name(\<CR>arg'
209           indent.should == shiftwidth * 2
210       end
211   end
212
213   describe "when using a class definition" do
214       it "indents shiftwidth spaces" do
215           vim.feedkeys 'iclass Foo(\<CR>'
216           indent.should == shiftwidth * 2
217       end
218   end
219
220   describe "when writing an 'else' block" do
221     it "aligns to the preceeding 'for' block" do
222       vim.feedkeys 'ifor x in "abc":\<CR>pass\<CR>else:'
223       indent.should == 0
224     end
225
226     it "aligns to the preceeding 'if' block" do
227       vim.feedkeys 'ifor x in "abc":\<CR>if True:\<CR>pass\<CR>else:'
228       indent.should == shiftwidth
229     end
230   end
231
232   describe "when using parens and control statements" do
233     it "avoids ambiguity by using extra indentation" do
234       vim.feedkeys 'iif (111 and\<CR>'
235       if shiftwidth == 4
236         indent.should == shiftwidth * 2
237       else
238         indent.should == 4
239       end
240       vim.feedkeys '222):\<CR>'
241       indent.should == shiftwidth
242       vim.feedkeys 'pass\<CR>'
243       indent.should == 0
244     end
245
246     it "still aligns parens properly if not ambiguous" do
247       vim.feedkeys 'iwhile (111 and\<CR>'
248       indent.should == 7
249       vim.feedkeys '222):\<CR>'
250       indent.should == shiftwidth
251       vim.feedkeys 'pass\<CR>'
252       indent.should == 0
253     end
254
255     it "still handles multiple parens correctly" do
256       vim.feedkeys 'iif (111 and (222 and 333\<CR>'
257       indent.should == 13
258       vim.feedkeys 'and 444\<CR>'
259       indent.should == 13
260       vim.feedkeys ')\<CR>'
261       if shiftwidth == 4
262         indent.should == shiftwidth * 2
263       else
264         indent.should == 4
265       end
266       vim.feedkeys 'and 555):\<CR>'
267       indent.should == shiftwidth
268       vim.feedkeys 'pass\<CR>'
269       indent.should == 0
270     end
271   end
272
273   describe "when a line breaks with a manual '\\'" do
274     it "indents shiftwidth spaces on normal line" do
275         vim.feedkeys 'ivalue = test + \\\\\<CR>'
276         indent.should == shiftwidth
277     end
278
279     it "indents 2x shiftwidth spaces for control structures" do
280         vim.feedkeys 'iif somevalue == xyz and \\\\\<CR>'
281         indent.should == shiftwidth * 2
282     end
283
284     it "indents relative to line above" do
285         vim.feedkeys 'i\<TAB>value = test + \\\\\<CR>'
286         indent.should == shiftwidth * 2
287     end
288   end
289
290   describe "when current line is dedented compared to previous line" do
291      before { vim.feedkeys 'i\<TAB>\<TAB>if x:\<CR>y = True\<CR>\<ESC>' }
292      it "and current line has a valid indentation (Part 1)" do
293         vim.feedkeys '0i\<TAB>if y:'
294         proposed_indent.should == -1
295      end
296
297      it "and current line has a valid indentation (Part 2)" do
298         vim.feedkeys '0i\<TAB>\<TAB>if y:'
299         proposed_indent.should == -1
300      end
301
302      it "and current line has an invalid indentation" do
303         vim.feedkeys 'i    while True:\<CR>'
304         indent.should == previous_indent + shiftwidth
305      end
306   end
307
308   describe "when current line is dedented compared to the last non-empty line" do
309      before { vim.feedkeys 'i\<TAB>\<TAB>if x:\<CR>y = True\<CR>\<CR>\<ESC>' }
310      it "and current line has a valid indentation" do
311         vim.feedkeys '0i\<TAB>if y:'
312         proposed_indent.should == -1
313      end
314   end
315
316   describe "when an 'if' is followed by" do
317      before { vim.feedkeys 'i\<TAB>\<TAB>if x:\<CR>' }
318      it "an elif, it lines up with the 'if'" do
319         vim.feedkeys 'elif y:'
320         indent.should == shiftwidth * 2
321      end
322
323      it "an 'else', it lines up with the 'if'" do
324         vim.feedkeys 'else:'
325         indent.should == shiftwidth * 2
326      end
327   end
328
329   describe "when an 'if' contains a try-except" do
330      before {
331        vim.feedkeys 'iif x:\<CR>try:\<CR>pass\<CR>except:\<CR>pass\<CR>'
332        indent.should == shiftwidth
333      }
334      it "an 'else' should be indented to the try" do
335        vim.feedkeys 'else:'
336        indent.should == shiftwidth
337        proposed_indent.should == shiftwidth
338      end
339      it "an 'else' should keep the indent of the 'if'" do
340        vim.feedkeys 'else:\<ESC><<'
341        indent.should == 0
342        proposed_indent.should == 0
343      end
344   end
345
346   describe "when a 'for' is followed by" do
347      before { vim.feedkeys 'i\<TAB>\<TAB>for x in y:\<CR>' }
348      it "an 'else', it lines up with the 'for'" do
349         vim.feedkeys 'else:'
350         indent.should == shiftwidth * 2
351      end
352   end
353
354   describe "when an 'else' is followed by" do
355      before { vim.feedkeys 'i\<TAB>\<TAB>else:\<CR>XXX\<CR>' }
356      it "a 'finally', it lines up with the 'else'" do
357         vim.feedkeys 'finally:'
358         indent.should == shiftwidth * 2
359      end
360   end
361
362
363   describe "when a 'try' is followed by" do
364      before { vim.feedkeys 'i\<TAB>\<TAB>try:\<CR>' }
365      it "an 'except', it lines up with the 'try'" do
366         vim.feedkeys 'except:'
367         indent.should == shiftwidth * 2
368      end
369
370      it "an 'else', it lines up with the 'try'" do
371         vim.feedkeys 'else:'
372         indent.should == shiftwidth * 2
373      end
374
375      it "a 'finally', it lines up with the 'try'" do
376         vim.feedkeys 'finally:'
377         indent.should == shiftwidth * 2
378      end
379   end
380
381   describe "when an 'except' is followed by" do
382      before { vim.feedkeys 'i\<TAB>\<TAB>except:\<CR>' }
383      it "an 'else', it lines up with the 'except'" do
384         vim.feedkeys 'else:'
385         indent.should == shiftwidth * 2
386      end
387
388      it "another 'except', it lines up with the previous 'except'" do
389         vim.feedkeys 'except:'
390         indent.should == shiftwidth * 2
391      end
392
393      it "a 'finally', it lines up with the 'except'" do
394         vim.feedkeys 'finally:'
395         indent.should == shiftwidth * 2
396      end
397   end
398
399   describe "when an else is used inside of a nested if" do
400     before { vim.feedkeys 'iif foo:\<CR>\<TAB>if bar:\<CR>\<TAB>\<TAB>pass\<CR>' }
401     it "indents an else to the inner if" do
402       vim.feedkeys 'else:'
403       indent.should == shiftwidth * 2
404     end
405   end
406
407   describe "when jedi-vim call signatures are used" do
408     before { vim.command 'syn match jediFunction "JEDI_CALL_SIGNATURE" keepend extend' }
409
410     it "ignores the call signature after a colon" do
411       vim.feedkeys 'iif True:  JEDI_CALL_SIGNATURE\<CR>'
412       indent.should == shiftwidth
413     end
414
415     it "ignores the call signature after a function" do
416       vim.feedkeys 'idef f(  JEDI_CALL_SIGNATURE\<CR>'
417       indent.should == shiftwidth * 2
418     end
419   end
420 end
421
422 shared_examples_for "multiline strings" do
423   before(:each) {
424     # clear buffer
425     vim.normal 'gg"_dG'
426
427     # Insert two blank lines.
428     # The first line is a corner case in this plugin that would shadow the
429     # correct behaviour of other tests. Thus we explicitly jump to the first
430     # line when we require so.
431     vim.feedkeys 'i\<CR>\<CR>\<ESC>'
432   }
433
434   describe "when after an '(' that is followed by an unfinished string" do
435     before { vim.feedkeys 'itest("""' }
436
437     it "it indents the next line" do
438       vim.feedkeys '\<CR>'
439       expected_proposed, expected_indent = multiline_indent(0, shiftwidth)
440       proposed_indent.should == expected_proposed
441       indent.should == expected_indent
442     end
443
444     it "with contents it indents the second line to the parenthesis" do
445       vim.feedkeys 'second line\<CR>'
446       expected_proposed, expected_indent = multiline_indent(0, 5)
447       proposed_indent.should == expected_proposed
448       indent.should == expected_indent
449     end
450   end
451
452   describe "when after assigning an unfinished string" do
453     before { vim.feedkeys 'itest = """' }
454
455     it "it indents the next line" do
456       vim.feedkeys '\<CR>'
457       expected_proposed, expected_indent = multiline_indent(0, shiftwidth)
458       proposed_indent.should == expected_proposed
459       indent.should == expected_indent
460     end
461   end
462
463   describe "when after assigning an unfinished string" do
464     before { vim.feedkeys 'i    test = """' }
465
466     it "it indents the next line" do
467       vim.feedkeys '\<CR>'
468       expected_proposed, expected_indent = multiline_indent(4, shiftwidth + 4)
469       proposed_indent.should == expected_proposed
470       indent.should == expected_indent
471     end
472   end
473
474   describe "when after assigning a finished string" do
475     before { vim.feedkeys 'i    test = ""' }
476
477     it "it does indent the next line" do
478       vim.feedkeys '\<CR>'
479       indent.should == 4
480     end
481
482     it "and writing a new string, it does indent the next line" do
483       vim.feedkeys '\<CR>""'
484       indent.should == 4
485     end
486   end
487
488   describe "when after a docstring" do
489     before { vim.feedkeys 'i    """' }
490     it "it does indent the next line to the docstring" do
491       vim.feedkeys '\<CR>'
492       indent.should == 4
493       proposed_indent.should == 4
494     end
495   end
496
497   describe "when after a docstring with contents" do
498     before { vim.feedkeys 'i    """First line' }
499     it "it does indent the next line to the docstring" do
500       vim.feedkeys '\<CR>'
501       indent.should == 4
502       proposed_indent.should == 4
503     end
504   end
505
506   describe "when breaking a string after opening parenthesis" do
507     before { vim.feedkeys 'i    foo("""bar<Left><Left><Left>' }
508     it "it does indent the next line as after an opening multistring" do
509       vim.feedkeys '\<CR>'
510       expected_proposed, expected_indent = multiline_indent(4, 4 + shiftwidth)
511       indent.should == expected_indent
512       proposed_indent.should == expected_proposed
513     end
514   end
515 end
516
517 describe "vim when using width of 4" do
518   before {
519     vim.command("set sw=4 ts=4 sts=4 et")
520   }
521   it_behaves_like "vim"
522 end
523
524 describe "vim when using width of 3" do
525   before {
526     vim.command("set sw=3 ts=3 sts=3 et")
527   }
528   it_behaves_like "vim"
529 end
530
531 describe "vim when not using python_pep8_indent_multiline_string" do
532   before {
533     vim.command("set sw=4 ts=4 sts=4 et")
534     vim.command("unlet! g:python_pep8_indent_multiline_string")
535   }
536   it_behaves_like "multiline strings"
537 end
538
539 describe "vim when using python_pep8_indent_multiline_first=0" do
540   before {
541     vim.command("set sw=4 ts=4 sts=4 et")
542     vim.command("let g:python_pep8_indent_multiline_string=0")
543   }
544   it_behaves_like "multiline strings"
545 end
546
547 describe "vim when using python_pep8_indent_multiline_string=-1" do
548   before {
549     vim.command("set sw=4 ts=4 sts=4 et")
550     vim.command("let g:python_pep8_indent_multiline_string=-1")
551   }
552   it_behaves_like "multiline strings"
553 end
554
555 describe "vim when using python_pep8_indent_multiline_string=-2" do
556   before {
557     vim.command("set sw=4 ts=4 sts=4 et")
558     vim.command("let g:python_pep8_indent_multiline_string=-2")
559   }
560   it_behaves_like "multiline strings"
561 end
562
563 describe "vim for cython" do
564   before {
565     vim.command "enew"
566     vim.command "set ft=cython"
567     vim.command "runtime indent/python.vim"
568
569     # Insert two blank lines.
570     # The first line is a corner case in this plugin that would shadow the
571     # correct behaviour of other tests. Thus we explicitly jump to the first
572     # line when we require so.
573     vim.feedkeys 'i\<CR>\<CR>\<ESC>'
574   }
575
576   describe "when using a cdef function definition" do
577       it "indents shiftwidth spaces" do
578           vim.feedkeys 'icdef long_function_name(\<CR>arg'
579           indent.should == shiftwidth * 2
580       end
581   end
582
583   describe "when using a cpdef function definition" do
584       it "indents shiftwidth spaces" do
585           vim.feedkeys 'icpdef long_function_name(\<CR>arg'
586           indent.should == shiftwidth * 2
587       end
588   end
589 end
590
591 describe "Handles far away opening parens" do
592   before { vim.feedkeys '\<ESC>ggdGifrom foo import (' }
593
594   it "indents by one level" do
595     vim.feedkeys '\<CR>'
596     proposed_indent.should == shiftwidth
597   end
598
599   it "indents by one level for 10 lines" do
600     vim.command('set paste | exe "norm 9o" | set nopaste')
601     vim.feedkeys '\<Esc>o'
602     indent.should == shiftwidth
603   end
604
605   it "indents by one level for 50 lines" do
606     vim.command('set paste | exe "norm 49o" | set nopaste')
607     vim.feedkeys '\<Esc>o'
608     indent.should == shiftwidth
609   end
610 end
611
612 describe "Handles far away opening square brackets" do
613   before { vim.feedkeys '\<ESC>ggdGibar = [' }
614
615   it "indents by one level" do
616     vim.feedkeys '\<CR>'
617     proposed_indent.should == shiftwidth
618   end
619
620   it "indents by one level for 10 lines" do
621     vim.command('set paste | exe "norm 9o" | set nopaste')
622     vim.feedkeys '\<Esc>o'
623     indent.should == shiftwidth
624   end
625
626   it "indents by one level for 100 lines" do
627     vim.command('set paste | exe "norm 99o" | set nopaste')
628     vim.feedkeys '\<Esc>o'
629     indent.should == shiftwidth
630   end
631 end
632
633 describe "Handles far away opening curly brackets" do
634   before { vim.feedkeys '\<ESC>ggdGijson = {' }
635
636   it "indents by one level" do
637     vim.feedkeys '\<CR>'
638     vim.feedkeys '\<Esc>o'
639     proposed_indent.should == shiftwidth
640   end
641
642   it "indents by one level for 10 lines" do
643     vim.command('set paste | exe "norm 9o" | set nopaste')
644     vim.feedkeys '\<Esc>o'
645     indent.should == shiftwidth
646   end
647
648   it "indents by one level for 1000 lines" do
649     vim.command('set paste | exe "norm 999o" | set nopaste')
650     vim.feedkeys '\<Esc>o'
651     indent.should == shiftwidth
652   end
653 end
654
655 describe "Compact multiline dict" do
656   before { vim.feedkeys '\<ESC>ggdGid = {"one": 1,' }
657
658   it "gets indented correctly" do
659     vim.feedkeys '\<CR>'
660     proposed_indent.should == 5
661
662     vim.feedkeys '"two": 2}'
663     proposed_indent.should == 5
664
665     vim.feedkeys '\<CR>'
666     proposed_indent.should == 0
667   end
668 end