sourceutils.py 2.9 KB

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