Skip to content

Commit e93c275

Browse files
committed
facade for rope #220
1 parent 280f77e commit e93c275

1 file changed

Lines changed: 245 additions & 0 deletions

File tree

pythonFiles/refactor.py

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

0 commit comments

Comments
 (0)