5353def after_last_dot (name ):
5454 return name .rstrip ('.' ).rsplit ('.' )[- 1 ]
5555
56- def get_completer (completers , cursor_offset , line , ** kwargs ):
57- """Returns a list of matches and an applicable completer
58-
59- If no matches available, returns a tuple of an empty list and None
60-
61- kwargs (all required):
62- cursor_offset is the current cursor column
63- line is a string of the current line
64- locals_ is a dictionary of the environment
65- argspec is an inspect.ArgSpec instance for the current function where
66- the cursor is
67- current_block is the possibly multiline not-yet-evaluated block of
68- code which the current line is part of
69- complete_magic_methods is a bool of whether we ought to complete
70- double underscore methods like __len__ in method signatures
71- """
72-
73- for completer in completers :
74- matches = completer .matches (cursor_offset , line , ** kwargs )
75- if matches is not None :
76- return matches , (completer if matches else None )
77- return [], None
78-
79- def get_completer_bpython (** kwargs ):
80- """"""
81- return get_completer ([DictKeyCompletion ,
82- StringLiteralAttrCompletion ,
83- ImportCompletion ,
84- FilenameCompletion ,
85- MagicMethodCompletion ,
86- GlobalCompletion ,
87- CumulativeCompleter ([AttrCompletion , ParameterNameCompletion ])],
88- ** kwargs )
8956
9057class BaseCompletionType (object ):
9158 """Describes different completion types"""
92- @classmethod
93- def matches (cls , cursor_offset , line , ** kwargs ):
59+
60+ def __init__ (self , shown_before_tab = True ):
61+ self ._shown_before_tab = shown_before_tab
62+
63+ def matches (self , cursor_offset , line , ** kwargs ):
9464 """Returns a list of possible matches given a line and cursor, or None
9565 if this completion type isn't applicable.
9666
@@ -105,37 +75,42 @@ def matches(cls, cursor_offset, line, **kwargs):
10575 * `substitute(cur, line, match)` in a match for what's found with `target`
10676 """
10777 raise NotImplementedError
108- @ classmethod
109- def locate (cls , cursor_offset , line ):
78+
79+ def locate (self , cursor_offset , line ):
11080 """Returns a start, stop, and word given a line and cursor, or None
11181 if no target for this type of completion is found under the cursor"""
11282 raise NotImplementedError
113- @ classmethod
114- def format (cls , word ):
83+
84+ def format (self , word ):
11585 return word
116- shown_before_tab = True # whether suggestions should be shown before the
117- # user hits tab, or only once that has happened
118- def substitute (cls , cursor_offset , line , match ):
86+
87+ def substitute (self , cursor_offset , line , match ):
11988 """Returns a cursor offset and line with match swapped in"""
120- start , end , word = cls .locate (cursor_offset , line )
89+ start , end , word = self .locate (cursor_offset , line )
12190 result = start + len (match ), line [:start ] + match + line [end :]
12291 return result
12392
124- class CumulativeCompleter (object ):
93+ @property
94+ def shown_before_tab (self ):
95+ """Whether suggestions should be shown before the user hits tab, or only
96+ once that has happened."""
97+ return self ._shown_before_tab
98+
99+ class CumulativeCompleter (BaseCompletionType ):
125100 """Returns combined matches from several completers"""
101+
126102 def __init__ (self , completers ):
127103 if not completers :
128104 raise ValueError ("CumulativeCompleter requires at least one completer" )
129105 self ._completers = completers
130- self .shown_before_tab = True
131106
132- @property
133- def locate (self ):
134- return self ._completers [0 ].locate if self ._completers else lambda * args : None
107+ super (CumulativeCompleter , self ).__init__ (True )
135108
136- @property
137- def format (self ):
138- return self ._completers [0 ].format if self ._completers else lambda s : s
109+ def locate (self , current_offset , line ):
110+ return self ._completers [0 ].locate (current_offset , line )
111+
112+ def format (self , word ):
113+ return self ._completers [0 ].format (word )
139114
140115 def matches (self , cursor_offset , line , locals_ , argspec , current_block , complete_magic_methods ):
141116 all_matches = []
@@ -155,16 +130,22 @@ def matches(self, cursor_offset, line, locals_, argspec, current_block, complete
155130
156131
157132class ImportCompletion (BaseCompletionType ):
158- @ classmethod
159- def matches (cls , cursor_offset , line , ** kwargs ):
133+
134+ def matches (self , cursor_offset , line , ** kwargs ):
160135 return importcompletion .complete (cursor_offset , line )
161- locate = staticmethod (lineparts .current_word )
162- format = staticmethod (after_last_dot )
136+
137+ def locate (self , current_offset , line ):
138+ return lineparts .current_word (current_offset , line )
139+
140+ def format (self , word ):
141+ return after_last_dot (word )
163142
164143class FilenameCompletion (BaseCompletionType ):
165- shown_before_tab = False
166- @classmethod
167- def matches (cls , cursor_offset , line , ** kwargs ):
144+
145+ def __init__ (self ):
146+ super (FilenameCompletion , self ).__init__ (False )
147+
148+ def matches (self , cursor_offset , line , ** kwargs ):
168149 cs = lineparts .current_string (cursor_offset , line )
169150 if cs is None :
170151 return None
@@ -180,19 +161,20 @@ def matches(cls, cursor_offset, line, **kwargs):
180161 matches .append (filename )
181162 return matches
182163
183- locate = staticmethod (lineparts .current_string )
184- @classmethod
185- def format (cls , filename ):
164+ def locate (self , current_offset , line ):
165+ return lineparts .current_string (current_offset , line )
166+
167+ def format (self , filename ):
186168 filename .rstrip (os .sep ).rsplit (os .sep )[- 1 ]
187169 if os .sep in filename [:- 1 ]:
188170 return filename [filename .rindex (os .sep , 0 , - 1 )+ 1 :]
189171 else :
190172 return filename
191173
192174class AttrCompletion (BaseCompletionType ):
193- @ classmethod
194- def matches (cls , cursor_offset , line , locals_ , ** kwargs ):
195- r = cls .locate (cursor_offset , line )
175+
176+ def matches (self , cursor_offset , line , locals_ , ** kwargs ):
177+ r = self .locate (cursor_offset , line )
196178 if r is None :
197179 return None
198180 text = r [2 ]
@@ -217,14 +199,16 @@ def matches(cls, cursor_offset, line, locals_, **kwargs):
217199 if not match .split ('.' )[- 1 ].startswith ('_' )]
218200 return matches
219201
220- locate = staticmethod (lineparts .current_dotted_attribute )
221- format = staticmethod (after_last_dot )
202+ def locate (self , current_offset , line ):
203+ return lineparts .current_dotted_attribute (current_offset , line )
204+
205+ def format (self , word ):
206+ return after_last_dot (word )
222207
223208class DictKeyCompletion (BaseCompletionType ):
224- locate = staticmethod (lineparts .current_dict_key )
225- @classmethod
226- def matches (cls , cursor_offset , line , locals_ , ** kwargs ):
227- r = cls .locate (cursor_offset , line )
209+
210+ def matches (self , cursor_offset , line , locals_ , ** kwargs ):
211+ r = self .locate (cursor_offset , line )
228212 if r is None :
229213 return None
230214 start , end , orig = r
@@ -237,30 +221,35 @@ def matches(cls, cursor_offset, line, locals_, **kwargs):
237221 return ["{!r}]" .format (k ) for k in obj .keys () if repr (k ).startswith (orig )]
238222 else :
239223 return []
240- @classmethod
241- def format (cls , match ):
224+
225+ def locate (self , current_offset , line ):
226+ return lineparts .current_dict_key (current_offset , line )
227+
228+ def format (self , match ):
242229 return match [:- 1 ]
243230
244231class MagicMethodCompletion (BaseCompletionType ):
245- locate = staticmethod (lineparts .current_method_definition_name )
246- @classmethod
247- def matches (cls , cursor_offset , line , current_block , ** kwargs ):
248- r = cls .locate (cursor_offset , line )
232+
233+ def matches (self , cursor_offset , line , current_block , ** kwargs ):
234+ r = self .locate (cursor_offset , line )
249235 if r is None :
250236 return None
251237 if 'class' not in current_block :
252238 return None
253239 start , end , word = r
254240 return [name for name in MAGIC_METHODS if name .startswith (word )]
255241
242+ def locate (self , current_offset , line ):
243+ return lineparts .current_method_definition_name (current_offset , line )
244+
256245class GlobalCompletion (BaseCompletionType ):
257- @ classmethod
258- def matches (cls , cursor_offset , line , locals_ , ** kwargs ):
246+
247+ def matches (self , cursor_offset , line , locals_ , ** kwargs ):
259248 """Compute matches when text is a simple name.
260249 Return a list of all keywords, built-in functions and names currently
261250 defined in self.namespace that match.
262251 """
263- r = cls .locate (cursor_offset , line )
252+ r = self .locate (cursor_offset , line )
264253 if r is None :
265254 return None
266255 start , end , text = r
@@ -279,14 +268,15 @@ def matches(cls, cursor_offset, line, locals_, **kwargs):
279268 matches .sort ()
280269 return matches
281270
282- locate = staticmethod (lineparts .current_single_word )
271+ def locate (self , current_offset , line ):
272+ return lineparts .current_single_word (current_offset , line )
283273
284274class ParameterNameCompletion (BaseCompletionType ):
285- @ classmethod
286- def matches (cls , cursor_offset , line , argspec , ** kwargs ):
275+
276+ def matches (self , cursor_offset , line , argspec , ** kwargs ):
287277 if not argspec :
288278 return None
289- r = cls .locate (cursor_offset , line )
279+ r = self .locate (cursor_offset , line )
290280 if r is None :
291281 return None
292282 start , end , word = r
@@ -297,13 +287,14 @@ def matches(cls, cursor_offset, line, argspec, **kwargs):
297287 matches .extend (name + '=' for name in argspec [1 ][4 ]
298288 if name .startswith (word ))
299289 return matches
300- locate = staticmethod (lineparts .current_word )
290+
291+ def locate (self , current_offset , line ):
292+ return lineparts .current_word (current_offset , line )
301293
302294class StringLiteralAttrCompletion (BaseCompletionType ):
303- locate = staticmethod (lineparts .current_string_literal_attr )
304- @classmethod
305- def matches (cls , cursor_offset , line , ** kwargs ):
306- r = cls .locate (cursor_offset , line )
295+
296+ def matches (self , cursor_offset , line , ** kwargs ):
297+ r = self .locate (cursor_offset , line )
307298 if r is None :
308299 return None
309300 start , end , word = r
@@ -313,6 +304,48 @@ def matches(cls, cursor_offset, line, **kwargs):
313304 return [match for match in matches if not match .startswith ('_' )]
314305 return matches
315306
307+ def locate (self , current_offset , line ):
308+ return lineparts .current_string_literal_attr (current_offset , line )
309+
310+
311+ def get_completer (completers , cursor_offset , line , ** kwargs ):
312+ """Returns a list of matches and an applicable completer
313+
314+ If no matches available, returns a tuple of an empty list and None
315+
316+ kwargs (all required):
317+ cursor_offset is the current cursor column
318+ line is a string of the current line
319+ locals_ is a dictionary of the environment
320+ argspec is an inspect.ArgSpec instance for the current function where
321+ the cursor is
322+ current_block is the possibly multiline not-yet-evaluated block of
323+ code which the current line is part of
324+ complete_magic_methods is a bool of whether we ought to complete
325+ double underscore methods like __len__ in method signatures
326+ """
327+
328+ for completer in completers :
329+ matches = completer .matches (cursor_offset , line , ** kwargs )
330+ if matches is not None :
331+ return matches , (completer if matches else None )
332+ return [], None
333+
334+ BPYTHON_COMPLETER = (
335+ DictKeyCompletion (),
336+ StringLiteralAttrCompletion (),
337+ ImportCompletion (),
338+ FilenameCompletion (),
339+ MagicMethodCompletion (),
340+ GlobalCompletion (),
341+ CumulativeCompleter ((AttrCompletion (), ParameterNameCompletion ()))
342+ )
343+
344+ def get_completer_bpython (** kwargs ):
345+ """"""
346+ return get_completer (BPYTHON_COMPLETER ,
347+ ** kwargs )
348+
316349
317350class EvaluationError (Exception ):
318351 """Raised if an exception occurred in safe_eval."""
0 commit comments