Sublime Forum

Run command on space

#1

I want to make a command that is to be executed every time the user adds one of a set of characters (tab, space, enter and a few others). I’ve tried looking into the API reference, under the EventListener class, but the on_modified event does not seem to let me know which modifications were made. I also tried to bind my command to the “space” key, but apparently “space” is not a valid key. I suspect that it is because it actually changes the buffer.

Can someone shed a light on whether this is possible and how to do it?   [I’ve been trying to find a way to do this for the past hour, but my google-fu and searching this forum led to no useful results.]

1 Like

#2

It’s possible in a couple of different ways.

space is indeed a valid key, but it doesn’t work to use it without a modifier. However, you can create a key binding with a literal space in it to get a similar effect:

    {
        "keys": [" "],
        "command": "do_something_space"
    },
import sublime_plugin

class DoSomethingSpaceCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        if not self.view.settings().get("is_widget", False):
            print("Space was pressed in DoSomethingSpace")

        self.view.run_command("insert", {"characters": " "})

An important takeaway here is that if you don’t explicitly insert a space in response to the command, you lose the ability to enter spaces in any files (which among other things can get in the way of you fixing the problem ;)).

Also, the command will trigger everywhere that space is pressed, which includes when you’re entering text in a quick panel, in the console input area, and so on. In these cases the views have a setting called is_widget set to distinguish them, so in this example the indication that space was pressed only happens not within a widget.

Since you mention that you plan to do this for several characters, another alternative (assuming that what you’re doing in response is generally similar and could be handled by a single command) is something like this:

    {
        "keys": ["<character>"],
        "command": "do_something_character"
    }
import sublime_plugin

class DoSomethingCharacterCommand(sublime_plugin.TextCommand):
    def run(self, edit, character):
        if not self.view.settings().get("is_widget", False):
            if character == " ":
                print("Space pressed in DoSomethingCharacter!")

        self.view.run_command("insert", {"characters": character})

The special key binding <character> triggers for any entered character, and the command that you define will be passed character argument to tell you what the character was.

The same caveats apply here with regards to the event triggering for more than just file views and that you need to handle the event by inserting the character that was pressed.

7 Likes

How to get typed key name?
#3

Thanks for the quick reply! :slight_smile:
As for the command running everywhere, I was thinking about associating a context to the key binding, something akin to:

    {
        "keys": ["<character>"],
        "command": "MY-COMMAND",
        "context": [
            {
                "key": "selector",
                "operator": "equal",
                "operand": "MY-SCOPE",
                "match_all": false,
            }
        ],
    }

It is my understanding that widgets use the text.plain scope, so as long as I don’t want to use this in plain text, I should be fine, right?

0 Likes

#4

Another problem I’m having here is that each inserted character is treated as a new edition. Nornally, if I type a word quickly enough and then press “ctrl+z” to undo, the whole word is erased. With this plugin active, each character is a new modification to the buffer and is undone individually, which is kind of a pain. Is there any way to circumvent this issue?

0 Likes

#5

What are you trying to do exactly? Perhaps there is a more straightforward way to do things.

0 Likes

#6

I want to create a plugin that can automatically correct some mistakes that I usually make, such as double capitalization, typos, etc. For example, I want to be able to write:

"ONce upon a time, a litle girl  went into my house"

and let sublime automatically correct it to

"Once upon a time, a little girl went into my house"

I want corrections that are simple substitutions (e.g. litle → little) and also some other rules: ignore duplicate spaces, remove double duplication, etc.

My idea would be to detect a new word by finding when the user presses the space bar, enter key, tabulation and some punctuation characters, see what word is written, pass it through the function that corrects it, and if necessary replace the current word with the correct one.

0 Likes

#7

Do you already have a function that can correct wrong words? Because then you could use SublimeLinter.

0 Likes

#8

You could probably use an on_text_command hook and perform an action whenever one of your word separator characters (notably a space) is inserted. You’ll have the view’s selection then and know what will be inserted.

0 Likes