##// END OF EJS Templates
Backport PR #10153: Use prompt_toolkit's patch_stdout_context when finding completions...
Min RK -
Show More
@@ -1,108 +1,112 b''
1 1 """prompt-toolkit utilities
2 2
3 3 Everything in this module is a private API,
4 4 not to be used outside IPython.
5 5 """
6 6
7 7 # Copyright (c) IPython Development Team.
8 8 # Distributed under the terms of the Modified BSD License.
9 9
10 10 import unicodedata
11 11 from wcwidth import wcwidth
12 12
13 13 from IPython.utils.py3compat import PY3
14 14
15 15 from IPython.core.completer import IPCompleter
16 16 from prompt_toolkit.completion import Completer, Completion
17 17 from prompt_toolkit.layout.lexers import Lexer
18 18 from prompt_toolkit.layout.lexers import PygmentsLexer
19 19
20 20 import pygments.lexers as pygments_lexers
21 21
22 22
23 23 class IPythonPTCompleter(Completer):
24 24 """Adaptor to provide IPython completions to prompt_toolkit"""
25 25 def __init__(self, ipy_completer=None, shell=None):
26 26 if shell is None and ipy_completer is None:
27 27 raise TypeError("Please pass shell=an InteractiveShell instance.")
28 28 self._ipy_completer = ipy_completer
29 29 self.shell = shell
30 30
31 31 @property
32 32 def ipy_completer(self):
33 33 if self._ipy_completer:
34 34 return self._ipy_completer
35 35 else:
36 36 return self.shell.Completer
37 37
38 38 def get_completions(self, document, complete_event):
39 39 if not document.current_line.strip():
40 40 return
41 41
42 used, matches = self.ipy_completer.complete(
43 line_buffer=document.current_line,
44 cursor_pos=document.cursor_position_col
45 )
42 # Some bits of our completion system may print stuff (e.g. if a module
43 # is imported). This context manager ensures that doesn't interfere with
44 # the prompt.
45 with self.shell.pt_cli.patch_stdout_context():
46 used, matches = self.ipy_completer.complete(
47 line_buffer=document.current_line,
48 cursor_pos=document.cursor_position_col
49 )
46 50 start_pos = -len(used)
47 51 for m in matches:
48 52 if not m:
49 53 # Guard against completion machinery giving us an empty string.
50 54 continue
51 55
52 56 m = unicodedata.normalize('NFC', m)
53 57
54 58 # When the first character of the completion has a zero length,
55 59 # then it's probably a decomposed unicode character. E.g. caused by
56 60 # the "\dot" completion. Try to compose again with the previous
57 61 # character.
58 62 if wcwidth(m[0]) == 0:
59 63 if document.cursor_position + start_pos > 0:
60 64 char_before = document.text[document.cursor_position + start_pos - 1]
61 65 m = unicodedata.normalize('NFC', char_before + m)
62 66
63 67 # Yield the modified completion instead, if this worked.
64 68 if wcwidth(m[0:1]) == 1:
65 69 yield Completion(m, start_position=start_pos - 1)
66 70 continue
67 71
68 72 # TODO: Use Jedi to determine meta_text
69 73 # (Jedi currently has a bug that results in incorrect information.)
70 74 # meta_text = ''
71 75 # yield Completion(m, start_position=start_pos,
72 76 # display_meta=meta_text)
73 77 yield Completion(m, start_position=start_pos)
74 78
75 79 class IPythonPTLexer(Lexer):
76 80 """
77 81 Wrapper around PythonLexer and BashLexer.
78 82 """
79 83 def __init__(self):
80 84 l = pygments_lexers
81 85 self.python_lexer = PygmentsLexer(l.Python3Lexer if PY3 else l.PythonLexer)
82 86 self.shell_lexer = PygmentsLexer(l.BashLexer)
83 87
84 88 self.magic_lexers = {
85 89 'HTML': PygmentsLexer(l.HtmlLexer),
86 90 'html': PygmentsLexer(l.HtmlLexer),
87 91 'javascript': PygmentsLexer(l.JavascriptLexer),
88 92 'js': PygmentsLexer(l.JavascriptLexer),
89 93 'perl': PygmentsLexer(l.PerlLexer),
90 94 'ruby': PygmentsLexer(l.RubyLexer),
91 95 'latex': PygmentsLexer(l.TexLexer),
92 96 }
93 97
94 98 def lex_document(self, cli, document):
95 99 text = document.text.lstrip()
96 100
97 101 lexer = self.python_lexer
98 102
99 103 if text.startswith('!') or text.startswith('%%bash'):
100 104 lexer = self.shell_lexer
101 105
102 106 elif text.startswith('%%'):
103 107 for magic, l in self.magic_lexers.items():
104 108 if text.startswith('%%' + magic):
105 109 lexer = l
106 110 break
107 111
108 112 return lexer.lex_document(cli, document)
General Comments 0
You need to be logged in to leave comments. Login now