You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.8 KiB
128 lines
3.8 KiB
6 years ago
|
"""
|
||
|
For internal use only.
|
||
|
"""
|
||
|
from __future__ import unicode_literals
|
||
|
|
||
|
from prompt_toolkit.mouse_events import MouseEventType
|
||
|
import re
|
||
|
|
||
|
__all__ = (
|
||
|
'has_unclosed_brackets',
|
||
|
'get_jedi_script_from_document',
|
||
|
'document_is_multiline_python',
|
||
|
)
|
||
|
|
||
|
|
||
|
def has_unclosed_brackets(text):
|
||
|
"""
|
||
|
Starting at the end of the string. If we find an opening bracket
|
||
|
for which we didn't had a closing one yet, return True.
|
||
|
"""
|
||
|
stack = []
|
||
|
|
||
|
# Ignore braces inside strings
|
||
|
text = re.sub(r'''('[^']*'|"[^"]*")''', '', text) # XXX: handle escaped quotes.!
|
||
|
|
||
|
for c in reversed(text):
|
||
|
if c in '])}':
|
||
|
stack.append(c)
|
||
|
|
||
|
elif c in '[({':
|
||
|
if stack:
|
||
|
if ((c == '[' and stack[-1] == ']') or
|
||
|
(c == '{' and stack[-1] == '}') or
|
||
|
(c == '(' and stack[-1] == ')')):
|
||
|
stack.pop()
|
||
|
else:
|
||
|
# Opening bracket for which we didn't had a closing one.
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
|
||
|
def get_jedi_script_from_document(document, locals, globals):
|
||
|
import jedi # We keep this import in-line, to improve start-up time.
|
||
|
# Importing Jedi is 'slow'.
|
||
|
|
||
|
try:
|
||
|
return jedi.Interpreter(
|
||
|
document.text,
|
||
|
column=document.cursor_position_col,
|
||
|
line=document.cursor_position_row + 1,
|
||
|
path='input-text',
|
||
|
namespaces=[locals, globals])
|
||
|
except ValueError:
|
||
|
# Invalid cursor position.
|
||
|
# ValueError('`column` parameter is not in a valid range.')
|
||
|
return None
|
||
|
except AttributeError:
|
||
|
# Workaround for #65: https://github.com/jonathanslenders/python-prompt-toolkit/issues/65
|
||
|
# See also: https://github.com/davidhalter/jedi/issues/508
|
||
|
return None
|
||
|
except IndexError:
|
||
|
# Workaround Jedi issue #514: for https://github.com/davidhalter/jedi/issues/514
|
||
|
return None
|
||
|
except KeyError:
|
||
|
# Workaroud for a crash when the input is "u'", the start of a unicode string.
|
||
|
return None
|
||
|
except Exception:
|
||
|
# Workaround for: https://github.com/jonathanslenders/ptpython/issues/91
|
||
|
return None
|
||
|
|
||
|
|
||
|
_multiline_string_delims = re.compile('''[']{3}|["]{3}''')
|
||
|
|
||
|
|
||
|
def document_is_multiline_python(document):
|
||
|
"""
|
||
|
Determine whether this is a multiline Python document.
|
||
|
"""
|
||
|
def ends_in_multiline_string():
|
||
|
"""
|
||
|
``True`` if we're inside a multiline string at the end of the text.
|
||
|
"""
|
||
|
delims = _multiline_string_delims.findall(document.text)
|
||
|
opening = None
|
||
|
for delim in delims:
|
||
|
if opening is None:
|
||
|
opening = delim
|
||
|
elif delim == opening:
|
||
|
opening = None
|
||
|
return bool(opening)
|
||
|
|
||
|
if '\n' in document.text or ends_in_multiline_string():
|
||
|
return True
|
||
|
|
||
|
def line_ends_with_colon():
|
||
|
return document.current_line.rstrip()[-1:] == ':'
|
||
|
|
||
|
# If we just typed a colon, or still have open brackets, always insert a real newline.
|
||
|
if line_ends_with_colon() or \
|
||
|
(document.is_cursor_at_the_end and
|
||
|
has_unclosed_brackets(document.text_before_cursor)) or \
|
||
|
document.text.startswith('@'):
|
||
|
return True
|
||
|
|
||
|
# If the character before the cursor is a backslash (line continuation
|
||
|
# char), insert a new line.
|
||
|
elif document.text_before_cursor[-1:] == '\\':
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
|
||
|
def if_mousedown(handler):
|
||
|
"""
|
||
|
Decorator for mouse handlers.
|
||
|
Only handle event when the user pressed mouse down.
|
||
|
|
||
|
(When applied to a token list. Scroll events will bubble up and are handled
|
||
|
by the Window.)
|
||
|
"""
|
||
|
def handle_if_mouse_down(mouse_event):
|
||
|
if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
|
||
|
return handler(mouse_event)
|
||
|
else:
|
||
|
return NotImplemented
|
||
|
return handle_if_mouse_down
|