Search code examples
htmlvisual-studio-codecode-snippets

VS Code : variables in custom snippet


How do I create a custom snippet that will automatically enter a variable's value that I type into its prefix?

I want a snippet that will create a html start-end tag comment block. For example if I type /se hello I want the result to be

<!-- $var start-->

<!-- $var end-->

Where $var is replaced with "hello". Thank you for reading!


Solution

  • As the VSCode snippet docs says, it uses TextMate to power its snippets. TextMate uses variables of the form $name and ${name:default}, and luckily supplies $TM_CURRENT_WORD which may be sufficient for your needs. However there is no built in variable to get multiple arguments directly after the snippet name i.e. $arg1 and $arg2 as variables. Thought you could do a similar effect with interpolated shell code, but unfortunately:

    The snippet syntax follows the TextMate snippet syntax with the exceptions of 'interpolated shell code' and the use of \u; both are not supported.

    Emphasis mine

    However for this simple example, the following indexed variable example is probably sufficient.

    <!-- $1 start-->
        $0
    <!-- $1 end-->
    

    $i gives you a value to fill in, you can go between each one with tabbing. The $0 is where the cursor goes at the end(the end of the snippet by default). Optionally you can do something like:

    <!-- ${1: default text} start-->
        $0
    <!-- $1 end-->
    

    and it'll start looking like:

    <!-- default text start-->
    
    <!-- default text end-->
    

    with both of the defaults selected to edit.

    This all put together would look like this together in the snippets.json file:

    {
        "se": {
            "scope": "html",
            "prefix": "se",
            "body": [
                "<!-- ${1:default text} start-->",
                "\t$0",
                "<!--$1 end-->"
            ]
        }
    }
    

    As @Mark pointed out, if you want it to work for more than just HTML you can use $BLOCK_COMMENT_START and $BLOCK_COMMENT_END which will vary for each language. The snippet would then look like this:

    {
        "se": {
            // Leaving scope off will make it a global snippet
            "prefix": "se",
            "body": [
                "$BLOCK_COMMENT_START ${1:default text} start $BLOCK_COMMENT_END",
                "\t$0",
                "$BLOCK_COMMENT_START$1 end $BLOCK_COMMENT_END"
            ]
        }
    }