18
18
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19
19
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
20
21
+ import re
21
22
from pyrepl import commands , reader
22
23
from pyrepl .reader import Reader
23
24
24
25
25
- def prefix (wordlist , j = 0 ):
26
+ def prefix (wordlist , j = 0 ):
26
27
d = {}
27
28
i = j
28
29
try :
@@ -36,14 +37,18 @@ def prefix(wordlist, j = 0):
36
37
except IndexError :
37
38
return wordlist [0 ][j :i ]
38
39
39
- import re
40
+
41
+ STRIPCOLOR_REGEX = re .compile (r"\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[m|K]" )
42
+
43
+
40
44
def stripcolor (s ):
41
- return stripcolor .regexp .sub ('' , s )
42
- stripcolor . regexp = re . compile ( r"\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[m|K]" )
45
+ return STRIPCOLOR_REGEX .regexp .sub ('' , s )
46
+
43
47
44
48
def real_len (s ):
45
49
return len (stripcolor (s ))
46
50
51
+
47
52
def left_align (s , maxlen ):
48
53
stripped = stripcolor (s )
49
54
if len (stripped ) > maxlen :
@@ -52,6 +57,7 @@ def left_align(s, maxlen):
52
57
padding = maxlen - len (stripped )
53
58
return s + ' ' * padding
54
59
60
+
55
61
def build_menu (cons , wordlist , start , use_brackets , sort_in_column ):
56
62
if use_brackets :
57
63
item = "[ %s ]"
@@ -66,14 +72,14 @@ def build_menu(cons, wordlist, start, use_brackets, sort_in_column):
66
72
if sort_in_column :
67
73
# sort_in_column=False (default) sort_in_column=True
68
74
# A B C A D G
69
- # D E F B E
75
+ # D E F B E
70
76
# G C F
71
77
#
72
78
# "fill" the table with empty words, so we always have the same amout
73
79
# of rows for each column
74
80
missing = cols * rows - len (wordlist )
75
81
wordlist = wordlist + ['' ]* missing
76
- indexes = [(i % cols )* rows + i // cols for i in range (len (wordlist ))]
82
+ indexes = [(i % cols ) * rows + i // cols for i in range (len (wordlist ))]
77
83
wordlist = [wordlist [i ] for i in indexes ]
78
84
menu = []
79
85
i = start
@@ -84,14 +90,14 @@ def build_menu(cons, wordlist, start, use_brackets, sort_in_column):
84
90
i += 1
85
91
if i >= len (wordlist ):
86
92
break
87
- menu .append ( '' .join (row ) )
93
+ menu .append ('' .join (row ))
88
94
if i >= len (wordlist ):
89
95
i = 0
90
96
break
91
97
if r + 5 > cons .height :
92
- menu .append (" %d more... " % (len (wordlist ) - i ))
98
+ menu .append (" %d more... " % (len (wordlist ) - i ))
93
99
break
94
- return menu , i
100
+ return menu , i
95
101
96
102
# this gets somewhat user interface-y, and as a result the logic gets
97
103
# very convoluted.
@@ -118,7 +124,7 @@ def build_menu(cons, wordlist, start, use_brackets, sort_in_column):
118
124
# only if the ``assume_immutable_completions`` is True.
119
125
#
120
126
# now it gets complicated.
121
- #
127
+ #
122
128
# for the first press of a completion key:
123
129
# if there's a common prefix, stick it in.
124
130
@@ -140,30 +146,30 @@ def build_menu(cons, wordlist, start, use_brackets, sort_in_column):
140
146
# for subsequent bangs, rotate the menu around (if there are sufficient
141
147
# choices).
142
148
149
+
143
150
class complete (commands .Command ):
144
151
def do (self ):
145
152
r = self .reader
153
+ last_is_completer = r .last_command_is (self .__class__ )
154
+ immutable_completions = r .assume_immutable_completions
155
+ completions_unchangable = last_is_completer and immutable_completions
146
156
stem = r .get_stem ()
147
- if r .assume_immutable_completions and \
148
- r .last_command_is (self .__class__ ):
149
- completions = r .cmpltn_menu_choices
150
- else :
151
- r .cmpltn_menu_choices = completions = \
152
- r .get_completions (stem )
153
- if len (completions ) == 0 :
157
+ if not completions_unchangable :
158
+ r .cmpltn_menu_choices = r .get_completions (stem )
159
+
160
+ completions = r .cmpltn_menu_choices
161
+ if not completions :
154
162
r .error ("no matches" )
155
163
elif len (completions ) == 1 :
156
- if r .assume_immutable_completions and \
157
- len (completions [0 ]) == len (stem ) and \
158
- r .last_command_is (self .__class__ ):
164
+ if completions_unchangable and len (completions [0 ]) == len (stem ):
159
165
r .msg = "[ sole completion ]"
160
166
r .dirty = 1
161
167
r .insert (completions [0 ][len (stem ):])
162
168
else :
163
169
p = prefix (completions , len (stem ))
164
170
if p :
165
171
r .insert (p )
166
- if r . last_command_is ( self . __class__ ) :
172
+ if last_is_completer :
167
173
if not r .cmpltn_menu_vis :
168
174
r .cmpltn_menu_vis = 1
169
175
r .cmpltn_menu , r .cmpltn_menu_end = build_menu (
@@ -177,6 +183,7 @@ def do(self):
177
183
r .msg = "[ not unique ]"
178
184
r .dirty = 1
179
185
186
+
180
187
class self_insert (commands .self_insert ):
181
188
def do (self ):
182
189
commands .self_insert .do (self )
@@ -195,6 +202,7 @@ def do(self):
195
202
else :
196
203
r .cmpltn_reset ()
197
204
205
+
198
206
class CompletingReader (Reader ):
199
207
"""Adds completion support
200
208
@@ -204,26 +212,25 @@ class CompletingReader(Reader):
204
212
"""
205
213
# see the comment for the complete command
206
214
assume_immutable_completions = True
207
- use_brackets = True # display completions inside []
215
+ use_brackets = True # display completions inside []
208
216
sort_in_column = False
209
-
217
+
210
218
def collect_keymap (self ):
211
219
return super (CompletingReader , self ).collect_keymap () + (
212
220
(r'\t' , 'complete' ),)
213
-
221
+
214
222
def __init__ (self , console ):
215
223
super (CompletingReader , self ).__init__ (console )
216
224
self .cmpltn_menu = ["[ menu 1 ]" , "[ menu 2 ]" ]
217
225
self .cmpltn_menu_vis = 0
218
226
self .cmpltn_menu_end = 0
219
- for c in [ complete , self_insert ] :
227
+ for c in ( complete , self_insert ) :
220
228
self .commands [c .__name__ ] = c
221
- self .commands [c .__name__ .replace ('_' , '-' )] = c
229
+ self .commands [c .__name__ .replace ('_' , '-' )] = c
222
230
223
231
def after_command (self , cmd ):
224
232
super (CompletingReader , self ).after_command (cmd )
225
- if not isinstance (cmd , self .commands ['complete' ]) \
226
- and not isinstance (cmd , self .commands ['self_insert' ]):
233
+ if not isinstance (cmd , (complete , self_insert )):
227
234
self .cmpltn_reset ()
228
235
229
236
def calc_screen (self ):
@@ -243,7 +250,7 @@ def cmpltn_reset(self):
243
250
self .cmpltn_menu = []
244
251
self .cmpltn_menu_vis = 0
245
252
self .cmpltn_menu_end = 0
246
- self .cmpltn_menu_choices = []
253
+ self .cmpltn_menu_choices = []
247
254
248
255
def get_stem (self ):
249
256
st = self .syntax_table
@@ -257,11 +264,14 @@ def get_stem(self):
257
264
def get_completions (self , stem ):
258
265
return []
259
266
267
+
260
268
def test ():
261
269
class TestReader (CompletingReader ):
262
270
def get_completions (self , stem ):
263
- return [s for l in map (lambda x :x .split (),self .history )
264
- for s in l if s and s .startswith (stem )]
271
+ return [s for l in self .history
272
+ for s in l .split ()
273
+ if s and s .startswith (stem )]
274
+
265
275
reader = TestReader ()
266
276
reader .ps1 = "c**> "
267
277
reader .ps2 = "c/*> "
@@ -270,5 +280,6 @@ def get_completions(self, stem):
270
280
while reader .readline ():
271
281
pass
272
282
273
- if __name__ == '__main__' :
283
+
284
+ if __name__ == '__main__' :
274
285
test ()
0 commit comments