Sublime Forum

Concatenating String Arguments in Key Bindings

#1

First post here. Hey all.

I’m trying to write a key binding to execute an external program, but I need to change the file extension on my file base name argument, and I’m at a loss for how to do that.

Here’s what I mean:

[
{ “keys”: [“ctrl+shift+x”], “command”: “exec”, “args”: { “cmd”: [“executable”, “$file_base_name”]} }
]
This runs the correct program, but the file is missing the extension. The compiled project has a different extension than the working file, so I must use the base name + a different extension:

[
{ “keys”: [“ctrl+shift+x”], “command”: “exec”, “args”: { “cmd”: [“executable”, “$file_base_name”+".extension"]} }
]

This does not work, clearly. I have tried a number of things and I’m not sure how I can get this to work.

Any help would be appreciated!
Thanks in advance.

0 Likes

#2

you could try ${file_base_name}.extension:

[
    { "keys": ["ctrl+shift+x"], "command": "exec", "args": { "cmd": ["executable", "${file_base_name}.extension"]} }
]
1 Like

#3

unfortunately that doesn’t work.

I get an error:
“Cannot open file: ${file_base_name}.extension”

0 Likes

#4

As I learned recently, these variables don’t expand outside of build systems. In fact I believe that the documentation I referenced there has been amended accordingly.

In the case of that particular post I made my own simple command that did what I wanted. Something similar could work for you as well:

import sublime_plugin

# Make an executable of the current file based on an extension and then 
# execute it
class RunCurrentFileCommand (sublime_plugin.WindowCommand):
    def run(self, extension):
        # Get vars and make sure that we have all of the ones we need
        vars = self.window.extract_variables ()
        if "file_base_name" in vars and "file_path" in vars:

            # The executable is the current file with a new extension
            executable = vars['file_base_name'] + extension

            # Make the working directory be the path of the current file
            working_dir = vars['file_path']

            self.window.run_command ("exec", {
                "cmd": [executable],
                 "working_dir": working_dir
                })
        else:
            sublime.status_message ("Error: No file")

Save this in (for example) run_current_file.py in your User Package (Preferences > Browse Packages) and the command will become available using a binding similar to:

{ 
    "keys": ["ctrl+shift+x"], 
    "command": "run_current_file" , 
    "args": {"extension": ".exe"}
}

As written you need to specify the extension to append to the current filename. If you’re not going for cross platform action this could be modified to not require the extension argument and just use a hard coded extension.

As a variation, you might want to use the variables that give you the full path to the file less it’s extension instead of setting the working directory to be where the file is, if you need the working directory to be some other path.

Note that the name of the command is derived from the name of the class in the Python code (RunCurrentFileCommand) and not from the name of the file you save the code in, if you want to modify that as well.

1 Like

#5

Thank you very much. I was able to get it working thanks to your python code.

I just had to modify “cmd” in self.window.run_command like so:
“cmd”: [“programname”, executable]

The executable’s base name is the same as the source code file, but changing the source file’s extension makes it refer to the compiled binary. The binary must be executed by an external program (hardware emulator), which I refer to as “programname” above.

0 Likes

#6

Glad it helped! Ironically, that situation (in my case, language interpreter) is what I originally did too, but I took that bit out when I accidentally glossed over that aspect of your original question. :blush:

0 Likes