Sublime Forum

Close show_input_panel panel in on_change callback

#1

Is there any way to close the input panel that gets opened up at the bottom of the screen programmatically? The user can close it either via the enter or esc keys. I’d like to be able to close/hide it in the on_change callback depending on what the user has entered without them having to hit the enter key.

To get more specific about what I’m trying to do:

I’ve got a plugin called EasyMotion (https://github.com/tednaleid/sublime-EasyMotion, renamed from SublimeJump because PackageControl strongly suggests that plugins not be named starting with “Sublime”).

To use it, the user presses the shortcut followed by a visible character that they’d like to move the cursor to. I then change all of the visible instances of that character to one of a-z0-9A-Z and open up the show_input_panel for them to pick which one they want to go to.

Here is the github issue that describes what I want as well as some other people saying that it’s a feature they’d like: https://github.com/tednaleid/sublime-EasyMotion/issues/5

Then they enter the letter of the instance they want to move the cursor to and have to hit enter. I’d rather they not have to hit “enter” as it’s redundant. I never want more than one character. There’s no way for me to stop the user from typing more than one character in the input box.

If there are alternative ways that I can gather a single character of input from the user when the plugin is active, I’d be interested in knowing that. From what I can tell, using show_overlay won’t work for me as it seems more specialized and using show_quick_panel isn’t good because it occludes a large part of the screen that has a good chance of containing the character the user wants to jump to.

Ideally, I’d actually be able to capture a character of input without any sort of UI at all when the plugin is active. Similar to how vintage mode does things, but that looks like I’d need to implement an entire mode for that to work (maybe that’s not as hard as I’m thinking it is…).

0 Likes

#2

Since “escape” is able to close the panel you could’ve looked into the keybindings and see this:

	{ "keys": "escape"], "command": "hide_panel", "args": {"cancel": true},
		"context":
		
			{ "key": "panel_visible", "operator": "equal", "operand": true }
		]
	},

Here is my example code (again, using sublime_lib):

class TestCommandCommand(sublime_lib.WindowAndTextCommand):
    def run(self, param=None):
        print(self._window_command)
        self.window.show_input_panel("Enter something", "test", self.on_done, self.on_change, None)

    def on_done(self, result):
        print("result", result)

    def on_change(self, text):
        print("current text", text)
        if text.endswith("x"):
            self.window.run_command("hide_panel", {"cancel": True})
0 Likes

#3

Ah, should have thought of looking at the keybindings for escape, thanks for the pointer as well as the example code. I didn’t fully understand the context stuff previously. Very helpful!

I’d also be interested to know if there’s a way to accept input without showing the input panel (any simple mode examples out there?). All of the ones that I know about end up covering up at least a little of the visible screen and might end up occluding a jump target.

0 Likes

#4

I was able to get this working with the suggestion from FichteFoll and close out the issue I was working on (https://github.com/tednaleid/sublime-EasyMotion/issues/5).

One caveat to this behavior is that calling “hide_panel” this way seems to always call the on_cancel method you’ve given to show_input_panel (even if you pass in “False” to the cancel argument). It also seems to run asynchronously in another thread so doing something in on_change, and then calling hide_panel will cause the on_cancel method to run afterwards. For me this was causing my changes to get overwritten because of what I was doing in the on_cancel, so I had to save off information in the on_change and then react to it if it’s available in the on_cancel flow. It worked, but was a little less clean than I was hoping for in the code.

The user experience is much better though, which is the most important thing :smile:. Thanks again for the help!

0 Likes

#5

I am wondering if there is a way to get more than just text.
I want to implement a history stack on my little search bar using the up and down arrows.

Is there a way in the onChange method to detect other input other than text changes? I get one change notification when the user presses the up arrow but I can’t figure out how I could detect that the user pressed up or down?
Any guidance would be helpful.

Ian

0 Likes

#6

Maybe you want to take a look at sublime.show_quick_panel? The ST3 version also supports a selected_index parameter which you can set to be the last - or just start at the top.

0 Likes

#7

Ian - did you get anything working for input panel history? I too want to implement this feature! I was hoping there was something built in like that used by Find (Cmd-f).

0 Likes