##// END OF EJS Templates
Initial messing around....
Brian E. Granger -
Show More
@@ -1,1156 +1,1165
1 # encoding: utf-8
1 """Word completion for IPython.
2 """Word completion for IPython.
2
3
3 This module is a fork of the rlcompleter module in the Python standard
4 This module is a fork of the rlcompleter module in the Python standard
4 library. The original enhancements made to rlcompleter have been sent
5 library. The original enhancements made to rlcompleter have been sent
5 upstream and were accepted as of Python 2.3, but we need a lot more
6 upstream and were accepted as of Python 2.3, but we need a lot more
6 functionality specific to IPython, so this module will continue to live as an
7 functionality specific to IPython, so this module will continue to live as an
7 IPython-specific utility.
8 IPython-specific utility.
8
9
9 Original rlcompleter documentation:
10 Original rlcompleter documentation:
10
11
11 This requires the latest extension to the readline module (the
12 This requires the latest extension to the readline module (the
12 completes keywords, built-ins and globals in __main__; when completing
13 completes keywords, built-ins and globals in __main__; when completing
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 completes its attributes.
15 completes its attributes.
15
16
16 It's very cool to do "import string" type "string.", hit the
17 It's very cool to do "import string" type "string.", hit the
17 completion key (twice), and see the list of names defined by the
18 completion key (twice), and see the list of names defined by the
18 string module!
19 string module!
19
20
20 Tip: to use the tab key as the completion key, call
21 Tip: to use the tab key as the completion key, call
21
22
22 readline.parse_and_bind("tab: complete")
23 readline.parse_and_bind("tab: complete")
23
24
24 Notes:
25 Notes:
25
26
26 - Exceptions raised by the completer function are *ignored* (and
27 - Exceptions raised by the completer function are *ignored* (and
27 generally cause the completion to fail). This is a feature -- since
28 generally cause the completion to fail). This is a feature -- since
28 readline sets the tty device in raw (or cbreak) mode, printing a
29 readline sets the tty device in raw (or cbreak) mode, printing a
29 traceback wouldn't work well without some complicated hoopla to save,
30 traceback wouldn't work well without some complicated hoopla to save,
30 reset and restore the tty state.
31 reset and restore the tty state.
31
32
32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 - The evaluation of the NAME.NAME... form may cause arbitrary
33 application defined code to be executed if an object with a
34 application defined code to be executed if an object with a
34 ``__getattr__`` hook is found. Since it is the responsibility of the
35 ``__getattr__`` hook is found. Since it is the responsibility of the
35 application (or the user) to enable this feature, I consider this an
36 application (or the user) to enable this feature, I consider this an
36 acceptable risk. More complicated expressions (e.g. function calls or
37 acceptable risk. More complicated expressions (e.g. function calls or
37 indexing operations) are *not* evaluated.
38 indexing operations) are *not* evaluated.
38
39
39 - GNU readline is also used by the built-in functions input() and
40 - GNU readline is also used by the built-in functions input() and
40 raw_input(), and thus these also benefit/suffer from the completer
41 raw_input(), and thus these also benefit/suffer from the completer
41 features. Clearly an interactive application can benefit by
42 features. Clearly an interactive application can benefit by
42 specifying its own completer function and using raw_input() for all
43 specifying its own completer function and using raw_input() for all
43 its input.
44 its input.
44
45
45 - When the original stdin is not a tty device, GNU readline is never
46 - When the original stdin is not a tty device, GNU readline is never
46 used, and this module (and the readline module) are silently inactive.
47 used, and this module (and the readline module) are silently inactive.
47 """
48 """
48
49
49 #*****************************************************************************
50 #*****************************************************************************
50 #
51 #
51 # Since this file is essentially a minimally modified copy of the rlcompleter
52 # Since this file is essentially a minimally modified copy of the rlcompleter
52 # module which is part of the standard Python distribution, I assume that the
53 # module which is part of the standard Python distribution, I assume that the
53 # proper procedure is to maintain its copyright as belonging to the Python
54 # proper procedure is to maintain its copyright as belonging to the Python
54 # Software Foundation (in addition to my own, for all new code).
55 # Software Foundation (in addition to my own, for all new code).
55 #
56 #
56 # Copyright (C) 2008 IPython Development Team
57 # Copyright (C) 2008 IPython Development Team
57 # Copyright (C) 2001 Fernando Perez. <fperez@colorado.edu>
58 # Copyright (C) 2001 Fernando Perez. <fperez@colorado.edu>
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 #
60 #
60 # Distributed under the terms of the BSD License. The full license is in
61 # Distributed under the terms of the BSD License. The full license is in
61 # the file COPYING, distributed as part of this software.
62 # the file COPYING, distributed as part of this software.
62 #
63 #
63 #*****************************************************************************
64 #*****************************************************************************
64
65
65 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
66 # Imports
67 # Imports
67 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
68
69
69 import __main__
70 import __main__
70 import glob
71 import glob
71 import inspect
72 import inspect
72 import itertools
73 import itertools
73 import keyword
74 import keyword
74 import os
75 import os
75 import re
76 import re
76 import sys
77 import sys
77
78
78 from IPython.config.configurable import Configurable
79 from IPython.config.configurable import Configurable
79 from IPython.core.error import TryNext
80 from IPython.core.error import TryNext
80 from IPython.core.inputsplitter import ESC_MAGIC
81 from IPython.core.inputsplitter import ESC_MAGIC
81 from IPython.utils import generics
82 from IPython.utils import generics
82 from IPython.utils import io
83 from IPython.utils import io
83 from IPython.utils.decorators import undoc
84 from IPython.utils.decorators import undoc
84 from IPython.utils.dir2 import dir2
85 from IPython.utils.dir2 import dir2
85 from IPython.utils.process import arg_split
86 from IPython.utils.process import arg_split
86 from IPython.utils.py3compat import builtin_mod, string_types
87 from IPython.utils.py3compat import builtin_mod, string_types
87 from IPython.utils.traitlets import CBool, Enum
88 from IPython.utils.traitlets import CBool, Enum
88
89
89 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
90 # Globals
91 # Globals
91 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
92
93
93 # Public API
94 # Public API
94 __all__ = ['Completer','IPCompleter']
95 __all__ = ['Completer','IPCompleter']
95
96
96 if sys.platform == 'win32':
97 if sys.platform == 'win32':
97 PROTECTABLES = ' '
98 PROTECTABLES = ' '
98 else:
99 else:
99 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
100 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
100
101
101
102
102 #-----------------------------------------------------------------------------
103 #-----------------------------------------------------------------------------
103 # Main functions and classes
104 # Main functions and classes
104 #-----------------------------------------------------------------------------
105 #-----------------------------------------------------------------------------
105
106
106 def has_open_quotes(s):
107 def has_open_quotes(s):
107 """Return whether a string has open quotes.
108 """Return whether a string has open quotes.
108
109
109 This simply counts whether the number of quote characters of either type in
110 This simply counts whether the number of quote characters of either type in
110 the string is odd.
111 the string is odd.
111
112
112 Returns
113 Returns
113 -------
114 -------
114 If there is an open quote, the quote character is returned. Else, return
115 If there is an open quote, the quote character is returned. Else, return
115 False.
116 False.
116 """
117 """
117 # We check " first, then ', so complex cases with nested quotes will get
118 # We check " first, then ', so complex cases with nested quotes will get
118 # the " to take precedence.
119 # the " to take precedence.
119 if s.count('"') % 2:
120 if s.count('"') % 2:
120 return '"'
121 return '"'
121 elif s.count("'") % 2:
122 elif s.count("'") % 2:
122 return "'"
123 return "'"
123 else:
124 else:
124 return False
125 return False
125
126
126
127
127 def protect_filename(s):
128 def protect_filename(s):
128 """Escape a string to protect certain characters."""
129 """Escape a string to protect certain characters."""
129
130
130 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
131 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
131 for ch in s])
132 for ch in s])
132
133
133 def expand_user(path):
134 def expand_user(path):
134 """Expand '~'-style usernames in strings.
135 """Expand '~'-style usernames in strings.
135
136
136 This is similar to :func:`os.path.expanduser`, but it computes and returns
137 This is similar to :func:`os.path.expanduser`, but it computes and returns
137 extra information that will be useful if the input was being used in
138 extra information that will be useful if the input was being used in
138 computing completions, and you wish to return the completions with the
139 computing completions, and you wish to return the completions with the
139 original '~' instead of its expanded value.
140 original '~' instead of its expanded value.
140
141
141 Parameters
142 Parameters
142 ----------
143 ----------
143 path : str
144 path : str
144 String to be expanded. If no ~ is present, the output is the same as the
145 String to be expanded. If no ~ is present, the output is the same as the
145 input.
146 input.
146
147
147 Returns
148 Returns
148 -------
149 -------
149 newpath : str
150 newpath : str
150 Result of ~ expansion in the input path.
151 Result of ~ expansion in the input path.
151 tilde_expand : bool
152 tilde_expand : bool
152 Whether any expansion was performed or not.
153 Whether any expansion was performed or not.
153 tilde_val : str
154 tilde_val : str
154 The value that ~ was replaced with.
155 The value that ~ was replaced with.
155 """
156 """
156 # Default values
157 # Default values
157 tilde_expand = False
158 tilde_expand = False
158 tilde_val = ''
159 tilde_val = ''
159 newpath = path
160 newpath = path
160
161
161 if path.startswith('~'):
162 if path.startswith('~'):
162 tilde_expand = True
163 tilde_expand = True
163 rest = len(path)-1
164 rest = len(path)-1
164 newpath = os.path.expanduser(path)
165 newpath = os.path.expanduser(path)
165 if rest:
166 if rest:
166 tilde_val = newpath[:-rest]
167 tilde_val = newpath[:-rest]
167 else:
168 else:
168 tilde_val = newpath
169 tilde_val = newpath
169
170
170 return newpath, tilde_expand, tilde_val
171 return newpath, tilde_expand, tilde_val
171
172
172
173
173 def compress_user(path, tilde_expand, tilde_val):
174 def compress_user(path, tilde_expand, tilde_val):
174 """Does the opposite of expand_user, with its outputs.
175 """Does the opposite of expand_user, with its outputs.
175 """
176 """
176 if tilde_expand:
177 if tilde_expand:
177 return path.replace(tilde_val, '~')
178 return path.replace(tilde_val, '~')
178 else:
179 else:
179 return path
180 return path
180
181
181
182
182
183
183 def penalize_magics_key(word):
184 def penalize_magics_key(word):
184 """key for sorting that penalizes magic commands in the ordering
185 """key for sorting that penalizes magic commands in the ordering
185
186
186 Normal words are left alone.
187 Normal words are left alone.
187
188
188 Magic commands have the initial % moved to the end, e.g.
189 Magic commands have the initial % moved to the end, e.g.
189 %matplotlib is transformed as follows:
190 %matplotlib is transformed as follows:
190
191
191 %matplotlib -> matplotlib%
192 %matplotlib -> matplotlib%
192
193
193 [The choice of the final % is arbitrary.]
194 [The choice of the final % is arbitrary.]
194
195
195 Since "matplotlib" < "matplotlib%" as strings,
196 Since "matplotlib" < "matplotlib%" as strings,
196 "timeit" will appear before the magic "%timeit" in the ordering
197 "timeit" will appear before the magic "%timeit" in the ordering
197
198
198 For consistency, move "%%" to the end, so cell magics appear *after*
199 For consistency, move "%%" to the end, so cell magics appear *after*
199 line magics with the same name.
200 line magics with the same name.
200
201
201 A check is performed that there are no other "%" in the string;
202 A check is performed that there are no other "%" in the string;
202 if there are, then the string is not a magic command and is left unchanged.
203 if there are, then the string is not a magic command and is left unchanged.
203
204
204 """
205 """
205
206
206 # Move any % signs from start to end of the key
207 # Move any % signs from start to end of the key
207 # provided there are no others elsewhere in the string
208 # provided there are no others elsewhere in the string
208
209
209 if word[:2] == "%%":
210 if word[:2] == "%%":
210 if not "%" in word[2:]:
211 if not "%" in word[2:]:
211 return word[2:] + "%%"
212 return word[2:] + "%%"
212
213
213 if word[:1] == "%":
214 if word[:1] == "%":
214 if not "%" in word[1:]:
215 if not "%" in word[1:]:
215 return word[1:] + "%"
216 return word[1:] + "%"
216
217
217 return word
218 return word
218
219
219
220
220 @undoc
221 @undoc
221 class Bunch(object): pass
222 class Bunch(object): pass
222
223
223
224
224 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
225 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
225 GREEDY_DELIMS = ' =\r\n'
226 GREEDY_DELIMS = ' =\r\n'
226
227
227
228
228 class CompletionSplitter(object):
229 class CompletionSplitter(object):
229 """An object to split an input line in a manner similar to readline.
230 """An object to split an input line in a manner similar to readline.
230
231
231 By having our own implementation, we can expose readline-like completion in
232 By having our own implementation, we can expose readline-like completion in
232 a uniform manner to all frontends. This object only needs to be given the
233 a uniform manner to all frontends. This object only needs to be given the
233 line of text to be split and the cursor position on said line, and it
234 line of text to be split and the cursor position on said line, and it
234 returns the 'word' to be completed on at the cursor after splitting the
235 returns the 'word' to be completed on at the cursor after splitting the
235 entire line.
236 entire line.
236
237
237 What characters are used as splitting delimiters can be controlled by
238 What characters are used as splitting delimiters can be controlled by
238 setting the `delims` attribute (this is a property that internally
239 setting the `delims` attribute (this is a property that internally
239 automatically builds the necessary regular expression)"""
240 automatically builds the necessary regular expression)"""
240
241
241 # Private interface
242 # Private interface
242
243
243 # A string of delimiter characters. The default value makes sense for
244 # A string of delimiter characters. The default value makes sense for
244 # IPython's most typical usage patterns.
245 # IPython's most typical usage patterns.
245 _delims = DELIMS
246 _delims = DELIMS
246
247
247 # The expression (a normal string) to be compiled into a regular expression
248 # The expression (a normal string) to be compiled into a regular expression
248 # for actual splitting. We store it as an attribute mostly for ease of
249 # for actual splitting. We store it as an attribute mostly for ease of
249 # debugging, since this type of code can be so tricky to debug.
250 # debugging, since this type of code can be so tricky to debug.
250 _delim_expr = None
251 _delim_expr = None
251
252
252 # The regular expression that does the actual splitting
253 # The regular expression that does the actual splitting
253 _delim_re = None
254 _delim_re = None
254
255
255 def __init__(self, delims=None):
256 def __init__(self, delims=None):
256 delims = CompletionSplitter._delims if delims is None else delims
257 delims = CompletionSplitter._delims if delims is None else delims
257 self.delims = delims
258 self.delims = delims
258
259
259 @property
260 @property
260 def delims(self):
261 def delims(self):
261 """Return the string of delimiter characters."""
262 """Return the string of delimiter characters."""
262 return self._delims
263 return self._delims
263
264
264 @delims.setter
265 @delims.setter
265 def delims(self, delims):
266 def delims(self, delims):
266 """Set the delimiters for line splitting."""
267 """Set the delimiters for line splitting."""
267 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
268 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
268 self._delim_re = re.compile(expr)
269 self._delim_re = re.compile(expr)
269 self._delims = delims
270 self._delims = delims
270 self._delim_expr = expr
271 self._delim_expr = expr
271
272
272 def split_line(self, line, cursor_pos=None):
273 def split_line(self, line, cursor_pos=None):
273 """Split a line of text with a cursor at the given position.
274 """Split a line of text with a cursor at the given position.
274 """
275 """
275 l = line if cursor_pos is None else line[:cursor_pos]
276 l = line if cursor_pos is None else line[:cursor_pos]
276 return self._delim_re.split(l)[-1]
277 return self._delim_re.split(l)[-1]
277
278
278
279
279 class Completer(Configurable):
280 class Completer(Configurable):
280
281
281 greedy = CBool(False, config=True,
282 greedy = CBool(False, config=True,
282 help="""Activate greedy completion
283 help="""Activate greedy completion
283
284
284 This will enable completion on elements of lists, results of function calls, etc.,
285 This will enable completion on elements of lists, results of function calls, etc.,
285 but can be unsafe because the code is actually evaluated on TAB.
286 but can be unsafe because the code is actually evaluated on TAB.
286 """
287 """
287 )
288 )
288
289
289
290
290 def __init__(self, namespace=None, global_namespace=None, **kwargs):
291 def __init__(self, namespace=None, global_namespace=None, **kwargs):
291 """Create a new completer for the command line.
292 """Create a new completer for the command line.
292
293
293 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
294 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
294
295
295 If unspecified, the default namespace where completions are performed
296 If unspecified, the default namespace where completions are performed
296 is __main__ (technically, __main__.__dict__). Namespaces should be
297 is __main__ (technically, __main__.__dict__). Namespaces should be
297 given as dictionaries.
298 given as dictionaries.
298
299
299 An optional second namespace can be given. This allows the completer
300 An optional second namespace can be given. This allows the completer
300 to handle cases where both the local and global scopes need to be
301 to handle cases where both the local and global scopes need to be
301 distinguished.
302 distinguished.
302
303
303 Completer instances should be used as the completion mechanism of
304 Completer instances should be used as the completion mechanism of
304 readline via the set_completer() call:
305 readline via the set_completer() call:
305
306
306 readline.set_completer(Completer(my_namespace).complete)
307 readline.set_completer(Completer(my_namespace).complete)
307 """
308 """
308
309
309 # Don't bind to namespace quite yet, but flag whether the user wants a
310 # Don't bind to namespace quite yet, but flag whether the user wants a
310 # specific namespace or to use __main__.__dict__. This will allow us
311 # specific namespace or to use __main__.__dict__. This will allow us
311 # to bind to __main__.__dict__ at completion time, not now.
312 # to bind to __main__.__dict__ at completion time, not now.
312 if namespace is None:
313 if namespace is None:
313 self.use_main_ns = 1
314 self.use_main_ns = 1
314 else:
315 else:
315 self.use_main_ns = 0
316 self.use_main_ns = 0
316 self.namespace = namespace
317 self.namespace = namespace
317
318
318 # The global namespace, if given, can be bound directly
319 # The global namespace, if given, can be bound directly
319 if global_namespace is None:
320 if global_namespace is None:
320 self.global_namespace = {}
321 self.global_namespace = {}
321 else:
322 else:
322 self.global_namespace = global_namespace
323 self.global_namespace = global_namespace
323
324
324 super(Completer, self).__init__(**kwargs)
325 super(Completer, self).__init__(**kwargs)
325
326
326 def complete(self, text, state):
327 def complete(self, text, state):
327 """Return the next possible completion for 'text'.
328 """Return the next possible completion for 'text'.
328
329
329 This is called successively with state == 0, 1, 2, ... until it
330 This is called successively with state == 0, 1, 2, ... until it
330 returns None. The completion should begin with 'text'.
331 returns None. The completion should begin with 'text'.
331
332
332 """
333 """
333 if self.use_main_ns:
334 if self.use_main_ns:
334 self.namespace = __main__.__dict__
335 self.namespace = __main__.__dict__
335
336
336 if state == 0:
337 if state == 0:
337 if "." in text:
338 if "." in text:
338 self.matches = self.attr_matches(text)
339 self.matches = self.attr_matches(text)
339 else:
340 else:
340 self.matches = self.global_matches(text)
341 self.matches = self.global_matches(text)
341 try:
342 try:
342 return self.matches[state]
343 return self.matches[state]
343 except IndexError:
344 except IndexError:
344 return None
345 return None
345
346
346 def global_matches(self, text):
347 def global_matches(self, text):
347 """Compute matches when text is a simple name.
348 """Compute matches when text is a simple name.
348
349
349 Return a list of all keywords, built-in functions and names currently
350 Return a list of all keywords, built-in functions and names currently
350 defined in self.namespace or self.global_namespace that match.
351 defined in self.namespace or self.global_namespace that match.
351
352
352 """
353 """
353 #print 'Completer->global_matches, txt=%r' % text # dbg
354 #print 'Completer->global_matches, txt=%r' % text # dbg
354 matches = []
355 matches = []
355 match_append = matches.append
356 match_append = matches.append
356 n = len(text)
357 n = len(text)
357 for lst in [keyword.kwlist,
358 for lst in [keyword.kwlist,
358 builtin_mod.__dict__.keys(),
359 builtin_mod.__dict__.keys(),
359 self.namespace.keys(),
360 self.namespace.keys(),
360 self.global_namespace.keys()]:
361 self.global_namespace.keys()]:
361 for word in lst:
362 for word in lst:
362 if word[:n] == text and word != "__builtins__":
363 if word[:n] == text and word != "__builtins__":
363 match_append(word)
364 match_append(word)
364 return matches
365 return matches
365
366
366 def attr_matches(self, text):
367 def attr_matches(self, text):
367 """Compute matches when text contains a dot.
368 """Compute matches when text contains a dot.
368
369
369 Assuming the text is of the form NAME.NAME....[NAME], and is
370 Assuming the text is of the form NAME.NAME....[NAME], and is
370 evaluatable in self.namespace or self.global_namespace, it will be
371 evaluatable in self.namespace or self.global_namespace, it will be
371 evaluated and its attributes (as revealed by dir()) are used as
372 evaluated and its attributes (as revealed by dir()) are used as
372 possible completions. (For class instances, class members are are
373 possible completions. (For class instances, class members are are
373 also considered.)
374 also considered.)
374
375
375 WARNING: this can still invoke arbitrary C code, if an object
376 WARNING: this can still invoke arbitrary C code, if an object
376 with a __getattr__ hook is evaluated.
377 with a __getattr__ hook is evaluated.
377
378
378 """
379 """
379
380
380 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
381 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
381 # Another option, seems to work great. Catches things like ''.<tab>
382 # Another option, seems to work great. Catches things like ''.<tab>
382 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
383 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
383
384
384 if m:
385 if m:
385 expr, attr = m.group(1, 3)
386 expr, attr = m.group(1, 3)
386 elif self.greedy:
387 elif self.greedy:
387 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
388 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
388 if not m2:
389 if not m2:
389 return []
390 return []
390 expr, attr = m2.group(1,2)
391 expr, attr = m2.group(1,2)
391 else:
392 else:
392 return []
393 return []
393
394
394 try:
395 try:
395 obj = eval(expr, self.namespace)
396 obj = eval(expr, self.namespace)
396 except:
397 except:
397 try:
398 try:
398 obj = eval(expr, self.global_namespace)
399 obj = eval(expr, self.global_namespace)
399 except:
400 except:
400 return []
401 return []
401
402
402 if self.limit_to__all__ and hasattr(obj, '__all__'):
403 if self.limit_to__all__ and hasattr(obj, '__all__'):
403 words = get__all__entries(obj)
404 words = get__all__entries(obj)
404 else:
405 else:
405 words = dir2(obj)
406 words = dir2(obj)
406
407
407 try:
408 try:
408 words = generics.complete_object(obj, words)
409 words = generics.complete_object(obj, words)
409 except TryNext:
410 except TryNext:
410 pass
411 pass
411 except Exception:
412 except Exception:
412 # Silence errors from completion function
413 # Silence errors from completion function
413 #raise # dbg
414 #raise # dbg
414 pass
415 pass
415 # Build match list to return
416 # Build match list to return
416 n = len(attr)
417 n = len(attr)
417 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
418 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
418 return res
419 return res
419
420
420
421
421 def get__all__entries(obj):
422 def get__all__entries(obj):
422 """returns the strings in the __all__ attribute"""
423 """returns the strings in the __all__ attribute"""
423 try:
424 try:
424 words = getattr(obj, '__all__')
425 words = getattr(obj, '__all__')
425 except:
426 except:
426 return []
427 return []
427
428
428 return [w for w in words if isinstance(w, string_types)]
429 return [w for w in words if isinstance(w, string_types)]
429
430
430
431
431 def match_dict_keys(keys, prefix):
432 def match_dict_keys(keys, prefix):
432 """Used by dict_key_matches, matching the prefix to a list of keys"""
433 """Used by dict_key_matches, matching the prefix to a list of keys"""
433 if not prefix:
434 if not prefix:
434 return None, 0, [repr(k) for k in keys
435 return None, 0, [repr(k) for k in keys
435 if isinstance(k, (string_types, bytes))]
436 if isinstance(k, (string_types, bytes))]
436 quote_match = re.search('["\']', prefix)
437 quote_match = re.search('["\']', prefix)
437 quote = quote_match.group()
438 quote = quote_match.group()
438 try:
439 try:
439 prefix_str = eval(prefix + quote, {})
440 prefix_str = eval(prefix + quote, {})
440 except Exception:
441 except Exception:
441 return None, 0, []
442 return None, 0, []
442
443
443 token_match = re.search(r'\w*$', prefix, re.UNICODE)
444 token_match = re.search(r'\w*$', prefix, re.UNICODE)
444 token_start = token_match.start()
445 token_start = token_match.start()
445 token_prefix = token_match.group()
446 token_prefix = token_match.group()
446
447
447 # TODO: support bytes in Py3k
448 # TODO: support bytes in Py3k
448 matched = []
449 matched = []
449 for key in keys:
450 for key in keys:
450 try:
451 try:
451 if not key.startswith(prefix_str):
452 if not key.startswith(prefix_str):
452 continue
453 continue
453 except (AttributeError, TypeError, UnicodeError):
454 except (AttributeError, TypeError, UnicodeError):
454 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
455 # Python 3+ TypeError on b'a'.startswith('a') or vice-versa
455 continue
456 continue
456
457
457 # reformat remainder of key to begin with prefix
458 # reformat remainder of key to begin with prefix
458 rem = key[len(prefix_str):]
459 rem = key[len(prefix_str):]
459 # force repr wrapped in '
460 # force repr wrapped in '
460 rem_repr = repr(rem + '"')
461 rem_repr = repr(rem + '"')
461 if rem_repr.startswith('u') and prefix[0] not in 'uU':
462 if rem_repr.startswith('u') and prefix[0] not in 'uU':
462 # Found key is unicode, but prefix is Py2 string.
463 # Found key is unicode, but prefix is Py2 string.
463 # Therefore attempt to interpret key as string.
464 # Therefore attempt to interpret key as string.
464 try:
465 try:
465 rem_repr = repr(rem.encode('ascii') + '"')
466 rem_repr = repr(rem.encode('ascii') + '"')
466 except UnicodeEncodeError:
467 except UnicodeEncodeError:
467 continue
468 continue
468
469
469 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
470 rem_repr = rem_repr[1 + rem_repr.index("'"):-2]
470 if quote == '"':
471 if quote == '"':
471 # The entered prefix is quoted with ",
472 # The entered prefix is quoted with ",
472 # but the match is quoted with '.
473 # but the match is quoted with '.
473 # A contained " hence needs escaping for comparison:
474 # A contained " hence needs escaping for comparison:
474 rem_repr = rem_repr.replace('"', '\\"')
475 rem_repr = rem_repr.replace('"', '\\"')
475
476
476 # then reinsert prefix from start of token
477 # then reinsert prefix from start of token
477 matched.append('%s%s' % (token_prefix, rem_repr))
478 matched.append('%s%s' % (token_prefix, rem_repr))
478 return quote, token_start, matched
479 return quote, token_start, matched
479
480
480
481
481 def _safe_isinstance(obj, module, class_name):
482 def _safe_isinstance(obj, module, class_name):
482 """Checks if obj is an instance of module.class_name if loaded
483 """Checks if obj is an instance of module.class_name if loaded
483 """
484 """
484 return (module in sys.modules and
485 return (module in sys.modules and
485 isinstance(obj, getattr(__import__(module), class_name)))
486 isinstance(obj, getattr(__import__(module), class_name)))
486
487
487
488
488
489
489 class IPCompleter(Completer):
490 class IPCompleter(Completer):
490 """Extension of the completer class with IPython-specific features"""
491 """Extension of the completer class with IPython-specific features"""
491
492
492 def _greedy_changed(self, name, old, new):
493 def _greedy_changed(self, name, old, new):
493 """update the splitter and readline delims when greedy is changed"""
494 """update the splitter and readline delims when greedy is changed"""
494 if new:
495 if new:
495 self.splitter.delims = GREEDY_DELIMS
496 self.splitter.delims = GREEDY_DELIMS
496 else:
497 else:
497 self.splitter.delims = DELIMS
498 self.splitter.delims = DELIMS
498
499
499 if self.readline:
500 if self.readline:
500 self.readline.set_completer_delims(self.splitter.delims)
501 self.readline.set_completer_delims(self.splitter.delims)
501
502
502 merge_completions = CBool(True, config=True,
503 merge_completions = CBool(True, config=True,
503 help="""Whether to merge completion results into a single list
504 help="""Whether to merge completion results into a single list
504
505
505 If False, only the completion results from the first non-empty
506 If False, only the completion results from the first non-empty
506 completer will be returned.
507 completer will be returned.
507 """
508 """
508 )
509 )
509 omit__names = Enum((0,1,2), default_value=2, config=True,
510 omit__names = Enum((0,1,2), default_value=2, config=True,
510 help="""Instruct the completer to omit private method names
511 help="""Instruct the completer to omit private method names
511
512
512 Specifically, when completing on ``object.<tab>``.
513 Specifically, when completing on ``object.<tab>``.
513
514
514 When 2 [default]: all names that start with '_' will be excluded.
515 When 2 [default]: all names that start with '_' will be excluded.
515
516
516 When 1: all 'magic' names (``__foo__``) will be excluded.
517 When 1: all 'magic' names (``__foo__``) will be excluded.
517
518
518 When 0: nothing will be excluded.
519 When 0: nothing will be excluded.
519 """
520 """
520 )
521 )
521 limit_to__all__ = CBool(default_value=False, config=True,
522 limit_to__all__ = CBool(default_value=False, config=True,
522 help="""Instruct the completer to use __all__ for the completion
523 help="""Instruct the completer to use __all__ for the completion
523
524
524 Specifically, when completing on ``object.<tab>``.
525 Specifically, when completing on ``object.<tab>``.
525
526
526 When True: only those names in obj.__all__ will be included.
527 When True: only those names in obj.__all__ will be included.
527
528
528 When False [default]: the __all__ attribute is ignored
529 When False [default]: the __all__ attribute is ignored
529 """
530 """
530 )
531 )
531
532
532 def __init__(self, shell=None, namespace=None, global_namespace=None,
533 def __init__(self, shell=None, namespace=None, global_namespace=None,
533 use_readline=True, config=None, **kwargs):
534 use_readline=True, config=None, **kwargs):
534 """IPCompleter() -> completer
535 """IPCompleter() -> completer
535
536
536 Return a completer object suitable for use by the readline library
537 Return a completer object suitable for use by the readline library
537 via readline.set_completer().
538 via readline.set_completer().
538
539
539 Inputs:
540 Inputs:
540
541
541 - shell: a pointer to the ipython shell itself. This is needed
542 - shell: a pointer to the ipython shell itself. This is needed
542 because this completer knows about magic functions, and those can
543 because this completer knows about magic functions, and those can
543 only be accessed via the ipython instance.
544 only be accessed via the ipython instance.
544
545
545 - namespace: an optional dict where completions are performed.
546 - namespace: an optional dict where completions are performed.
546
547
547 - global_namespace: secondary optional dict for completions, to
548 - global_namespace: secondary optional dict for completions, to
548 handle cases (such as IPython embedded inside functions) where
549 handle cases (such as IPython embedded inside functions) where
549 both Python scopes are visible.
550 both Python scopes are visible.
550
551
551 use_readline : bool, optional
552 use_readline : bool, optional
552 If true, use the readline library. This completer can still function
553 If true, use the readline library. This completer can still function
553 without readline, though in that case callers must provide some extra
554 without readline, though in that case callers must provide some extra
554 information on each call about the current line."""
555 information on each call about the current line."""
555
556
556 self.magic_escape = ESC_MAGIC
557 self.magic_escape = ESC_MAGIC
557 self.splitter = CompletionSplitter()
558 self.splitter = CompletionSplitter()
558
559
559 # Readline configuration, only used by the rlcompleter method.
560 # Readline configuration, only used by the rlcompleter method.
560 if use_readline:
561 if use_readline:
561 # We store the right version of readline so that later code
562 # We store the right version of readline so that later code
562 import IPython.utils.rlineimpl as readline
563 import IPython.utils.rlineimpl as readline
563 self.readline = readline
564 self.readline = readline
564 else:
565 else:
565 self.readline = None
566 self.readline = None
566
567
567 # _greedy_changed() depends on splitter and readline being defined:
568 # _greedy_changed() depends on splitter and readline being defined:
568 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
569 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
569 config=config, **kwargs)
570 config=config, **kwargs)
570
571
571 # List where completion matches will be stored
572 # List where completion matches will be stored
572 self.matches = []
573 self.matches = []
573 self.shell = shell
574 self.shell = shell
574 # Regexp to split filenames with spaces in them
575 # Regexp to split filenames with spaces in them
575 self.space_name_re = re.compile(r'([^\\] )')
576 self.space_name_re = re.compile(r'([^\\] )')
576 # Hold a local ref. to glob.glob for speed
577 # Hold a local ref. to glob.glob for speed
577 self.glob = glob.glob
578 self.glob = glob.glob
578
579
579 # Determine if we are running on 'dumb' terminals, like (X)Emacs
580 # Determine if we are running on 'dumb' terminals, like (X)Emacs
580 # buffers, to avoid completion problems.
581 # buffers, to avoid completion problems.
581 term = os.environ.get('TERM','xterm')
582 term = os.environ.get('TERM','xterm')
582 self.dumb_terminal = term in ['dumb','emacs']
583 self.dumb_terminal = term in ['dumb','emacs']
583
584
584 # Special handling of backslashes needed in win32 platforms
585 # Special handling of backslashes needed in win32 platforms
585 if sys.platform == "win32":
586 if sys.platform == "win32":
586 self.clean_glob = self._clean_glob_win32
587 self.clean_glob = self._clean_glob_win32
587 else:
588 else:
588 self.clean_glob = self._clean_glob
589 self.clean_glob = self._clean_glob
589
590
590 #regexp to parse docstring for function signature
591 #regexp to parse docstring for function signature
591 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
592 self.docstring_sig_re = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
592 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
593 self.docstring_kwd_re = re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
593 #use this if positional argument name is also needed
594 #use this if positional argument name is also needed
594 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
595 #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)')
595
596
596 # All active matcher routines for completion
597 # All active matcher routines for completion
597 self.matchers = [self.python_matches,
598 self.matchers = [
599 self.python_matches,
598 self.file_matches,
600 self.file_matches,
599 self.magic_matches,
601 self.magic_matches,
600 self.python_func_kw_matches,
602 self.python_func_kw_matches,
601 self.dict_key_matches,
603 self.dict_key_matches,
604 self.latex_matches
602 ]
605 ]
603
606
604 def all_completions(self, text):
607 def all_completions(self, text):
605 """
608 """
606 Wrapper around the complete method for the benefit of emacs
609 Wrapper around the complete method for the benefit of emacs
607 and pydb.
610 and pydb.
608 """
611 """
609 return self.complete(text)[1]
612 return self.complete(text)[1]
610
613
611 def _clean_glob(self,text):
614 def _clean_glob(self,text):
612 return self.glob("%s*" % text)
615 return self.glob("%s*" % text)
613
616
614 def _clean_glob_win32(self,text):
617 def _clean_glob_win32(self,text):
615 return [f.replace("\\","/")
618 return [f.replace("\\","/")
616 for f in self.glob("%s*" % text)]
619 for f in self.glob("%s*" % text)]
617
620
618 def file_matches(self, text):
621 def file_matches(self, text):
619 """Match filenames, expanding ~USER type strings.
622 """Match filenames, expanding ~USER type strings.
620
623
621 Most of the seemingly convoluted logic in this completer is an
624 Most of the seemingly convoluted logic in this completer is an
622 attempt to handle filenames with spaces in them. And yet it's not
625 attempt to handle filenames with spaces in them. And yet it's not
623 quite perfect, because Python's readline doesn't expose all of the
626 quite perfect, because Python's readline doesn't expose all of the
624 GNU readline details needed for this to be done correctly.
627 GNU readline details needed for this to be done correctly.
625
628
626 For a filename with a space in it, the printed completions will be
629 For a filename with a space in it, the printed completions will be
627 only the parts after what's already been typed (instead of the
630 only the parts after what's already been typed (instead of the
628 full completions, as is normally done). I don't think with the
631 full completions, as is normally done). I don't think with the
629 current (as of Python 2.3) Python readline it's possible to do
632 current (as of Python 2.3) Python readline it's possible to do
630 better."""
633 better."""
631
634
632 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
635 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
633
636
634 # chars that require escaping with backslash - i.e. chars
637 # chars that require escaping with backslash - i.e. chars
635 # that readline treats incorrectly as delimiters, but we
638 # that readline treats incorrectly as delimiters, but we
636 # don't want to treat as delimiters in filename matching
639 # don't want to treat as delimiters in filename matching
637 # when escaped with backslash
640 # when escaped with backslash
638 if text.startswith('!'):
641 if text.startswith('!'):
639 text = text[1:]
642 text = text[1:]
640 text_prefix = '!'
643 text_prefix = '!'
641 else:
644 else:
642 text_prefix = ''
645 text_prefix = ''
643
646
644 text_until_cursor = self.text_until_cursor
647 text_until_cursor = self.text_until_cursor
645 # track strings with open quotes
648 # track strings with open quotes
646 open_quotes = has_open_quotes(text_until_cursor)
649 open_quotes = has_open_quotes(text_until_cursor)
647
650
648 if '(' in text_until_cursor or '[' in text_until_cursor:
651 if '(' in text_until_cursor or '[' in text_until_cursor:
649 lsplit = text
652 lsplit = text
650 else:
653 else:
651 try:
654 try:
652 # arg_split ~ shlex.split, but with unicode bugs fixed by us
655 # arg_split ~ shlex.split, but with unicode bugs fixed by us
653 lsplit = arg_split(text_until_cursor)[-1]
656 lsplit = arg_split(text_until_cursor)[-1]
654 except ValueError:
657 except ValueError:
655 # typically an unmatched ", or backslash without escaped char.
658 # typically an unmatched ", or backslash without escaped char.
656 if open_quotes:
659 if open_quotes:
657 lsplit = text_until_cursor.split(open_quotes)[-1]
660 lsplit = text_until_cursor.split(open_quotes)[-1]
658 else:
661 else:
659 return []
662 return []
660 except IndexError:
663 except IndexError:
661 # tab pressed on empty line
664 # tab pressed on empty line
662 lsplit = ""
665 lsplit = ""
663
666
664 if not open_quotes and lsplit != protect_filename(lsplit):
667 if not open_quotes and lsplit != protect_filename(lsplit):
665 # if protectables are found, do matching on the whole escaped name
668 # if protectables are found, do matching on the whole escaped name
666 has_protectables = True
669 has_protectables = True
667 text0,text = text,lsplit
670 text0,text = text,lsplit
668 else:
671 else:
669 has_protectables = False
672 has_protectables = False
670 text = os.path.expanduser(text)
673 text = os.path.expanduser(text)
671
674
672 if text == "":
675 if text == "":
673 return [text_prefix + protect_filename(f) for f in self.glob("*")]
676 return [text_prefix + protect_filename(f) for f in self.glob("*")]
674
677
675 # Compute the matches from the filesystem
678 # Compute the matches from the filesystem
676 m0 = self.clean_glob(text.replace('\\',''))
679 m0 = self.clean_glob(text.replace('\\',''))
677
680
678 if has_protectables:
681 if has_protectables:
679 # If we had protectables, we need to revert our changes to the
682 # If we had protectables, we need to revert our changes to the
680 # beginning of filename so that we don't double-write the part
683 # beginning of filename so that we don't double-write the part
681 # of the filename we have so far
684 # of the filename we have so far
682 len_lsplit = len(lsplit)
685 len_lsplit = len(lsplit)
683 matches = [text_prefix + text0 +
686 matches = [text_prefix + text0 +
684 protect_filename(f[len_lsplit:]) for f in m0]
687 protect_filename(f[len_lsplit:]) for f in m0]
685 else:
688 else:
686 if open_quotes:
689 if open_quotes:
687 # if we have a string with an open quote, we don't need to
690 # if we have a string with an open quote, we don't need to
688 # protect the names at all (and we _shouldn't_, as it
691 # protect the names at all (and we _shouldn't_, as it
689 # would cause bugs when the filesystem call is made).
692 # would cause bugs when the filesystem call is made).
690 matches = m0
693 matches = m0
691 else:
694 else:
692 matches = [text_prefix +
695 matches = [text_prefix +
693 protect_filename(f) for f in m0]
696 protect_filename(f) for f in m0]
694
697
695 #io.rprint('mm', matches) # dbg
698 #io.rprint('mm', matches) # dbg
696
699
697 # Mark directories in input list by appending '/' to their names.
700 # Mark directories in input list by appending '/' to their names.
698 matches = [x+'/' if os.path.isdir(x) else x for x in matches]
701 matches = [x+'/' if os.path.isdir(x) else x for x in matches]
699 return matches
702 return matches
700
703
701 def magic_matches(self, text):
704 def magic_matches(self, text):
702 """Match magics"""
705 """Match magics"""
703 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
706 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
704 # Get all shell magics now rather than statically, so magics loaded at
707 # Get all shell magics now rather than statically, so magics loaded at
705 # runtime show up too.
708 # runtime show up too.
706 lsm = self.shell.magics_manager.lsmagic()
709 lsm = self.shell.magics_manager.lsmagic()
707 line_magics = lsm['line']
710 line_magics = lsm['line']
708 cell_magics = lsm['cell']
711 cell_magics = lsm['cell']
709 pre = self.magic_escape
712 pre = self.magic_escape
710 pre2 = pre+pre
713 pre2 = pre+pre
711
714
712 # Completion logic:
715 # Completion logic:
713 # - user gives %%: only do cell magics
716 # - user gives %%: only do cell magics
714 # - user gives %: do both line and cell magics
717 # - user gives %: do both line and cell magics
715 # - no prefix: do both
718 # - no prefix: do both
716 # In other words, line magics are skipped if the user gives %% explicitly
719 # In other words, line magics are skipped if the user gives %% explicitly
717 bare_text = text.lstrip(pre)
720 bare_text = text.lstrip(pre)
718 comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)]
721 comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)]
719 if not text.startswith(pre2):
722 if not text.startswith(pre2):
720 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
723 comp += [ pre+m for m in line_magics if m.startswith(bare_text)]
721 return comp
724 return comp
722
725
723 def python_matches(self,text):
726 def python_matches(self,text):
724 """Match attributes or global python names"""
727 """Match attributes or global python names"""
725
728
726 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
729 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
727 if "." in text:
730 if "." in text:
728 try:
731 try:
729 matches = self.attr_matches(text)
732 matches = self.attr_matches(text)
730 if text.endswith('.') and self.omit__names:
733 if text.endswith('.') and self.omit__names:
731 if self.omit__names == 1:
734 if self.omit__names == 1:
732 # true if txt is _not_ a __ name, false otherwise:
735 # true if txt is _not_ a __ name, false otherwise:
733 no__name = (lambda txt:
736 no__name = (lambda txt:
734 re.match(r'.*\.__.*?__',txt) is None)
737 re.match(r'.*\.__.*?__',txt) is None)
735 else:
738 else:
736 # true if txt is _not_ a _ name, false otherwise:
739 # true if txt is _not_ a _ name, false otherwise:
737 no__name = (lambda txt:
740 no__name = (lambda txt:
738 re.match(r'.*\._.*?',txt) is None)
741 re.match(r'.*\._.*?',txt) is None)
739 matches = filter(no__name, matches)
742 matches = filter(no__name, matches)
740 except NameError:
743 except NameError:
741 # catches <undefined attributes>.<tab>
744 # catches <undefined attributes>.<tab>
742 matches = []
745 matches = []
743 else:
746 else:
744 matches = self.global_matches(text)
747 matches = self.global_matches(text)
745
748
746 return matches
749 return matches
747
750
748 def _default_arguments_from_docstring(self, doc):
751 def _default_arguments_from_docstring(self, doc):
749 """Parse the first line of docstring for call signature.
752 """Parse the first line of docstring for call signature.
750
753
751 Docstring should be of the form 'min(iterable[, key=func])\n'.
754 Docstring should be of the form 'min(iterable[, key=func])\n'.
752 It can also parse cython docstring of the form
755 It can also parse cython docstring of the form
753 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
756 'Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)'.
754 """
757 """
755 if doc is None:
758 if doc is None:
756 return []
759 return []
757
760
758 #care only the firstline
761 #care only the firstline
759 line = doc.lstrip().splitlines()[0]
762 line = doc.lstrip().splitlines()[0]
760
763
761 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
764 #p = re.compile(r'^[\w|\s.]+\(([^)]*)\).*')
762 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
765 #'min(iterable[, key=func])\n' -> 'iterable[, key=func]'
763 sig = self.docstring_sig_re.search(line)
766 sig = self.docstring_sig_re.search(line)
764 if sig is None:
767 if sig is None:
765 return []
768 return []
766 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
769 # iterable[, key=func]' -> ['iterable[' ,' key=func]']
767 sig = sig.groups()[0].split(',')
770 sig = sig.groups()[0].split(',')
768 ret = []
771 ret = []
769 for s in sig:
772 for s in sig:
770 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
773 #re.compile(r'[\s|\[]*(\w+)(?:\s*=\s*.*)')
771 ret += self.docstring_kwd_re.findall(s)
774 ret += self.docstring_kwd_re.findall(s)
772 return ret
775 return ret
773
776
774 def _default_arguments(self, obj):
777 def _default_arguments(self, obj):
775 """Return the list of default arguments of obj if it is callable,
778 """Return the list of default arguments of obj if it is callable,
776 or empty list otherwise."""
779 or empty list otherwise."""
777 call_obj = obj
780 call_obj = obj
778 ret = []
781 ret = []
779 if inspect.isbuiltin(obj):
782 if inspect.isbuiltin(obj):
780 pass
783 pass
781 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
784 elif not (inspect.isfunction(obj) or inspect.ismethod(obj)):
782 if inspect.isclass(obj):
785 if inspect.isclass(obj):
783 #for cython embededsignature=True the constructor docstring
786 #for cython embededsignature=True the constructor docstring
784 #belongs to the object itself not __init__
787 #belongs to the object itself not __init__
785 ret += self._default_arguments_from_docstring(
788 ret += self._default_arguments_from_docstring(
786 getattr(obj, '__doc__', ''))
789 getattr(obj, '__doc__', ''))
787 # for classes, check for __init__,__new__
790 # for classes, check for __init__,__new__
788 call_obj = (getattr(obj, '__init__', None) or
791 call_obj = (getattr(obj, '__init__', None) or
789 getattr(obj, '__new__', None))
792 getattr(obj, '__new__', None))
790 # for all others, check if they are __call__able
793 # for all others, check if they are __call__able
791 elif hasattr(obj, '__call__'):
794 elif hasattr(obj, '__call__'):
792 call_obj = obj.__call__
795 call_obj = obj.__call__
793
796
794 ret += self._default_arguments_from_docstring(
797 ret += self._default_arguments_from_docstring(
795 getattr(call_obj, '__doc__', ''))
798 getattr(call_obj, '__doc__', ''))
796
799
797 try:
800 try:
798 args,_,_1,defaults = inspect.getargspec(call_obj)
801 args,_,_1,defaults = inspect.getargspec(call_obj)
799 if defaults:
802 if defaults:
800 ret+=args[-len(defaults):]
803 ret+=args[-len(defaults):]
801 except TypeError:
804 except TypeError:
802 pass
805 pass
803
806
804 return list(set(ret))
807 return list(set(ret))
805
808
806 def python_func_kw_matches(self,text):
809 def python_func_kw_matches(self,text):
807 """Match named parameters (kwargs) of the last open function"""
810 """Match named parameters (kwargs) of the last open function"""
808
811
809 if "." in text: # a parameter cannot be dotted
812 if "." in text: # a parameter cannot be dotted
810 return []
813 return []
811 try: regexp = self.__funcParamsRegex
814 try: regexp = self.__funcParamsRegex
812 except AttributeError:
815 except AttributeError:
813 regexp = self.__funcParamsRegex = re.compile(r'''
816 regexp = self.__funcParamsRegex = re.compile(r'''
814 '.*?(?<!\\)' | # single quoted strings or
817 '.*?(?<!\\)' | # single quoted strings or
815 ".*?(?<!\\)" | # double quoted strings or
818 ".*?(?<!\\)" | # double quoted strings or
816 \w+ | # identifier
819 \w+ | # identifier
817 \S # other characters
820 \S # other characters
818 ''', re.VERBOSE | re.DOTALL)
821 ''', re.VERBOSE | re.DOTALL)
819 # 1. find the nearest identifier that comes before an unclosed
822 # 1. find the nearest identifier that comes before an unclosed
820 # parenthesis before the cursor
823 # parenthesis before the cursor
821 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
824 # e.g. for "foo (1+bar(x), pa<cursor>,a=1)", the candidate is "foo"
822 tokens = regexp.findall(self.text_until_cursor)
825 tokens = regexp.findall(self.text_until_cursor)
823 tokens.reverse()
826 tokens.reverse()
824 iterTokens = iter(tokens); openPar = 0
827 iterTokens = iter(tokens); openPar = 0
825
828
826 for token in iterTokens:
829 for token in iterTokens:
827 if token == ')':
830 if token == ')':
828 openPar -= 1
831 openPar -= 1
829 elif token == '(':
832 elif token == '(':
830 openPar += 1
833 openPar += 1
831 if openPar > 0:
834 if openPar > 0:
832 # found the last unclosed parenthesis
835 # found the last unclosed parenthesis
833 break
836 break
834 else:
837 else:
835 return []
838 return []
836 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
839 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
837 ids = []
840 ids = []
838 isId = re.compile(r'\w+$').match
841 isId = re.compile(r'\w+$').match
839
842
840 while True:
843 while True:
841 try:
844 try:
842 ids.append(next(iterTokens))
845 ids.append(next(iterTokens))
843 if not isId(ids[-1]):
846 if not isId(ids[-1]):
844 ids.pop(); break
847 ids.pop(); break
845 if not next(iterTokens) == '.':
848 if not next(iterTokens) == '.':
846 break
849 break
847 except StopIteration:
850 except StopIteration:
848 break
851 break
849 # lookup the candidate callable matches either using global_matches
852 # lookup the candidate callable matches either using global_matches
850 # or attr_matches for dotted names
853 # or attr_matches for dotted names
851 if len(ids) == 1:
854 if len(ids) == 1:
852 callableMatches = self.global_matches(ids[0])
855 callableMatches = self.global_matches(ids[0])
853 else:
856 else:
854 callableMatches = self.attr_matches('.'.join(ids[::-1]))
857 callableMatches = self.attr_matches('.'.join(ids[::-1]))
855 argMatches = []
858 argMatches = []
856 for callableMatch in callableMatches:
859 for callableMatch in callableMatches:
857 try:
860 try:
858 namedArgs = self._default_arguments(eval(callableMatch,
861 namedArgs = self._default_arguments(eval(callableMatch,
859 self.namespace))
862 self.namespace))
860 except:
863 except:
861 continue
864 continue
862
865
863 for namedArg in namedArgs:
866 for namedArg in namedArgs:
864 if namedArg.startswith(text):
867 if namedArg.startswith(text):
865 argMatches.append("%s=" %namedArg)
868 argMatches.append("%s=" %namedArg)
866 return argMatches
869 return argMatches
867
870
868 def dict_key_matches(self, text):
871 def dict_key_matches(self, text):
869 "Match string keys in a dictionary, after e.g. 'foo[' "
872 "Match string keys in a dictionary, after e.g. 'foo[' "
870 def get_keys(obj):
873 def get_keys(obj):
871 # Only allow completion for known in-memory dict-like types
874 # Only allow completion for known in-memory dict-like types
872 if isinstance(obj, dict) or\
875 if isinstance(obj, dict) or\
873 _safe_isinstance(obj, 'pandas', 'DataFrame'):
876 _safe_isinstance(obj, 'pandas', 'DataFrame'):
874 try:
877 try:
875 return list(obj.keys())
878 return list(obj.keys())
876 except Exception:
879 except Exception:
877 return []
880 return []
878 elif _safe_isinstance(obj, 'numpy', 'ndarray'):
881 elif _safe_isinstance(obj, 'numpy', 'ndarray'):
879 return obj.dtype.names or []
882 return obj.dtype.names or []
880 return []
883 return []
881
884
882 try:
885 try:
883 regexps = self.__dict_key_regexps
886 regexps = self.__dict_key_regexps
884 except AttributeError:
887 except AttributeError:
885 dict_key_re_fmt = r'''(?x)
888 dict_key_re_fmt = r'''(?x)
886 ( # match dict-referring expression wrt greedy setting
889 ( # match dict-referring expression wrt greedy setting
887 %s
890 %s
888 )
891 )
889 \[ # open bracket
892 \[ # open bracket
890 \s* # and optional whitespace
893 \s* # and optional whitespace
891 ([uUbB]? # string prefix (r not handled)
894 ([uUbB]? # string prefix (r not handled)
892 (?: # unclosed string
895 (?: # unclosed string
893 '(?:[^']|(?<!\\)\\')*
896 '(?:[^']|(?<!\\)\\')*
894 |
897 |
895 "(?:[^"]|(?<!\\)\\")*
898 "(?:[^"]|(?<!\\)\\")*
896 )
899 )
897 )?
900 )?
898 $
901 $
899 '''
902 '''
900 regexps = self.__dict_key_regexps = {
903 regexps = self.__dict_key_regexps = {
901 False: re.compile(dict_key_re_fmt % '''
904 False: re.compile(dict_key_re_fmt % '''
902 # identifiers separated by .
905 # identifiers separated by .
903 (?!\d)\w+
906 (?!\d)\w+
904 (?:\.(?!\d)\w+)*
907 (?:\.(?!\d)\w+)*
905 '''),
908 '''),
906 True: re.compile(dict_key_re_fmt % '''
909 True: re.compile(dict_key_re_fmt % '''
907 .+
910 .+
908 ''')
911 ''')
909 }
912 }
910
913
911 match = regexps[self.greedy].search(self.text_until_cursor)
914 match = regexps[self.greedy].search(self.text_until_cursor)
912 if match is None:
915 if match is None:
913 return []
916 return []
914
917
915 expr, prefix = match.groups()
918 expr, prefix = match.groups()
916 try:
919 try:
917 obj = eval(expr, self.namespace)
920 obj = eval(expr, self.namespace)
918 except Exception:
921 except Exception:
919 try:
922 try:
920 obj = eval(expr, self.global_namespace)
923 obj = eval(expr, self.global_namespace)
921 except Exception:
924 except Exception:
922 return []
925 return []
923
926
924 keys = get_keys(obj)
927 keys = get_keys(obj)
925 if not keys:
928 if not keys:
926 return keys
929 return keys
927 closing_quote, token_offset, matches = match_dict_keys(keys, prefix)
930 closing_quote, token_offset, matches = match_dict_keys(keys, prefix)
928 if not matches:
931 if not matches:
929 return matches
932 return matches
930
933
931 # get the cursor position of
934 # get the cursor position of
932 # - the text being completed
935 # - the text being completed
933 # - the start of the key text
936 # - the start of the key text
934 # - the start of the completion
937 # - the start of the completion
935 text_start = len(self.text_until_cursor) - len(text)
938 text_start = len(self.text_until_cursor) - len(text)
936 if prefix:
939 if prefix:
937 key_start = match.start(2)
940 key_start = match.start(2)
938 completion_start = key_start + token_offset
941 completion_start = key_start + token_offset
939 else:
942 else:
940 key_start = completion_start = match.end()
943 key_start = completion_start = match.end()
941
944
942 # grab the leading prefix, to make sure all completions start with `text`
945 # grab the leading prefix, to make sure all completions start with `text`
943 if text_start > key_start:
946 if text_start > key_start:
944 leading = ''
947 leading = ''
945 else:
948 else:
946 leading = text[text_start:completion_start]
949 leading = text[text_start:completion_start]
947
950
948 # the index of the `[` character
951 # the index of the `[` character
949 bracket_idx = match.end(1)
952 bracket_idx = match.end(1)
950
953
951 # append closing quote and bracket as appropriate
954 # append closing quote and bracket as appropriate
952 # this is *not* appropriate if the opening quote or bracket is outside
955 # this is *not* appropriate if the opening quote or bracket is outside
953 # the text given to this method
956 # the text given to this method
954 suf = ''
957 suf = ''
955 continuation = self.line_buffer[len(self.text_until_cursor):]
958 continuation = self.line_buffer[len(self.text_until_cursor):]
956 if key_start > text_start and closing_quote:
959 if key_start > text_start and closing_quote:
957 # quotes were opened inside text, maybe close them
960 # quotes were opened inside text, maybe close them
958 if continuation.startswith(closing_quote):
961 if continuation.startswith(closing_quote):
959 continuation = continuation[len(closing_quote):]
962 continuation = continuation[len(closing_quote):]
960 else:
963 else:
961 suf += closing_quote
964 suf += closing_quote
962 if bracket_idx > text_start:
965 if bracket_idx > text_start:
963 # brackets were opened inside text, maybe close them
966 # brackets were opened inside text, maybe close them
964 if not continuation.startswith(']'):
967 if not continuation.startswith(']'):
965 suf += ']'
968 suf += ']'
966
969
967 return [leading + k + suf for k in matches]
970 return [leading + k + suf for k in matches]
968
971
972 def latex_matches(self, text):
973 if text.startswith('\\foo'):
974 return ['foo']
975 else:
976 return []
977
969 def dispatch_custom_completer(self, text):
978 def dispatch_custom_completer(self, text):
970 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
979 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
971 line = self.line_buffer
980 line = self.line_buffer
972 if not line.strip():
981 if not line.strip():
973 return None
982 return None
974
983
975 # Create a little structure to pass all the relevant information about
984 # Create a little structure to pass all the relevant information about
976 # the current completion to any custom completer.
985 # the current completion to any custom completer.
977 event = Bunch()
986 event = Bunch()
978 event.line = line
987 event.line = line
979 event.symbol = text
988 event.symbol = text
980 cmd = line.split(None,1)[0]
989 cmd = line.split(None,1)[0]
981 event.command = cmd
990 event.command = cmd
982 event.text_until_cursor = self.text_until_cursor
991 event.text_until_cursor = self.text_until_cursor
983
992
984 #print "\ncustom:{%s]\n" % event # dbg
993 #print "\ncustom:{%s]\n" % event # dbg
985
994
986 # for foo etc, try also to find completer for %foo
995 # for foo etc, try also to find completer for %foo
987 if not cmd.startswith(self.magic_escape):
996 if not cmd.startswith(self.magic_escape):
988 try_magic = self.custom_completers.s_matches(
997 try_magic = self.custom_completers.s_matches(
989 self.magic_escape + cmd)
998 self.magic_escape + cmd)
990 else:
999 else:
991 try_magic = []
1000 try_magic = []
992
1001
993 for c in itertools.chain(self.custom_completers.s_matches(cmd),
1002 for c in itertools.chain(self.custom_completers.s_matches(cmd),
994 try_magic,
1003 try_magic,
995 self.custom_completers.flat_matches(self.text_until_cursor)):
1004 self.custom_completers.flat_matches(self.text_until_cursor)):
996 #print "try",c # dbg
1005 #print "try",c # dbg
997 try:
1006 try:
998 res = c(event)
1007 res = c(event)
999 if res:
1008 if res:
1000 # first, try case sensitive match
1009 # first, try case sensitive match
1001 withcase = [r for r in res if r.startswith(text)]
1010 withcase = [r for r in res if r.startswith(text)]
1002 if withcase:
1011 if withcase:
1003 return withcase
1012 return withcase
1004 # if none, then case insensitive ones are ok too
1013 # if none, then case insensitive ones are ok too
1005 text_low = text.lower()
1014 text_low = text.lower()
1006 return [r for r in res if r.lower().startswith(text_low)]
1015 return [r for r in res if r.lower().startswith(text_low)]
1007 except TryNext:
1016 except TryNext:
1008 pass
1017 pass
1009
1018
1010 return None
1019 return None
1011
1020
1012 def complete(self, text=None, line_buffer=None, cursor_pos=None):
1021 def complete(self, text=None, line_buffer=None, cursor_pos=None):
1013 """Find completions for the given text and line context.
1022 """Find completions for the given text and line context.
1014
1023
1015 Note that both the text and the line_buffer are optional, but at least
1024 Note that both the text and the line_buffer are optional, but at least
1016 one of them must be given.
1025 one of them must be given.
1017
1026
1018 Parameters
1027 Parameters
1019 ----------
1028 ----------
1020 text : string, optional
1029 text : string, optional
1021 Text to perform the completion on. If not given, the line buffer
1030 Text to perform the completion on. If not given, the line buffer
1022 is split using the instance's CompletionSplitter object.
1031 is split using the instance's CompletionSplitter object.
1023
1032
1024 line_buffer : string, optional
1033 line_buffer : string, optional
1025 If not given, the completer attempts to obtain the current line
1034 If not given, the completer attempts to obtain the current line
1026 buffer via readline. This keyword allows clients which are
1035 buffer via readline. This keyword allows clients which are
1027 requesting for text completions in non-readline contexts to inform
1036 requesting for text completions in non-readline contexts to inform
1028 the completer of the entire text.
1037 the completer of the entire text.
1029
1038
1030 cursor_pos : int, optional
1039 cursor_pos : int, optional
1031 Index of the cursor in the full line buffer. Should be provided by
1040 Index of the cursor in the full line buffer. Should be provided by
1032 remote frontends where kernel has no access to frontend state.
1041 remote frontends where kernel has no access to frontend state.
1033
1042
1034 Returns
1043 Returns
1035 -------
1044 -------
1036 text : str
1045 text : str
1037 Text that was actually used in the completion.
1046 Text that was actually used in the completion.
1038
1047
1039 matches : list
1048 matches : list
1040 A list of completion matches.
1049 A list of completion matches.
1041 """
1050 """
1042 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
1051 io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
1043
1052
1044 # if the cursor position isn't given, the only sane assumption we can
1053 # if the cursor position isn't given, the only sane assumption we can
1045 # make is that it's at the end of the line (the common case)
1054 # make is that it's at the end of the line (the common case)
1046 if cursor_pos is None:
1055 if cursor_pos is None:
1047 cursor_pos = len(line_buffer) if text is None else len(text)
1056 cursor_pos = len(line_buffer) if text is None else len(text)
1048
1057
1049 # if text is either None or an empty string, rely on the line buffer
1058 # if text is either None or an empty string, rely on the line buffer
1050 if not text:
1059 if not text:
1051 text = self.splitter.split_line(line_buffer, cursor_pos)
1060 text = self.splitter.split_line(line_buffer, cursor_pos)
1052
1061
1053 # If no line buffer is given, assume the input text is all there was
1062 # If no line buffer is given, assume the input text is all there was
1054 if line_buffer is None:
1063 if line_buffer is None:
1055 line_buffer = text
1064 line_buffer = text
1056
1065
1057 self.line_buffer = line_buffer
1066 self.line_buffer = line_buffer
1058 self.text_until_cursor = self.line_buffer[:cursor_pos]
1067 self.text_until_cursor = self.line_buffer[:cursor_pos]
1059 #io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
1068 io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
1060
1069
1061 # Start with a clean slate of completions
1070 # Start with a clean slate of completions
1062 self.matches[:] = []
1071 self.matches[:] = []
1063 custom_res = self.dispatch_custom_completer(text)
1072 custom_res = self.dispatch_custom_completer(text)
1064 if custom_res is not None:
1073 if custom_res is not None:
1065 # did custom completers produce something?
1074 # did custom completers produce something?
1066 self.matches = custom_res
1075 self.matches = custom_res
1067 else:
1076 else:
1068 # Extend the list of completions with the results of each
1077 # Extend the list of completions with the results of each
1069 # matcher, so we return results to the user from all
1078 # matcher, so we return results to the user from all
1070 # namespaces.
1079 # namespaces.
1071 if self.merge_completions:
1080 if self.merge_completions:
1072 self.matches = []
1081 self.matches = []
1073 for matcher in self.matchers:
1082 for matcher in self.matchers:
1074 try:
1083 try:
1075 self.matches.extend(matcher(text))
1084 self.matches.extend(matcher(text))
1076 except:
1085 except:
1077 # Show the ugly traceback if the matcher causes an
1086 # Show the ugly traceback if the matcher causes an
1078 # exception, but do NOT crash the kernel!
1087 # exception, but do NOT crash the kernel!
1079 sys.excepthook(*sys.exc_info())
1088 sys.excepthook(*sys.exc_info())
1080 else:
1089 else:
1081 for matcher in self.matchers:
1090 for matcher in self.matchers:
1082 self.matches = matcher(text)
1091 self.matches = matcher(text)
1083 if self.matches:
1092 if self.matches:
1084 break
1093 break
1085 # FIXME: we should extend our api to return a dict with completions for
1094 # FIXME: we should extend our api to return a dict with completions for
1086 # different types of objects. The rlcomplete() method could then
1095 # different types of objects. The rlcomplete() method could then
1087 # simply collapse the dict into a list for readline, but we'd have
1096 # simply collapse the dict into a list for readline, but we'd have
1088 # richer completion semantics in other evironments.
1097 # richer completion semantics in other evironments.
1089
1098
1090 # use penalize_magics_key to put magics after variables with same name
1099 # use penalize_magics_key to put magics after variables with same name
1091 self.matches = sorted(set(self.matches), key=penalize_magics_key)
1100 self.matches = sorted(set(self.matches), key=penalize_magics_key)
1092
1101
1093 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
1102 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
1094 return text, self.matches
1103 return text, self.matches
1095
1104
1096 def rlcomplete(self, text, state):
1105 def rlcomplete(self, text, state):
1097 """Return the state-th possible completion for 'text'.
1106 """Return the state-th possible completion for 'text'.
1098
1107
1099 This is called successively with state == 0, 1, 2, ... until it
1108 This is called successively with state == 0, 1, 2, ... until it
1100 returns None. The completion should begin with 'text'.
1109 returns None. The completion should begin with 'text'.
1101
1110
1102 Parameters
1111 Parameters
1103 ----------
1112 ----------
1104 text : string
1113 text : string
1105 Text to perform the completion on.
1114 Text to perform the completion on.
1106
1115
1107 state : int
1116 state : int
1108 Counter used by readline.
1117 Counter used by readline.
1109 """
1118 """
1110 if state==0:
1119 if state==0:
1111
1120
1112 self.line_buffer = line_buffer = self.readline.get_line_buffer()
1121 self.line_buffer = line_buffer = self.readline.get_line_buffer()
1113 cursor_pos = self.readline.get_endidx()
1122 cursor_pos = self.readline.get_endidx()
1114
1123
1115 #io.rprint("\nRLCOMPLETE: %r %r %r" %
1124 #io.rprint("\nRLCOMPLETE: %r %r %r" %
1116 # (text, line_buffer, cursor_pos) ) # dbg
1125 # (text, line_buffer, cursor_pos) ) # dbg
1117
1126
1118 # if there is only a tab on a line with only whitespace, instead of
1127 # if there is only a tab on a line with only whitespace, instead of
1119 # the mostly useless 'do you want to see all million completions'
1128 # the mostly useless 'do you want to see all million completions'
1120 # message, just do the right thing and give the user his tab!
1129 # message, just do the right thing and give the user his tab!
1121 # Incidentally, this enables pasting of tabbed text from an editor
1130 # Incidentally, this enables pasting of tabbed text from an editor
1122 # (as long as autoindent is off).
1131 # (as long as autoindent is off).
1123
1132
1124 # It should be noted that at least pyreadline still shows file
1133 # It should be noted that at least pyreadline still shows file
1125 # completions - is there a way around it?
1134 # completions - is there a way around it?
1126
1135
1127 # don't apply this on 'dumb' terminals, such as emacs buffers, so
1136 # don't apply this on 'dumb' terminals, such as emacs buffers, so
1128 # we don't interfere with their own tab-completion mechanism.
1137 # we don't interfere with their own tab-completion mechanism.
1129 if not (self.dumb_terminal or line_buffer.strip()):
1138 if not (self.dumb_terminal or line_buffer.strip()):
1130 self.readline.insert_text('\t')
1139 self.readline.insert_text('\t')
1131 sys.stdout.flush()
1140 sys.stdout.flush()
1132 return None
1141 return None
1133
1142
1134 # Note: debugging exceptions that may occur in completion is very
1143 # Note: debugging exceptions that may occur in completion is very
1135 # tricky, because readline unconditionally silences them. So if
1144 # tricky, because readline unconditionally silences them. So if
1136 # during development you suspect a bug in the completion code, turn
1145 # during development you suspect a bug in the completion code, turn
1137 # this flag on temporarily by uncommenting the second form (don't
1146 # this flag on temporarily by uncommenting the second form (don't
1138 # flip the value in the first line, as the '# dbg' marker can be
1147 # flip the value in the first line, as the '# dbg' marker can be
1139 # automatically detected and is used elsewhere).
1148 # automatically detected and is used elsewhere).
1140 DEBUG = False
1149 DEBUG = False
1141 #DEBUG = True # dbg
1150 #DEBUG = True # dbg
1142 if DEBUG:
1151 if DEBUG:
1143 try:
1152 try:
1144 self.complete(text, line_buffer, cursor_pos)
1153 self.complete(text, line_buffer, cursor_pos)
1145 except:
1154 except:
1146 import traceback; traceback.print_exc()
1155 import traceback; traceback.print_exc()
1147 else:
1156 else:
1148 # The normal production version is here
1157 # The normal production version is here
1149
1158
1150 # This method computes the self.matches array
1159 # This method computes the self.matches array
1151 self.complete(text, line_buffer, cursor_pos)
1160 self.complete(text, line_buffer, cursor_pos)
1152
1161
1153 try:
1162 try:
1154 return self.matches[state]
1163 return self.matches[state]
1155 except IndexError:
1164 except IndexError:
1156 return None
1165 return None
@@ -1,352 +1,353
1 # encoding: utf-8
1 """Implementations for various useful completers.
2 """Implementations for various useful completers.
2
3
3 These are all loaded by default by IPython.
4 These are all loaded by default by IPython.
4 """
5 """
5 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
6 # Copyright (C) 2010-2011 The IPython Development Team.
7 # Copyright (C) 2010-2011 The IPython Development Team.
7 #
8 #
8 # Distributed under the terms of the BSD License.
9 # Distributed under the terms of the BSD License.
9 #
10 #
10 # The full license is in the file COPYING.txt, distributed with this software.
11 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
12
13
13 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
14 # Imports
15 # Imports
15 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
16 from __future__ import print_function
17 from __future__ import print_function
17
18
18 # Stdlib imports
19 # Stdlib imports
19 import glob
20 import glob
20 import inspect
21 import inspect
21 import os
22 import os
22 import re
23 import re
23 import sys
24 import sys
24
25
25 try:
26 try:
26 # Python >= 3.3
27 # Python >= 3.3
27 from importlib.machinery import all_suffixes
28 from importlib.machinery import all_suffixes
28 _suffixes = all_suffixes()
29 _suffixes = all_suffixes()
29 except ImportError:
30 except ImportError:
30 from imp import get_suffixes
31 from imp import get_suffixes
31 _suffixes = [ s[0] for s in get_suffixes() ]
32 _suffixes = [ s[0] for s in get_suffixes() ]
32
33
33 # Third-party imports
34 # Third-party imports
34 from time import time
35 from time import time
35 from zipimport import zipimporter
36 from zipimport import zipimporter
36
37
37 # Our own imports
38 # Our own imports
38 from IPython.core.completer import expand_user, compress_user
39 from IPython.core.completer import expand_user, compress_user
39 from IPython.core.error import TryNext
40 from IPython.core.error import TryNext
40 from IPython.utils._process_common import arg_split
41 from IPython.utils._process_common import arg_split
41 from IPython.utils.py3compat import string_types
42 from IPython.utils.py3compat import string_types
42
43
43 # FIXME: this should be pulled in with the right call via the component system
44 # FIXME: this should be pulled in with the right call via the component system
44 from IPython import get_ipython
45 from IPython import get_ipython
45
46
46 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
47 # Globals and constants
48 # Globals and constants
48 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
49
50
50 # Time in seconds after which the rootmodules will be stored permanently in the
51 # Time in seconds after which the rootmodules will be stored permanently in the
51 # ipython ip.db database (kept in the user's .ipython dir).
52 # ipython ip.db database (kept in the user's .ipython dir).
52 TIMEOUT_STORAGE = 2
53 TIMEOUT_STORAGE = 2
53
54
54 # Time in seconds after which we give up
55 # Time in seconds after which we give up
55 TIMEOUT_GIVEUP = 20
56 TIMEOUT_GIVEUP = 20
56
57
57 # Regular expression for the python import statement
58 # Regular expression for the python import statement
58 import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
59 import_re = re.compile(r'(?P<name>[a-zA-Z_][a-zA-Z0-9_]*?)'
59 r'(?P<package>[/\\]__init__)?'
60 r'(?P<package>[/\\]__init__)?'
60 r'(?P<suffix>%s)$' %
61 r'(?P<suffix>%s)$' %
61 r'|'.join(re.escape(s) for s in _suffixes))
62 r'|'.join(re.escape(s) for s in _suffixes))
62
63
63 # RE for the ipython %run command (python + ipython scripts)
64 # RE for the ipython %run command (python + ipython scripts)
64 magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
65 magic_run_re = re.compile(r'.*(\.ipy|\.ipynb|\.py[w]?)$')
65
66
66 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
67 # Local utilities
68 # Local utilities
68 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
69
70
70 def module_list(path):
71 def module_list(path):
71 """
72 """
72 Return the list containing the names of the modules available in the given
73 Return the list containing the names of the modules available in the given
73 folder.
74 folder.
74 """
75 """
75 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
76 # sys.path has the cwd as an empty string, but isdir/listdir need it as '.'
76 if path == '':
77 if path == '':
77 path = '.'
78 path = '.'
78
79
79 # A few local constants to be used in loops below
80 # A few local constants to be used in loops below
80 pjoin = os.path.join
81 pjoin = os.path.join
81
82
82 if os.path.isdir(path):
83 if os.path.isdir(path):
83 # Build a list of all files in the directory and all files
84 # Build a list of all files in the directory and all files
84 # in its subdirectories. For performance reasons, do not
85 # in its subdirectories. For performance reasons, do not
85 # recurse more than one level into subdirectories.
86 # recurse more than one level into subdirectories.
86 files = []
87 files = []
87 for root, dirs, nondirs in os.walk(path, followlinks=True):
88 for root, dirs, nondirs in os.walk(path, followlinks=True):
88 subdir = root[len(path)+1:]
89 subdir = root[len(path)+1:]
89 if subdir:
90 if subdir:
90 files.extend(pjoin(subdir, f) for f in nondirs)
91 files.extend(pjoin(subdir, f) for f in nondirs)
91 dirs[:] = [] # Do not recurse into additional subdirectories.
92 dirs[:] = [] # Do not recurse into additional subdirectories.
92 else:
93 else:
93 files.extend(nondirs)
94 files.extend(nondirs)
94
95
95 else:
96 else:
96 try:
97 try:
97 files = list(zipimporter(path)._files.keys())
98 files = list(zipimporter(path)._files.keys())
98 except:
99 except:
99 files = []
100 files = []
100
101
101 # Build a list of modules which match the import_re regex.
102 # Build a list of modules which match the import_re regex.
102 modules = []
103 modules = []
103 for f in files:
104 for f in files:
104 m = import_re.match(f)
105 m = import_re.match(f)
105 if m:
106 if m:
106 modules.append(m.group('name'))
107 modules.append(m.group('name'))
107 return list(set(modules))
108 return list(set(modules))
108
109
109
110
110 def get_root_modules():
111 def get_root_modules():
111 """
112 """
112 Returns a list containing the names of all the modules available in the
113 Returns a list containing the names of all the modules available in the
113 folders of the pythonpath.
114 folders of the pythonpath.
114
115
115 ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
116 ip.db['rootmodules_cache'] maps sys.path entries to list of modules.
116 """
117 """
117 ip = get_ipython()
118 ip = get_ipython()
118 rootmodules_cache = ip.db.get('rootmodules_cache', {})
119 rootmodules_cache = ip.db.get('rootmodules_cache', {})
119 rootmodules = list(sys.builtin_module_names)
120 rootmodules = list(sys.builtin_module_names)
120 start_time = time()
121 start_time = time()
121 store = False
122 store = False
122 for path in sys.path:
123 for path in sys.path:
123 try:
124 try:
124 modules = rootmodules_cache[path]
125 modules = rootmodules_cache[path]
125 except KeyError:
126 except KeyError:
126 modules = module_list(path)
127 modules = module_list(path)
127 try:
128 try:
128 modules.remove('__init__')
129 modules.remove('__init__')
129 except ValueError:
130 except ValueError:
130 pass
131 pass
131 if path not in ('', '.'): # cwd modules should not be cached
132 if path not in ('', '.'): # cwd modules should not be cached
132 rootmodules_cache[path] = modules
133 rootmodules_cache[path] = modules
133 if time() - start_time > TIMEOUT_STORAGE and not store:
134 if time() - start_time > TIMEOUT_STORAGE and not store:
134 store = True
135 store = True
135 print("\nCaching the list of root modules, please wait!")
136 print("\nCaching the list of root modules, please wait!")
136 print("(This will only be done once - type '%rehashx' to "
137 print("(This will only be done once - type '%rehashx' to "
137 "reset cache!)\n")
138 "reset cache!)\n")
138 sys.stdout.flush()
139 sys.stdout.flush()
139 if time() - start_time > TIMEOUT_GIVEUP:
140 if time() - start_time > TIMEOUT_GIVEUP:
140 print("This is taking too long, we give up.\n")
141 print("This is taking too long, we give up.\n")
141 return []
142 return []
142 rootmodules.extend(modules)
143 rootmodules.extend(modules)
143 if store:
144 if store:
144 ip.db['rootmodules_cache'] = rootmodules_cache
145 ip.db['rootmodules_cache'] = rootmodules_cache
145 rootmodules = list(set(rootmodules))
146 rootmodules = list(set(rootmodules))
146 return rootmodules
147 return rootmodules
147
148
148
149
149 def is_importable(module, attr, only_modules):
150 def is_importable(module, attr, only_modules):
150 if only_modules:
151 if only_modules:
151 return inspect.ismodule(getattr(module, attr))
152 return inspect.ismodule(getattr(module, attr))
152 else:
153 else:
153 return not(attr[:2] == '__' and attr[-2:] == '__')
154 return not(attr[:2] == '__' and attr[-2:] == '__')
154
155
155
156
156 def try_import(mod, only_modules=False):
157 def try_import(mod, only_modules=False):
157 try:
158 try:
158 m = __import__(mod)
159 m = __import__(mod)
159 except:
160 except:
160 return []
161 return []
161 mods = mod.split('.')
162 mods = mod.split('.')
162 for module in mods[1:]:
163 for module in mods[1:]:
163 m = getattr(m, module)
164 m = getattr(m, module)
164
165
165 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
166 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
166
167
167 completions = []
168 completions = []
168 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
169 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
169 completions.extend( [attr for attr in dir(m) if
170 completions.extend( [attr for attr in dir(m) if
170 is_importable(m, attr, only_modules)])
171 is_importable(m, attr, only_modules)])
171
172
172 completions.extend(getattr(m, '__all__', []))
173 completions.extend(getattr(m, '__all__', []))
173 if m_is_init:
174 if m_is_init:
174 completions.extend(module_list(os.path.dirname(m.__file__)))
175 completions.extend(module_list(os.path.dirname(m.__file__)))
175 completions = set(completions)
176 completions = set(completions)
176 if '__init__' in completions:
177 if '__init__' in completions:
177 completions.remove('__init__')
178 completions.remove('__init__')
178 return list(completions)
179 return list(completions)
179
180
180
181
181 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
182 # Completion-related functions.
183 # Completion-related functions.
183 #-----------------------------------------------------------------------------
184 #-----------------------------------------------------------------------------
184
185
185 def quick_completer(cmd, completions):
186 def quick_completer(cmd, completions):
186 """ Easily create a trivial completer for a command.
187 """ Easily create a trivial completer for a command.
187
188
188 Takes either a list of completions, or all completions in string (that will
189 Takes either a list of completions, or all completions in string (that will
189 be split on whitespace).
190 be split on whitespace).
190
191
191 Example::
192 Example::
192
193
193 [d:\ipython]|1> import ipy_completers
194 [d:\ipython]|1> import ipy_completers
194 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
195 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
195 [d:\ipython]|3> foo b<TAB>
196 [d:\ipython]|3> foo b<TAB>
196 bar baz
197 bar baz
197 [d:\ipython]|3> foo ba
198 [d:\ipython]|3> foo ba
198 """
199 """
199
200
200 if isinstance(completions, string_types):
201 if isinstance(completions, string_types):
201 completions = completions.split()
202 completions = completions.split()
202
203
203 def do_complete(self, event):
204 def do_complete(self, event):
204 return completions
205 return completions
205
206
206 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
207 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
207
208
208 def module_completion(line):
209 def module_completion(line):
209 """
210 """
210 Returns a list containing the completion possibilities for an import line.
211 Returns a list containing the completion possibilities for an import line.
211
212
212 The line looks like this :
213 The line looks like this :
213 'import xml.d'
214 'import xml.d'
214 'from xml.dom import'
215 'from xml.dom import'
215 """
216 """
216
217
217 words = line.split(' ')
218 words = line.split(' ')
218 nwords = len(words)
219 nwords = len(words)
219
220
220 # from whatever <tab> -> 'import '
221 # from whatever <tab> -> 'import '
221 if nwords == 3 and words[0] == 'from':
222 if nwords == 3 and words[0] == 'from':
222 return ['import ']
223 return ['import ']
223
224
224 # 'from xy<tab>' or 'import xy<tab>'
225 # 'from xy<tab>' or 'import xy<tab>'
225 if nwords < 3 and (words[0] in ['import','from']) :
226 if nwords < 3 and (words[0] in ['import','from']) :
226 if nwords == 1:
227 if nwords == 1:
227 return get_root_modules()
228 return get_root_modules()
228 mod = words[1].split('.')
229 mod = words[1].split('.')
229 if len(mod) < 2:
230 if len(mod) < 2:
230 return get_root_modules()
231 return get_root_modules()
231 completion_list = try_import('.'.join(mod[:-1]), True)
232 completion_list = try_import('.'.join(mod[:-1]), True)
232 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
233 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
233
234
234 # 'from xyz import abc<tab>'
235 # 'from xyz import abc<tab>'
235 if nwords >= 3 and words[0] == 'from':
236 if nwords >= 3 and words[0] == 'from':
236 mod = words[1]
237 mod = words[1]
237 return try_import(mod)
238 return try_import(mod)
238
239
239 #-----------------------------------------------------------------------------
240 #-----------------------------------------------------------------------------
240 # Completers
241 # Completers
241 #-----------------------------------------------------------------------------
242 #-----------------------------------------------------------------------------
242 # These all have the func(self, event) signature to be used as custom
243 # These all have the func(self, event) signature to be used as custom
243 # completers
244 # completers
244
245
245 def module_completer(self,event):
246 def module_completer(self,event):
246 """Give completions after user has typed 'import ...' or 'from ...'"""
247 """Give completions after user has typed 'import ...' or 'from ...'"""
247
248
248 # This works in all versions of python. While 2.5 has
249 # This works in all versions of python. While 2.5 has
249 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
250 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
250 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
251 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
251 # of possibly problematic side effects.
252 # of possibly problematic side effects.
252 # This search the folders in the sys.path for available modules.
253 # This search the folders in the sys.path for available modules.
253
254
254 return module_completion(event.line)
255 return module_completion(event.line)
255
256
256 # FIXME: there's a lot of logic common to the run, cd and builtin file
257 # FIXME: there's a lot of logic common to the run, cd and builtin file
257 # completers, that is currently reimplemented in each.
258 # completers, that is currently reimplemented in each.
258
259
259 def magic_run_completer(self, event):
260 def magic_run_completer(self, event):
260 """Complete files that end in .py or .ipy or .ipynb for the %run command.
261 """Complete files that end in .py or .ipy or .ipynb for the %run command.
261 """
262 """
262 comps = arg_split(event.line, strict=False)
263 comps = arg_split(event.line, strict=False)
263 # relpath should be the current token that we need to complete.
264 # relpath should be the current token that we need to complete.
264 if (len(comps) > 1) and (not event.line.endswith(' ')):
265 if (len(comps) > 1) and (not event.line.endswith(' ')):
265 relpath = comps[-1].strip("'\"")
266 relpath = comps[-1].strip("'\"")
266 else:
267 else:
267 relpath = ''
268 relpath = ''
268
269
269 #print("\nev=", event) # dbg
270 #print("\nev=", event) # dbg
270 #print("rp=", relpath) # dbg
271 #print("rp=", relpath) # dbg
271 #print('comps=', comps) # dbg
272 #print('comps=', comps) # dbg
272
273
273 lglob = glob.glob
274 lglob = glob.glob
274 isdir = os.path.isdir
275 isdir = os.path.isdir
275 relpath, tilde_expand, tilde_val = expand_user(relpath)
276 relpath, tilde_expand, tilde_val = expand_user(relpath)
276
277
277 # Find if the user has already typed the first filename, after which we
278 # Find if the user has already typed the first filename, after which we
278 # should complete on all files, since after the first one other files may
279 # should complete on all files, since after the first one other files may
279 # be arguments to the input script.
280 # be arguments to the input script.
280
281
281 if any(magic_run_re.match(c) for c in comps):
282 if any(magic_run_re.match(c) for c in comps):
282 matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
283 matches = [f.replace('\\','/') + ('/' if isdir(f) else '')
283 for f in lglob(relpath+'*')]
284 for f in lglob(relpath+'*')]
284 else:
285 else:
285 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
286 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
286 pys = [f.replace('\\','/')
287 pys = [f.replace('\\','/')
287 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
288 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
288 lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
289 lglob(relpath+'*.ipynb') + lglob(relpath + '*.pyw')]
289
290
290 matches = dirs + pys
291 matches = dirs + pys
291
292
292 #print('run comp:', dirs+pys) # dbg
293 #print('run comp:', dirs+pys) # dbg
293 return [compress_user(p, tilde_expand, tilde_val) for p in matches]
294 return [compress_user(p, tilde_expand, tilde_val) for p in matches]
294
295
295
296
296 def cd_completer(self, event):
297 def cd_completer(self, event):
297 """Completer function for cd, which only returns directories."""
298 """Completer function for cd, which only returns directories."""
298 ip = get_ipython()
299 ip = get_ipython()
299 relpath = event.symbol
300 relpath = event.symbol
300
301
301 #print(event) # dbg
302 #print(event) # dbg
302 if event.line.endswith('-b') or ' -b ' in event.line:
303 if event.line.endswith('-b') or ' -b ' in event.line:
303 # return only bookmark completions
304 # return only bookmark completions
304 bkms = self.db.get('bookmarks', None)
305 bkms = self.db.get('bookmarks', None)
305 if bkms:
306 if bkms:
306 return bkms.keys()
307 return bkms.keys()
307 else:
308 else:
308 return []
309 return []
309
310
310 if event.symbol == '-':
311 if event.symbol == '-':
311 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
312 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
312 # jump in directory history by number
313 # jump in directory history by number
313 fmt = '-%0' + width_dh +'d [%s]'
314 fmt = '-%0' + width_dh +'d [%s]'
314 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
315 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
315 if len(ents) > 1:
316 if len(ents) > 1:
316 return ents
317 return ents
317 return []
318 return []
318
319
319 if event.symbol.startswith('--'):
320 if event.symbol.startswith('--'):
320 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
321 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
321
322
322 # Expand ~ in path and normalize directory separators.
323 # Expand ~ in path and normalize directory separators.
323 relpath, tilde_expand, tilde_val = expand_user(relpath)
324 relpath, tilde_expand, tilde_val = expand_user(relpath)
324 relpath = relpath.replace('\\','/')
325 relpath = relpath.replace('\\','/')
325
326
326 found = []
327 found = []
327 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
328 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
328 if os.path.isdir(f)]:
329 if os.path.isdir(f)]:
329 if ' ' in d:
330 if ' ' in d:
330 # we don't want to deal with any of that, complex code
331 # we don't want to deal with any of that, complex code
331 # for this is elsewhere
332 # for this is elsewhere
332 raise TryNext
333 raise TryNext
333
334
334 found.append(d)
335 found.append(d)
335
336
336 if not found:
337 if not found:
337 if os.path.isdir(relpath):
338 if os.path.isdir(relpath):
338 return [compress_user(relpath, tilde_expand, tilde_val)]
339 return [compress_user(relpath, tilde_expand, tilde_val)]
339
340
340 # if no completions so far, try bookmarks
341 # if no completions so far, try bookmarks
341 bks = self.db.get('bookmarks',{})
342 bks = self.db.get('bookmarks',{})
342 bkmatches = [s for s in bks if s.startswith(event.symbol)]
343 bkmatches = [s for s in bks if s.startswith(event.symbol)]
343 if bkmatches:
344 if bkmatches:
344 return bkmatches
345 return bkmatches
345
346
346 raise TryNext
347 raise TryNext
347
348
348 return [compress_user(p, tilde_expand, tilde_val) for p in found]
349 return [compress_user(p, tilde_expand, tilde_val) for p in found]
349
350
350 def reset_completer(self, event):
351 def reset_completer(self, event):
351 "A completer for %reset magic"
352 "A completer for %reset magic"
352 return '-f -s in out array dhist'.split()
353 return '-f -s in out array dhist'.split()
@@ -1,399 +1,400
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'base/js/utils',
7 'base/js/utils',
8 'base/js/keyboard',
8 'base/js/keyboard',
9 'notebook/js/contexthint',
9 'notebook/js/contexthint',
10 ], function(IPython, $, utils, keyboard) {
10 ], function(IPython, $, utils, keyboard) {
11 "use strict";
11 "use strict";
12
12
13 // easier key mapping
13 // easier key mapping
14 var keycodes = keyboard.keycodes;
14 var keycodes = keyboard.keycodes;
15
15
16 var prepend_n_prc = function(str, n) {
16 var prepend_n_prc = function(str, n) {
17 for( var i =0 ; i< n ; i++){
17 for( var i =0 ; i< n ; i++){
18 str = '%'+str ;
18 str = '%'+str ;
19 }
19 }
20 return str;
20 return str;
21 };
21 };
22
22
23 var _existing_completion = function(item, completion_array){
23 var _existing_completion = function(item, completion_array){
24 for( var i=0; i < completion_array.length; i++) {
24 for( var i=0; i < completion_array.length; i++) {
25 if (completion_array[i].trim().substr(-item.length) == item) {
25 if (completion_array[i].trim().substr(-item.length) == item) {
26 return true;
26 return true;
27 }
27 }
28 }
28 }
29 return false;
29 return false;
30 };
30 };
31
31
32 // what is the common start of all completions
32 // what is the common start of all completions
33 function shared_start(B, drop_prct) {
33 function shared_start(B, drop_prct) {
34 if (B.length == 1) {
34 if (B.length == 1) {
35 return B[0];
35 return B[0];
36 }
36 }
37 var A = [];
37 var A = [];
38 var common;
38 var common;
39 var min_lead_prct = 10;
39 var min_lead_prct = 10;
40 for (var i = 0; i < B.length; i++) {
40 for (var i = 0; i < B.length; i++) {
41 var str = B[i].str;
41 var str = B[i].str;
42 var localmin = 0;
42 var localmin = 0;
43 if(drop_prct === true){
43 if(drop_prct === true){
44 while ( str.substr(0, 1) == '%') {
44 while ( str.substr(0, 1) == '%') {
45 localmin = localmin+1;
45 localmin = localmin+1;
46 str = str.substring(1);
46 str = str.substring(1);
47 }
47 }
48 }
48 }
49 min_lead_prct = Math.min(min_lead_prct, localmin);
49 min_lead_prct = Math.min(min_lead_prct, localmin);
50 A.push(str);
50 A.push(str);
51 }
51 }
52
52
53 if (A.length > 1) {
53 if (A.length > 1) {
54 var tem1, tem2, s;
54 var tem1, tem2, s;
55 A = A.slice(0).sort();
55 A = A.slice(0).sort();
56 tem1 = A[0];
56 tem1 = A[0];
57 s = tem1.length;
57 s = tem1.length;
58 tem2 = A.pop();
58 tem2 = A.pop();
59 while (s && tem2.indexOf(tem1) == -1) {
59 while (s && tem2.indexOf(tem1) == -1) {
60 tem1 = tem1.substring(0, --s);
60 tem1 = tem1.substring(0, --s);
61 }
61 }
62 if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
62 if (tem1 === "" || tem2.indexOf(tem1) !== 0) {
63 return {
63 return {
64 str:prepend_n_prc('', min_lead_prct),
64 str:prepend_n_prc('', min_lead_prct),
65 type: "computed",
65 type: "computed",
66 from: B[0].from,
66 from: B[0].from,
67 to: B[0].to
67 to: B[0].to
68 };
68 };
69 }
69 }
70 return {
70 return {
71 str: prepend_n_prc(tem1, min_lead_prct),
71 str: prepend_n_prc(tem1, min_lead_prct),
72 type: "computed",
72 type: "computed",
73 from: B[0].from,
73 from: B[0].from,
74 to: B[0].to
74 to: B[0].to
75 };
75 };
76 }
76 }
77 return null;
77 return null;
78 }
78 }
79
79
80
80
81 var Completer = function (cell, events) {
81 var Completer = function (cell, events) {
82 this.cell = cell;
82 this.cell = cell;
83 this.editor = cell.code_mirror;
83 this.editor = cell.code_mirror;
84 var that = this;
84 var that = this;
85 events.on('status_busy.Kernel', function () {
85 events.on('status_busy.Kernel', function () {
86 that.skip_kernel_completion = true;
86 that.skip_kernel_completion = true;
87 });
87 });
88 events.on('status_idle.Kernel', function () {
88 events.on('status_idle.Kernel', function () {
89 that.skip_kernel_completion = false;
89 that.skip_kernel_completion = false;
90 });
90 });
91 };
91 };
92
92
93 Completer.prototype.startCompletion = function () {
93 Completer.prototype.startCompletion = function () {
94 // call for a 'first' completion, that will set the editor and do some
94 // call for a 'first' completion, that will set the editor and do some
95 // special behavior like autopicking if only one completion available.
95 // special behavior like autopicking if only one completion available.
96 if (this.editor.somethingSelected()) return;
96 if (this.editor.somethingSelected()) return;
97 this.done = false;
97 this.done = false;
98 // use to get focus back on opera
98 // use to get focus back on opera
99 this.carry_on_completion(true);
99 this.carry_on_completion(true);
100 };
100 };
101
101
102
102
103 // easy access for julia to monkeypatch
103 // easy access for julia to monkeypatch
104 //
104 //
105 Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;
105 Completer.reinvoke_re = /[%0-9a-z._/\\:~-]/i;
106
106
107 Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
107 Completer.prototype.reinvoke= function(pre_cursor, block, cursor){
108 return Completer.reinvoke_re.test(pre_cursor);
108 return Completer.reinvoke_re.test(pre_cursor);
109 };
109 };
110
110
111 /**
111 /**
112 *
112 *
113 * pass true as parameter if this is the first invocation of the completer
113 * pass true as parameter if this is the first invocation of the completer
114 * this will prevent the completer to dissmiss itself if it is not on a
114 * this will prevent the completer to dissmiss itself if it is not on a
115 * word boundary like pressing tab after a space, and make it autopick the
115 * word boundary like pressing tab after a space, and make it autopick the
116 * only choice if there is only one which prevent from popping the UI. as
116 * only choice if there is only one which prevent from popping the UI. as
117 * well as fast-forwarding the typing if all completion have a common
117 * well as fast-forwarding the typing if all completion have a common
118 * shared start
118 * shared start
119 **/
119 **/
120 Completer.prototype.carry_on_completion = function (first_invocation) {
120 Completer.prototype.carry_on_completion = function (first_invocation) {
121 // Pass true as parameter if you want the completer to autopick when
121 // Pass true as parameter if you want the completer to autopick when
122 // only one completion. This function is automatically reinvoked at
122 // only one completion. This function is automatically reinvoked at
123 // each keystroke with first_invocation = false
123 // each keystroke with first_invocation = false
124 var cur = this.editor.getCursor();
124 var cur = this.editor.getCursor();
125 var line = this.editor.getLine(cur.line);
125 var line = this.editor.getLine(cur.line);
126 var pre_cursor = this.editor.getRange({
126 var pre_cursor = this.editor.getRange({
127 line: cur.line,
127 line: cur.line,
128 ch: cur.ch - 1
128 ch: cur.ch - 1
129 }, cur);
129 }, cur);
130
130
131 // we need to check that we are still on a word boundary
131 // we need to check that we are still on a word boundary
132 // because while typing the completer is still reinvoking itself
132 // because while typing the completer is still reinvoking itself
133 // so dismiss if we are on a "bad" caracter
133 // so dismiss if we are on a "bad" caracter
134 if (!this.reinvoke(pre_cursor) && !first_invocation) {
134 if (!this.reinvoke(pre_cursor) && !first_invocation) {
135 this.close();
135 this.close();
136 return;
136 return;
137 }
137 }
138
138
139 this.autopick = false;
139 this.autopick = false;
140 if (first_invocation) {
140 if (first_invocation) {
141 this.autopick = true;
141 this.autopick = true;
142 }
142 }
143
143
144 // We want a single cursor position.
144 // We want a single cursor position.
145 if (this.editor.somethingSelected()) {
145 if (this.editor.somethingSelected()) {
146 return;
146 return;
147 }
147 }
148
148
149 // one kernel completion came back, finish_completing will be called with the results
149 // one kernel completion came back, finish_completing will be called with the results
150 // we fork here and directly call finish completing if kernel is busy
150 // we fork here and directly call finish completing if kernel is busy
151 var cursor_pos = utils.to_absolute_cursor_pos(this.editor, cur);
151 var cursor_pos = utils.to_absolute_cursor_pos(this.editor, cur);
152 if (this.skip_kernel_completion) {
152 if (this.skip_kernel_completion) {
153 this.finish_completing({ content: {
153 this.finish_completing({ content: {
154 matches: [],
154 matches: [],
155 cursor_start: cursor_pos,
155 cursor_start: cursor_pos,
156 cursor_end: cursor_pos,
156 cursor_end: cursor_pos,
157 }});
157 }});
158 } else {
158 } else {
159 this.cell.kernel.complete(this.editor.getValue(), cursor_pos,
159 this.cell.kernel.complete(this.editor.getValue(), cursor_pos,
160 $.proxy(this.finish_completing, this)
160 $.proxy(this.finish_completing, this)
161 );
161 );
162 }
162 }
163 };
163 };
164
164
165 Completer.prototype.finish_completing = function (msg) {
165 Completer.prototype.finish_completing = function (msg) {
166 // let's build a function that wrap all that stuff into what is needed
166 // let's build a function that wrap all that stuff into what is needed
167 // for the new completer:
167 // for the new completer:
168 console.log(msg);
168 var content = msg.content;
169 var content = msg.content;
169 var start = content.cursor_start;
170 var start = content.cursor_start;
170 var end = content.cursor_end;
171 var end = content.cursor_end;
171 var matches = content.matches;
172 var matches = content.matches;
172
173
173 var cur = this.editor.getCursor();
174 var cur = this.editor.getCursor();
174 if (end === null) {
175 if (end === null) {
175 // adapted message spec replies don't have cursor position info,
176 // adapted message spec replies don't have cursor position info,
176 // interpret end=null as current position,
177 // interpret end=null as current position,
177 // and negative start relative to that
178 // and negative start relative to that
178 end = utils.to_absolute_cursor_pos(this.editor, cur);
179 end = utils.to_absolute_cursor_pos(this.editor, cur);
179 if (start < 0) {
180 if (start < 0) {
180 start = end + start;
181 start = end + start;
181 }
182 }
182 }
183 }
183 var results = CodeMirror.contextHint(this.editor);
184 var results = CodeMirror.contextHint(this.editor);
184 var filtered_results = [];
185 var filtered_results = [];
185 //remove results from context completion
186 //remove results from context completion
186 //that are already in kernel completion
187 //that are already in kernel completion
187 var i;
188 var i;
188 for (i=0; i < results.length; i++) {
189 for (i=0; i < results.length; i++) {
189 if (!_existing_completion(results[i].str, matches)) {
190 if (!_existing_completion(results[i].str, matches)) {
190 filtered_results.push(results[i]);
191 filtered_results.push(results[i]);
191 }
192 }
192 }
193 }
193
194
194 // append the introspection result, in order, at at the beginning of
195 // append the introspection result, in order, at at the beginning of
195 // the table and compute the replacement range from current cursor
196 // the table and compute the replacement range from current cursor
196 // positon and matched_text length.
197 // positon and matched_text length.
197 for (i = matches.length - 1; i >= 0; --i) {
198 for (i = matches.length - 1; i >= 0; --i) {
198 filtered_results.unshift({
199 filtered_results.unshift({
199 str: matches[i],
200 str: matches[i],
200 type: "introspection",
201 type: "introspection",
201 from: utils.from_absolute_cursor_pos(this.editor, start),
202 from: utils.from_absolute_cursor_pos(this.editor, start),
202 to: utils.from_absolute_cursor_pos(this.editor, end)
203 to: utils.from_absolute_cursor_pos(this.editor, end)
203 });
204 });
204 }
205 }
205
206
206 // one the 2 sources results have been merge, deal with it
207 // one the 2 sources results have been merge, deal with it
207 this.raw_result = filtered_results;
208 this.raw_result = filtered_results;
208
209
209 // if empty result return
210 // if empty result return
210 if (!this.raw_result || !this.raw_result.length) return;
211 if (!this.raw_result || !this.raw_result.length) return;
211
212
212 // When there is only one completion, use it directly.
213 // When there is only one completion, use it directly.
213 if (this.autopick && this.raw_result.length == 1) {
214 if (this.autopick && this.raw_result.length == 1) {
214 this.insert(this.raw_result[0]);
215 this.insert(this.raw_result[0]);
215 return;
216 return;
216 }
217 }
217
218
218 if (this.raw_result.length == 1) {
219 if (this.raw_result.length == 1) {
219 // test if first and only completion totally matches
220 // test if first and only completion totally matches
220 // what is typed, in this case dismiss
221 // what is typed, in this case dismiss
221 var str = this.raw_result[0].str;
222 var str = this.raw_result[0].str;
222 var pre_cursor = this.editor.getRange({
223 var pre_cursor = this.editor.getRange({
223 line: cur.line,
224 line: cur.line,
224 ch: cur.ch - str.length
225 ch: cur.ch - str.length
225 }, cur);
226 }, cur);
226 if (pre_cursor == str) {
227 if (pre_cursor == str) {
227 this.close();
228 this.close();
228 return;
229 return;
229 }
230 }
230 }
231 }
231
232
232 if (!this.visible) {
233 if (!this.visible) {
233 this.complete = $('<div/>').addClass('completions');
234 this.complete = $('<div/>').addClass('completions');
234 this.complete.attr('id', 'complete');
235 this.complete.attr('id', 'complete');
235
236
236 // Currently webkit doesn't use the size attr correctly. See:
237 // Currently webkit doesn't use the size attr correctly. See:
237 // https://code.google.com/p/chromium/issues/detail?id=4579
238 // https://code.google.com/p/chromium/issues/detail?id=4579
238 this.sel = $('<select/>')
239 this.sel = $('<select/>')
239 .attr('tabindex', -1)
240 .attr('tabindex', -1)
240 .attr('multiple', 'true');
241 .attr('multiple', 'true');
241 this.complete.append(this.sel);
242 this.complete.append(this.sel);
242 this.visible = true;
243 this.visible = true;
243 $('body').append(this.complete);
244 $('body').append(this.complete);
244
245
245 //build the container
246 //build the container
246 var that = this;
247 var that = this;
247 this.sel.dblclick(function () {
248 this.sel.dblclick(function () {
248 that.pick();
249 that.pick();
249 });
250 });
250 this.sel.focus(function () {
251 this.sel.focus(function () {
251 that.editor.focus();
252 that.editor.focus();
252 });
253 });
253 this._handle_keydown = function (cm, event) {
254 this._handle_keydown = function (cm, event) {
254 that.keydown(event);
255 that.keydown(event);
255 };
256 };
256 this.editor.on('keydown', this._handle_keydown);
257 this.editor.on('keydown', this._handle_keydown);
257 this._handle_keypress = function (cm, event) {
258 this._handle_keypress = function (cm, event) {
258 that.keypress(event);
259 that.keypress(event);
259 };
260 };
260 this.editor.on('keypress', this._handle_keypress);
261 this.editor.on('keypress', this._handle_keypress);
261 }
262 }
262 this.sel.attr('size', Math.min(10, this.raw_result.length));
263 this.sel.attr('size', Math.min(10, this.raw_result.length));
263
264
264 // After everything is on the page, compute the postion.
265 // After everything is on the page, compute the postion.
265 // We put it above the code if it is too close to the bottom of the page.
266 // We put it above the code if it is too close to the bottom of the page.
266 var pos = this.editor.cursorCoords(
267 var pos = this.editor.cursorCoords(
267 utils.from_absolute_cursor_pos(this.editor, start)
268 utils.from_absolute_cursor_pos(this.editor, start)
268 );
269 );
269 var left = pos.left-3;
270 var left = pos.left-3;
270 var top;
271 var top;
271 var cheight = this.complete.height();
272 var cheight = this.complete.height();
272 var wheight = $(window).height();
273 var wheight = $(window).height();
273 if (pos.bottom+cheight+5 > wheight) {
274 if (pos.bottom+cheight+5 > wheight) {
274 top = pos.top-cheight-4;
275 top = pos.top-cheight-4;
275 } else {
276 } else {
276 top = pos.bottom+1;
277 top = pos.bottom+1;
277 }
278 }
278 this.complete.css('left', left + 'px');
279 this.complete.css('left', left + 'px');
279 this.complete.css('top', top + 'px');
280 this.complete.css('top', top + 'px');
280
281
281 // Clear and fill the list.
282 // Clear and fill the list.
282 this.sel.text('');
283 this.sel.text('');
283 this.build_gui_list(this.raw_result);
284 this.build_gui_list(this.raw_result);
284 return true;
285 return true;
285 };
286 };
286
287
287 Completer.prototype.insert = function (completion) {
288 Completer.prototype.insert = function (completion) {
288 this.editor.replaceRange(completion.str, completion.from, completion.to);
289 this.editor.replaceRange(completion.str, completion.from, completion.to);
289 };
290 };
290
291
291 Completer.prototype.build_gui_list = function (completions) {
292 Completer.prototype.build_gui_list = function (completions) {
292 for (var i = 0; i < completions.length; ++i) {
293 for (var i = 0; i < completions.length; ++i) {
293 var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
294 var opt = $('<option/>').text(completions[i].str).addClass(completions[i].type);
294 this.sel.append(opt);
295 this.sel.append(opt);
295 }
296 }
296 this.sel.children().first().attr('selected', 'true');
297 this.sel.children().first().attr('selected', 'true');
297 this.sel.scrollTop(0);
298 this.sel.scrollTop(0);
298 };
299 };
299
300
300 Completer.prototype.close = function () {
301 Completer.prototype.close = function () {
301 this.done = true;
302 this.done = true;
302 $('#complete').remove();
303 $('#complete').remove();
303 this.editor.off('keydown', this._handle_keydown);
304 this.editor.off('keydown', this._handle_keydown);
304 this.editor.off('keypress', this._handle_keypress);
305 this.editor.off('keypress', this._handle_keypress);
305 this.visible = false;
306 this.visible = false;
306 };
307 };
307
308
308 Completer.prototype.pick = function () {
309 Completer.prototype.pick = function () {
309 this.insert(this.raw_result[this.sel[0].selectedIndex]);
310 this.insert(this.raw_result[this.sel[0].selectedIndex]);
310 this.close();
311 this.close();
311 };
312 };
312
313
313 Completer.prototype.keydown = function (event) {
314 Completer.prototype.keydown = function (event) {
314 var code = event.keyCode;
315 var code = event.keyCode;
315 var that = this;
316 var that = this;
316
317
317 // Enter
318 // Enter
318 if (code == keycodes.enter) {
319 if (code == keycodes.enter) {
319 CodeMirror.e_stop(event);
320 CodeMirror.e_stop(event);
320 this.pick();
321 this.pick();
321 // Escape or backspace
322 // Escape or backspace
322 } else if (code == keycodes.esc || code == keycodes.backspace) {
323 } else if (code == keycodes.esc || code == keycodes.backspace) {
323 CodeMirror.e_stop(event);
324 CodeMirror.e_stop(event);
324 this.close();
325 this.close();
325 } else if (code == keycodes.tab) {
326 } else if (code == keycodes.tab) {
326 //all the fastforwarding operation,
327 //all the fastforwarding operation,
327 //Check that shared start is not null which can append with prefixed completion
328 //Check that shared start is not null which can append with prefixed completion
328 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
329 // like %pylab , pylab have no shred start, and ff will result in py<tab><tab>
329 // to erase py
330 // to erase py
330 var sh = shared_start(this.raw_result, true);
331 var sh = shared_start(this.raw_result, true);
331 if (sh) {
332 if (sh) {
332 this.insert(sh);
333 this.insert(sh);
333 }
334 }
334 this.close();
335 this.close();
335 //reinvoke self
336 //reinvoke self
336 setTimeout(function () {
337 setTimeout(function () {
337 that.carry_on_completion();
338 that.carry_on_completion();
338 }, 50);
339 }, 50);
339 } else if (code == keycodes.up || code == keycodes.down) {
340 } else if (code == keycodes.up || code == keycodes.down) {
340 // need to do that to be able to move the arrow
341 // need to do that to be able to move the arrow
341 // when on the first or last line ofo a code cell
342 // when on the first or last line ofo a code cell
342 CodeMirror.e_stop(event);
343 CodeMirror.e_stop(event);
343
344
344 var options = this.sel.find('option');
345 var options = this.sel.find('option');
345 var index = this.sel[0].selectedIndex;
346 var index = this.sel[0].selectedIndex;
346 if (code == keycodes.up) {
347 if (code == keycodes.up) {
347 index--;
348 index--;
348 }
349 }
349 if (code == keycodes.down) {
350 if (code == keycodes.down) {
350 index++;
351 index++;
351 }
352 }
352 index = Math.min(Math.max(index, 0), options.length-1);
353 index = Math.min(Math.max(index, 0), options.length-1);
353 this.sel[0].selectedIndex = index;
354 this.sel[0].selectedIndex = index;
354 } else if (code == keycodes.pageup || code == keycodes.pagedown) {
355 } else if (code == keycodes.pageup || code == keycodes.pagedown) {
355 CodeMirror.e_stop(event);
356 CodeMirror.e_stop(event);
356
357
357 var options = this.sel.find('option');
358 var options = this.sel.find('option');
358 var index = this.sel[0].selectedIndex;
359 var index = this.sel[0].selectedIndex;
359 if (code == keycodes.pageup) {
360 if (code == keycodes.pageup) {
360 index -= 10; // As 10 is the hard coded size of the drop down menu
361 index -= 10; // As 10 is the hard coded size of the drop down menu
361 } else {
362 } else {
362 index += 10;
363 index += 10;
363 }
364 }
364 index = Math.min(Math.max(index, 0), options.length-1);
365 index = Math.min(Math.max(index, 0), options.length-1);
365 this.sel[0].selectedIndex = index;
366 this.sel[0].selectedIndex = index;
366 } else if (code == keycodes.left || code == keycodes.right) {
367 } else if (code == keycodes.left || code == keycodes.right) {
367 this.close();
368 this.close();
368 }
369 }
369 };
370 };
370
371
371 Completer.prototype.keypress = function (event) {
372 Completer.prototype.keypress = function (event) {
372 // FIXME: This is a band-aid.
373 // FIXME: This is a band-aid.
373 // on keypress, trigger insertion of a single character.
374 // on keypress, trigger insertion of a single character.
374 // This simulates the old behavior of completion as you type,
375 // This simulates the old behavior of completion as you type,
375 // before events were disconnected and CodeMirror stopped
376 // before events were disconnected and CodeMirror stopped
376 // receiving events while the completer is focused.
377 // receiving events while the completer is focused.
377
378
378 var that = this;
379 var that = this;
379 var code = event.keyCode;
380 var code = event.keyCode;
380
381
381 // don't handle keypress if it's not a character (arrows on FF)
382 // don't handle keypress if it's not a character (arrows on FF)
382 // or ENTER/TAB
383 // or ENTER/TAB
383 if (event.charCode === 0 ||
384 if (event.charCode === 0 ||
384 code == keycodes.tab ||
385 code == keycodes.tab ||
385 code == keycodes.enter
386 code == keycodes.enter
386 ) return;
387 ) return;
387
388
388 this.close();
389 this.close();
389 this.editor.focus();
390 this.editor.focus();
390 setTimeout(function () {
391 setTimeout(function () {
391 that.carry_on_completion();
392 that.carry_on_completion();
392 }, 50);
393 }, 50);
393 };
394 };
394
395
395 // For backwards compatability.
396 // For backwards compatability.
396 IPython.Completer = Completer;
397 IPython.Completer = Completer;
397
398
398 return {'Completer': Completer};
399 return {'Completer': Completer};
399 });
400 });
General Comments 0
You need to be logged in to leave comments. Login now