Sublime Forum

How to see the output of a POpen in a window or console

#1

First off, I’m using Sublime 3 on OSX…

I’m trying to run an outside program and see the output on the console but I can’t seem to find a way. Note that I don’t want any thread locking as they should still be able to use Sublime while the other command runs. Here is an example of the command:

subprocess.Popen(‘moai’, ‘main.lua’], shell=True, cwd=folder);

It would also be acceptable to pipe this to another view, but I was looking for the easiest solution so I was trying to avoid polling the process’ output and writing it manually to a view.

Thanks!
David

0 Likes

#2

Here is a class I used to be able to run some command related to mercurial and display teh result:
Basically you simply redirect the stdout to be able to access it after a wait. Then, once it is done, I display it in a sublimeText Panel. Maybe not exactly what you want …

class HgScript :

	# main_thread uses sublime.set_timeout to send things onto the main thread
	# most sublime.[something] calls need to be on the main thread
	## (Copied from plugin NodeJs by tanepiper) ##
	def main_thread(callback, *args, **kwargs):
  		sublime.set_timeout(functools.partial(callback, *args, **kwargs), 0)

	#
	def exec_cmdhg(self, cmd_a, show_stdout=True):
		p = subprocess.Popen(cmd_a, cwd=self.dname,  stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
		p.wait()
		if p.stderr is not None :
			stderr_lines = p.stderr.readlines()
			self.print_to_panel(cmd_a[1],stderr_lines)
			return False
		if p.stdout is not None :
			self.exec_msg = p.stdout.readlines()
			if show_stdout :
				self.print_to_panel(cmd_a[1],self.exec_msg)
		return True

	# Show a panel with a message.
	# Apply the diff syntax hilighting if the command run was diff
	def print_to_panel(self,cmd,str_a):
		sublime.set_timeout(lambda: self.print_to_panel_mainthread(cmd,str_a), 0)

	def print_to_panel_mainthread(self,cmd,str_a):
		win = sublime.active_window()
		strtxt = u"".join(line.decode("utf-8") for line in str_a)
		if(len(str_a)):
			v = win.create_output_panel('hg_out')
			if cmd=="diff" :
				v.set_syntax_file('Packages/Diff/Diff.tmLanguage')
				v.settings().set('word_wrap', self.view.settings().get('word_wrap'))
			# edit = v.begin_edit(1,"")
			# v.insert(edit, 0, strtxt)
			# v.end_edit(edit)
			v.run_command('append', {'characters': strtxt})
			win.run_command("show_panel", {"panel": "output.hg_out"})

And to have something non blocking you simply wrap that in a thread:

[code]#Simple execute file wrapped in a thread
class RunScriptThread(threading.Thread, HgScript):
def init(self, dname,fname,script_name):
self.dname = dname
self.fname = fname
self.script_name = script_name
threading.Thread.init(self)

def run(self):
	exec(open(self.script_name).read())[/code]
0 Likes

#3

You can just spawn a new thread to run the command in the background (so sublime does not hang). You can either use the threading module or the sublime.set_timeout_async function.

Anything you print() will show up in the console. It’s fairly easy to capture the output as a string using the subprocess module. Check the docs as there are multiple ways depending on your needs.

A bare minimum example:

class ExampleCommand(sublime_plugin.TextCommand):
	def run(self, edit):
		sublime.set_timeout_async(self.doit, 0)

	def doit(self):
		try:
			a = subprocess.check_output('ls'], stderr=subprocess.STDOUT)
		except subprocess.CalledProcessError as e:
			print(e.output)
		else:
			print(a)
0 Likes

#4

Thanks guys; This really helped!

I’ve come up with code for Sublime 3 (Python 3) that does exactly what I want based on this:

[code]def RunToConsole(args, current_dir = None):
sublime.set_timeout_async(lambda: run_in_background(args, current_dir), 0)

def run_in_background(args, current_dir):
proc = ‘’
if current_dir is None:
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
else:
proc = subprocess.Popen(args, cwd=current_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while proc.poll() is None:
try:
data = proc.stdout.readline().decode(encoding=‘UTF-8’)
print(data, end="")
except:
print(“process ended…”)
return;
print(“process ended…”)[/code]

0 Likes