Skip to content

Instantly share code, notes, and snippets.

@james2doyle
Last active July 28, 2020 21:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james2doyle/3ceb44ae1235537e51919a661c3a05b2 to your computer and use it in GitHub Desktop.
Save james2doyle/3ceb44ae1235537e51919a661c3a05b2 to your computer and use it in GitHub Desktop.
A sublime build system for better Node.js output by highlighting with the right syntax
{
"target": "node_build",
"selector": "source.js",
"variants": [
{
"name": "JSON Output",
"json": true
}
]
}
# modified from: https://www.sublimetext.com/docs/3/build_systems.html#advanced_example
import sublime
import sublime_plugin
import subprocess
import threading
import os
class NodeBuildCommand(sublime_plugin.WindowCommand):
encoding = 'utf-8'
proc = None
panel = None
panel_lock = threading.Lock()
def is_enabled(self):
return True
def run(self, js=True, json=False):
vars = self.window.extract_variables()
working_dir = vars['file_path']
# A lock is used to ensure only one thread is
# touching the output panel at a time
with self.panel_lock:
# Creating the panel implicitly clears any previous contents
self.panel = self.window.create_output_panel('exec')
settings = self.panel.settings()
settings.set('result_base_dir', working_dir)
if js and not json:
settings.set('syntax', 'Packages/JavaScript/JavaScript.sublime-syntax')
if json:
settings.set('syntax', 'Packages/JavaScript/JSON.sublime-syntax')
self.window.run_command('show_panel', {'panel': 'output.exec'})
if self.proc is not None:
self.proc.terminate()
self.proc = None
args = ['node']
args.append(vars['file'])
self.proc = subprocess.Popen(
args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=working_dir
)
threading.Thread(
target=self.read_handle,
args=(self.proc.stdout,)
).start()
def read_handle(self, handle):
chunk_size = 2 ** 13
out = b''
while True:
try:
data = os.read(handle.fileno(), chunk_size)
# If exactly the requested number of bytes was
# read, there may be more data, and the current
# data may contain part of a multibyte char
out += data
if len(data) == chunk_size:
continue
if data == b'' and out == b'':
raise IOError('EOF')
# We pass out to a function to ensure the
# timeout gets the value of out right now,
# rather than a future (mutated) version
self.queue_write(out.decode(self.encoding))
if data == b'':
raise IOError('EOF')
out = b''
except (UnicodeDecodeError) as e:
msg = 'Error decoding output using %s - %s'
self.queue_write(msg % (self.encoding, str(e)))
break
except (IOError):
self.queue_write('\n[%s]' % msg)
break
def queue_write(self, text):
sublime.set_timeout(lambda: self.do_write(text), 1)
def do_write(self, text):
with self.panel_lock:
self.panel.run_command('append', {'characters': text})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment