-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathsublime_python_refactorings.py
150 lines (117 loc) · 5.06 KB
/
sublime_python_refactorings.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from abc import ABCMeta, abstractmethod
import sublime
import sublime_plugin
from SublimePythonIDE.sublime_python import proxy_for, file_or_buffer_name, root_folder_for
class PythonAbstractRefactoring(object):
'''
Implements basic interaction for simple refactorings:
1.) Ask user for some input using some message and default input
2.) Collect necessary context (selection, source, file_path etc)
3.) Save, call server to do the refactoring, reload view
Subclasses should implement default_input, input_msg and refactor
'''
__metaclass__ = ABCMeta
def run(self, edit, block=False):
self.sel = self.view.sel()[0]
self.default = self.default_input()
self.view.window().show_input_panel(
self.input_msg(),
self.default,
self.input_callback,
None,
None
)
def refactoring_context(self):
project_path = root_folder_for(self.view)
file_path = file_or_buffer_name(self.view)
start = self.sel.a
end = self.sel.b
source = self.view.substr(sublime.Region(0, self.view.size()))
return project_path, file_path, start, end, source
def input_callback(self, input_str):
if input_str == self.default:
return
proxy = proxy_for(self.view)
if not proxy:
return
self.view.run_command("save")
self.refactor(proxy, input_str, *self.refactoring_context())
self.view.run_command('revert') # reload view
@abstractmethod
def default_input(self):
'''Default value shown in the input box'''
pass
@abstractmethod
def input_msg(self):
'''Message displayed to the user in the input box'''
pass
@abstractmethod
def refactor(self, proxy, input_str, project_path, file_path, start, end, source):
'''Given all the necessary context, a server proxy and the user's input,
perform the refactoring'''
pass
class PythonRefactorRename(PythonAbstractRefactoring, sublime_plugin.TextCommand):
'''Renames the identifier under the cursor throughout the project'''
def __init__(self, *args, **kwargs):
sublime_plugin.TextCommand.__init__(self, *args, **kwargs)
def default_input(self):
return self.view.substr(self.view.word(self.sel.a))
def input_msg(self):
return "New name:"
def refactor(self, proxy, input_str, project_path, file_path, start, _, source):
print("calling rename with ", proxy, input_str, project_path, file_path, start)
proxy.rename(project_path, file_path, start, source, input_str)
class PythonExtractMethod(PythonAbstractRefactoring, sublime_plugin.TextCommand):
'''Extracts the selected code and creates a new method to contain it
Tries to guess the correct arguments and return values for this new method'''
def __init__(self, *args, **kwargs):
sublime_plugin.TextCommand.__init__(self, *args, **kwargs)
def input_msg(self):
return "New method name:"
def default_input(self):
return ""
def refactor(self, proxy, input_str, project_path, file_path, start, end, source):
proxy.extract_method(project_path, file_path, start, end, source, input_str)
class PythonOrganizeImports(sublime_plugin.TextCommand):
'''
Organizes the imports of the current view.
Tries to saves the view beforehand
and organizes the imports only on a successful save.
'''
def run(self, edit):
if self.view.is_dirty():
self.view.run_command("save")
if self.view.file_name():
row, col = self.view.rowcol(self.view.sel()[0].a)
path = file_or_buffer_name(self.view)
all_view = sublime.Region(0, self.view.size())
source = self.view.substr(all_view)
proxy = proxy_for(self.view)
if not proxy:
return
organized_source = proxy.organize_imports(source, root_folder_for(self.view), path)
self.view.replace(edit, all_view, organized_source)
# end with a saved view to be compatible with the other refactorings
self.view.run_command("save")
class PythonOrganizeImportsOnSave(sublime_plugin.EventListener):
'''
Applies the organize imports refactoring everytime a file is saved.
Only works if "python_organize_imports_on_save" is "True" in the project settings.
That can be achieved by editing the project to have:
"settings": {
...
"python_organize_imports_on_save": true
}
'''
_post_save_is_on = True
def on_post_save(self, view):
if view.settings().get("python_organize_imports_on_save") is True:
# since the refactoring itself calls "save"
# the event has to be turned off/on
# otherwise we would enter an infinite recursion
if self._post_save_is_on:
try:
self._post_save_is_on = False
view.run_command("python_organize_imports")
finally:
self._post_save_is_on = True