It lets you write a quick sequence of commands/scripts to automate VS Code tasks.
- A run command that opens up a terminal, starts an SSH connection, and then runs commands on the SSH server
 - A new-project command that goes to where ever you typically save projects, uses the GUI to ask for the name of the project, creates the folder, creates a .gitignore with your preferences, runs an init command, and then opens the folder in your current VS Code window.
 - A command that opens a project folder, pulls the latest changes, opens several files in that folder, and then displays the recent changes in those files.
 - A folder-specific start command, that pulls the latest changes, installs dependences, formats files, and then opens the debugger with a specific file.
 
- Find the name of commands you want to run. You can do this by going to the VS Code keybindings.json
(go to gear-icon -> keybindings, then press the βͺπ in the top right corner)
All of the 
"command":'s (ex:"command": "workbench.action.terminal.new") can be copied and pasted into the macro - Open up your VS Code settings.json and create a new section like this: (go to gear-icon -> settings, then press the {}'s in the top right corner)
 
- To run the macro open the command pallet (cmd+shift+P or ctrl+shift+P) and type 
run macrothen pick which one you want to run. - To create a keybinding to the macro, simply open the Keyboard Shortcuts (Gear-icon -> Keyboard Shortcuts) and start to type "macros". All of the macros have a "macros." prefix.
 
Every element in the macro array should be one of these:
- string = simple command
 - command with args is an object like this 
{"command": "COMMAND_HERE", "args":/*stuff*/} - command + javascript using javascript-injections like this:  
{ "injections": [], "command": "COMMAND_HERE", "args":/*stuff*/} - run javascript likes this: 
{ "javascript": [] } - call a hidden console (childProcess) like this 
{ "injections": [], "hiddenConsole": [] } 
NOTE:
- The javascript runs inside of an async function, meaning you can use the 
awaitkeyword - Javascript has access to:
 
- the 
vscodeobject: (vscode.commands,vscode.env,vscode.workspace,vscode.tasks, etc.) is documented here: https://code.visualstudio.com/api/ - the 
windowobject, a shortcut tovscode.window. - the 
pathobject (from node path) - the 
fsobject (from node fs) - the 
macroToolsobject (helpers from this library) 
- The 
"withResultOf"argument can be a single value (3.14159 || null) or multiple statements (await window.showInputBox(); console.log("hi")). 
If you're writing JS macros:
- Use the "Macros: JS to JSON" command to make it easier to write macros (select JS code, then call the command)
 - Use the "Macros: JSON to JS" command to make it easier to read/edit macros
 
See also Level up your Coding with Macros
"macros": {
    "terminalExample1": [
        // a simple command to open a new terminal
        "workbench.action.terminal.new",
        // a command with arguments, that sends text to the terminal
        {
            "command": "workbench.action.terminal.sendSequence", 
            // the "text" arg was decided by VS Code (not me)
            "args": { "text": "echo hello\n" }
        },
    ],
    "terminalExample2" : [
        // Run some javascript
        {
            "javascript": [
                // docs for showInputBox: https://vscode-api.js.org/interfaces/vscode.InputBoxOptions.html
                "sharedMacroInfo.personName = await window.showInputBox({ title: `Whats your name?` })",
            ]
        },
        // a simple command to open a new terminal
        "workbench.action.terminal.new",
        // combine javascript and command
        {
            "injections" : [
                { "replace": "$personName", "withResultOf": "macroTools.escapeShellArg(sharedMacroInfo.personName)" },
                { "replace": "$selectedText", "withResultOf": "macroTools.escapeShellArg(window.activeTextEditor.document.getText(window.activeTextEditor.selections[0]))" },
                { "replace": "$currentFile", "withResultOf": "macroTools.escapeShellArg(window.activeTextEditor.document.uri.fsPath)" },
                { "replace": "$currentFolder", "withResultOf": "macroTools.escapeShellArg(vscode.workspace.rootPath)" },
            ],
            "command": "workbench.action.terminal.sendSequence",
            "args": { "text": "echo hi $personName\necho 'you selected' $selectedText\necho 'the current file is: '$currentFile\necho the current folder is: $currentFolder\n" }
        },
    ],
    "userInputExample1" : [
        // javascript execution (see https://code.visualstudio.com/api/extension-capabilities/common-capabilities)
        {
            // this has access to the `vscode` object, the `window` object and the `path` object (from node path)
            // the javascript is also run inside of an async function, meaning you can use the `await` keyword
            "javascript": "window.showInformationMessage(`You entered: ${await window.showInputBox()}`)"
        },
    ],
    "userInputExample2" : [
        {
            "javascript": [
                "let response = await window.showInputBox()",
                "let selectedText = window.activeTextEditor.document.getText(window.activeTextEditor.selections[0])",
                "await window.showInformationMessage(`You entered: ${response}`)",
            ]
        },
    ],
    "fileInputExample1" : [
        {
            "javascript": [
                "let cursorLineNumbers = window.activeTextEditor.selections.map(each=>each.start.line)",
                "let cursorCharNumbers = window.activeTextEditor.selections.map(each=>each.start.character)",
                "let textContent = window.activeTextEditor.document.lineAt(cursorLineNumbers[0]).text",
            ]
        },
    ],
    "userInputExample3" : [
        {
            "javascriptPath": "~/vs_code_stuff/macros/example3.js",
            // if you open up that file^  it could contain:
            //     const { window } = require("vscode")
            //     const vscode = require("vscode")
            //     const path = require("path")
            //     const fs = require("fs")
            // 
            //     await window.showInformationMessage(`Howdy!`)
            
            // NOTE: you cant use "import" or "export" because this script is evaled! not imported
        },
    ],
    "userInputExample4" : [
        {
            "javascriptPath": "./macros/build.js",
            // this path will be relative to the current WORKSPACE
            // if there is no active workspace, it will tell you to activate one (e.g. error)
        },
    ],
    "sharedInfo1" : [
        {
            // use this varible to share data between macros, and within the same macro
            "javascript": "sharedMacroInfo.prevMessage = 'howdy'",
        },
        {
            "javascript": "window.showInformationMessage(sharedMacroInfo.prevMessage)",
        },
    ],
    "javascriptPlusTerminalExample" : [
        // run a hidden console command (runs in the background)
        {
            // NOTE: don't start a command in a hiddenConsole
            //       that doesn't finish! there's no good way 
            //       of killing/canceling it
            // 
            // this echo will never be seen
            "hiddenConsole": [
                "touch .gitignore",
                "echo hello"
            ]
        },
        // combine javascript and hidden console commands
        {
            "injections" : [
                { "replace": "$currentFolder", "withResultOf": "vscode.workspace.rootPath" },
            ],
            "hiddenConsole": [
               "cd \"$currentFolder\"", 
               "touch .gitignore"
            ]
        },
    ],
    "terminalWithBashFunctions" : [
        {
            "injections" : [
                { "replace": "$currentFolder", "withResultOf": "vscode.workspace.rootPath" }
            ],
            // I wanted to use aliases defined in my bash profile
            // here's a hacky way of doing that
            "hiddenConsole": [
                "bash <<HEREDOC",
                "    source ~/.bash_profile",
                "    cd \"$currentFolder\"",
                "    echo now I can use aliases",
                "HEREDOC",
            ]
        }
    ],
    "exampleOfCommonInjections" : [
        {
            "injections" : [
                { "replace": "$userInput",       "withResultOf": "await window.showInputBox()" },
                { "replace": "$currentFolder",   "withResultOf": "vscode.workspace.rootPath" },
                { "replace": "$currentFile",     "withResultOf": "window.activeTextEditor.document.uri.fsPath" },
                { "replace": "$currentFileName", "withResultOf": "path.basename(window.activeTextEditor.document.uri.fsPath)" },
                { "replace": "$currentFileNameNoExtension", "withResultOf": "path.basename(window.activeTextEditor.document.uri.fsPath).replace(/\\.[^/.]+$/, '')" },
                { "replace": "$currentFileDir", "withResultOf": "path.dirname(window.activeTextEditor.document.uri.fsPath)" },
            ],
            "hiddenConsole" : "echo $userInput"
        }
    ],
    "WriteToOutputExample": [
        {
            "javascript": [
                //create a new OUTPUT log, with name "MyLog"
                "const myOutput = window.createOutputChannel('MyLog'); ",   
    
                //write a message to OUTPUT log                              
                "await myOutput.appendLine('Lorem ipsum dolor sit amet, consectetur adipisci elit.'); ",  
                //show the OUTPUT log       
                "await myOutput.show(); ",                                                                   
            ],
        },
    ],
    "unMultiSelectLast": [
        // For when you Ctrl-Click to multiselect 10 times and on the eleventh get it wrong. 
        // Just press Ctrl-0 (or whatever key you assign) to unselect the eleventh, then carry on.
        // (See also, https://github.com/danseethaler/vscode-tab-through-selections, for more along this line.)
        {
            "javascript": [
                "const editor = window.activeTextEditor;",
                "const newSelections = editor.selections.slice(0, editor.selections.length - 1);",
                "editor.selections = newSelections;"
            ]
        }
    ],
    "transformToSnake": [
        // A multi-select friendly macro to convert from CamelCase to snake_case.
        // If any particular selection is empty (just a cursor), this will automatically expand it to the whole word first.
        // (Kudos to https://stackoverflow.com/users/398630/brainslugs83 for some pointers)
        {
            "javascript": [
                "let editor = window.activeTextEditor;",
                "expandWords();",
                "doTransform(0);",
                "function expandWords() { let sels = editor.selections; let i = sels.length-1;",
                "  while (i >=0) { let sel = sels[i];",
                "    if (sel.isEmpty) {r = editor.document.getWordRangeAtPosition(sel.start); sels[i] = new vscode.Selection(r.start, r.end);}",
                "    i--; }",
                "  editor.selections = sels;",
                "}",
                "function doTransform(i) { let sels = editor.selections;",
                "  if (i < 0 || i >= sels.length) { return; }",
                "  let sel = sels[i];",
                "  let word_matches = editor.document.getText(sel).matchAll(/([a-z]+|[A-Z][a-z]*|[^A-Za-z]+)/g);",
                "  let words = [];",
                "  for (const match of word_matches) {words.push(match[0].toLowerCase())};",
                "  editor.edit(eb => {eb.replace(sel, words.join('_'))}).then(x => { doTransform(i+1); });",
                "}"
            ]
        }
    ],
    "transformToCamel": [
        // Same as transformToSnake, but vice versa
        {
            "javascript": [
                "let editor = window.activeTextEditor;",
                "expandWords();",
                "doTransform(0);",
                "function expandWords() { let sels = editor.selections; let i = sels.length-1;",
                "  while (i >=0) { let sel = sels[i];",
                "    if (sel.isEmpty) {r = editor.document.getWordRangeAtPosition(sel.start); sels[i] = new vscode.Selection(r.start, r.end);}",
                "    i--; }",
                "  editor.selections = sels;",
                "}",
                "function doTransform(i) { let sels = editor.selections;",
                "  if (i < 0 || i >= sels.length) { return; }",
                "  let sel = sels[i];",
                "  let words = editor.document.getText(sel).split('_')",
                "  let camel_words = words.map(function(w) {return w[0].toUpperCase() + w.slice(1,).toLowerCase()});",
                "  editor.edit(eb => {eb.replace(sel, camel_words.join(''))}).then(x => { doTransform(i+1); });",
                "}"
            ]
        }
    ],
    "replaceAllExample1": [
        {
            "javascript": [
                //save the current clipboard
                "var oldClip = await vscode.env.clipboard.readText(); ",    
                //copies the selected text to the clipboard
                "await vscode.commands.executeCommand('editor.action.clipboardCopyAction'); ",
                "var testoSelezionato = await vscode.env.clipboard.readText(); ",   
                //replace all "gatta" to "##########"
                "var nuovoTesto = testoSelezionato.replace(/gatta/g, '##########'); ",   
                //paste the new text
                "if( nuovoTesto != testoSelezionato ) { ",          
                "   await vscode.env.clipboard.writeText(nuovoTesto); ", 
                "   await vscode.commands.executeCommand('editor.action.clipboardPasteAction'); ",
                "} ",          
                //restore the original clipboard
                "await vscode.env.clipboard.writeText(oldClip); ", 
            ],
        },
    ],
    "replaceAllExample2": [
        { 
            "javascript": [
                // parameters
                "var cerca       = 'gatta'; ",
                "var opzioni     = 'g'; ",             // g = global; i = ignorecase     
                "var sostituisci = '##########'; ",
                // get the currently active editor
                "const myEditor = vscode.window.activeTextEditor; ",
                "if (myEditor) {",
                    // perform an edit on the document associated with this text editor
                    "myEditor.edit(myEditBuilder => { ",
                        // loop for each multi-cursor
                        "myEditor.selections.forEach(rangeSelezione => {",
                            // get selected text from a single multi-cursor
                            "var testoSelezionato = myEditor.document.getText(rangeSelezione);",
                            // replace all 
                            "var nuovoTesto = testoSelezionato.replace(new RegExp(cerca, opzioni), sostituisci);",
                            // if the text has changed, I write it in the document
                            "if(nuovoTesto != testoSelezionato) { ",
                                "myEditBuilder.replace(rangeSelezione, nuovoTesto);",
                            "}",
                        "});",
                    "});",
                "}",
            ]
        }
    ],    
}| Desired Action | Macro Step (example) | 
|---|---|
| execute a snippet | {"command": "type", "args": {"text": "mySnippetPrefixHere"}}, "insertSnippet" ] | 
| open a new terminal | "workbench.action.terminal.new" | 
| type into the terminal | { "command": "workbench.action.terminal.sendSequence", "args": { "text": "echo hello\n" } } | 
| message box | { "javascript": "window.showInformationMessage(You entered: ${await window.showInputBox()})" } | 
| user input | { "javascript": [ "let response = await window.showInputBox()" ], ... | 
| user output | ... [ "await window.showInformationMessage(You entered: ${response})" ] } | 
| Copy to clipboard | "editor.action.clipboardCopyAction" | 
| Desired Value | JavaScript Expression | 
|---|---|
| $userInput | await window.showInputBox() | 
| $currentFolder | vscode.workspace.rootPath | 
| $currentFile | window.activeTextEditor.document.uri.fsPath | 
| $currentFileName | path.basename(window.activeTextEditor.document.uri.fsPath) | 
| $currentFileNameNoExtension | path.basename(window.activeTextEditor.document.uri.fsPath).replace(/\.[^/.]+$/, '') | 
| $currentFileDir | path.dirname(window.activeTextEditor.document.uri.fsPath) | 
| $selectionText | window.activeTextEditor.document.getText(window.activeTextEditor.selection) | 
| $clipboardText | vscode.env.clipboard.readText() | 
| $preferedLanguage | vscode.env.language ("en-US") | 
| $machineId | vscode.env.machineId (The name of computer you are running on) | 
| $sessionId | vscode.env.sessionId (A unique string that changes when VS Code restarts) | 
| $shellName | vscode.env.shell (The name of the default terminal shell) | 
| Category | Desired Action | JavaScript Code | 
|---|---|---|
| Document text | The entire text | doc.getText() | 
| Document text | Part of the text | doc.getText(range) | 
| Document text | Range of the word at cursor | doc.getWordRangeAtPosition(position) | 
| Document text | The line of text at cursor | doc.lineAt(line: number) | 
| Document text | The line of text at a position | doc.lineAt(position) // a Position is a line number/char number pair | 
| Document text | Convert position to overall offset | doc.offsetAt(position) | 
| Document text | Convert overall offset to position | doc.positionAt(offset: number) | 
| Document info | EOL style | doc.eol // enum (LF=1, CRLF=2) | 
| Document info | File name | (doc.isUntitled ? "" : doc.fileName) | 
| Document info | Needs saving | doc.isDirty | 
| Document info | Line count | doc.lineCount | 
| Document info | Save to disk | doc.save() | 
| Multi-Select | If multi-selected... | if (window.activeTextEditor.selections.length > 1) { ... }; | 
| Multi-Select | Only act if index is in range | if (window.activeTextEditor.selections[index]) { ... }; | 
| Multi-Select | Scroll to a particular selection | window.activeTextEditor.revealRange(window.activeTextEditor.selections[index]); | 
| Multi-Select | Select only the last selection | window.activeTextEditor.selection = window.activeTextEditor.selections.pop(); | 
polyglot-jones improved the documentation and added three big examples (unMultiSelectLast, transformToSnake, transformToCamel)
The old extension was made by geddski
I modified it to have
- in-order execution
 - javascript / javascript-injections
 - async await
 - keybindings + named execution
 - error message pop-ups
 - auto reload when settings was edited
 - and a few other things