As you have correctly surmised, Sublime does indeed not wait for you to enter the text. For that to happen, your command would have to pause while the user is entering text. Since only one command can run at a time and things like moving the cursor or entering text are handled by running commands, if your command never stopped running Sublime would be effectively hung.
Instead, show_input_panel
returns immediately after showing the panel, and while other things are happening the user can enter text. When they press enter and the input is complete, the on_done
callback gets called to tell you what the text was.
I would guess that your code that doesn’t work looks something like this:
import sublime
import sublime_plugin
class ExampleOneCommand(sublime_plugin.TextCommand):
def run(self, edit):
def on_done(input_string):
self.text = input_string
window = self.view.window()
window.show_input_panel("Text to Insert:", "Hello, World!",
on_done, None, None)
self.view.insert(edit, 0, self.text)
This compiles, and when you run the command you get asked to enter text, but when you press enter nothing happens. If you look in the console, you see this:
AttributeError: 'ExampleOneCommand' object has no attribute 'text'
Why does that happen? What it’s trying to do is:
- Make a call to ask the user for input
- Use the input the user entered to do something
- Get notified that the user entered text
Or if you will, it’s trying to use the text before the user has even managed to type anything. If you were to run the same command again, it would immediately insert the text you entered the first time while still prompting you for text, because it’s using the value that it knows about from last time you ran it.
The proper way to do this is to re-order the steps that it’s trying to take. In this example, that would be:
- Make a call to ask the user for input
- Get notified that the user entered text
- Use the input the user entered to do something
By way of an example, here’s the example code from above rewritten to follow the steps in this order:
import sublime
import sublime_plugin
class ExampleTwoCommand(sublime_plugin.TextCommand):
def run(self, edit):
def on_done(input_string):
self.view.run_command("move_to", {"to": "bof"})
self.view.run_command("insert", {"characters": input_string})
def on_change(input_string):
print("Input changed: %s" % input_string)
def on_cancel():
print("User cancelled the input")
window = self.view.window()
window.show_input_panel("Text to Insert:", "Hello, World!",
on_done, on_change, on_cancel)
Now when you run the command, it uses show_input_panel
to ask for input, and leaves. As you’re entering text, on_change
keeps getting called, which is printed to the console to tell you what the text has been changed to. If you press Esc, on_cancel
gets called and the console reports that the you canceled the input.
If you press Enter, on_done
gets called, and then at this point it gets the text you typed entered and can do something with it (here insert it at the start of the current file).
Basically whatever it is you want the input for, you need to alter the flow of your code. For example you might try putting everything that’s supposed to happen after the user pressed enter into another function, and then call it from on_done
so it doesn’t happen until the text input is complete.