This is an issue that came up on IRC and I wasn’t sure if there was a solution or not. Basically, we needed a way to bind multiple commands to be run in a given order to a single keyboard shortcut. Ordinarily I’d say to just use macros, but as it turns out, you can’t use a macro to show the find panel or anything like that, so this is the solution I came up with: a command that runs multiple commands in whichever context the command needs to be run in.
The problem we had was emulating something like Emacs’s Ctrl+W, which apparently does roughly the same thing as hitting Cmd+D and Cmd+F, putting the selected text into the find panel. I don’t know that there’s any good, generic way to handle getting the selected text into the find panel other than simple modifying your preferences, so this doesn’t address that. So, macros won’t do it and as far as I know a key binding is limited to a single command. Clearly the solution is a command that runs multiple commands (note: this is not actually clear and is probably insane). Basically, we wanted to be able to do this:
{ "keys": "ctrl+w"],
"command": "run_multiple_commands",
"args": {
"commands":
{"command": "find_under_expand", "context": "window"},
{"command": "slurp_find_string", "context": "window"},
{"command": "show_panel", "args": {"panel": "find"}, "context": "window"}
]}}
]
(Edit: Updated binding to add slurp_find_string which was indirectly pointed out by adzenith. That should make find_selected_text unneeded.)
But you can’t do this normally. So, what do you do? Well, you do what I just pasted up there, but you also install this plugin down here:
# run_multiple_commands.py
import sublime, sublime_plugin
# Takes an array of commands (same as those you'd provide to a key binding) with
# an optional context (defaults to view commands) & runs each command in order.
# Valid contexts are 'text', 'window', and 'app' for running a TextCommand,
# WindowCommands, or ApplicationCommand respectively.
class RunMultipleCommandsCommand(sublime_plugin.TextCommand):
def exec_command(self, command):
if not 'command' in command:
raise Exception('No command name provided.')
args = None
if 'args' in command:
args = command'args']
# default context is the view since it's easiest to get the other contexts
# from the view
context = self.view
if 'context' in command:
context_name = command'context']
if context_name == 'window':
context = context.window()
elif context_name == 'app':
context = sublime
elif context_name == 'text':
pass
else:
raise Exception('Invalid command context "'+context_name+'".')
# skip args if not needed
if args is None:
context.run_command(command'command'])
else:
context.run_command(command'command'], args)
def run(self, edit, commands = None):
if commands is None:
return # not an error
for command in commands:
self.exec_command(command)
There you have it, a multiple-command-running command. It has a special context option for commands so you can run application and window commands as well (which is where I suspect macros are failing — they may only work with TextCommands, but I don’t know). See the comment block above the method for more on that. Aside from that option, you just do the same thing you would if you were making a normal binding, only the arguments to the command is ‘commands’, an array of commands. Really, the example is probably easier to understand than any explanation I’ll provide, so just look at that until it makes sense.
Also, in case you’re wondering why it’s “run_multiple_commands” and not just “run_commands,” that’s because I figure 1) it’s easier to tell it apart from “run_command” and 2) “run_commands” may later be added (I don’t know, but it’s possible). I wouldn’t want to have things blow up because an update conflicted with my command. As such, it’s a slightly longer and noticeable name.
There’s probably no reason to make this a package and throw it on Package Control when it’s mainly a utility thing for people to make use of rather than functionality that’s automatically available to you (such as you get with, say, a language package). Just plunk it in your User directory and it should be good enough. That’s it, now you can go on your way.