Sublime Forum

Plugin: show_input_panel in a text command for interactivity to edit the view



I’m developing a plugin with interactivity in mind. In particular, the same kind of interactivity you see in the search & replace panel.

The idea of my plugin is have a text command starting an input_panel, and the content of the view gets updated automatically with each key stroke. This lets the user do something with it until it’s done.

Here is the code I have so far (a simpler version, but it’s the idea):

class MyCommand(sublime_plugin.TextCommand):
  def run(self, edit):
    self.edit = edit
    size = self.view.size()
    region = sublime.Region(0, size)
    self.original_text = self.view.substr(region)

    self.view.window().show_input_panel('query', 'hello', self.on_done, self.on_change, self.on_cancel)

  def on_done(self, query):

  def on_change(self, query):
    # show the query in the view each time the user types a character
    size = self.view.size()
    selection = sublime.Region(0, size)
    self.view.replace(self.edit, selection, query)

  def on_cancel(self):
    # Revert view with original text
    size = self.view.size()
    selection = sublime.Region(0, size)
    self.view.replace(self.edit, selection, self.original_text)

This is fine: the current view text gets saved, and the input panel is shown, and ‘hello’ is shown in the view, but typing in the input panel does nothing.

Checking the console, I can see that:

ValueError: Edit objects may not be used after the TextCommand's run method has returned

So, is there a way to not return from the run command until on_done has been called?

I tried a time.sleep() with a class variable set to True when it’s done/cancelled, but that just blocks the entire editor.

If that’s not possible, how should I be doing that then?



No; as you’ve noticed the UI hangs and nothing else is allowed to happen while the command runs, since it would be a disaster if anything was allowed to potentially modify the content of files while a command was also potentially modifying the same thing.

Similarly, the edit object is used to bundle all changes made during the execution of a command (including commands executed by this one) in order to track them for doing an Undo, which is why you can’t keep the object around and use it later.

To do something like this you need to decompose your design a little bit by having the code in on_change/on_cancel use self.view.run_command() to execute a command whose job it is to make the modification for you.