1
- import sublime , sublime_plugin
2
- import re
3
- import os
4
- import sys
1
+ import sublime , sublime_plugin , re , os , sys
5
2
# ST2 uses Python 2.6 and ST3 uses Python 3.3.
6
3
PYTHON_VERSION = sys .version_info
7
4
if PYTHON_VERSION [0 ] == 2 :
8
5
import ConfigParser
9
6
from StringIO import StringIO
7
+ import imp
8
+ buildPackage = os .path .join (os .path .split (os .getcwd ())[0 ], "Default" , "exec.py" )
9
+ imp .load_source ("BUILD_SYSTEM" , buildPackage )
10
+ del buildPackage
11
+ import BUILD_SYSTEM
12
+ USER_SETTINGS = sublime .load_settings ('SublimePapyrus.sublime-settings' )
10
13
elif PYTHON_VERSION [0 ] == 3 :
11
14
import configparser
12
15
from io import StringIO
15
18
16
19
# INI related variables.
17
20
DEFAULT_INI_LOCATION = os .path .expanduser ("~\\ Documents\\ SublimePapyrus.ini" )
18
- INI_LOCATION = ""
21
+ INI_LOCATION = DEFAULT_INI_LOCATION
19
22
if (os .path .exists ("C:\\ Program Files (x86)" )):
20
23
END_USER_ROOT = "C:\\ Program Files (x86)\\ Steam\\ steamapps\\ common\\ skyrim"
21
24
else :
73
76
ERROR_HIGHLIGHT_SCOPE = "invalid"
74
77
PAPYRUS_SCRIPT_EXTENSION = ".psc"
75
78
79
+ # ST's API is ready to be used.
76
80
def plugin_loaded ():
77
81
global USER_SETTINGS
78
82
USER_SETTINGS = sublime .load_settings ('SublimePapyrus.sublime-settings' )
79
83
updateINIPath ()
80
84
85
+ # Reads the path, which may have been defined by the user, to the INI file containing settings specific to the Papyrus build system.
81
86
def updateINIPath ():
82
87
global INI_LOCATION
83
88
iniPath = USER_SETTINGS .get ('ini_path' , "" )
84
89
if iniPath == "" :
85
- if INI_LOCATION == DEFAULT_INI_LOCATION :
86
- return
87
- else :
90
+ if INI_LOCATION != DEFAULT_INI_LOCATION :
88
91
INI_LOCATION = DEFAULT_INI_LOCATION
89
92
elif iniPath != INI_LOCATION :
90
93
if iniPath .endswith (".ini" ):
@@ -97,6 +100,7 @@ def updateINIPath():
97
100
iniPath += "\\ SublimePapyrus.ini"
98
101
INI_LOCATION = iniPath
99
102
103
+ # Returns Papyrus compiler arguments based on the user's settings in the INI file.
100
104
def getPrefs (filePath ):
101
105
fileDir , fileName = os .path .split (filePath )
102
106
ret = {}
@@ -148,6 +152,7 @@ def getPrefs(filePath):
148
152
return None
149
153
return ret
150
154
155
+ # Generates an INI file based on the template defined in the variable DEFAULT_INI_TEXT.
151
156
class CreateDefaultSettingsFileCommand (sublime_plugin .WindowCommand ):
152
157
def run (self , ** args ):
153
158
updateINIPath ()
@@ -160,6 +165,7 @@ def run(self, **args):
160
165
outHandle .close ()
161
166
self .window .open_file (INI_LOCATION )
162
167
168
+ # Runs the Papyrus compiler with properly formatted arguments based on settings in the INI file.
163
169
class CompilePapyrusCommand (sublime_plugin .WindowCommand ):
164
170
def run (self , ** args ):
165
171
config = getPrefs (args ["cmd" ])
@@ -179,6 +185,7 @@ def run(self, **args):
179
185
else :
180
186
sublime .status_message ("No configuration for %s" % os .path .dirname (args ["cmd" ]))
181
187
188
+ # Disassembles bytecode (.pex) to assembly (.pas)
182
189
class DisassemblePapyrusCommand (sublime_plugin .WindowCommand ):
183
190
def run (self , ** args ):
184
191
scriptPath = args ["cmd" ]
@@ -196,6 +203,7 @@ def run(self, **args):
196
203
if (os .path .exists (disassemblyFinal )):
197
204
self .window .open_file (disassemblyFinal )
198
205
206
+ # Generates bytecode (.pex) from assembly (.pas).
199
207
class AssemblePapyrusCommand (sublime_plugin .WindowCommand ):
200
208
def run (self , ** args ):
201
209
scriptPath = args ["cmd" ]
@@ -207,70 +215,7 @@ def run(self, **args):
207
215
args ["working_dir" ] = scriptDir
208
216
self .window .run_command ("exec" , args )
209
217
210
- if PYTHON_VERSION [0 ] == 3 :
211
- class ClearPapyrusCompilerErrorHighlightsCommand (sublime_plugin .WindowCommand ):
212
- def run (self , ** args ):
213
- source = sublime .active_window ().active_view ()
214
- if source != None :
215
- source .erase_regions (ERROR_HIGHLIGHT_KEY )
216
-
217
- if PYTHON_VERSION [0 ] == 3 :
218
- class ExecCommand (BUILD_SYSTEM .ExecCommand ):
219
- def finish (self , proc ):
220
- super (ExecCommand , self ).finish (proc )
221
- source = sublime .active_window ().active_view ()
222
- if source != None :
223
- if source .file_name ().endswith (PAPYRUS_SCRIPT_EXTENSION ):
224
- source .erase_regions (ERROR_HIGHLIGHT_KEY )
225
- if USER_SETTINGS .get ('highlight_compiler_errors' , False ):
226
- output = GetOutput (self .output_view )
227
- if output != None :
228
- pattern = GetPattern (self .output_view )
229
- if pattern != None :
230
- errors = GetErrors (output , pattern )
231
- if errors != None :
232
- regions = GetRegions (source , errors )
233
- if regions != None :
234
- source .add_regions (ERROR_HIGHLIGHT_KEY , regions , ERROR_HIGHLIGHT_SCOPE )
235
- elif USER_SETTINGS .get ('hide_successful_build_results' , False ):
236
- self .window .run_command ("hide_panel" , {"panel" : "output.exec" })
237
-
238
- def GetOutput (view ):
239
- if view != None :
240
- return view .substr (sublime .Region (0 , view .size ()))
241
- else :
242
- return None
243
-
244
- def GetPattern (view ):
245
- if view != None :
246
- return view .settings ().get ("result_file_regex" )
247
- else :
248
- return None
249
-
250
- def GetErrors (output , pattern ):
251
- lines = output .rstrip ().split ('\n ' )
252
- matches = []
253
- regex = re .compile (pattern )
254
- for line in lines :
255
- match = regex .findall (line )
256
- if len (match ) > 0 :
257
- matches .append (match )
258
- if len (matches ) > 0 :
259
- return matches
260
- else :
261
- return None
262
-
263
- def GetRegions (view , errors ):
264
- regions = []
265
- for error in errors :
266
- region = view .line (sublime .Region (view .text_point (int (error [0 ][1 ]) - 1 , 0 )))
267
- regions .append (region )
268
- del region
269
- if len (regions ) > 0 :
270
- return regions
271
- else :
272
- return None
273
-
218
+ # Looks for matching files in all input paths defined in the INI file based on the given regular expression.
274
219
def GetMatchingFiles (self , filename ):
275
220
if filename != "" :
276
221
folderpaths = []
@@ -323,6 +268,7 @@ def GetMatchingFiles(self, filename):
323
268
elif nummatches > 1 :
324
269
self .window .run_command ("open_papyrus_script_selection" , {"items" : matches })
325
270
271
+ # Scans the current buffer for a script header that declares a parent script and then tries to open the parent script.
326
272
class OpenPapyrusParentScriptCommand (sublime_plugin .WindowCommand ):
327
273
def run (self ):
328
274
source = self .window .active_view ().file_name ()
@@ -337,6 +283,7 @@ def run(self):
337
283
return
338
284
sublime .status_message ("Parent script not declared in \" %s\" " % source )
339
285
286
+ # Tries to open the file(s) matching a given regular expression.
340
287
class OpenPapyrusScriptCommand (sublime_plugin .WindowCommand ):
341
288
def run (self ):
342
289
self .window .show_input_panel ("Open script:" , "" , self .on_done , None , None )
@@ -355,6 +302,7 @@ def on_done(self, text):
355
302
else :
356
303
sublime .status_message ("No input" )
357
304
305
+ # Shows a menu with a list of scripts that match the regular expression passed on to GetMatchingFiles.
358
306
class OpenPapyrusScriptSelectionCommand (sublime_plugin .WindowCommand ):
359
307
def run (self , ** args ):
360
308
items = args ["items" ]
@@ -369,6 +317,10 @@ def on_select(self, index):
369
317
if index >= 0 :
370
318
self .window .open_file (self .items [index ])
371
319
320
+ # Base class that is used in the framework for showing a list of valid arguments and then inserting them.
321
+ # Libraries that need this functionality should import at least "sublime", "sublime_plugin", "sys", and this module.
322
+ # Classes implementing this functionality need to inherit the "PapyrusShowSuggestionsCommand" class and override the "get_items" method.
323
+ # "get_items" should return a dictionary where the keys are the descriptions shown to the user and the values are what is inserted into the buffer.
372
324
class PapyrusShowSuggestionsCommand (sublime_plugin .TextCommand ):
373
325
def run (self , edit , ** args ):
374
326
selections = self .view .sel ()
@@ -377,8 +329,8 @@ def run(self, edit, **args):
377
329
self .argument = region
378
330
items = self .get_items ()
379
331
if items != None :
380
- self .items = list (items .values ())
381
- self .values = list (items .keys ())
332
+ self .items = list (items .keys ())
333
+ self .values = list (items .values ())
382
334
if PYTHON_VERSION [0 ] == 2 :
383
335
self .view .window ().show_quick_panel (self .items , self .on_select , 0 )
384
336
elif PYTHON_VERSION [0 ] == 3 :
@@ -392,6 +344,7 @@ def on_select(self, index):
392
344
args = {"region_start" : self .argument .a , "region_end" : self .argument .b , "replacement" : str (self .values [index ])}
393
345
self .view .run_command ("papyrus_insert_suggestion" , args )
394
346
347
+ # Inserts the value chosen in the class that inherits "PapyrusShowSuggestionsCommand".
395
348
class PapyrusInsertSuggestionCommand (sublime_plugin .TextCommand ):
396
349
def run (self , edit , ** args ):
397
350
region = sublime .Region (args ["region_start" ], args ["region_end" ])
@@ -400,3 +353,55 @@ def run(self, edit, **args):
400
353
self .view .insert (edit , args ["region_start" ], args ["replacement" ])
401
354
else :
402
355
self .view .insert (edit , args ["region_start" ], "\" " + args ["replacement" ] + "\" " )
356
+
357
+ # Manually clear any sections that were highlighted as a result of a failed compilation.
358
+ class ClearPapyrusCompilerErrorHighlightsCommand (sublime_plugin .WindowCommand ):
359
+ def run (self , ** args ):
360
+ source = sublime .active_window ().active_view ()
361
+ if source != None :
362
+ source .erase_regions (ERROR_HIGHLIGHT_KEY )
363
+
364
+ # Checks the build result for errors and, depending on the settings, highlights lines that caused errors and/or hides the build results when there are no errors.
365
+ class ExecCommand (BUILD_SYSTEM .ExecCommand ):
366
+ def finish (self , proc ):
367
+ super (ExecCommand , self ).finish (proc )
368
+ source = sublime .active_window ().active_view ()
369
+ if source != None :
370
+ if source .file_name ().endswith (PAPYRUS_SCRIPT_EXTENSION ):
371
+ source .erase_regions (ERROR_HIGHLIGHT_KEY )
372
+ if USER_SETTINGS .get ('highlight_compiler_errors' , False ):
373
+ output = self .output_view .substr (sublime .Region (0 , self .output_view .size ()))
374
+ if output != None :
375
+ pattern = self .output_view .settings ().get ("result_file_regex" )
376
+ if pattern != None :
377
+ errors = self .GetErrors (output , pattern )
378
+ if errors != None :
379
+ regions = self .GetRegions (source , errors )
380
+ if regions != None :
381
+ source .add_regions (ERROR_HIGHLIGHT_KEY , regions , ERROR_HIGHLIGHT_SCOPE )
382
+ elif USER_SETTINGS .get ('hide_successful_build_results' , False ):
383
+ self .window .run_command ("hide_panel" , {"panel" : "output.exec" })
384
+
385
+ def GetErrors (self , output , pattern ):
386
+ lines = output .rstrip ().split ('\n ' )
387
+ matches = []
388
+ regex = re .compile (pattern )
389
+ for line in lines :
390
+ match = regex .findall (line )
391
+ if len (match ) > 0 :
392
+ matches .append (match )
393
+ if len (matches ) > 0 :
394
+ return matches
395
+ else :
396
+ return None
397
+
398
+ def GetRegions (self , view , errors ):
399
+ regions = []
400
+ for error in errors :
401
+ region = view .line (sublime .Region (view .text_point (int (error [0 ][1 ]) - 1 , 0 )))
402
+ regions .append (region )
403
+ del region
404
+ if len (regions ) > 0 :
405
+ return regions
406
+ else :
407
+ return None
0 commit comments