X Tutup
"""Extracting and changing portions of the current line All functions take cursor offset from the beginning of the line and the line of Python code, and return None, or a tuple of the start index, end index, and the word.""" from itertools import chain from collections import namedtuple from .lazyre import LazyReCompile LinePart = namedtuple("LinePart", ["start", "stop", "word"]) current_word_re = LazyReCompile(r"(?= pos: start = m.start(1) end = m.end(1) word = m.group(1) if word is None: return None return LinePart(start, end, word) current_dict_key_re = LazyReCompile(r"""[\w_][\w0-9._]*\[([\w0-9._(), '"]*)""") def current_dict_key(cursor_offset, line): """If in dictionary completion, return the current key""" for m in current_dict_key_re.finditer(line): if m.start(1) <= cursor_offset and m.end(1) >= cursor_offset: return LinePart(m.start(1), m.end(1), m.group(1)) return None current_dict_re = LazyReCompile(r"""([\w_][\w0-9._]*)\[([\w0-9._(), '"]*)""") def current_dict(cursor_offset, line): """If in dictionary completion, return the dict that should be used""" for m in current_dict_re.finditer(line): if m.start(2) <= cursor_offset and m.end(2) >= cursor_offset: return LinePart(m.start(1), m.end(1), m.group(1)) return None current_string_re = LazyReCompile( '''(?P(?:""")|"|(?:''\')|')(?:((?P.+?)(?P=open))|''' """(?P.+))""" ) def current_string(cursor_offset, line): """If inside a string of nonzero length, return the string (excluding quotes) Weaker than bpython.Repl's current_string, because that checks that a string is a string based on previous lines in the buffer.""" for m in current_string_re.finditer(line): i = 3 if m.group(3) else 4 if m.start(i) <= cursor_offset and m.end(i) >= cursor_offset: return LinePart(m.start(i), m.end(i), m.group(i)) return None current_object_re = LazyReCompile(r"([\w_][\w0-9_]*)[.]") def current_object(cursor_offset, line): """If in attribute completion, the object on which attribute should be looked up.""" match = current_word(cursor_offset, line) if match is None: return None start, end, word = match s = "" for m in current_object_re.finditer(word): if m.end(1) + start < cursor_offset: if s: s += "." s += m.group(1) if not s: return None return LinePart(start, start + len(s), s) current_object_attribute_re = LazyReCompile(r"([\w_][\w0-9_]*)[.]?") def current_object_attribute(cursor_offset, line): """If in attribute completion, the attribute being completed""" # TODO replace with more general current_expression_attribute match = current_word(cursor_offset, line) if match is None: return None start, end, word = match matches = current_object_attribute_re.finditer(word) next(matches) for m in matches: if ( m.start(1) + start <= cursor_offset and m.end(1) + start >= cursor_offset ): return LinePart(m.start(1) + start, m.end(1) + start, m.group(1)) return None current_from_import_from_re = LazyReCompile( r"from +([\w0-9_.]*)(?:\s+import\s+([\w0-9_]+[,]?\s*)+)*" ) def current_from_import_from(cursor_offset, line): """If in from import completion, the word after from returns None if cursor not in or just after one of the two interesting parts of an import: from (module) import (name1, name2) """ # TODO allow for as's for m in current_from_import_from_re.finditer(line): if (m.start(1) < cursor_offset and m.end(1) >= cursor_offset) or ( m.start(2) < cursor_offset and m.end(2) >= cursor_offset ): return LinePart(m.start(1), m.end(1), m.group(1)) return None current_from_import_import_re_1 = LazyReCompile(r"from\s+([\w0-9_.]*)\s+import") current_from_import_import_re_2 = LazyReCompile(r"([\w0-9_]+)") current_from_import_import_re_3 = LazyReCompile(r", *([\w0-9_]*)") def current_from_import_import(cursor_offset, line): """If in from import completion, the word after import being completed returns None if cursor not in or just after one of these words """ baseline = current_from_import_import_re_1.search(line) if baseline is None: return None match1 = current_from_import_import_re_2.search(line[baseline.end() :]) if match1 is None: return None for m in chain( (match1,), current_from_import_import_re_3.finditer(line[baseline.end() :]), ): start = baseline.end() + m.start(1) end = baseline.end() + m.end(1) if start < cursor_offset and end >= cursor_offset: return LinePart(start, end, m.group(1)) return None current_import_re_1 = LazyReCompile(r"import") current_import_re_2 = LazyReCompile(r"([\w0-9_.]+)") current_import_re_3 = LazyReCompile(r"[,][ ]*([\w0-9_.]*)") def current_import(cursor_offset, line): # TODO allow for multiple as's baseline = current_import_re_1.search(line) if baseline is None: return None match1 = current_import_re_2.search(line[baseline.end() :]) if match1 is None: return None for m in chain( (match1,), current_import_re_3.finditer(line[baseline.end() :]) ): start = baseline.end() + m.start(1) end = baseline.end() + m.end(1) if start < cursor_offset and end >= cursor_offset: return LinePart(start, end, m.group(1)) current_method_definition_name_re = LazyReCompile(r"def\s+([a-zA-Z_][\w]*)") def current_method_definition_name(cursor_offset, line): """The name of a method being defined""" for m in current_method_definition_name_re.finditer(line): if m.start(1) <= cursor_offset and m.end(1) >= cursor_offset: return LinePart(m.start(1), m.end(1), m.group(1)) return None current_single_word_re = LazyReCompile(r"(?= cursor_offset: return LinePart(m.start(1), m.end(1), m.group(1)) return None def current_dotted_attribute(cursor_offset, line): """The dotted attribute-object pair before the cursor""" match = current_word(cursor_offset, line) if match is None: return None start, end, word = match if "." in word[1:]: return LinePart(start, end, word) current_expression_attribute_re = LazyReCompile( r"[.]\s*((?:[\w_][\w0-9_]*)|(?:))" ) def current_expression_attribute(cursor_offset, line): """If after a dot, the attribute being completed""" # TODO replace with more general current_expression_attribute for m in current_expression_attribute_re.finditer(line): if m.start(1) <= cursor_offset and m.end(1) >= cursor_offset: return LinePart(m.start(1), m.end(1), m.group(1)) return None
X Tutup