diff --git a/jedi/parsing.py b/jedi/parsing.py index 54c429af..99beb65b 100644 --- a/jedi/parsing.py +++ b/jedi/parsing.py @@ -782,7 +782,8 @@ class Statement(Simple): self._assignment_details.append((tok, top)) # All these calls wouldn't be important if nonlocal would # exist. -> Initialize the first items again. - top = result = Array(start_pos, Array.NOARRAY, self) + end_pos = start_pos[0], start_pos[1] + len(tok) + top = result = Array(end_pos, Array.NOARRAY, self) level = 0 close_brackets = False is_chain = False @@ -876,7 +877,10 @@ class Statement(Simple): "This is not normal behaviour." % level) while result is not None: - result.end_pos = start_pos[0], start_pos[1] + len(tok) + try: + result.end_pos = start_pos[0], start_pos[1] + len(tok) + except TypeError: + result.end_pos = tok.end_pos result = result.parent self._assignment_calls_calculated = True diff --git a/jedi/refactoring.py b/jedi/refactoring.py index c36232cb..64414f5b 100644 --- a/jedi/refactoring.py +++ b/jedi/refactoring.py @@ -44,15 +44,18 @@ def rename(script, new_name): :type source: str :return: list of changed lines/changed files """ - dct = {} + return Refactoring(_rename(script.related_names(), new_name)) + + +def _rename(names, replace_str): + """ For both rename and inline. """ + order = sorted(names, key=lambda x: (x.module_path, x.start_pos), + reverse=True) def process(path, old_lines, new_lines): if new_lines is not None: # goto next file, save last dct[path] = path, old_lines, new_lines - old_names = script.related_names() - order = sorted(old_names, key=lambda x: (x.module_path, x.start_pos), - reverse=True) - + dct = {} current_path = object() new_lines = old_lines = None for name in order: @@ -72,11 +75,10 @@ def rename(script, new_name): nr, indent = name.start_pos line = new_lines[nr - 1] - new_lines[nr - 1] = line[:indent] + new_name + \ + new_lines[nr - 1] = line[:indent] + replace_str + \ line[indent + len(name.name_part):] - process(current_path, old_lines, new_lines) - return Refactoring(dct) + return dct def extract(script, new_name): @@ -143,3 +145,46 @@ def extract(script, new_name): new_lines.insert(line_index, new) dct[script.source_path] = script.source_path, old_lines, new_lines return Refactoring(dct) + + +def inline(script): + """ + :type script: api.Script + """ + new_lines = modules.source_to_unicode(script.source).splitlines() + + dct = {} + + definitions = script.goto() + try: + assert len(definitions) == 1 + stmt = definitions[0].definition + related_names = script.related_names() + inlines = [r for r in related_names + if not stmt.start_pos <= r.start_pos <= stmt.end_pos] + inlines = sorted(inlines, key=lambda x: (x.module_path, x.start_pos), + reverse=True) + ass = stmt.get_assignment_calls() + # don't allow multiline refactorings for now. + assert ass.start_pos[0] == ass.end_pos[0] + index = ass.start_pos[0] - 1 + + line = new_lines[index] + replace_str = line[ass.start_pos[1]:ass.end_pos[1] + 1] + + # if it's the only assignment, remove the statement + if len(stmt.set_vars) == 1: + line = line[:stmt.start_pos[1]] + line[stmt.end_pos[1]:] + + dct = _rename(inlines, replace_str.strip()) + # remove the empty line + new_lines = dct[script.source_path][2] + if line.strip(): + new_lines[index] = line + else: + new_lines.pop(index) + + except AssertionError: + pass + + return Refactoring(dct)