-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathEclipseJavaFormatter.py
204 lines (145 loc) · 5.89 KB
/
EclipseJavaFormatter.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import sublime, sublime_plugin, re, os
from operator import attrgetter
from subprocess import Popen, PIPE
SETTINGS_NAME = 'EclipseJavaFormatter'
SETTINGS_FILE_NAME = '%s.sublime-settings' % SETTINGS_NAME
KEY_ECLIPSE_COMMAND = 'eclipse_command'
KEY_NOSPLASH = 'no_splash'
KEY_VERBOSE = 'verbose'
KEY_CONFIG = 'config_file'
KEY_RESTORE_ENDINGS = 'restore_line_endings'
KEY_SORT_IMPORTS = 'sort_imports'
KEY_SORT_ORDER = 'sort_imports_order'
IMP_RE = 'import( static)? ([\w\.]+)\.([\w]+|\*);'
IMP_PROG = re.compile(IMP_RE)
LANG_RE = "^((source|text\.)[\w+\-\.#]+)"
LANG_PROG = re.compile(LANG_RE)
def _get_setting(view, key):
view_settings = view.settings()
if view_settings.has(SETTINGS_NAME):
project_settings = view_settings.get(SETTINGS_NAME)
for proj_setting_key in project_settings:
if proj_setting_key == key:
return project_settings[proj_setting_key]
plugin_settings = sublime.load_settings(SETTINGS_FILE_NAME)
return plugin_settings.get(key, None)
"""
This is a wrapper command so that the final save can be run
"""
class EclipseFormatJavaCommand(sublime_plugin.WindowCommand):
def run(self):
view = self.window.active_view()
''' save if there are unsaved changes '''
if view.is_dirty():
view.run_command("save")
''' cache line endings, as we may need to restore them '''
line_endings = view.line_endings()
view.run_command('do_eclipse_format_java')
view.run_command('do_sort_imports')
''' restore line endings '''
if _get_setting(view, KEY_RESTORE_ENDINGS):
view.set_line_endings(line_endings)
view.run_command('save')
def is_visible(self):
return self.__get_language() == "source.java"
def __get_language(self):
view = self.window.active_view()
cursor = view.sel()[0].a
scope = view.scope_name(cursor).strip()
language = LANG_PROG.search(scope)
if language == None:
return None
return language.group(0)
class DoEclipseFormatJavaCommand(sublime_plugin.TextCommand):
def run(self, edit):
''' save if there are unsaved changes '''
if self.view.is_dirty():
self.view.run_command('save')
''' cache line endings, as we may need to restore them '''
line_endings = self.view.line_endings()
''' do external call to eclipse formatter '''
if self.__run_external_command(self.__assemble_eclipse_command()):
self.__refresh_view(edit)
def __run_external_command(self, args):
child = Popen(args, stdout=PIPE, stderr=PIPE)
output, error = child.communicate()
print(output)
if error:
sublime.error_message(error)
return False
return True
def __assemble_eclipse_command(self):
args = []
platform = sublime.platform()
args.append(os.path.expanduser(_get_setting(self.view, KEY_ECLIPSE_COMMAND)))
if _get_setting(self.view, KEY_NOSPLASH):
args.append('-nosplash')
args.append('-application')
args.append('org.eclipse.jdt.core.JavaCodeFormatter')
is_verbose = _get_setting(self.view, KEY_VERBOSE)
if is_verbose:
args.append('-verbose')
args.append('-config')
args.append(os.path.expanduser(_get_setting(self.view, KEY_CONFIG)))
args.append(self.view.file_name())
if is_verbose:
print("running command: %s" % ' '.join(args))
return args
def __refresh_view(self, edit):
document = sublime.Region(0, self.view.size())
f = open(self.view.file_name())
self.view.replace(edit, document, f.read())
class DoSortImportsCommand(sublime_plugin.TextCommand):
def run(self, edit):
if _get_setting(self.view, KEY_SORT_IMPORTS):
import_regions = self.view.find_all(IMP_RE)
mega_region = import_regions[0].cover(import_regions[-1])
imports = [JavaImport(self.view.substr(region)) for region in import_regions]
sorter = ImportSorter(imports, _get_setting(self.view, KEY_SORT_ORDER))
self.view.replace(edit, mega_region, str(sorter))
class JavaImport(object):
def __init__(self, imp_str):
result = IMP_PROG.match(imp_str)
self.is_static = True if result.group(1) else False
self.package = result.group(2)
self.java_type = result.group(3)
self.imp_str = imp_str
def __repr__(self):
return self.imp_str
class ImportSorter(object):
def __init__(self, imports, sort_order):
self.imports = self.sort_imports(imports, sort_order)
def sort_imports(self, imports, sort_order):
'''
sort alphabetically and then by package depth,
reversed so that packages with similar substrings
(java and javax) don't get confused
'''
specific_first = sorted(sort_order, reverse=True)
pkg_depth = lambda package: len(package.split('.'))
specific_first = sorted(specific_first, key=pkg_depth, reverse=True)
'''
create dict for grouping packages and populate
'''
groups_by_package = dict(zip((sort_order + ['other']),
[[] for package in sort_order] + [[]]))
used = []
for imp in imports:
for package in specific_first:
if imp.package.startswith(package):
groups_by_package[package].append(imp)
used.append(imp)
break
''' other gets the dregs '''
groups_by_package['other'] = [imp for imp in imports if imp not in used]
sorted_groups = []
for key in (sort_order + ['other']):
if len(groups_by_package[key]) > 0:
pkg_group = sorted(groups_by_package[key], key=attrgetter('java_type'))
pkg_group = sorted(pkg_group, key=attrgetter('package'))
sorted_groups.append(pkg_group)
return sorted_groups
def __repr_group(self, group):
return '\n'.join([str(imp) for imp in group])
def __repr__(self):
return '\n\n'.join([self.__repr_group(group) for group in self.imports])