|
|
from IPython.core.interactiveshell import InteractiveShell
|
|
|
|
|
|
from prompt_toolkit.completion import Completer, Completion
|
|
|
from prompt_toolkit.history import InMemoryHistory
|
|
|
from prompt_toolkit.shortcuts import create_prompt_application
|
|
|
from prompt_toolkit.interface import CommandLineInterface
|
|
|
from prompt_toolkit.key_binding.manager import KeyBindingManager
|
|
|
from prompt_toolkit.keys import Keys
|
|
|
from prompt_toolkit.layout.lexers import PygmentsLexer
|
|
|
|
|
|
from pygments.lexers import Python3Lexer
|
|
|
from pygments.token import Token
|
|
|
|
|
|
|
|
|
class IPythonPTCompleter(Completer):
|
|
|
"""Adaptor to provide IPython completions to prompt_toolkit"""
|
|
|
def __init__(self, ipy_completer):
|
|
|
self.ipy_completer = ipy_completer
|
|
|
|
|
|
def get_completions(self, document, complete_event):
|
|
|
used, matches = self.ipy_completer.complete(
|
|
|
line_buffer=document.current_line,
|
|
|
cursor_pos=document.cursor_position_col
|
|
|
)
|
|
|
start_pos = -len(used)
|
|
|
for m in matches:
|
|
|
yield Completion(m, start_position=start_pos)
|
|
|
|
|
|
|
|
|
class PTInteractiveShell(InteractiveShell):
|
|
|
pt_cli = None
|
|
|
|
|
|
def get_prompt_tokens(self, cli):
|
|
|
return [
|
|
|
(Token.Prompt, 'In ['),
|
|
|
(Token.Prompt, str(self.execution_count)),
|
|
|
(Token.Prompt, ']: '),
|
|
|
]
|
|
|
|
|
|
|
|
|
def init_prompt_toolkit_cli(self):
|
|
|
kbmanager = KeyBindingManager.for_prompt()
|
|
|
@kbmanager.registry.add_binding(Keys.ControlJ) # Ctrl+J == Enter, seemingly
|
|
|
def _(event):
|
|
|
b = event.current_buffer
|
|
|
if not b.document.on_last_line:
|
|
|
b.newline()
|
|
|
return
|
|
|
|
|
|
status, indent = self.input_splitter.check_complete(b.document.text)
|
|
|
|
|
|
if (status != 'incomplete') and b.accept_action.is_returnable:
|
|
|
b.accept_action.validate_and_handle(event.cli, b)
|
|
|
else:
|
|
|
b.insert_text('\n' + (' ' * (indent or 0)))
|
|
|
|
|
|
@kbmanager.registry.add_binding(Keys.ControlC)
|
|
|
def _(event):
|
|
|
event.current_buffer.reset()
|
|
|
|
|
|
# Pre-populate history from IPython's history database
|
|
|
history = InMemoryHistory()
|
|
|
last_cell = u""
|
|
|
for _, _, cell in self.history_manager.get_tail(self.history_load_length,
|
|
|
include_latest=True):
|
|
|
# Ignore blank lines and consecutive duplicates
|
|
|
cell = cell.rstrip()
|
|
|
if cell and (cell != last_cell):
|
|
|
history.append(cell)
|
|
|
|
|
|
app = create_prompt_application(multiline=True,
|
|
|
lexer=PygmentsLexer(Python3Lexer),
|
|
|
get_prompt_tokens=self.get_prompt_tokens,
|
|
|
key_bindings_registry=kbmanager.registry,
|
|
|
history=history,
|
|
|
completer=IPythonPTCompleter(self.Completer),
|
|
|
)
|
|
|
|
|
|
self.pt_cli = CommandLineInterface(app)
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
super(PTInteractiveShell, self).__init__(*args, **kwargs)
|
|
|
self.init_prompt_toolkit_cli()
|
|
|
self.keep_running = True
|
|
|
|
|
|
def ask_exit(self):
|
|
|
self.keep_running = False
|
|
|
|
|
|
def interact(self):
|
|
|
while self.keep_running:
|
|
|
try:
|
|
|
document = self.pt_cli.run()
|
|
|
except EOFError:
|
|
|
if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'):
|
|
|
self.ask_exit()
|
|
|
|
|
|
else:
|
|
|
if document:
|
|
|
self.run_cell(document.text, store_history=True)
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
PTInteractiveShell.instance().interact()
|
|
|
|