Search code examples
variablesvisual-studio-codeduplicatestextmatevscode-snippets

Reduce duplications (save complicated transforms for later use) in VScode snippets


Is there a way to create custom variables inside a VScode snippet? I have these kind of snippets where I create a singleton, based on the name of a file and a folder.

Here's the snippet:

 "Service": {
   "prefix": "singletonByPath",
   "body": [
     "class ${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/upcase}$2/g}${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g} {",
     "  $0",
     "}",
     "",
     "export const ${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/downcase}$2/g}${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g} = new ${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/upcase}$2/g}${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g}();",
     ""
   ],
   "description": "Create an exported singleton instance and a class based on the filename and path"
 },

So, when the snippet is triggered in a path like: '..../customers/service.ts' You will have this result:

class CustomersService {
  
}

export const customersService = new CustomersService();

The problem is that I have duplications of long hard to read regexes, and I would like to extract them to variables (or mirrors without tab stops).

I would even prefer having these variables in a "snippet-global location" so that I can use them in multiple snippets.

Is it possible to somehow reduce these duplications?


Solution

  • There are a couple of things you can do to simplify your snippet. There is no built-in way to save "variables" of pre-defined snippet parts.

    Here though is a simplification of your code:

    "Service": {
      "prefix": "singletonByPath",
      "body": [
        // "class ${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/upcase}$2/g}${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g} {",
    
        "class ${1:${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/upcase}$2/g}}${2:${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g}} {",
                --                                                           --
    
        "  $0",
        "}",
        "",
        // "export const ${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/downcase}$2/g}${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g} = new ${TM_DIRECTORY/.*[^\\w]([a-z])(\\w+)$/${1:/upcase}$2/g}${TM_FILENAME_BASE/([a-z])(\\w+)/${1:/upcase}$2/g}();",
    
        "export const ${1/(\\w+)/${1:/downcase}/}$2 = new $1$2();",
    
        ""
      ],
      "description": "Create an exported singleton instance and a class based on the filename and path"
    }
    

    Note the use of $1:${TM_DIRECTORY...} and likewise ${2:${TM_FILENAME_BASE...}

    This effectively sets $1 to the result of the TM_DIRECTORY transform and $2 to the result of the TM_FILENAME_BASE transform and those "variables" can be used elsewhere in the snippet by just referring to $1 and $2.

    Those "variables" can even be transformed themselves as in the ${1/(\\w+)/${1:/downcase}/} transform in the last line.

    The last line of your snippet then becomes simply:

    "export const ${1/(\\w+)/${1:/downcase}/}$2 = new $1$2();",

    You will have to tab a couple of times because those "variables" are now tabstops, and the last transform won't be completed until you do tabstop past it, but that is a small price to pay for such a simplification.


    There are other simplifications to your snippet that aren't "variable-related":

      "body": [
        "class ${1:${TM_DIRECTORY/.*[\\/\\\\](.*)/${1:/capitalize}/}}${2:${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}} {",
        "  $0",
        "}",
        "",
        "export const ${1/(\\w+)/${1:/downcase}/g}$2 = new $1$2();",
        ""
      ],
    

    You can use the capitalize transform. Also note that this last body works for Windows and linux path separators.

    simplify snippet demo