-
Notifications
You must be signed in to change notification settings - Fork 161
/
sourceutils.py
93 lines (77 loc) · 2.93 KB
/
sourceutils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from rope.base import codeanalyze
def get_indents(lines, lineno):
return codeanalyze.count_line_indents(lines.get_line(lineno))
def find_minimum_indents(source_code):
result = 80
lines = source_code.split("\n")
for line in lines:
if line.strip() == "":
continue
result = min(result, codeanalyze.count_line_indents(line))
return result
def indent_lines(source_code, amount):
if amount == 0:
return source_code
lines = source_code.splitlines(True)
result = []
for line in lines:
if line.strip() == "":
result.append("\n")
continue
if amount < 0:
indents = codeanalyze.count_line_indents(line)
result.append(max(0, indents + amount) * " " + line.lstrip())
else:
result.append(" " * amount + line)
return "".join(result)
def fix_indentation(code: str, new_indents: int) -> str:
"""Change the indentation of `code` to `new_indents`"""
min_indents = find_minimum_indents(code)
return indent_lines(code, new_indents - min_indents)
def add_methods(pymodule, class_scope, methods_sources):
source_code = pymodule.source_code
lines = pymodule.lines
insertion_line = class_scope.get_end()
if class_scope.get_scopes():
insertion_line = class_scope.get_scopes()[-1].get_end()
insertion_offset = lines.get_line_end(insertion_line)
methods = "\n\n" + "\n\n".join(methods_sources)
indented_methods = fix_indentation(
methods,
get_indents(lines, class_scope.get_start())
+ get_indent(pymodule.pycore.project),
)
result = []
result.append(source_code[:insertion_offset])
result.append(indented_methods)
result.append(source_code[insertion_offset:])
return "".join(result)
def get_body(pyfunction):
"""Return unindented function body"""
# FIXME scope = pyfunction.get_scope()
pymodule = pyfunction.get_module()
start, end = get_body_region(pyfunction)
return fix_indentation(pymodule.source_code[start:end], 0)
def get_body_region(defined):
"""Return the start and end offsets of function body"""
scope = defined.get_scope()
pymodule = defined.get_module()
lines = pymodule.lines
node = defined.get_ast()
start_line = node.lineno
if defined.get_doc() is None:
start_line = node.body[0].lineno
elif len(node.body) > 1:
start_line = node.body[1].lineno
start = lines.get_line_start(start_line)
scope_start = pymodule.logical_lines.logical_line_in(scope.start)
if scope_start[1] >= start_line:
# a one-liner!
# XXX: what if colon appears in a string
start = pymodule.source_code.index(":", start) + 1
while pymodule.source_code[start].isspace():
start += 1
end = min(lines.get_line_end(scope.end) + 1, len(pymodule.source_code))
return start, end
def get_indent(project):
return project.prefs.get("indent_size", 4)