forked from prompt-toolkit/ptpython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpython_input.py
More file actions
203 lines (165 loc) · 7.37 KB
/
python_input.py
File metadata and controls
203 lines (165 loc) · 7.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
"""
CommandLineInterface for reading Python input.
This can be used for creation of Python REPLs.
::
from prompt_toolkit.contrib.python_import import PythonCommandLineInterface
python_interface = PythonCommandLineInterface()
python_interface.cli.read_input()
"""
from __future__ import unicode_literals
from prompt_toolkit import AbortAction
from prompt_toolkit import CommandLineInterface
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.filters import Condition, Always
from prompt_toolkit.history import FileHistory, History
from prompt_toolkit.key_binding.manager import KeyBindingManager
from ptpython.completer import PythonCompleter
from ptpython.key_bindings import load_python_bindings
from ptpython.layout import PythonPrompt, create_layout
from ptpython.style import PythonStyle
from ptpython.utils import get_jedi_script_from_document, document_is_multiline_python
from ptpython.validator import PythonValidator
from pygments.lexers import PythonLexer
import six
__all__ = (
'PythonCommandLineInterface',
)
class PythonCLISettings(object):
"""
Settings for the Python REPL which can change at runtime.
"""
def __init__(self, paste_mode=False):
self.show_sidebar = False
self.show_signature = True
self.show_docstring = False
self.show_completions_toolbar = False
self.show_completions_menu = True
self.show_line_numbers = True
self.complete_while_typing = True
#: Boolean `paste` flag. If True, don't insert whitespace after a
#: newline.
self.paste_mode = paste_mode
#: Incremeting integer counting the current statement.
self.current_statement_index = 1
# Code signatures. (This is set asynchronously after a timeout.)
self.signatures = []
class PythonCommandLineInterface(object):
def __init__(self,
eventloop,
get_globals=None, get_locals=None,
stdin=None, stdout=None,
vi_mode=False, history_filename=None,
style=PythonStyle,
# For internal use.
_completer=None,
_validator=None,
_lexer=None,
_python_prompt_control=None,
_extra_buffers=None,
_extra_buffer_processors=None,
_extra_sidebars=None):
self.settings = PythonCLISettings()
self.get_globals = get_globals or (lambda: {})
self.get_locals = get_locals or self.get_globals
self.completer = _completer or PythonCompleter(self.get_globals, self.get_locals)
self.validator = _validator or PythonValidator()
self.history = FileHistory(history_filename) if history_filename else History()
self.python_prompt_control = _python_prompt_control or PythonPrompt(self.settings)
self._extra_sidebars = _extra_sidebars or []
self._extra_buffer_processors = _extra_buffer_processors or []
self._lexer = _lexer or PythonLexer
# Use a KeyBindingManager for loading the key bindings.
self.key_bindings_manager = KeyBindingManager(enable_vi_mode=vi_mode,
enable_open_in_editor=True,
enable_system_prompt=True)
load_python_bindings(self.key_bindings_manager, self.settings)
self.get_signatures_thread_running = False
buffers = {
'default': self._create_python_buffer(),
'docstring': Buffer(), # XXX: make docstring read only.
}
buffers.update(_extra_buffers or {})
self.cli = CommandLineInterface(
eventloop=eventloop,
style=style,
key_bindings_registry=self.key_bindings_manager.registry,
buffers=buffers,
paste_mode=Condition(lambda cli: self.settings.paste_mode),
layout=self._create_layout(),
on_abort=AbortAction.RETRY,
on_exit=AbortAction.RAISE_EXCEPTION)
def on_input_timeout():
"""
When there is no input activity,
in another thread, get the signature of the current code.
"""
if self.cli.focus_stack.current != 'default':
return
# Never run multiple get-signature threads.
if self.get_signatures_thread_running:
return
self.get_signatures_thread_running = True
buffer = self.cli.current_buffer
document = buffer.document
def run():
script = get_jedi_script_from_document(document, self.get_locals(), self.get_globals())
# Show signatures in help text.
if script:
try:
signatures = script.call_signatures()
except ValueError:
# e.g. in case of an invalid \\x escape.
signatures = []
except Exception:
# Sometimes we still get an exception (TypeError), because
# of probably bugs in jedi. We can silence them.
# See: https://github.com/davidhalter/jedi/issues/492
signatures = []
else:
signatures = []
self.get_signatures_thread_running = False
# Set signatures and redraw if the text didn't change in the
# meantime. Otherwise request new signatures.
if buffer.text == document.text:
self.settings.signatures = signatures
# Set docstring in docstring buffer.
if signatures:
string = signatures[0].docstring()
if not isinstance(string, six.text_type):
string = string.decode('utf-8')
self.cli.buffers['docstring'].reset(
initial_document=Document(string, cursor_position=0))
else:
self.cli.buffers['docstring'].reset()
self.cli.request_redraw()
else:
on_input_timeout()
self.cli.eventloop.run_in_executor(run)
def reset():
self.key_bindings_manager.reset()
self.settings.signatures = []
self.cli.onReset += reset
self.cli.onInputTimeout += on_input_timeout
def _create_layout(self):
"""
Generate new layout.
"""
return create_layout(
self.settings, self.key_bindings_manager, self.python_prompt_control,
lexer=self._lexer,
extra_buffer_processors=self._extra_buffer_processors,
extra_sidebars=self._extra_sidebars)
def _create_python_buffer(self):
def is_buffer_multiline():
return (self.settings.paste_mode or
document_is_multiline_python(b.document))
b = Buffer(
is_multiline=Condition(is_buffer_multiline),
complete_while_typing=Condition(lambda: self.settings.complete_while_typing),
enable_history_search=Always(),
tempfile_suffix='.py',
history=self.history,
completer=self.completer,
validator=self.validator)
return b