In-Depth

How to Use AI to Create Your Own 'Super Macro' VS Code Extensions

Advanced AI like ChatGPT makes it super easy for the most clueless dev novice to create their very own personalized Visual Studio Code extensions. They can provide just about whatever functionality you need instantly with a three-stroke key combination.

After some initial experiments, I can now quickly spin up such a "super macro" in just a few minutes. I've long wanted this functionality and have explored creating such tools, but some proved to be just too complex to code. I have made simple tools for things like inserting HTML boiler plate code or quickly wrapping selected text in URL link code. However, I didn't want to have to further learn TypeScript -- apparently the preferred extension language -- for more complex things.

I use VS Code for my Visual Studio Magazine articles and have customized my environment to do this in HTML files, but I've always wanted quick-hit macros to automate tedious tasks. That's "quick hit" for creating and for using.

After learning the process and ironing out at least one annoying bug, I have quickly created helpful super macros (what I call extensions executed by a three-key combo) for:

  • Wrapping a series of lines in HTML list item tags to create bullet-point lists
  • Creating HTML tables, prompting the user for the number of columns and rows (and conceivably any other number of HTML table features)

Sure, there are third-party widgets and utilities all over the web to do these kinds of things, but I wanted something to execute immediately in my domain, with no context switching. There are also published tools in the marketplace for this kind of stuff, but I wanted something I could quickly customize or enhance if needed.

Here's how to it.

Setup
The AI I used was ChatGPT Plus powered by GPT-4, with the new browsing functionality (beta) enabled.

To get started creating your first extension, go to "Your First Extension" at the VS Code site. You need a bunch of stuff, including Node.js, Git, and specifically for this, Yeoman and the VS Code Extension Generator for creating the extension via the command line.

[Click on image for larger view.] Yo Code with Yeoman (source: Microsoft).

Creating an Extension
When set up, from the terminal, just type "yo code" to generate a script that builds a barebones extension simply to display a message, based on user inputs for the language used, name of the tool and more, as shown in the graphic above.

Once you've done that and tested the new tool in a popup "Extension Development Host" window (executing the command from the Command Palette to make sure it generates the shell's default "Hello World" message), AI comes into play.

As noted, I used ChatGPT to provide the TypeScript code to wrap text lines in HTML bullet points and generate HTML tables. Rather than laboriously learn what code to use and then type all that code in TypeScript/JavaScript, I just have ChatGPT do the grunt work. I use it in a browser tab, but tools abound to provide ChatGPT access within the code editor.

For my purposes, I had it replace the code in the project's extension.js file (the programming) and package.json file, which lists tool metadata like display name, identifier, command name and title (what you see in the Command Palette), along with other information like dependencies.

Fine Tuning
Regarding the latter, you have to be careful. ChatGPT at first generated code that used old versions of VS Code and dependencies. I had to tell it to modernize things by using its brand-new browsing functionality, provided in beta last week. I'm no LLM-savvy prompt engineer, but this is what I used:

please regenerate all of that code with the latest versions of node.js, typescript, visual studio code and any other dependencies or affected data. For example, "@types/vscode": "^1.55.0" should be "@types/vscode": "^1.78.0"

That kicked in the browsing functionality, and ChatGPT quickly regenerated the code with up-to-date dependencies, telling me it was using said browsing functionality.

[Click on image for larger view.] "Here's the updated information for the dependencies you've mentioned:" (source: Ramel).

Interestingly, after updating the dependencies as shown in the screenshot above, ChatGPT said:

Please note that the above "vscode-test": "^1.7.0" is hypothetical as I wasn't able to find the exact version number on GitHub. I made an assumption based on the most recent commit date. Please verify this before use.

It also did more, providing relevant information such as the process used and even telling me (the dummy) that while VS Code 1.78 might be the latest edition, it doesn't need to be included in the package.json file. But then again, why did it generate this line in the package.json file in the first place?

"@types/vscode": "^1.55.0",

Anyway, it also provided helpful guidance, including:

However, before you proceed, it's critical to ensure compatibility between all these packages in your specific context. Major version updates often come with breaking changes, so you might need to adjust your code accordingly. If possible, run tests after updating these dependencies to make sure everything still works as expected.

To give examples of the code generated by ChatGPT, here are snippets of code to generate tables:

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
	let disposable = vscode.commands.registerCommand('table-generator.generateHtmlTable', async () = >  {
		const numberOfRows = await vscode.window.showInputBox({ prompt: 'Enter the number of rows' });
		const numberOfColumns = await vscode.window.showInputBox({ prompt: 'Enter the number of columns' });

		if (numberOfRows && numberOfColumns) {
			let table = ' < table > \n';
			
			for (let i = 0; i < parseInt(numberOfRows); i++) {
				table += '\t < tr > \n';
				for (let j = 0; j < parseInt(numberOfColumns); j++) {
					table += '\t\t < td >  < /td > \n';
				}
				table += '\t < /tr > \n';
			}

			table += ' < /table > ';

			const activeTextEditor = vscode.window.activeTextEditor;

			if (activeTextEditor) {
				const activeDocument = activeTextEditor.document;
				const edit = new vscode.WorkspaceEdit();
				edit.insert(activeDocument.uri, activeTextEditor.selection.active, table);
				vscode.workspace.applyEdit(edit);
			}
		}
	});

	context.subscriptions.push(disposable);
}

export function deactivate() {}
and to wrap text lines in bullet-point lists:
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    let disposable = vscode.commands.registerCommand('html-list.createList', () = >  {
        const editor = vscode.window.activeTextEditor;

        if (editor) {
            const document = editor.document;
            const selection = editor.selection;

            // Get the selected text as a string.
            const selectedText = document.getText(selection);

            // Split the selected text into lines.
            const lines = selectedText.split('\n');

            // Wrap each line in  < li >  < /li >  tags.
            const wrappedLines = lines.map(line = >  ` < li > ${line} < /li > `);

            // Join the wrapped lines back together and wrap them in  < ul >  < /ul >  tags.
            const newText = ` < ul > \n${wrappedLines.join('\n')}\n < /ul > `;

            // Create an edit that replaces the selected text with the new text.
            const edit = new vscode.WorkspaceEdit();
            edit.replace(document.uri, selection, newText);

            // Apply the edit.
            vscode.workspace.applyEdit(edit);
        }
    });

    context.subscriptions.push(disposable);
}

Once you've tested your final extension code, to use it you just need to package it in a local .vsix file for your own use, as opposed to publishing it to the VS Code Marketplace.

Bug Workaround
One thing to note here, however, is the vsce package command run from the terminal to create the .vsix file failed every time for me, with an error message telling me to "Make sure to edit the README.md file before you package or publish your extension."

I didn't know why that would be needed, but I dutifully edited and saved the project's README.md file only to keep getting the same error message no matter how many or how big the edits I made to the file. After some web searching, I saw a GitHub issue indicating that completely deleting the contents of the file worked. It did, and I investigated that issue no further. This known issue really should be fixed, though.

Anyway, I eventually got my table generator and list generator to appear in my list of extensions by going to the Extensions view and, instead of pulling one down from the marketplace, clicking on the three dots (...) at the top right of the view to pull up a menu featuring the option to "Install from VSIX...." Then you just point to the .vsix file you created to install it and your super macro is ready to use.

[Click on image for larger view.] Table Generator Entry in the Extensions view. (source: Ramel).

Command Shortcuts
I don't like having to hit Ctrl+Shift+P to fire up the Command Palette and then find my tools from the huge list, though, so I assigned them three-key command shortcuts via the Ctrl+K Ctrl+S (on Windows) command.

[Click on image for larger view.] Keybinding (source: Ramel).

Finding unused three-key combinations for commands is getting harder and harder, but I managed to set up Ctrl+Alt+T for tables and Ctrl+Alt+L for lists, making them easy to remember.

Now that I've learned the process, I'm eager to spin up new tools to handle whatever annoying repetitive tasks that keep coming up, or any other functionality I can dream up.

I might even explore doing this with the Visual Studio IDE, which is surely more complicated.

Another thing to explore would be to install one of those ChatGPT-access extensions to do all of the above directly within VS Code, rather than having to switch contexts to ChatGPT in a browser. I'm sure they're among the useful AI tools for VS Code being regularly added to the marketplace, probably almost daily.

GitHub Copilot can probably do the exact same thing, but it can't browse the web for the latest data. (I would test it, but GitHub insists I didn't pay for Copilot, though my repo account info clearly shows I did -- don't get me started.)

Anyway, this is another example of how advanced AI is affecting many everyday jobs -- and everything else.

About the Author

David Ramel is an editor and writer at Converge 360.

comments powered by Disqus

Featured

  • Diving Deep into .NET MAUI

    Ever since someone figured out that fiddling bits results in source code, developers have sought one codebase for all types of apps on all platforms, with Microsoft's latest attempt to further that effort being .NET MAUI.

  • Copilot AI Boosts Abound in New VS Code v1.96

    Microsoft improved on its new "Copilot Edit" functionality in the latest release of Visual Studio Code, v1.96, its open-source based code editor that has become the most popular in the world according to many surveys.

  • AdaBoost Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the AdaBoost.R2 algorithm for regression problems (where the goal is to predict a single numeric value). The implementation follows the original source research paper closely, so you can use it as a guide for customization for specific scenarios.

  • Versioning and Documenting ASP.NET Core Services

    Building an API with ASP.NET Core is only half the job. If your API is going to live more than one release cycle, you're going to need to version it. If you have other people building clients for it, you're going to need to document it.

  • TypeScript Tops New JetBrains 'Language Promise Index'

    In its latest annual developer ecosystem report, JetBrains introduced a new "Language Promise Index" topped by Microsoft's TypeScript programming language.

Subscribe on YouTube