My dotfiles
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 

304 rader
11 KiB

  1. # Arguments are:
  2. # 1. Working directory.
  3. # 2. Rope folder
  4. import difflib
  5. import io
  6. import json
  7. import os
  8. import sys
  9. import traceback
  10. try:
  11. import rope
  12. from rope.base import libutils
  13. from rope.refactor.rename import Rename
  14. from rope.refactor.extract import ExtractMethod, ExtractVariable
  15. import rope.base.project
  16. import rope.base.taskhandle
  17. except:
  18. jsonMessage = {'error': True, 'message': 'Rope not installed', 'traceback': '', 'type': 'ModuleNotFoundError'}
  19. sys.stderr.write(json.dumps(jsonMessage))
  20. sys.stderr.flush()
  21. WORKSPACE_ROOT = sys.argv[1]
  22. ROPE_PROJECT_FOLDER = '.vim/.ropeproject'
  23. class RefactorProgress():
  24. """
  25. Refactor progress information
  26. """
  27. def __init__(self, name='Task Name', message=None, percent=0):
  28. self.name = name
  29. self.message = message
  30. self.percent = percent
  31. class ChangeType():
  32. """
  33. Change Type Enum
  34. """
  35. EDIT = 0
  36. NEW = 1
  37. DELETE = 2
  38. class Change():
  39. """
  40. """
  41. EDIT = 0
  42. NEW = 1
  43. DELETE = 2
  44. def __init__(self, filePath, fileMode=ChangeType.EDIT, diff=""):
  45. self.filePath = filePath
  46. self.diff = diff
  47. self.fileMode = fileMode
  48. def get_diff(changeset):
  49. """This is a copy of the code form the ChangeSet.get_description method found in Rope."""
  50. new = changeset.new_contents
  51. old = changeset.old_contents
  52. if old is None:
  53. if changeset.resource.exists():
  54. old = changeset.resource.read()
  55. else:
  56. old = ''
  57. # Ensure code has a trailing empty lines, before generating a diff.
  58. # https://github.com/Microsoft/vscode-python/issues/695.
  59. old_lines = old.splitlines(True)
  60. if not old_lines[-1].endswith('\n'):
  61. old_lines[-1] = old_lines[-1] + os.linesep
  62. new = new + os.linesep
  63. result = difflib.unified_diff(
  64. old_lines, new.splitlines(True),
  65. 'a/' + changeset.resource.path, 'b/' + changeset.resource.path)
  66. return ''.join(list(result))
  67. class BaseRefactoring(object):
  68. """
  69. Base class for refactorings
  70. """
  71. def __init__(self, project, resource, name="Refactor", progressCallback=None):
  72. self._progressCallback = progressCallback
  73. self._handle = rope.base.taskhandle.TaskHandle(name)
  74. self._handle.add_observer(self._update_progress)
  75. self.project = project
  76. self.resource = resource
  77. self.changes = []
  78. def _update_progress(self):
  79. jobset = self._handle.current_jobset()
  80. if jobset and not self._progressCallback is None:
  81. progress = RefactorProgress()
  82. # getting current job set name
  83. if jobset.get_name() is not None:
  84. progress.name = jobset.get_name()
  85. # getting active job name
  86. if jobset.get_active_job_name() is not None:
  87. progress.message = jobset.get_active_job_name()
  88. # adding done percent
  89. percent = jobset.get_percent_done()
  90. if percent is not None:
  91. progress.percent = percent
  92. if not self._progressCallback is None:
  93. self._progressCallback(progress)
  94. def stop(self):
  95. self._handle.stop()
  96. def refactor(self):
  97. try:
  98. self.onRefactor()
  99. except rope.base.exceptions.InterruptedTaskError:
  100. # we can ignore this exception, as user has cancelled refactoring
  101. pass
  102. def onRefactor(self):
  103. """
  104. To be implemented by each base class
  105. """
  106. pass
  107. class RenameRefactor(BaseRefactoring):
  108. def __init__(self, project, resource, name="Rename", progressCallback=None, startOffset=None, newName="new_Name"):
  109. BaseRefactoring.__init__(self, project, resource,
  110. name, progressCallback)
  111. self._newName = newName
  112. self.startOffset = startOffset
  113. def onRefactor(self):
  114. renamed = Rename(self.project, self.resource, self.startOffset)
  115. changes = renamed.get_changes(self._newName, task_handle=self._handle)
  116. for item in changes.changes:
  117. if isinstance(item, rope.base.change.ChangeContents):
  118. self.changes.append(
  119. Change(item.resource.real_path, ChangeType.EDIT, get_diff(item)))
  120. else:
  121. raise Exception('Unknown Change')
  122. class ExtractVariableRefactor(BaseRefactoring):
  123. def __init__(self, project, resource, name="Extract Variable", progressCallback=None, startOffset=None, endOffset=None, newName="new_Name", similar=False, global_=False):
  124. BaseRefactoring.__init__(self, project, resource,
  125. name, progressCallback)
  126. self._newName = newName
  127. self._startOffset = startOffset
  128. self._endOffset = endOffset
  129. self._similar = similar
  130. self._global = global_
  131. def onRefactor(self):
  132. renamed = ExtractVariable(
  133. self.project, self.resource, self._startOffset, self._endOffset)
  134. changes = renamed.get_changes(
  135. self._newName, self._similar, self._global)
  136. for item in changes.changes:
  137. if isinstance(item, rope.base.change.ChangeContents):
  138. self.changes.append(
  139. Change(item.resource.real_path, ChangeType.EDIT, get_diff(item)))
  140. else:
  141. raise Exception('Unknown Change')
  142. class ExtractMethodRefactor(ExtractVariableRefactor):
  143. def __init__(self, project, resource, name="Extract Method", progressCallback=None, startOffset=None, endOffset=None, newName="new_Name", similar=False, global_=False):
  144. ExtractVariableRefactor.__init__(self, project, resource,
  145. name, progressCallback, startOffset=startOffset, endOffset=endOffset, newName=newName, similar=similar, global_=global_)
  146. def onRefactor(self):
  147. renamed = ExtractMethod(
  148. self.project, self.resource, self._startOffset, self._endOffset)
  149. changes = renamed.get_changes(
  150. self._newName, self._similar, self._global)
  151. for item in changes.changes:
  152. if isinstance(item, rope.base.change.ChangeContents):
  153. self.changes.append(
  154. Change(item.resource.real_path, ChangeType.EDIT, get_diff(item)))
  155. else:
  156. raise Exception('Unknown Change')
  157. class RopeRefactoring(object):
  158. def __init__(self):
  159. self.default_sys_path = sys.path
  160. self._input = io.open(sys.stdin.fileno(), encoding='utf-8')
  161. def _rename(self, filePath, start, newName, indent_size):
  162. """
  163. Renames a variable
  164. """
  165. project = rope.base.project.Project(
  166. WORKSPACE_ROOT, ropefolder=ROPE_PROJECT_FOLDER, save_history=False, indent_size=indent_size)
  167. resourceToRefactor = libutils.path_to_resource(project, filePath)
  168. refactor = RenameRefactor(
  169. project, resourceToRefactor, startOffset=start, newName=newName)
  170. refactor.refactor()
  171. changes = refactor.changes
  172. project.close()
  173. valueToReturn = []
  174. for change in changes:
  175. valueToReturn.append({'diff': change.diff})
  176. return valueToReturn
  177. def _extractVariable(self, filePath, start, end, newName, indent_size):
  178. """
  179. Extracts a variable
  180. """
  181. project = rope.base.project.Project(
  182. WORKSPACE_ROOT, ropefolder=ROPE_PROJECT_FOLDER, save_history=False, indent_size=indent_size)
  183. resourceToRefactor = libutils.path_to_resource(project, filePath)
  184. refactor = ExtractVariableRefactor(
  185. project, resourceToRefactor, startOffset=start, endOffset=end, newName=newName, similar=True)
  186. refactor.refactor()
  187. changes = refactor.changes
  188. project.close()
  189. valueToReturn = []
  190. for change in changes:
  191. valueToReturn.append({'diff': change.diff})
  192. return valueToReturn
  193. def _extractMethod(self, filePath, start, end, newName, indent_size):
  194. """
  195. Extracts a method
  196. """
  197. project = rope.base.project.Project(
  198. WORKSPACE_ROOT, ropefolder=ROPE_PROJECT_FOLDER, save_history=False, indent_size=indent_size)
  199. resourceToRefactor = libutils.path_to_resource(project, filePath)
  200. refactor = ExtractMethodRefactor(
  201. project, resourceToRefactor, startOffset=start, endOffset=end, newName=newName, similar=True)
  202. refactor.refactor()
  203. changes = refactor.changes
  204. project.close()
  205. valueToReturn = []
  206. for change in changes:
  207. valueToReturn.append({'diff': change.diff})
  208. return valueToReturn
  209. def _serialize(self, identifier, results):
  210. """
  211. Serializes the refactor results
  212. """
  213. return json.dumps({'id': identifier, 'results': results})
  214. def _deserialize(self, request):
  215. """Deserialize request from VSCode.
  216. Args:
  217. request: String with raw request from VSCode.
  218. Returns:
  219. Python dictionary with request data.
  220. """
  221. return json.loads(request)
  222. def _process_request(self, request):
  223. """Accept serialized request from VSCode and write response.
  224. """
  225. request = self._deserialize(request)
  226. lookup = request.get('lookup', '')
  227. if lookup == '':
  228. pass
  229. elif lookup == 'rename':
  230. changes = self._rename(request['file'], int(
  231. request['start']), request['name'], int(request['indent_size']))
  232. return self._write_response(self._serialize(request['id'], changes))
  233. elif lookup == 'extract_variable':
  234. changes = self._extractVariable(request['file'], int(
  235. request['start']), int(request['end']), request['name'], int(request['indent_size']))
  236. return self._write_response(self._serialize(request['id'], changes))
  237. elif lookup == 'extract_method':
  238. changes = self._extractMethod(request['file'], int(
  239. request['start']), int(request['end']), request['name'], int(request['indent_size']))
  240. return self._write_response(self._serialize(request['id'], changes))
  241. def _write_response(self, response):
  242. sys.stdout.write(response + '\n')
  243. sys.stdout.flush()
  244. def watch(self):
  245. self._write_response("STARTED")
  246. while True:
  247. try:
  248. self._process_request(self._input.readline())
  249. except:
  250. exc_type, exc_value, exc_tb = sys.exc_info()
  251. tb_info = traceback.extract_tb(exc_tb)
  252. jsonMessage = {'error': True, 'message': str(exc_value), 'traceback': str(tb_info), 'type': str(exc_type)}
  253. sys.stderr.write(json.dumps(jsonMessage))
  254. sys.stderr.flush()
  255. if __name__ == '__main__':
  256. RopeRefactoring().watch()