]> 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:

85bc04b21974508abe352c6c8e65496b3b258feb
[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 line is empty inside a block following multi-line statement" do
172     it "is indented like the previous line" do
173       vim.feedkeys 'idef a():\<CR>x = (1 +\<CR>2)\<CR>\<CR>y\<ESC>kcc'
174       indent.should == shiftwidth
175     end
176   end
177
178   describe "when line is empty inside a block following stop statement" do
179     it "is indented like the previous line minus shiftwidth" do
180       vim.feedkeys 'iif x:\<CR>if y:\<CR>pass\<CR>\<CR>z\<ESC>kcc'
181       indent.should == shiftwidth
182     end
183   end
184
185   describe "when using simple control structures" do
186       it "indents shiftwidth spaces" do
187           vim.feedkeys 'iwhile True:\<CR>pass'
188           indent.should == shiftwidth
189       end
190   end
191
192   describe "when using a function definition" do
193       it "indents shiftwidth spaces" do
194           vim.feedkeys 'idef long_function_name(\<CR>arg'
195           indent.should == shiftwidth * 2
196       end
197   end
198
199   describe "when using a class definition" do
200       it "indents shiftwidth spaces" do
201           vim.feedkeys 'iclass Foo(\<CR>'
202           indent.should == shiftwidth * 2
203       end
204   end
205
206   describe "when writing an 'else' block" do
207     it "aligns to the preceeding 'for' block" do
208       vim.feedkeys 'ifor x in "abc":\<CR>pass\<CR>else:'
209       indent.should == 0
210     end
211
212     it "aligns to the preceeding 'if' block" do
213       vim.feedkeys 'ifor x in "abc":\<CR>if True:\<CR>pass\<CR>else:'
214       indent.should == shiftwidth
215     end
216   end
217
218   describe "when using parens and control statements" do
219     it "avoids ambiguity by using extra indentation" do
220       vim.feedkeys 'iif (111 and\<CR>'
221       if shiftwidth == 4
222         indent.should == shiftwidth * 2
223       else
224         indent.should == 4
225       end
226       vim.feedkeys '222):\<CR>'
227       indent.should == shiftwidth
228       vim.feedkeys 'pass\<CR>'
229       indent.should == 0
230     end
231
232     it "still aligns parens properly if not ambiguous" do
233       vim.feedkeys 'iwhile (111 and\<CR>'
234       indent.should == 7
235       vim.feedkeys '222):\<CR>'
236       indent.should == shiftwidth
237       vim.feedkeys 'pass\<CR>'
238       indent.should == 0
239     end
240
241     it "still handles multiple parens correctly" do
242       vim.feedkeys 'iif (111 and (222 and 333\<CR>'
243       indent.should == 13
244       vim.feedkeys 'and 444\<CR>'
245       indent.should == 13
246       vim.feedkeys ')\<CR>'
247       if shiftwidth == 4
248         indent.should == shiftwidth * 2
249       else
250         indent.should == 4
251       end
252       vim.feedkeys 'and 555):\<CR>'
253       indent.should == shiftwidth
254       vim.feedkeys 'pass\<CR>'
255       indent.should == 0
256     end
257   end
258
259   describe "when a line breaks with a manual '\\'" do
260     it "indents shiftwidth spaces on normal line" do
261         vim.feedkeys 'ivalue = test + \\\\\<CR>'
262         indent.should == shiftwidth
263     end
264
265     it "indents 2x shiftwidth spaces for control structures" do
266         vim.feedkeys 'iif somevalue == xyz and \\\\\<CR>'
267         indent.should == shiftwidth * 2
268     end
269
270     it "indents relative to line above" do
271         vim.feedkeys 'i\<TAB>value = test + \\\\\<CR>'
272         indent.should == shiftwidth * 2
273     end
274   end
275
276   describe "when current line is dedented compared to previous line" do
277      before { vim.feedkeys 'i\<TAB>\<TAB>if x:\<CR>y = True\<CR>\<ESC>' }
278      it "and current line has a valid indentation (Part 1)" do
279         vim.feedkeys '0i\<TAB>if y:'
280         proposed_indent.should == -1
281      end
282
283      it "and current line has a valid indentation (Part 2)" do
284         vim.feedkeys '0i\<TAB>\<TAB>if y:'
285         proposed_indent.should == -1
286      end
287
288      it "and current line has an invalid indentation" do
289         vim.feedkeys 'i    while True:\<CR>'
290         indent.should == previous_indent + shiftwidth
291      end
292   end
293
294   describe "when current line is dedented compared to the last non-empty line" do
295      before { vim.feedkeys 'i\<TAB>\<TAB>if x:\<CR>y = True\<CR>\<CR>\<ESC>' }
296      it "and current line has a valid indentation" do
297         vim.feedkeys '0i\<TAB>if y:'
298         proposed_indent.should == -1
299      end
300   end
301
302   describe "when an 'if' is followed by" do
303      before { vim.feedkeys 'i\<TAB>\<TAB>if x:\<CR>' }
304      it "an elif, it lines up with the 'if'" do
305         vim.feedkeys 'elif y:'
306         indent.should == shiftwidth * 2
307      end
308
309      it "an 'else', it lines up with the 'if'" do
310         vim.feedkeys 'else:'
311         indent.should == shiftwidth * 2
312      end
313   end
314
315   describe "when an 'if' contains a try-except" do
316      before {
317        vim.feedkeys 'iif x:\<CR>try:\<CR>pass\<CR>except:\<CR>pass\<CR>'
318        indent.should == shiftwidth
319      }
320      it "an 'else' should be indented to the try" do
321        vim.feedkeys 'else:'
322        indent.should == shiftwidth
323        proposed_indent.should == shiftwidth
324      end
325      it "an 'else' should keep the indent of the 'if'" do
326        vim.feedkeys 'else:\<ESC><<'
327        indent.should == 0
328        proposed_indent.should == 0
329      end
330   end
331
332   describe "when a 'for' is followed by" do
333      before { vim.feedkeys 'i\<TAB>\<TAB>for x in y:\<CR>' }
334      it "an 'else', it lines up with the 'for'" do
335         vim.feedkeys 'else:'
336         indent.should == shiftwidth * 2
337      end
338   end
339
340   describe "when an 'else' is followed by" do
341      before { vim.feedkeys 'i\<TAB>\<TAB>else:\<CR>XXX\<CR>' }
342      it "a 'finally', it lines up with the 'else'" do
343         vim.feedkeys 'finally:'
344         indent.should == shiftwidth * 2
345      end
346   end
347
348
349   describe "when a 'try' is followed by" do
350      before { vim.feedkeys 'i\<TAB>\<TAB>try:\<CR>' }
351      it "an 'except', it lines up with the 'try'" do
352         vim.feedkeys 'except:'
353         indent.should == shiftwidth * 2
354      end
355
356      it "an 'else', it lines up with the 'try'" do
357         vim.feedkeys 'else:'
358         indent.should == shiftwidth * 2
359      end
360
361      it "a 'finally', it lines up with the 'try'" do
362         vim.feedkeys 'finally:'
363         indent.should == shiftwidth * 2
364      end
365   end
366
367   describe "when an 'except' is followed by" do
368      before { vim.feedkeys 'i\<TAB>\<TAB>except:\<CR>' }
369      it "an 'else', it lines up with the 'except'" do
370         vim.feedkeys 'else:'
371         indent.should == shiftwidth * 2
372      end
373
374      it "another 'except', it lines up with the previous 'except'" do
375         vim.feedkeys 'except:'
376         indent.should == shiftwidth * 2
377      end
378
379      it "a 'finally', it lines up with the 'except'" do
380         vim.feedkeys 'finally:'
381         indent.should == shiftwidth * 2
382      end
383   end
384
385   describe "when an else is used inside of a nested if" do
386     before { vim.feedkeys 'iif foo:\<CR>\<TAB>if bar:\<CR>\<TAB>\<TAB>pass\<CR>' }
387     it "indents an else to the inner if" do
388       vim.feedkeys 'else:'
389       indent.should == shiftwidth * 2
390     end
391   end
392
393   describe "when jedi-vim call signatures are used" do
394     before { vim.command 'syn match jediFunction "JEDI_CALL_SIGNATURE" keepend extend' }
395
396     it "ignores the call signature after a colon" do
397       vim.feedkeys 'iif True:  JEDI_CALL_SIGNATURE\<CR>'
398       indent.should == shiftwidth
399     end
400
401     it "ignores the call signature after a function" do
402       vim.feedkeys 'idef f(  JEDI_CALL_SIGNATURE\<CR>'
403       indent.should == shiftwidth * 2
404     end
405   end
406 end
407
408 shared_examples_for "multiline strings" do
409   before(:each) {
410     # clear buffer
411     vim.normal 'gg"_dG'
412
413     # Insert two blank lines.
414     # The first line is a corner case in this plugin that would shadow the
415     # correct behaviour of other tests. Thus we explicitly jump to the first
416     # line when we require so.
417     vim.feedkeys 'i\<CR>\<CR>\<ESC>'
418   }
419
420   describe "when after an '(' that is followed by an unfinished string" do
421     before { vim.feedkeys 'itest("""' }
422
423     it "it indents the next line" do
424       vim.feedkeys '\<CR>'
425       expected_proposed, expected_indent = multiline_indent(0, shiftwidth)
426       proposed_indent.should == expected_proposed
427       indent.should == expected_indent
428     end
429
430     it "with contents it indents the second line to the parenthesis" do
431       vim.feedkeys 'second line\<CR>'
432       expected_proposed, expected_indent = multiline_indent(0, 5)
433       proposed_indent.should == expected_proposed
434       indent.should == expected_indent
435     end
436   end
437
438   describe "when after assigning an unfinished string" do
439     before { vim.feedkeys 'itest = """' }
440
441     it "it indents the next line" do
442       vim.feedkeys '\<CR>'
443       expected_proposed, expected_indent = multiline_indent(0, shiftwidth)
444       proposed_indent.should == expected_proposed
445       indent.should == expected_indent
446     end
447   end
448
449   describe "when after assigning an unfinished string" do
450     before { vim.feedkeys 'i    test = """' }
451
452     it "it indents the next line" do
453       vim.feedkeys '\<CR>'
454       expected_proposed, expected_indent = multiline_indent(4, shiftwidth + 4)
455       proposed_indent.should == expected_proposed
456       indent.should == expected_indent
457     end
458   end
459
460   describe "when after assigning a finished string" do
461     before { vim.feedkeys 'i    test = ""' }
462
463     it "it does indent the next line" do
464       vim.feedkeys '\<CR>'
465       indent.should == 4
466     end
467
468     it "and writing a new string, it does indent the next line" do
469       vim.feedkeys '\<CR>""'
470       indent.should == 4
471     end
472   end
473
474   describe "when after a docstring" do
475     before { vim.feedkeys 'i    """' }
476     it "it does indent the next line to the docstring" do
477       vim.feedkeys '\<CR>'
478       indent.should == 4
479       proposed_indent.should == 4
480     end
481   end
482
483   describe "when after a docstring with contents" do
484     before { vim.feedkeys 'i    """First line' }
485     it "it does indent the next line to the docstring" do
486       vim.feedkeys '\<CR>'
487       indent.should == 4
488       proposed_indent.should == 4
489     end
490   end
491
492   describe "when breaking a string after opening parenthesis" do
493     before { vim.feedkeys 'i    foo("""bar<Left><Left><Left>' }
494     it "it does indent the next line as after an opening multistring" do
495       vim.feedkeys '\<CR>'
496       expected_proposed, expected_indent = multiline_indent(4, 4 + shiftwidth)
497       indent.should == expected_indent
498       proposed_indent.should == expected_proposed
499     end
500   end
501 end
502
503 describe "vim when using width of 4" do
504   before {
505     vim.command("set sw=4 ts=4 sts=4 et")
506   }
507   it_behaves_like "vim"
508 end
509
510 describe "vim when using width of 3" do
511   before {
512     vim.command("set sw=3 ts=3 sts=3 et")
513   }
514   it_behaves_like "vim"
515 end
516
517 describe "vim when not using python_pep8_indent_multiline_string" do
518   before {
519     vim.command("set sw=4 ts=4 sts=4 et")
520     vim.command("unlet! g:python_pep8_indent_multiline_string")
521   }
522   it_behaves_like "multiline strings"
523 end
524
525 describe "vim when using python_pep8_indent_multiline_first=0" do
526   before {
527     vim.command("set sw=4 ts=4 sts=4 et")
528     vim.command("let g:python_pep8_indent_multiline_string=0")
529   }
530   it_behaves_like "multiline strings"
531 end
532
533 describe "vim when using python_pep8_indent_multiline_string=-1" do
534   before {
535     vim.command("set sw=4 ts=4 sts=4 et")
536     vim.command("let g:python_pep8_indent_multiline_string=-1")
537   }
538   it_behaves_like "multiline strings"
539 end
540
541 describe "vim when using python_pep8_indent_multiline_string=-2" do
542   before {
543     vim.command("set sw=4 ts=4 sts=4 et")
544     vim.command("let g:python_pep8_indent_multiline_string=-2")
545   }
546   it_behaves_like "multiline strings"
547 end
548
549 describe "vim for cython" do
550   before {
551     vim.command "enew"
552     vim.command "set ft=cython"
553     vim.command "runtime indent/python.vim"
554
555     # Insert two blank lines.
556     # The first line is a corner case in this plugin that would shadow the
557     # correct behaviour of other tests. Thus we explicitly jump to the first
558     # line when we require so.
559     vim.feedkeys 'i\<CR>\<CR>\<ESC>'
560   }
561
562   describe "when using a cdef function definition" do
563       it "indents shiftwidth spaces" do
564           vim.feedkeys 'icdef long_function_name(\<CR>arg'
565           indent.should == shiftwidth * 2
566       end
567   end
568
569   describe "when using a cpdef function definition" do
570       it "indents shiftwidth spaces" do
571           vim.feedkeys 'icpdef long_function_name(\<CR>arg'
572           indent.should == shiftwidth * 2
573       end
574   end
575 end