1
1
# coding: utf8
2
2
from __future__ import unicode_literals
3
- import sys
3
+ import itertools
4
+ import string
4
5
import os
6
+ import sys
5
7
from contextlib import contextmanager
6
8
7
9
from curtsies .formatstringarray import FormatStringTest , fsarray
21
23
def setup_config ():
22
24
config_struct = config .Struct ()
23
25
config .loadini (config_struct , os .devnull )
26
+ config_struct .cli_suggestion_width = 1
24
27
return config_struct
25
28
26
29
@@ -48,13 +51,18 @@ def _request_refresh(inner_self):
48
51
self .repl .rl_history = History ()
49
52
self .repl .height , self .repl .width = (5 , 10 )
50
53
54
+ @property
55
+ def locals (self ):
56
+ return self .repl .coderunner .interp .locals
57
+
51
58
def assert_paint (self , screen , cursor_row_col ):
52
59
array , cursor_pos = self .repl .paint ()
53
60
self .assertFSArraysEqual (array , screen )
54
61
self .assertEqual (cursor_pos , cursor_row_col )
55
62
56
- def assert_paint_ignoring_formatting (self , screen , cursor_row_col = None ):
57
- array , cursor_pos = self .repl .paint ()
63
+ def assert_paint_ignoring_formatting (self , screen , cursor_row_col = None ,
64
+ ** paint_kwargs ):
65
+ array , cursor_pos = self .repl .paint (** paint_kwargs )
58
66
self .assertFSArraysEqualIgnoringFormatting (array , screen )
59
67
if cursor_row_col is not None :
60
68
self .assertEqual (cursor_pos , cursor_row_col )
@@ -96,15 +104,15 @@ def test_completion(self):
96
104
self .cursor_offset = 2
97
105
if config .supports_box_chars ():
98
106
screen = ['>>> an' ,
99
- '┌───────────────────────┐' ,
100
- '│ and any( │' ,
101
- '└───────────────────────┘' ,
107
+ '┌────────────────────────────── ┐' ,
108
+ '│ and any( │' ,
109
+ '└────────────────────────────── ┘' ,
102
110
'Welcome to bpython! Press <F1> f' ]
103
111
else :
104
112
screen = ['>>> an' ,
105
- '+-----------------------+' ,
106
- '| and any( |' ,
107
- '+-----------------------+' ,
113
+ '+------------------------------ +' ,
114
+ '| and any( |' ,
115
+ '+------------------------------ +' ,
108
116
'Welcome to bpython! Press <F1> f' ]
109
117
self .assert_paint_ignoring_formatting (screen , (0 , 4 ))
110
118
@@ -155,7 +163,7 @@ def output_to_repl(repl):
155
163
sys .stdout , sys .stderr = old_out , old_err
156
164
157
165
158
- class TestCurtsiesRewindRedraw (CurtsiesPaintingTest ):
166
+ class HigherLevelCurtsiesPaintingTest (CurtsiesPaintingTest ):
159
167
def refresh (self ):
160
168
self .refresh_requests .append (RefreshRequestEvent ())
161
169
@@ -194,6 +202,12 @@ def _request_refresh(inner_self):
194
202
self .repl .rl_history = History ()
195
203
self .repl .height , self .repl .width = (5 , 32 )
196
204
205
+ def send_key (self , key ):
206
+ self .repl .process_event ('<SPACE>' if key == ' ' else key )
207
+ self .repl .paint () # has some side effects we need to be wary of
208
+
209
+
210
+ class TestCurtsiesRewindRedraw (HigherLevelCurtsiesPaintingTest ):
197
211
def test_rewind (self ):
198
212
self .repl .current_line = '1 + 1'
199
213
self .enter ()
@@ -564,10 +578,6 @@ def test_unhighlight_paren_bugs(self):
564
578
green ("... " ) + yellow (')' ) + bold (cyan (" " ))])
565
579
self .assert_paint (screen , (1 , 6 ))
566
580
567
- def send_key (self , key ):
568
- self .repl .process_event ('<SPACE>' if key == ' ' else key )
569
- self .repl .paint () # has some side effects we need to be wary of
570
-
571
581
def test_472 (self ):
572
582
[self .send_key (c ) for c in "(1, 2, 3)" ]
573
583
with output_to_repl (self .repl ):
@@ -586,3 +596,128 @@ def test_472(self):
586
596
'(1, 4, 3)' ,
587
597
'>>> ' ]
588
598
self .assert_paint_ignoring_formatting (screen , (4 , 4 ))
599
+
600
+
601
+ def completion_target (num_names , chars_in_first_name = 1 ):
602
+ class Class (object ):
603
+ pass
604
+
605
+ if chars_in_first_name < 1 :
606
+ raise ValueError ('need at least one char in each name' )
607
+ elif chars_in_first_name == 1 and num_names > len (string .ascii_letters ):
608
+ raise ValueError ('need more chars to make so many names' )
609
+
610
+ names = gen_names ()
611
+ if num_names > 0 :
612
+ setattr (Class , 'a' * chars_in_first_name , 1 )
613
+ next (names ) # use the above instead of first name
614
+ for _ , name in zip (range (num_names - 1 ), names ):
615
+ setattr (Class , name , 0 )
616
+
617
+ return Class ()
618
+
619
+
620
+ def gen_names ():
621
+ for letters in itertools .chain (
622
+ itertools .combinations_with_replacement (string .ascii_letters , 1 ),
623
+ itertools .combinations_with_replacement (string .ascii_letters , 2 )):
624
+ yield '' .join (letters )
625
+
626
+
627
+ class TestCompletionHelpers (TestCase ):
628
+ def test_gen_names (self ):
629
+ self .assertEqual (list (zip ([1 , 2 , 3 ], gen_names ())),
630
+ [(1 , 'a' ), (2 , 'b' ), (3 , 'c' )])
631
+
632
+ def test_completion_target (self ):
633
+ target = completion_target (14 )
634
+ self .assertEqual (len ([x for x in dir (target )
635
+ if not x .startswith ('_' )]),
636
+ 14 )
637
+
638
+
639
+ class TestCurtsiesInfoboxPaint (HigherLevelCurtsiesPaintingTest ):
640
+ def test_simple (self ):
641
+ self .repl .width , self .repl .height = (20 , 30 )
642
+ self .locals ['abc' ] = completion_target (3 , 50 )
643
+ self .repl .current_line = 'abc'
644
+ self .repl .cursor_offset = 3
645
+ self .repl .process_event ('.' )
646
+ screen = ['>>> abc.' ,
647
+ '+------------------+' ,
648
+ '| aaaaaaaaaaaaaaaa |' ,
649
+ '| b |' ,
650
+ '| c |' ,
651
+ '+------------------+' ]
652
+ self .assert_paint_ignoring_formatting (screen , (0 , 8 ))
653
+
654
+ def test_fill_screen (self ):
655
+ self .repl .width , self .repl .height = (20 , 15 )
656
+ self .locals ['abc' ] = completion_target (20 , 100 )
657
+ self .repl .current_line = 'abc'
658
+ self .repl .cursor_offset = 3
659
+ self .repl .process_event ('.' )
660
+ screen = ['>>> abc.' ,
661
+ '+------------------+' ,
662
+ '| aaaaaaaaaaaaaaaa |' ,
663
+ '| b |' ,
664
+ '| c |' ,
665
+ '| d |' ,
666
+ '| e |' ,
667
+ '| f |' ,
668
+ '| g |' ,
669
+ '| h |' ,
670
+ '| i |' ,
671
+ '| j |' ,
672
+ '| k |' ,
673
+ '| l |' ,
674
+ '+------------------+' ]
675
+ self .assert_paint_ignoring_formatting (screen , (0 , 8 ))
676
+
677
+ def test_lower_on_screen (self ):
678
+ self .repl .get_top_usable_line = lambda : 10 # halfway down terminal
679
+ self .repl .width , self .repl .height = (20 , 15 )
680
+ self .locals ['abc' ] = completion_target (20 , 100 )
681
+ self .repl .current_line = 'abc'
682
+ self .repl .cursor_offset = 3
683
+ self .repl .process_event ('.' )
684
+ screen = ['>>> abc.' ,
685
+ '+------------------+' ,
686
+ '| aaaaaaaaaaaaaaaa |' ,
687
+ '| b |' ,
688
+ '| c |' ,
689
+ '| d |' ,
690
+ '| e |' ,
691
+ '| f |' ,
692
+ '| g |' ,
693
+ '| h |' ,
694
+ '| i |' ,
695
+ '| j |' ,
696
+ '| k |' ,
697
+ '| l |' ,
698
+ '+------------------+' ]
699
+ self .assert_paint_ignoring_formatting (screen , (0 , 8 ))
700
+
701
+ def test_at_bottom_of_screen (self ):
702
+ self .repl .get_top_usable_line = lambda : 17 # two lines from bottom
703
+ self .repl .width , self .repl .height = (20 , 15 )
704
+ self .locals ['abc' ] = completion_target (20 , 100 )
705
+ self .repl .current_line = 'abc'
706
+ self .repl .cursor_offset = 3
707
+ self .repl .process_event ('.' )
708
+ screen = ['>>> abc.' ,
709
+ '+------------------+' ,
710
+ '| aaaaaaaaaaaaaaaa |' ,
711
+ '| b |' ,
712
+ '| c |' ,
713
+ '| d |' ,
714
+ '| e |' ,
715
+ '| f |' ,
716
+ '| g |' ,
717
+ '| h |' ,
718
+ '| i |' ,
719
+ '| j |' ,
720
+ '| k |' ,
721
+ '| l |' ,
722
+ '+------------------+' ]
723
+ self .assert_paint_ignoring_formatting (screen , (0 , 8 ))
0 commit comments