Sublime Forum

Execute external program in background (non-blocking thread)

#1

Good time of day everyone.
I want to create plugin for ST3. But I am not familar with Python3. I decided to write it in other script language. So, I need code snippet to run my script (external program) in backround mode and to do something when script is finished.

I have:

[code]class FuncThread(threading.Thread):
def init(self, target):
self._target = target
threading.Thread.init(self)

def run(self):
	self._target()[/code]

Somewhere in “run”

thread = threading.Thread(target = my_long_calculate, args = (self.view, edit))
thread.start()

my_long_calculate looks approximately as:

subprocess.Popen(cmd, stdout=subprocess.PIPE, startupinfo=startupinfo).communicate()[0]

But my ST still is hanging (locked) when my_long_calculate() is running.
What am I doing wrong?

0 Likes

#2

What on earth are you doing that would make it easier to shell out to a different process than to clutz through Python?

Also, how are you planning to turn the script’s output into changes to Sublime Text?

0 Likes

#3

It is not easier! I told that I dont known python (I dont understand languages without curly brackets). I’m sure that my task can be solved in Python, but I dont know it, everything is simple.

This is example ST3 plugin “Hello from node.js”
gist.github.com/unlight/6262932

run view.run_command(“hello_node”) command in ST console.

0 Likes

#4

You don’t really show enough code to see what is wrong. Also, you are not supposed to retain or pass the “edit” object between threads. Instead, call view.run_command of a second TextCommand that will apply the appropriate changes.

As an aside, using the sublime.set_timeout_async function might be simpler than manually creating a thread.

0 Likes

#5

@sapphirehamster
I upload full code of test plugin on github: github.com/unlight/HelloNode
I used sublime.set_timeout_async(lambda: self.view.run_command("long_loop"), 0)

In long_loop command occurs “long calculation” which I emulate by Javascript setTimeout() function, and in this time ST3 is “hanging” (cannot move cursor, cannot write something, etc.)

0 Likes

#6

I think you may have misunderstood when I said it needs to run a second TextCommand. You need to call set_timeout_async on your own function that will do the long computation, and then call the TextCommand. It would look something roughly like this:

class ExampleNodeCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        sublime.set_timeout_async(self.long_command, 0)

    def long_command(self):
        args = [get_node_path(), PLUGIN_FOLDER + "/longloop.js"]
        for region in self.view.sel():
            output = run_process(args)
            pos = region.begin()
            self.view.run_command('example_node2', {'pos': pos, 'output': output})

class ExampleNode2Command(sublime_plugin.TextCommand):
    def run(self, edit, pos=None, output=None):
        self.view.insert(edit, pos, output)

I didn’t test this, so there may be typos, but it’s the general idea. Also, you may have problems if there are multiple cursors (the positions may shift, so you may want to iterate over the Selection in reverse).

0 Likes

#7

Nice. It works! Thank you very much.

0 Likes

#8

thank you for your comment and example code, this has been very helpful for me! kudos!

0 Likes