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