463 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			463 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #aponxi v0.6.0
 | |
| import sublime
 | |
| import sys
 | |
| from os import path
 | |
| import os
 | |
| from subprocess import Popen, PIPE
 | |
| from sublime_plugin import TextCommand
 | |
| from sublime_plugin import WindowCommand
 | |
| import sublime_plugin
 | |
| import time
 | |
| import functools
 | |
| 
 | |
| settings = sublime.load_settings('CoffeeScript.sublime-settings')
 | |
| 
 | |
| 
 | |
| def run(cmd, args=[], source="", cwd=None, env=None):
 | |
|     if not type(args) is list:
 | |
|         args = [args]
 | |
|     if sys.platform == "win32":
 | |
|         proc = Popen([cmd] + args, env=env, cwd=cwd, stdout=PIPE, stdin=PIPE, stderr=PIPE, shell=True)
 | |
|         stat = proc.communicate(input=source.encode('utf-8'))
 | |
|     else:
 | |
|         if env is None:
 | |
|             env = {"PATH": settings.get('binDir', '/usr/local/bin')}
 | |
|         if source == "":
 | |
|             command = [cmd] + args
 | |
|         else:
 | |
|             command = [cmd] + args + [source]
 | |
|         # print "Debug - coffee command: "
 | |
|         # print command
 | |
|         proc = Popen(command, env=env, cwd=cwd, stdout=PIPE, stderr=PIPE)
 | |
|         stat = proc.communicate()
 | |
|     okay = proc.returncode == 0
 | |
|     return {"okay": okay, "out": stat[0].decode('utf-8'), "err": stat[1].decode('utf-8')}
 | |
| 
 | |
| 
 | |
| def brew(args, source):
 | |
|     if sys.platform == "win32":
 | |
|         args.append("-s")
 | |
|     else:
 | |
|         args.append("-e")
 | |
|     return run("coffee", args=args, source=source)
 | |
| 
 | |
| 
 | |
| def cake(task, cwd):
 | |
|     return run("cake", args=task, cwd=cwd)
 | |
| 
 | |
| 
 | |
| def isCoffee(view=None):
 | |
|     if view is None:
 | |
|         view = sublime.active_window().active_view()
 | |
|     return 'source.coffee' in view.scope_name(0)
 | |
| 
 | |
| 
 | |
| class Text():
 | |
|     @staticmethod
 | |
|     def all(view):
 | |
|         return view.substr(sublime.Region(0, view.size()))
 | |
| 
 | |
|     @staticmethod
 | |
|     def sel(view):
 | |
|         text = []
 | |
|         for region in view.sel():
 | |
|             if region.empty():
 | |
|                 continue
 | |
|             text.append(view.substr(region))
 | |
|         return "".join(text)
 | |
| 
 | |
|     @staticmethod
 | |
|     def get(view):
 | |
|         text = Text.sel(view)
 | |
|         if len(text) > 0:
 | |
|             return text
 | |
|         return Text.all(view)
 | |
| 
 | |
| 
 | |
| class CompileCommand(TextCommand):
 | |
|     def is_enabled(self):
 | |
|         return isCoffee(self.view)
 | |
| 
 | |
|     def run(self, *args, **kwargs):
 | |
|         no_wrapper = settings.get('noWrapper', True)
 | |
|         compile_dir = settings.get('compileDir')
 | |
|         args = ['-c', self.view.file_name()]
 | |
|         # print self.view.file_name()
 | |
|         if no_wrapper:
 | |
|             args = ['-b'] + args
 | |
|         # print compile_dir
 | |
|         # print isinstance(compile_dir, unicode)
 | |
|         if compile_dir and isinstance(compile_dir, str) or isinstance(compile_dir, unicode):
 | |
|             print "Compile dir specified: " + compile_dir
 | |
|             if not os.path.exists(compile_dir):
 | |
|                 os.makedirs(compile_dir)
 | |
|                 print "Compile dir did not exist, created folder: " + compile_dir
 | |
|             folder, file_nm = os.path.split(self.view.file_name())
 | |
|             print folder
 | |
|             args = ['--output', compile_dir] + args
 | |
|             # print args
 | |
|         # print args
 | |
|         result = run("coffee", args=args)
 | |
| 
 | |
|         if result['okay'] is True:
 | |
|             status = 'Compilation Succeeded'
 | |
|         else:
 | |
|             status = 'Compilation Failed'
 | |
| 
 | |
|         sublime.status_message(status)
 | |
| 
 | |
| 
 | |
| class CompileAndDisplayCommand(TextCommand):
 | |
|     def is_enabled(self):
 | |
|         return isCoffee(self.view)
 | |
| 
 | |
|     def run(self, edit, **kwargs):
 | |
|         output = self.view.window().new_file()
 | |
|         output.set_scratch(True)
 | |
|         opt = kwargs["opt"]
 | |
|         if opt == '-p':
 | |
|             output.set_syntax_file('Packages/JavaScript/JavaScript.tmLanguage')
 | |
|         no_wrapper = settings.get('noWrapper', True)
 | |
| 
 | |
|         args = [opt]
 | |
|         print args
 | |
|         if no_wrapper:
 | |
|             args = ['-b'] + args
 | |
| 
 | |
|         res = brew(args, Text.get(self.view))
 | |
|         if res["okay"] is True:
 | |
|             output.insert(edit, 0, res["out"])
 | |
|         else:
 | |
|             output.insert(edit, 0, res["err"].split("\n")[0])
 | |
| 
 | |
| 
 | |
| class CheckSyntaxCommand(TextCommand):
 | |
|     def is_enabled(self):
 | |
|         return isCoffee(self.view)
 | |
| 
 | |
|     def run(self, edit):
 | |
|         res = brew(['-b', '-p'], Text.get(self.view))
 | |
|         if res["okay"] is True:
 | |
|             status = 'Valid'
 | |
|         else:
 | |
|             status = res["err"].split("\n")[0]
 | |
|         sublime.status_message('Syntax %s' % status)
 | |
| 
 | |
| 
 | |
| class RunScriptCommand(WindowCommand):
 | |
|     def finish(self, text):
 | |
|         if text == '':
 | |
|             return
 | |
|         text = "{puts, print} = require 'util'\n" + text
 | |
|         res = brew(['-b'], text)
 | |
|         if res["okay"] is True:
 | |
|             output = self.window.new_file()
 | |
|             output.set_scratch(True)
 | |
|             edit = output.begin_edit()
 | |
|             output.insert(edit, 0, res["out"])
 | |
|             output.end_edit(edit)
 | |
|         else:
 | |
|             sublime.status_message('Syntax %s' % res["err"].split("\n")[0])
 | |
| 
 | |
|     def run(self):
 | |
|         sel = Text.sel(sublime.active_window().active_view())
 | |
|         if len(sel) > 0:
 | |
|             if not isCoffee():
 | |
|                 return
 | |
|             self.finish(sel)
 | |
|         else:
 | |
|             self.window.show_input_panel('Coffee >', '', self.finish, None, None)
 | |
| 
 | |
| 
 | |
| class RunCakeTaskCommand(WindowCommand):
 | |
|     def finish(self, task):
 | |
|         if task == '':
 | |
|             return
 | |
| 
 | |
|         if not self.window.folders():
 | |
|             cakepath = path.dirname(self.window.active_view().file_name())
 | |
|         else:
 | |
|             cakepath = path.join(self.window.folders()[0], 'Cakefile')
 | |
|             if not path.exists(cakepath):
 | |
|                 cakepath = path.dirname(self.window.active_view().file_name())
 | |
| 
 | |
|         if not path.exists(cakepath):
 | |
|             return sublime.status_message("Cakefile not found.")
 | |
| 
 | |
|         res = cake(task, cakepath)
 | |
|         if res["okay"] is True:
 | |
|             if "No such task" in res["out"]:
 | |
|                 msg = "doesn't exist"
 | |
|             else:
 | |
|                 msg = "suceeded"
 | |
|         else:
 | |
|             msg = "failed"
 | |
|         sublime.status_message("Task %s - %s." % (task, msg))
 | |
| 
 | |
|     def run(self):
 | |
|         self.window.show_input_panel('Cake >', '', self.finish, None, None)
 | |
| 
 | |
| 
 | |
| #                               _
 | |
| #   __ _ _ __   ___  _ __ __  _(_)
 | |
| #  / _` | '_ \ / _ \| '_ \\ \/ / |
 | |
| # | (_| | |_) | (_) | | | |>  <| |
 | |
| #  \__,_| .__/ \___/|_| |_/_/\_\_|
 | |
| #       |_|
 | |
| 
 | |
| def watched_filename(view_id):
 | |
|     view = ToggleWatch.views[view_id]['input_obj']
 | |
|     if view.file_name() is not None:
 | |
|         filename = view.file_name().split('/')[-1]
 | |
|     else:
 | |
|         filename = "Unsaved File"
 | |
|     return filename
 | |
| 
 | |
| 
 | |
| class ToggleWatch(TextCommand):
 | |
|     views = {}
 | |
|     outputs = {}
 | |
| 
 | |
|     def is_enabled(self):
 | |
|         return isCoffee(self.view)
 | |
| 
 | |
|     def run(self, edit):
 | |
|         myvid = self.view.id()
 | |
| 
 | |
|         if not myvid in ToggleWatch.views:
 | |
| 
 | |
|             views = ToggleWatch.views
 | |
|             views[myvid] = {'watched': True, 'modified': True, 'input_closed': False}
 | |
|             views[myvid]["input_obj"] = self.view
 | |
|             print "Now watching", watched_filename(myvid)
 | |
|             createOut(myvid)
 | |
| 
 | |
|         else:
 | |
|             views = ToggleWatch.views
 | |
| 
 | |
|             views[myvid]['watched'] = not views[myvid]['watched']
 | |
|             if not views[myvid]['watched']:
 | |
|                 print "Stopped watching", watched_filename(myvid)
 | |
| 
 | |
|             if views[myvid]['output_open'] is False:
 | |
|                 print "Openning output and watching", watched_filename(myvid)
 | |
|                 createOut(myvid)
 | |
| 
 | |
|             elif views[myvid]['watched'] is True:
 | |
|                 print "Resuming watching", watched_filename(myvid)
 | |
|                 refreshOut(myvid)
 | |
| 
 | |
| 
 | |
| def cleanUp(input_view_id):
 | |
|     del ToggleWatch.outputs[ToggleWatch.views[input_view_id]['output_id']]
 | |
|     del ToggleWatch.views[input_view_id]
 | |
|     return
 | |
| 
 | |
| 
 | |
| def get_output_filename(input_view_id):
 | |
|     input_filename = watched_filename(input_view_id)
 | |
|     fileName, fileExtension = os.path.splitext(input_filename)
 | |
|     output_filename = fileName + '.js'
 | |
|     return output_filename
 | |
| 
 | |
| 
 | |
| def createOut(input_view_id):
 | |
|     #create output panel and save
 | |
|     this_view = ToggleWatch.views[input_view_id]
 | |
|     outputs = ToggleWatch.outputs
 | |
|     #print this_view
 | |
|     input_filename = watched_filename(input_view_id)
 | |
|     print input_filename
 | |
| 
 | |
|     output = this_view["input_obj"].window().new_file()
 | |
|     output.set_scratch(True)
 | |
|     output.set_syntax_file('Packages/JavaScript/JavaScript.tmLanguage')
 | |
|     this_view['output_id'] = output.id()
 | |
|     this_view["output_obj"] = output
 | |
|     this_view["output_open"] = True
 | |
|     # setting output filename
 | |
|     # print output.settings().set('filename', '[Compiled]' + input_filename)
 | |
|     # Getting file extension
 | |
|     output_filename = get_output_filename(input_view_id)
 | |
|     output.set_name(output_filename)
 | |
| 
 | |
|     if not output.id() in outputs:
 | |
|         outputs[output.id()] = {'boundto': input_view_id}
 | |
|     refreshOut(input_view_id)
 | |
|     return output
 | |
| 
 | |
| 
 | |
| def refreshOut(view_id):
 | |
| 
 | |
|     this_view = ToggleWatch.views[view_id]
 | |
|     this_view['last_modified'] = time.mktime(time.gmtime())
 | |
|     #refresh the output view
 | |
|     no_wrapper = settings.get('noWrapper', True)
 | |
| 
 | |
|     args = ['-p']
 | |
|     if no_wrapper:
 | |
|         args = ['-b'] + args
 | |
| 
 | |
|     res = brew(args, Text.get(this_view['input_obj']))
 | |
|     output = this_view['output_obj']
 | |
|     this_view['modified'] = False
 | |
| 
 | |
|     if res["okay"] is True:
 | |
|         edit = output.begin_edit()
 | |
|         output.erase(edit, sublime.Region(0, output.size()))
 | |
|         output.insert(edit, 0, res["out"])
 | |
|         output.end_edit(edit)
 | |
|         print "Refreshed"
 | |
|     else:
 | |
|         edit = output.begin_edit()
 | |
|         output.erase(edit, sublime.Region(0, output.size()))
 | |
|         output.insert(edit, 0, res["err"].split("\n")[0])
 | |
|         output.end_edit(edit)
 | |
|     return
 | |
| 
 | |
| 
 | |
| def isView(view_id):
 | |
|     # are they modifying a view (rather than a panel, etc.)
 | |
|     if not view_id:
 | |
|         return False
 | |
|     window = sublime.active_window()
 | |
|     view = window.active_view() if window != None else None
 | |
|     return (view is not None and view.id() == view_id)
 | |
| 
 | |
| 
 | |
| def close_output(input_id):
 | |
|     views = ToggleWatch.views
 | |
|     v = views[input_id]
 | |
|     output = v['output_obj']
 | |
|     # output_id = v['output_id']
 | |
|     # print "close output"
 | |
|     if v['output_open'] is True:
 | |
|         #print "the output is open so we should attempt to close it"
 | |
|         output.window().focus_view(output)
 | |
|         output.window().run_command("close")
 | |
|         print watched_filename(input_id), "was closed. Closing the Output"
 | |
|         #v['output_open'] = False
 | |
|         cleanUp(input_id)
 | |
| 
 | |
|     return
 | |
| 
 | |
| 
 | |
| class CaptureEditing(sublime_plugin.EventListener):
 | |
| 
 | |
|     def handleTimeout(self, vid):
 | |
|         this_view = ToggleWatch.views[vid]
 | |
|         modified = this_view['modified']
 | |
|         if modified is True:
 | |
|             # been 1000ms since the last modification
 | |
|             #print "handling"
 | |
|             refreshOut(vid)
 | |
| 
 | |
|     def on_modified(self, view):
 | |
|         vid = view.id()
 | |
|         watch_modified = settings.get('watchOnModified')
 | |
| 
 | |
|         if watch_modified is not False and vid in ToggleWatch.views:
 | |
|             if watch_modified is True:
 | |
|                 delay = 0.5
 | |
|             elif watch_modified < 0.5:
 | |
|                 delay = 0.5
 | |
|             else:
 | |
|                 delay = watch_modified
 | |
|             #then we have a watched input.
 | |
|             this_view = ToggleWatch.views[vid]
 | |
|             #print " this view is ", this_view
 | |
|             if this_view['modified'] is False:
 | |
|                 this_view['modified'] = True
 | |
|                 #print " trigger "
 | |
|                 if this_view['watched'] is True:
 | |
|                     sublime.set_timeout(functools.partial(self.handleTimeout, vid), int(delay * 1000))
 | |
|             return
 | |
| 
 | |
|     def on_post_save(self, view):
 | |
|         # print "isCoffee " + str(isCoffee())
 | |
|         watch_save = settings.get('watchOnSave', True)
 | |
|         if watch_save:
 | |
|             save_id = view.id()
 | |
|             views = ToggleWatch.views
 | |
|             if save_id in views:
 | |
|                 # getting view object
 | |
|                 save_view = ToggleWatch.views[save_id]
 | |
|                 # check if modified
 | |
|                 if save_view['modified'] is True:
 | |
|                     refreshOut(save_id)
 | |
|         compile_on_save = settings.get('compileOnSave', True)
 | |
|         if compile_on_save is True and isCoffee() is True:
 | |
|             print "Compiling on save..."
 | |
|             view.run_command("compile")
 | |
|         show_compile_output_on_save = settings.get('showOutputOnSave', True)
 | |
|         if show_compile_output_on_save is True and isCoffee() is True and CompileOutput.IS_OPEN is True:
 | |
|             print "Updating output panel..."
 | |
|             view.run_command("compile_output")
 | |
| 
 | |
|         return
 | |
| 
 | |
|     def on_close(self, view):
 | |
|         close_id = view.id()
 | |
|         views = ToggleWatch.views
 | |
|         if close_id in views:
 | |
|             #this is an input
 | |
|             #print "input was closed"
 | |
|             views[close_id]['input_closed'] = True
 | |
|             close_output(close_id)
 | |
| 
 | |
|         if close_id in ToggleWatch.outputs and views[ToggleWatch.outputs[close_id]['boundto']]['input_closed'] is not True:
 | |
|             #this is an output
 | |
|             #print "an output was closed!"
 | |
|             boundview = ToggleWatch.outputs[close_id]['boundto']
 | |
|             thatview = views[boundview]
 | |
|             thatview['output_open'] = False
 | |
|             thatview['watched'] = False
 | |
| 
 | |
|             filename = watched_filename(boundview)
 | |
|             print "The output was closed. No longer watching", filename
 | |
| 
 | |
|         return
 | |
| 
 | |
| 
 | |
| class CompileOutput(TextCommand):
 | |
|     PANEL_NAME = 'coffee_compile_output'
 | |
|     IS_OPEN = False
 | |
| 
 | |
|     def is_enabled(self):
 | |
|         return isCoffee(self.view)
 | |
| 
 | |
|     def run(self, edit):
 | |
|         window = self.view.window()
 | |
| 
 | |
|         #refresh the output view
 | |
|         no_wrapper = settings.get('noWrapper', True)
 | |
| 
 | |
|         # args = ['-p']
 | |
|         if no_wrapper:
 | |
|             args = ['-b']
 | |
| 
 | |
|         res = brew(args, Text.get(self.view))
 | |
|         panel = window.get_output_panel(self.PANEL_NAME)
 | |
|         panel.set_syntax_file('Packages/JavaScript/JavaScript.tmLanguage')
 | |
|         panel.set_read_only(False)
 | |
|         output = panel
 | |
|         # print res["err"]
 | |
| 
 | |
|         if res["okay"] is True:
 | |
|             edit = output.begin_edit()
 | |
|             output.erase(edit, sublime.Region(0, output.size()))
 | |
|             output.insert(edit, 0, res["out"])
 | |
|             output.end_edit(edit)
 | |
|             # print "Refreshed"
 | |
|         else:
 | |
|             edit = output.begin_edit()
 | |
|             output.erase(edit, sublime.Region(0, output.size()))
 | |
|             output.insert(edit, 0, res["err"])
 | |
|             output.end_edit(edit)
 | |
|         output.sel().clear()
 | |
|         output.set_read_only(True)
 | |
| 
 | |
|         window.run_command('show_panel', {'panel': 'output.%s' % self.PANEL_NAME})
 | |
|         self.IS_OPEN = True
 | |
|         return
 |