ptutils.py
115 lines
| 4.1 KiB
| text/x-python
|
PythonLexer
Min RK
|
r22768 | """prompt-toolkit utilities | ||
Everything in this module is a private API, | ||||
not to be used outside IPython. | ||||
""" | ||||
# Copyright (c) IPython Development Team. | ||||
# Distributed under the terms of the Modified BSD License. | ||||
Thomas Kluyver
|
r22388 | import unicodedata | ||
from wcwidth import wcwidth | ||||
from IPython.utils.py3compat import PY3 | ||||
Min RK
|
r22767 | from IPython.core.completer import IPCompleter | ||
Thomas Kluyver
|
r22388 | from prompt_toolkit.completion import Completer, Completion | ||
from prompt_toolkit.layout.lexers import Lexer | ||||
from prompt_toolkit.layout.lexers import PygmentsLexer | ||||
Jonathan Slenders
|
r22512 | import pygments.lexers as pygments_lexers | ||
Thomas Kluyver
|
r22388 | |||
class IPythonPTCompleter(Completer): | ||||
"""Adaptor to provide IPython completions to prompt_toolkit""" | ||||
Min RK
|
r23276 | def __init__(self, ipy_completer=None, shell=None, patch_stdout=None): | ||
Min RK
|
r22768 | if shell is None and ipy_completer is None: | ||
raise TypeError("Please pass shell=an InteractiveShell instance.") | ||||
self._ipy_completer = ipy_completer | ||||
Min RK
|
r22765 | self.shell = shell | ||
Min RK
|
r23276 | if patch_stdout is None: | ||
raise TypeError("Please pass patch_stdout") | ||||
self.patch_stdout = patch_stdout | ||||
Min RK
|
r22767 | |||
Min RK
|
r22765 | @property | ||
def ipy_completer(self): | ||||
Min RK
|
r22768 | if self._ipy_completer: | ||
return self._ipy_completer | ||||
else: | ||||
return self.shell.Completer | ||||
Thomas Kluyver
|
r22388 | |||
def get_completions(self, document, complete_event): | ||||
if not document.current_line.strip(): | ||||
return | ||||
Min RK
|
r23246 | # Some bits of our completion system may print stuff (e.g. if a module | ||
# is imported). This context manager ensures that doesn't interfere with | ||||
# the prompt. | ||||
Min RK
|
r23276 | with self.patch_stdout(): | ||
Min RK
|
r23246 | used, matches = self.ipy_completer.complete( | ||
line_buffer=document.current_line, | ||||
cursor_pos=document.cursor_position_col | ||||
) | ||||
Thomas Kluyver
|
r22388 | start_pos = -len(used) | ||
for m in matches: | ||||
Thomas Kluyver
|
r22445 | if not m: | ||
# Guard against completion machinery giving us an empty string. | ||||
continue | ||||
Thomas Kluyver
|
r22388 | m = unicodedata.normalize('NFC', m) | ||
# When the first character of the completion has a zero length, | ||||
# then it's probably a decomposed unicode character. E.g. caused by | ||||
# the "\dot" completion. Try to compose again with the previous | ||||
# character. | ||||
if wcwidth(m[0]) == 0: | ||||
if document.cursor_position + start_pos > 0: | ||||
char_before = document.text[document.cursor_position + start_pos - 1] | ||||
m = unicodedata.normalize('NFC', char_before + m) | ||||
# Yield the modified completion instead, if this worked. | ||||
if wcwidth(m[0:1]) == 1: | ||||
yield Completion(m, start_position=start_pos - 1) | ||||
continue | ||||
# TODO: Use Jedi to determine meta_text | ||||
# (Jedi currently has a bug that results in incorrect information.) | ||||
# meta_text = '' | ||||
# yield Completion(m, start_position=start_pos, | ||||
# display_meta=meta_text) | ||||
yield Completion(m, start_position=start_pos) | ||||
class IPythonPTLexer(Lexer): | ||||
""" | ||||
Wrapper around PythonLexer and BashLexer. | ||||
""" | ||||
def __init__(self): | ||||
Jonathan Slenders
|
r22512 | l = pygments_lexers | ||
self.python_lexer = PygmentsLexer(l.Python3Lexer if PY3 else l.PythonLexer) | ||||
self.shell_lexer = PygmentsLexer(l.BashLexer) | ||||
self.magic_lexers = { | ||||
'HTML': PygmentsLexer(l.HtmlLexer), | ||||
'html': PygmentsLexer(l.HtmlLexer), | ||||
'javascript': PygmentsLexer(l.JavascriptLexer), | ||||
'js': PygmentsLexer(l.JavascriptLexer), | ||||
'perl': PygmentsLexer(l.PerlLexer), | ||||
'ruby': PygmentsLexer(l.RubyLexer), | ||||
'latex': PygmentsLexer(l.TexLexer), | ||||
} | ||||
Thomas Kluyver
|
r22388 | |||
def lex_document(self, cli, document): | ||||
Jonathan Slenders
|
r22512 | text = document.text.lstrip() | ||
lexer = self.python_lexer | ||||
if text.startswith('!') or text.startswith('%%bash'): | ||||
lexer = self.shell_lexer | ||||
elif text.startswith('%%'): | ||||
for magic, l in self.magic_lexers.items(): | ||||
if text.startswith('%%' + magic): | ||||
lexer = l | ||||
break | ||||
return lexer.lex_document(cli, document) | ||||