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