Sublime Forum

run_command return code

#1

Hi Everyone,

I have a run_command that execute an external command. It works great. Now i would like to get the result code to send a Growl Notification depending on the failure or not.
I dont see any way of doing that (ST2 and ST3)

Any one sees a way to do that?
Thanks

0 Likes

#2

Ever figure this out? I was looking to do something similar.

0 Likes

#3

Continuing the discussion from Why no return value for plugin command run() method?:

This is impossible at the moment, but I too would love this feature. Just make a post in the “API suggestions” thread in this subforum.

0 Likes

#4

OK, I screwed around a bit and it is in fact possible, but you must avoid Sublime in some way:

class CommandWithReturnValueCommand(sublime_plugin.ApplicationCommand):
    def run(self):
        return 'Hello, world!'

class ReturnValuePrinterCommand(sublime_plugin.ApplicationCommand):
    def run(self):
        klass = next((x for x in sublime_plugin.application_command_classes if CommandWithReturnValueCommand is x), None)
        if not klass:
            return
        inst = klass()
        print(inst.run())

If you open the Python console in Sublime and type

sublime.run_command('return_value_printer')

it will print “Hello, world!”. But this is hacky, and it should be part of the standard API.

1 Like

#5

Wow!

On two fronts I suppose…

  1. I would never have thought to write that code and

  2. why in the name of @#$@ is a simple return statement not figured into the standard API for commands? So much of Sublime is architected so well… that for it to be missing such a basic utility seems beyond mere oversight or laziness… thus I wonder if it is an intended design decision.

In my attempts, I was plinking away on trying to figure this out… based off this post:

The poster wanted to get a return code…

self.view.window().run_command(“exec”, {
“cmd”: [command],
“shell”: True,
“working_dir”: working_dir
})

The “exec” command though seems to be used for external programs

during the discussion, jps suggested “subclassing” the ExecCommand

I was wondering if something similar (subclassing) could be done with ApplicationCommand or WindowCommand to avoid “hackyness”

Python isn’t my native language so, I’m not sure if I was running down the wrong rabbit hole… maybe you’ll see something I don’t.

Either way, just want to thank you for taking the time to help a fellow coder :slightly_smiling:

0 Likes

#6

Well, if you want the return code from an external process, then that IS perfectly possible. Here is a complete example:

import Default.exec

class FunnyCommand(Default.exec.ExecCommand):
    """This does funny things."""

    def description(self):
        return 'Does funny things'

    def run(self):
        cmd = 'echo "hello, world!"'
        super().run(shell_cmd=cmd, working_dir='/home/your-name/')
    
    def on_finished(self, proc):
        super().on_finished(proc)
        if proc.exit_code() == 0: # <-- this is the exit code
            print('success!')
        else:
            print('failure :-(')

Open the Python console and run with

window.run_command('funny')

I advise you to get the “PackageResourceViewer” from Package Control and open the “Default” package, check out “exec.py” there.

I think one issue is the fact that running commands go through the sublime_api module, which, I believe, is a Boost.Python module.

1 Like

#7

I was all up in exec.py checking out the guts…

And since it seemed possible to get the return code from an external process, I was trying to “extrapolate” on that implementation… and somehow figure out a way for just ordinary commands…

but alas…

your chops are greater than mine… so if hacky it is… then so be it. :slight_smile:

0 Likes

#8

Subclassing Default.exec.ExecCommand is perfectly fine I think :slightly_smiling:

0 Likes

#9

but does not this work to run external processes? not your standard commands?
I came to the conclusion this was for stuff like build processes… running command line tools and such… not internal sublime commands like WindowCommand…

these go back to the sublime module and run_command… which goes back to sublime_api…

0 Likes

#10

If I had to guess I would say that the reason why commands don’t return a value is because they’re primarily meant to be used to perform an action in response to a user key press, menu selection, command palette entry and (for TextCommands) execution as a part of a user recorded macro. In those sort of cases, a return value doesn’t make a lot of sense because there’s nothing to use it.

For the purposes of a plugin, the standard commands are commands that do a thing (move the cursor, insert text, etc) for which again the utility of a return value is not (usually) particularly useful.

Generally I would say that if you’re trying to take an action and know what happened, you should less be trying to use the command system to do it and more writing code to take the action and see what happened.

2 Likes

#11

Yes, what I wrote is for an external process like make and such. It wasn’t clear to me if that is what you wanted. Anyway, do as @OdatNurd says and consider writing regular Python functions if you want to get return values.

I do still wish commands could return values. Imagine that being possible; all of the sublime module could then be ApplicationCommands, no? And if so, you could get JSON return values from the command line, as in $ subl --command packages_path, if it were PackagesPathCommand(sublime_plugin.ApplicationCommand) and not sublime.packages_path().

2 Likes

Why no return value for plugin command run() method?
#12

Alas, my actions get pretty involved not just in the view, but on the file system. And in the spirit of code reuse, I was going to have commands run commands… but I need to know if called commands fail/succeed.

How depressing this isn’t standard… and limiting… especially for an application that prides itself on its extensibility.

Thanks guys for all your help… :slightly_smiling:

0 Likes

#13

If you mean code reuse in terms of having your own commands that can call each other you can create functions in your plugin files that perform the required tasks, returning values as needed and then build your commands by calling those methods.

On the other hand if you mean trying to leverage existing commands and know if they worked, there may still be a way to use them to do something and then see what happened after the fact.

Do you have some examples of what you’re trying to do?

0 Likes

#14

An example…

Say I have a Content Manager
I use the sidebar to execute the command content_mgr_create_my_file
it creates MyFile.txt

but after file creation I need to setup history management

History Management
upon creation of MyFile.txt, I want to create a history folder that will capture the evolution of MyFile.txt

so the first idea was to just call a function in the content_mgr_create_my_file that would create this folder. simple enough… def create_history_folder()

But the idea was to keep the logical concerns separate. content manager manages content. history manager manages history.

So, the idea was to keep history functionality out of content creation functionality. Thus, I wanted to create another command history_mgr_create_datastore, which would handle the creation of the datastore folder. I was aiming for separation of concerns and bite-sized reusable commands. commands I could call from other commands…

so within my content_mgr_create_my_file command I would subsequently call a line of code like…

result = sublime.active_window().run_command(‘history_mgr_create_datastore’)

THAT command creates my history folder for the content… but if something went terribly wrong during folder creation… I could try except and catch a failure and return that failure to handle appropriately…

Basically I was really hoping for clean organization of separation of concerns.

Hope the example helped. I tried to make it simple.

0 Likes

#15

You can just define and import that functions to reuse them.

from .history_manager import history_mgr_create_datastore

# ...

def content_mgr_create_my_file():
    # ...
    result = history_mgr_create_datastore()
    # ...

class ContentMgrCreateMyFile(sublime_plugin.ApplicationCommand):
    def run(self):
        content_mgr_create_my_file()

commands are not made to communicate between python functions, but to execute user actions. I don’t think json-return values are a bad idea, but they are not necessary or useful for your example.

2 Likes

#16

i get what you are sayin’

I think basically I’ve “out grown” the way I was doing things… the scope of what I’ve been doing has been getting larger and larger and I need to reassess/refactor… figure out a framework instead of just going to town with my commands. lol

Thanks everyone.

0 Likes