forked from elm-community/SublimeElmLanguageSupport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
elm_project.py
182 lines (152 loc) · 5.86 KB
/
elm_project.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
import collections
import json
try: # ST3
from .elm_plugin import *
except: # ST2
from elm_plugin import *
class ElmProjectCommand(sublime_plugin.TextCommand):
def is_enabled(self):
self.project = ElmProject(self.view.file_name())
return self.project.exists
def run(self, edit, prop_name=None, choices=None, caption=None):
self.window = self.view.window()
if not prop_name:
self.window.open_file(self.project.json_path, sublime.TRANSIENT)
return
self.prop_name = prop_name
initial_value = getattr(self.project, prop_name)
if choices:
self.show_choices(choices, initial_value)
else:
self.window.show_input_panel(caption, initial_value, self.on_finished, None, None)
def show_choices(self, choices, initial_value):
self.norm_choices = [choice.lower() for choice in choices]
try:
# ValueError: $initial_value is not in list
initial_index = self.norm_choices.index(initial_value.lower())
# ST2: Boost.Python.ArgumentError: Python argument types
self.window.show_quick_panel(choices, self.on_choice, selected_index=initial_index)
except: # simplest control flow
if not is_ST2():
log_string('project.logging.invalid_choice', initial_value)
self.window.show_quick_panel(choices, self.on_choice)
def on_choice(self, index):
if index != -1:
self.on_finished(self.norm_choices[index])
def on_finished(self, value):
setattr(self.project, self.prop_name, value)
keys = self.project._last_updated_key_path
if keys:
sublime.status_message(get_string('project.updated', '.'.join(keys), value))
BUILD_KEY = ('sublime-build',)
MAIN_KEY = BUILD_KEY + ('main',)
HTML_KEY = BUILD_KEY + ('html',)
OUTPUT_KEY = BUILD_KEY + ('output',)
OUTPUT_PATH_KEY = OUTPUT_KEY + ('path',)
OUTPUT_COMP_KEY = OUTPUT_KEY + ('components',)
OUTPUT_DIR_KEY = OUTPUT_COMP_KEY + ('dir',)
OUTPUT_NAME_KEY = OUTPUT_COMP_KEY + ('name',)
OUTPUT_EXT_KEY = OUTPUT_COMP_KEY + ('ext',)
class ElmProject(object):
@classmethod
def find_json(cls, dir_path):
if not fs.isdir(fs.abspath(dir_path)):
return None
file_path = fs.abspath(fs.join(dir_path, 'elm-package.json'))
if fs.isfile(file_path):
return file_path
parent_path = fs.join(dir_path, fs.pardir)
if fs.abspath(parent_path) == fs.abspath(dir_path):
return None
return cls.find_json(parent_path)
def __init__(self, file_path):
self.file_path = file_path
self.json_path = self.find_json(fs.dirname(file_path or ''))
self.data_dict = self.load_json()
def __getitem__(self, keys):
if not self.exists:
return None
item = self.data_dict
for key in keys:
item = item.get(key)
if not item:
break
return item
def __setitem__(self, keys, value):
self._last_updated_key_path = None
if not self.exists:
sublime.error_message(get_string('project.not_found'))
return
item = self.data_dict
for key in keys[0:-1]:
item = item.setdefault(key, {})
item[keys[-1]] = value
self.save_json()
self._last_updated_key_path = keys
def __repr__(self):
members = [(name, getattr(self, name), ' ' * 4)
for name in dir(self) if name[0] != '_']
properties = ["{indent}{name}={value},".format(**locals())
for name, value, indent in members if not callable(value)]
return "{0}(\n{1}\n)".format(self.__class__.__name__, '\n'.join(properties))
def load_json(self):
try:
with open(self.json_path) as json_file:
if is_ST2(): # AttributeError: 'module' object has no attribute 'OrderedDict'
return json.load(json_file)
else:
return json.load(json_file, object_pairs_hook=collections.OrderedDict)
except TypeError: # self.json_path == None
pass
except ValueError:
log_string('project.logging.invalid_json', self.json_path)
return None
def save_json(self):
with open(self.json_path, 'w') as json_file:
json.dump(self.data_dict, json_file,
indent=4,
separators=(',', ': '),
sort_keys=is_ST2())
@property
def exists(self):
return bool(self.data_dict)
@property
def working_dir(self):
return fs.dirname(self.json_path) if self.json_path else None
@property
def main_path(self):
return self[MAIN_KEY] or fs.relpath(self.file_path, self.working_dir)
@main_path.setter
def main_path(self, value):
self[MAIN_KEY] = value
@property
def html_path(self):
return self[HTML_KEY] or self.output_path
@html_path.setter
def html_path(self, value):
self[HTML_KEY] = value
@property
def output_path(self):
output_path = fs.join(self.output_dir, self.output_name + '.' + self.output_ext)
return self[OUTPUT_PATH_KEY] or fs.normpath(output_path)
@output_path.setter
def output_path(self, value):
self[OUTPUT_PATH_KEY] = value
@property
def output_dir(self):
return self[OUTPUT_DIR_KEY] or 'build'
@output_dir.setter
def output_dir(self, value):
self[OUTPUT_DIR_KEY] = value
@property
def output_name(self):
return self[OUTPUT_NAME_KEY] or fs.splitext(fs.basename(self.main_path))[0]
@output_name.setter
def output_name(self, value):
self[OUTPUT_NAME_KEY] = value
@property
def output_ext(self):
return self[OUTPUT_EXT_KEY] or 'html'
@output_ext.setter
def output_ext(self, value):
self[OUTPUT_EXT_KEY] = value