-->

SublimeText: Run the exec with current file as arg

2019-08-30 09:10发布

问题:

I have created a tab context menu to decode some data. Now, I need to take current file(Tab context menu) as 1st argument to decode this file using exec.

Currently I'm using hardcoded path. How can I pass the name of the current file instead?

[
  { "command": "exec", "args": {"cmd": "P:\\decoder.exe P:\\in.txt"}, "caption": "DecodeJ" },
]

回答1:

Generally speaking there's no way to execute a command and provide to it the name of the currently active file without using some sort of plugin code to convey that information to the command.

As defined in key bindings, menus and so on you need to provide arguments to commands that are predefined, which means that something in the command needs to be able to know based on the argument that you provided that you meant the current file, or the command needs to implicitly just work on the current file without being told to do so.

The most expedient way to do something like this would be to create a sublime-build file that runs the command that you want to run, and then use the $file variable in the cmd entry to represent the current file, followed by binding your menu command to the build command instead so that it triggers a build.

The downsides here are that this can get in the way of using builds for other uses; the build command only executes the currently selected build so it requires that you first set the build system before you start using the menu, or that you set the build system to Automatic so that Sublime will execute the correct build at the correct time. Either way may or may not get in the way of your ability to use builds for other purposes without having to take manual steps in the middle.

An alternative to this would be to create a plugin that implements a version of the exec command that will expand variables itself instead of requiring that the build command expand them for it.

An example of such a plugin would be the following (see this video if you're unfamiliar with using custom plugins):

import sublime
import sublime_plugin

from Default.exec import ExecCommand


class MenuExecCommand(ExecCommand):
    def run(self, **kwargs):
        variables = self.window.extract_variables()

        for key in ("cmd", "shell_cmd", "working_dir"):
            if key in kwargs:
                kwargs[key] =  sublime.expand_variables(kwargs[key], variables)

        super().run(**kwargs)

This implements a command named menu_exec that does exactly what exec would do when invoked, except that variables in the cmd, shell_cmd and working_dir arguments will be expanded the same way as they are in sublime-build files.

With that plugin your sublime-menu entry would swap exec for menu_exec and use $file to represent the current file:

[
    { 
        "caption": "DecodeJ",
        "command": "menu_exec", 
        "args": {
            "cmd": "P:\\decoder.exe $file"
        }
    },
]

Note: If your file names contain spaces, you should wrap the variable in double quotes; "P:\\decoder.exe \"$file\"" for example; otherwise the external command might not get the right filename.