Single-Shot Binding

I had a purpose today to have a binding happen once and I realized that others might have this sort of use case. I figured I’d share this in hopes that it is useful to you one day (or if you want to improve upon it, feel free to post what you’ve done).

Theory of Operation

The idea behind this code is that we are generating an event table that we push and then later clean up. The callback uses the return value to determine if it should be cleaned up (in my use case, I want to keep it around if the event contents contains certain values).

Once the callback returns True, the event table will be torn down so the event is no longer handled.

Code

Note that this is a method on a MinorMode. Defining the event table is part of the mode’s definition hence this lives with a mode.

def singleShotBind(self, eventName, callback):
    """Create a bind that will automatically clean itself up after the first successful run.

    eventName: The event to bind to.
    callback: A runnable that takes the event object.  Returning True from this function will
              cause the cleanup to occur.  Returning False will keep the binding around.​
              If an unhandled exception occurs in the callback, the binding will be torn down.
    """

    tableName = "singleshot-%s-%s" % (eventName, str(time.time()))

    def runner(event):
        cleanupTable = True
        try:
            cleanupTable = callback(event)
        finally:
            if cleanupTable:
                runtime.eval("""popEventTable("%s");""" % tableName, ["commands"])

    self.defineEventTable(tableName,
        [(eventName, runner, "")]
    )
    commands.pushEventTable(tableName)
5 Likes