Skip to content

Commit

Permalink
merged refactor #220
Browse files Browse the repository at this point in the history
  • Loading branch information
DonJayamanne committed Jul 20, 2016
2 parents 74e1a5e + f1e5018 commit cf679b6
Show file tree
Hide file tree
Showing 81 changed files with 18,115 additions and 3 deletions.
17 changes: 15 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"author": {
"name": "Don Jayamanne",
"email": "don.jayamanne@yahoo.com"
},
},
"license": "MIT",
"homepage": "http://donjayamanne.github.io/pythonVSCode/",
"repository": {
Expand Down Expand Up @@ -48,11 +48,19 @@
"commands": [
{
"command": "python.sortImports",
"title": "Python: Sort Imports"
"title": "Python: Sort Imports"
},
{
"command": "python.runtests",
"title": "Python: Run Unit Tests"
},
{
"command": "python.refactorExtractVariable",
"title": "Python: Extract Variable"
},
{
"command": "python.refactorExtractMethod",
"title": "Python: Extract Method"
}
],
"debuggers": [
Expand Down Expand Up @@ -267,6 +275,11 @@
"default": "python",
"description": "Path to Python, you can use a custom version of Python by modifying this setting to include the full path."
},
"python.python2Path": {
"type": "string",
"default": "python",
"description": "Path to Python 2.x used for Refactoring. Refactoring only works when using Python 2.x"
},
"python.linting.enabled": {
"type": "boolean",
"default": true,
Expand Down
245 changes: 245 additions & 0 deletions pythonFiles/refactor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
# Arguments are:
# 1. Working directory.
# 2. Rope folder

import io
import sys
import json
import traceback
import rope

from rope.base import libutils
from rope.refactor.rename import Rename
from rope.refactor.extract import ExtractMethod, ExtractVariable
import rope.base.project
import rope.base.taskhandle

WORKSPACE_ROOT = sys.argv[1]
ROPE_PROJECT_FOLDER = sys.argv[2]


class RefactorProgress():
"""
Refactor progress information
"""

def __init__(self, name='Task Name', message=None, percent=0):
self.name = name
self.message = message
self.percent = percent


class ChangeType():
"""
Change Type Enum
"""
EDIT = 0
NEW = 1
DELETE = 2


class Change():
"""
"""
EDIT = 0
NEW = 1
DELETE = 2

def __init__(self, filePath, fileMode=ChangeType.EDIT, diff=""):
self.filePath = filePath
self.diff = diff
self.fileMode = fileMode


class BaseRefactoring(object):
"""
Base class for refactorings
"""

def __init__(self, project, resource, name="Refactor", progressCallback=None):
self._progressCallback = progressCallback
self._handle = rope.base.taskhandle.TaskHandle(name)
self._handle.add_observer(self._update_progress)
self.project = project
self.resource = resource
self.changes = []

def _update_progress(self):
jobset = self._handle.current_jobset()
if jobset and not self._progressCallback is None:
progress = RefactorProgress()
# getting current job set name
if jobset.get_name() is not None:
progress.name = jobset.get_name()
# getting active job name
if jobset.get_active_job_name() is not None:
progress.message = jobset.get_active_job_name()
# adding done percent
percent = jobset.get_percent_done()
if percent is not None:
progress.percent = percent
if not self._progressCallback is None:
self._progressCallback(progress)

def stop(self):
self._handle.stop()

def refactor(self):
try:
self.onRefactor()
except rope.base.exceptions.InterruptedTaskError:
# we can ignore this exception, as user has cancelled refactoring
pass

def onRefactor(self):
"""
To be implemented by each base class
"""
pass


class RenameRefactor(BaseRefactoring):

def __init__(self, project, resource, name="Rename", progressCallback=None, startOffset=None, newName="new_Name"):
BaseRefactoring.__init__(self, project, resource,
name, progressCallback)
self._newName = newName
self.startOffset = startOffset

def onRefactor(self):
renamed = Rename(self.project, self.resource, self.startOffset)
changes = renamed.get_changes(self._newName, task_handle=self._handle)
for item in changes.changes:
if isinstance(item, rope.base.change.ChangeContents):
self.changes.append(
Change(item.resource.real_path, ChangeType.EDIT, item.get_description()))
else:
raise Exception('Unknown Change')


class ExtractVariableRefactor(BaseRefactoring):

def __init__(self, project, resource, name="Extract Variable", progressCallback=None, startOffset=None, endOffset=None, newName="new_Name", similar=False, global_=False):
BaseRefactoring.__init__(self, project, resource,
name, progressCallback)
self._newName = newName
self._startOffset = startOffset
self._endOffset = endOffset
self._similar = similar
self._global = global_

def onRefactor(self):
renamed = ExtractVariable(
self.project, self.resource, self._startOffset, self._endOffset)
changes = renamed.get_changes(
self._newName, self._similar, self._global)
for item in changes.changes:
if isinstance(item, rope.base.change.ChangeContents):
self.changes.append(
Change(item.resource.real_path, ChangeType.EDIT, item.get_description()))
else:
raise Exception('Unknown Change')


class ExtractMethodRefactor(ExtractVariableRefactor):

def __init__(self, project, resource, name="Extract Method", progressCallback=None, startOffset=None, endOffset=None, newName="new_Name", similar=False, global_=False):
ExtractVariableRefactor.__init__(self, project, resource,
name, progressCallback, startOffset=startOffset, endOffset=endOffset, newName=newName, similar=similar, global_=global_)
def onRefactor(self):
renamed = ExtractMethod(
self.project, self.resource, self._startOffset, self._endOffset)
changes = renamed.get_changes(
self._newName, self._similar, self._global)
for item in changes.changes:
if isinstance(item, rope.base.change.ChangeContents):
self.changes.append(
Change(item.resource.real_path, ChangeType.EDIT, item.get_description()))
else:
raise Exception('Unknown Change')


class RopeRefactoring(object):

def __init__(self):
self.default_sys_path = sys.path
self._input = io.open(sys.stdin.fileno(), encoding='utf-8')

def _extractVariable(self, filePath, start, end, newName):
"""
Extracts a variale
"""
project = rope.base.project.Project(WORKSPACE_ROOT, ropefolder=ROPE_PROJECT_FOLDER, save_history=False)
resourceToRefactor = libutils.path_to_resource(project, filePath)
refactor = ExtractVariableRefactor(project, resourceToRefactor, startOffset=start, endOffset=end, newName=newName)
refactor.refactor()
changes = refactor.changes
project.close()
valueToReturn = []
for change in changes:
valueToReturn.append({'diff':change.diff})
return valueToReturn

def _extractMethod(self, filePath, start, end, newName):
"""
Extracts a method
"""
project = rope.base.project.Project(WORKSPACE_ROOT, ropefolder=ROPE_PROJECT_FOLDER, save_history=False)
resourceToRefactor = libutils.path_to_resource(project, filePath)
refactor = ExtractMethodRefactor(project, resourceToRefactor, startOffset=start, endOffset=end, newName=newName)
refactor.refactor()
changes = refactor.changes
project.close()
valueToReturn = []
for change in changes:
valueToReturn.append({'diff':change.diff})
return valueToReturn

def _serialize(self, identifier, results):
"""
Serializes the refactor results
"""
return json.dumps({'id': identifier, 'results': results})

def _deserialize(self, request):
"""Deserialize request from VSCode.
Args:
request: String with raw request from VSCode.
Returns:
Python dictionary with request data.
"""
return json.loads(request)

def _process_request(self, request):
"""Accept serialized request from VSCode and write response.
"""
request = self._deserialize(request)
lookup = request.get('lookup', '')

if lookup == '':
pass
elif lookup == 'extract_variable':
changes = self._extractVariable(request['file'], int(request['start']), int(request['end']), request['name'])
return self._write_response(self._serialize(request['id'], changes))
elif lookup == 'extract_method':
changes = self._extractMethod(request['file'], int(request['start']), int(request['end']), request['name'])
return self._write_response(self._serialize(request['id'], changes))

def _write_response(self, response):
sys.stdout.write(response + '\n')
sys.stdout.flush()

def watch(self):
self._write_response("STARTED")
while True:
try:
self._process_request(self._input.readline())
except Exception as ex:
message = ex.message + ' \n' + traceback.format_exc()
sys.stderr.write(str(len(message)) + ':' + message)
sys.stderr.flush()

if __name__ == '__main__':
RopeRefactoring().watch()
18 changes: 18 additions & 0 deletions pythonFiles/rope/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""rope, a python refactoring library"""

INFO = __doc__
VERSION = '0.10.3'
COPYRIGHT = """\
Copyright (C) 2014-2015 Matej Cepl
Copyright (C) 2006-2012 Ali Gholami Rudi
Copyright (C) 2009-2012 Anton Gritsay
This program is free software; you can redistribute it and/or modify it
under the terms of GNU General Public License as published by the
Free Software Foundation; either version 2 of the license, or (at your
opinion) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details."""
8 changes: 8 additions & 0 deletions pythonFiles/rope/base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Base rope package
This package contains rope core modules that are used by other modules
and packages.
"""

__all__ = ['project', 'libutils', 'exceptions']
Loading

0 comments on commit cf679b6

Please sign in to comment.