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