Skip to content

Commit dc91bc2

Browse files
committed
Core plugin update
- Fixed the issue that caused Papyrus build system issues (added support for user settings in ST2 version). - Made all of the features that were previously only working in ST3 also work in ST2.
1 parent f438189 commit dc91bc2

File tree

1 file changed

+79
-74
lines changed

1 file changed

+79
-74
lines changed

Core/SublimePapyrus.py

Lines changed: 79 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import sublime, sublime_plugin
2-
import re
3-
import os
4-
import sys
1+
import sublime, sublime_plugin, re, os, sys
52
# ST2 uses Python 2.6 and ST3 uses Python 3.3.
63
PYTHON_VERSION = sys.version_info
74
if PYTHON_VERSION[0] == 2:
85
import ConfigParser
96
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')
1013
elif PYTHON_VERSION[0] == 3:
1114
import configparser
1215
from io import StringIO
@@ -15,7 +18,7 @@
1518

1619
# INI related variables.
1720
DEFAULT_INI_LOCATION = os.path.expanduser("~\\Documents\\SublimePapyrus.ini")
18-
INI_LOCATION = ""
21+
INI_LOCATION = DEFAULT_INI_LOCATION
1922
if (os.path.exists("C:\\Program Files (x86)")):
2023
END_USER_ROOT = "C:\\Program Files (x86)\\Steam\\steamapps\\common\\skyrim"
2124
else:
@@ -73,18 +76,18 @@
7376
ERROR_HIGHLIGHT_SCOPE = "invalid"
7477
PAPYRUS_SCRIPT_EXTENSION = ".psc"
7578

79+
# ST's API is ready to be used.
7680
def plugin_loaded():
7781
global USER_SETTINGS
7882
USER_SETTINGS = sublime.load_settings('SublimePapyrus.sublime-settings')
7983
updateINIPath()
8084

85+
# Reads the path, which may have been defined by the user, to the INI file containing settings specific to the Papyrus build system.
8186
def updateINIPath():
8287
global INI_LOCATION
8388
iniPath = USER_SETTINGS.get('ini_path', "")
8489
if iniPath == "":
85-
if INI_LOCATION == DEFAULT_INI_LOCATION:
86-
return
87-
else:
90+
if INI_LOCATION != DEFAULT_INI_LOCATION:
8891
INI_LOCATION = DEFAULT_INI_LOCATION
8992
elif iniPath != INI_LOCATION:
9093
if iniPath.endswith(".ini"):
@@ -97,6 +100,7 @@ def updateINIPath():
97100
iniPath += "\\SublimePapyrus.ini"
98101
INI_LOCATION = iniPath
99102

103+
# Returns Papyrus compiler arguments based on the user's settings in the INI file.
100104
def getPrefs(filePath):
101105
fileDir, fileName = os.path.split(filePath)
102106
ret = {}
@@ -148,6 +152,7 @@ def getPrefs(filePath):
148152
return None
149153
return ret
150154

155+
# Generates an INI file based on the template defined in the variable DEFAULT_INI_TEXT.
151156
class CreateDefaultSettingsFileCommand(sublime_plugin.WindowCommand):
152157
def run(self, **args):
153158
updateINIPath()
@@ -160,6 +165,7 @@ def run(self, **args):
160165
outHandle.close()
161166
self.window.open_file(INI_LOCATION)
162167

168+
# Runs the Papyrus compiler with properly formatted arguments based on settings in the INI file.
163169
class CompilePapyrusCommand(sublime_plugin.WindowCommand):
164170
def run(self, **args):
165171
config = getPrefs(args["cmd"])
@@ -179,6 +185,7 @@ def run(self, **args):
179185
else:
180186
sublime.status_message("No configuration for %s" % os.path.dirname(args["cmd"]))
181187

188+
# Disassembles bytecode (.pex) to assembly (.pas)
182189
class DisassemblePapyrusCommand(sublime_plugin.WindowCommand):
183190
def run(self, **args):
184191
scriptPath = args["cmd"]
@@ -196,6 +203,7 @@ def run(self, **args):
196203
if (os.path.exists(disassemblyFinal)):
197204
self.window.open_file(disassemblyFinal)
198205

206+
# Generates bytecode (.pex) from assembly (.pas).
199207
class AssemblePapyrusCommand(sublime_plugin.WindowCommand):
200208
def run(self, **args):
201209
scriptPath = args["cmd"]
@@ -207,70 +215,7 @@ def run(self, **args):
207215
args["working_dir"] = scriptDir
208216
self.window.run_command("exec", args)
209217

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.
274219
def GetMatchingFiles(self, filename):
275220
if filename != "":
276221
folderpaths = []
@@ -323,6 +268,7 @@ def GetMatchingFiles(self, filename):
323268
elif nummatches > 1:
324269
self.window.run_command("open_papyrus_script_selection", {"items": matches})
325270

271+
# Scans the current buffer for a script header that declares a parent script and then tries to open the parent script.
326272
class OpenPapyrusParentScriptCommand(sublime_plugin.WindowCommand):
327273
def run(self):
328274
source = self.window.active_view().file_name()
@@ -337,6 +283,7 @@ def run(self):
337283
return
338284
sublime.status_message("Parent script not declared in \"%s\"" % source)
339285

286+
# Tries to open the file(s) matching a given regular expression.
340287
class OpenPapyrusScriptCommand(sublime_plugin.WindowCommand):
341288
def run(self):
342289
self.window.show_input_panel("Open script:", "", self.on_done, None, None)
@@ -355,6 +302,7 @@ def on_done(self, text):
355302
else:
356303
sublime.status_message("No input")
357304

305+
# Shows a menu with a list of scripts that match the regular expression passed on to GetMatchingFiles.
358306
class OpenPapyrusScriptSelectionCommand(sublime_plugin.WindowCommand):
359307
def run(self, **args):
360308
items = args["items"]
@@ -369,6 +317,10 @@ def on_select(self, index):
369317
if index >= 0:
370318
self.window.open_file(self.items[index])
371319

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.
372324
class PapyrusShowSuggestionsCommand(sublime_plugin.TextCommand):
373325
def run(self, edit, **args):
374326
selections = self.view.sel()
@@ -377,8 +329,8 @@ def run(self, edit, **args):
377329
self.argument = region
378330
items = self.get_items()
379331
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())
382334
if PYTHON_VERSION[0] == 2:
383335
self.view.window().show_quick_panel(self.items, self.on_select, 0)
384336
elif PYTHON_VERSION[0] == 3:
@@ -392,6 +344,7 @@ def on_select(self, index):
392344
args = {"region_start": self.argument.a, "region_end": self.argument.b, "replacement": str(self.values[index])}
393345
self.view.run_command("papyrus_insert_suggestion", args)
394346

347+
# Inserts the value chosen in the class that inherits "PapyrusShowSuggestionsCommand".
395348
class PapyrusInsertSuggestionCommand(sublime_plugin.TextCommand):
396349
def run(self, edit, **args):
397350
region = sublime.Region(args["region_start"], args["region_end"])
@@ -400,3 +353,55 @@ def run(self, edit, **args):
400353
self.view.insert(edit, args["region_start"], args["replacement"])
401354
else:
402355
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

Comments
 (0)