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

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