Sublime Text 3 Build System: Backslash in a JSON

Omer Lubin

I want to use MinGW to compile a c program through Sublime Text. The command I need to run is:

gcc "${file}" -o "${file_path}\${file_base_name}.exe"

(Note the \ in the file path)

I need to write this string as a value in a JSON file. So, I tried to convert the problematic characters:

" => \"
\ => \\
...

There is no problem with the " character, it converts correctly - the backslash behaves weirdly. Here's the command that runs when I try to compile through Sublime:

gcc C:\Users\omer\Desktop${file_base_name}.c -o C:\Users\omer\Desktop${file_base_name}.exe

Is the conversion \ => \\ incorrect? What am I missing?

Edit: This is the full build system JSON.

{
"shell_cmd": "gcc \"${file}\" -o \"${file_path}\\${file_base_name}.exe\"",
"file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
"working_dir": "${file_path}",
"selector": "source.c",

"variants":
[
    {
        "name": "Run",
        "shell_cmd": "gcc \"${file}\" -o \"${file_path}\\${file_base_name}.exe\" && \"${file_path}\\${file_base_name}.exe\""
    }
]

}

OdatNurd

The short answer to your question is that you have some but not all of the required escaping going on here because there are both JSON escape characters and Sublime escape characters that you need to contend with, so as a result you're being caught unaware by a feature of Sublime.

I'm guessing you're on Windows since you're using \ as the path separator; Windows also allows / to be used as a path separator as well, so you can resolve your problem by replacing all of the \\ sequences with / instead (which may also look a bit cleaner overall).

The longer version of the answer which explains what's going on (and another way to solve the problem which is more visually messy) is below.


You are indeed correct that in JSON the \ character is special and introduces an escape sequence, so in order to have a literal \ character in a JSON string you need to write it as \\ instead.

However, Sublime also supports its own \ escape sequences as well, so there are cases where you need to use more escape characters than you might expect in your input file in order to get the result that you want.

In sublime-build files, Sublime expands any word that is prefixed with $ as a variable and replaces the entire variable with it's value (e.g. $file is replaced with the name of the current file). This also holds true for any sequence that is prefixed with a $, such as $test; in such a case the value of the variable is the empty string, so the whole variable is replaced with the empty string.

In addition, Sublime also handles the \ character internally as meaning "the next character is not special". So if you needed to have a $ character somewhere in your build command (maybe as a command line argument or such), you would need to quote it as \$ to tell Sublime not to treat it specially.

This is what you're seeing in your output above; The command executed contains the text ${file_base_name} because the way the string is seen by Sublime is telling it that it should not expand the variable.

The reason is perhaps best illustrated with some examples:

"shell_cmd": "echo ${file}"

This would display the name of the current file in the build output

"shell_cmd": "echo \${file}

Here if you try to run the build, nothing happens but the status bar will say No Build System. The idea was to tell Sublime not to expand the variable, but actually this is invalid JSON because when processed as JSON data, \$ is not a valid escape sequence. Thus the file load fails and there is no build system to run.

"shell_cmd": "echo \\${file}

When this is read as JSON, the \\ is replaced with \, leaving the string as Sublime sees it as \${file}. When it executes the build, Sublime itself replaces \$ with $, and the output in the build output panel is literally ${file} (i.e. there is no expansion).

This last example shows what's happening to you in your case, the \\ is telling the JSON loader that this should be a a single \ character and that's what happens. However Sublime then follows that up by treating \$ as special.

In order to expand something that has the file path and base name with a literal \ in between them you need to do something like this:

"shell_cmd": "echo ${file_path}\\\\${file_base_name}"

The sequence of events goes like this:

  1. The JSON loader loads the string and converts escape sequences, so each \\ is converted into a single \, leaving the string as Sublime sees it as echo "${file_path}\\${file_base_name}".

  2. When Sublime is executing the build, it sees \\ as a single \, leaving the full processed string as echo "${file_path}\${file_base_name}"

  3. The variables are expanded, and you end up with C:\Users\Me\Desktop\MyFile (or what have you), which is what you wanted.

So one way to solve your problem would be to double up on all of the \\ sequences to make them \\\\ instead; then the JSON processor will convert it to what you have currently when it loads the file and Sublime will handle it like you expect.

That's pretty hairy overall, but it turns out that on Windows you can use / as a path separator and it's handled internally the same as anything else, so a quicker solution is to replace \\ with / instead, which should net you the same working solution without being quite as confusing to look at.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related