An online markdown blog and knowledge repository.
This document will store my experiences learning about, and interacting with the process of building a VSCode Extension.
At the end of this experience, I hope to have learned the following:
In addition, I am challenging myself to complete the following:
Yeoman: Aka "yo". VSCode Extension Generator. Enables creating new:
Yeoman supports NPM, Yarn, and PNPM.
npm install -g yo generator-code
.yo code
Update Package.json:
Newly saved code is now running.
Build Development Host is a live build+run version of VSCode using the Extension code in the parent VSCode instance from 'Run Extension' (F5) command.
Naming a Command requires editing package.json: 'contributes:commands:command:' and 'contributes:commands:title'. This is different than naming the Extension Project (top of Package.json 'name' and 'displayName' KVPs).
VSCode Commands follow a disposable pattern:
activate(context: vscode.ExtensionContext)
method.vscode.commands.registerCommand()
with the package.json command name followed by a lambda that executes a function or code block.activate()
function, call context.subscriptions.push(disposable_variable_from_step2)
.Live Debugging is supported! Use breakpoints and view in-execution variable values just like any other code.
Async-Await and Promises are supported example code source.
// the following code was copied on 7-June-23 from github.com/microsoft/vscode-extension-samples
import * as vscode from 'vscode';
import { SampleKernel } from './controller';
import { SampleContentSerializer } from './serializer';
const NOTEBOOK_TYPE = 'test-notebook-serializer';
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand(
'notebook-serializer-sample.createJsonNotebook',
// ASYNC
async () => {
const language = 'json';
const defaultValue = `{ "hello_world": 123 }`;
const cell = new vscode.NotebookCellData(
vscode.NotebookCellKind.Code,
defaultValue,
language
);
const data = new vscode.NotebookData([cell]);
data.metadata = {
custom: {
cells: [],
metadata: {
orig_nbformat: 4,
},
nbformat: 4,
nbformat_minor: 2,
},
};
const doc = await vscode.workspace.openNotebookDocument(
NOTEBOOK_TYPE,
data
);
// AWAIT
await vscode.window.showNotebookDocument(doc);
}
)
);
context.subscriptions.push(
vscode.workspace.registerNotebookSerializer(
NOTEBOOK_TYPE,
new SampleContentSerializer(),
{ transientOutputs: true }
),
new SampleKernel()
);
}
Cancellation Tokens: The last parameter of a function call (optional). Use isCancellationRequested
to check if canceled, or register for notifications via onCancellationRequested
. A Cancellation Token will be valid on events that cause an API call to become obsolete. For example: During an API Call the user types more characters, so a new API call could be made with more up-to-date context and data.
Events are exposed as Functions. Use the Listener Pattern (example below) to subscribe to Events. Return a Disposable so the Event Listener can be removed. From vscode api patterns documentation: '...an event fired when the active text editor (noun) has been (onDid) changed (verb)'
// Event Listener Pattern from code.visualstudio.com
var listener = function (event) {
console.log('It happened', event);
};
// start listening using 'onWillVerbNoun' and 'onDidVerbNoun' terminology
var subscription = fsWatcher.onDidDelete(listener);
// do stuff
// ...
// stop listening
subscription.dispose();
Commands can be hidden until a when clause
returns true, for example: Only show the command when the editor language is markdown:
{
"contributes": {
"menus": {
"commandPallete": [
{
"command": "markdowntocer:markdownTOCer",
"title": "Markdown TOCer",
"when": "editorLangId == markdown"
}
]
}
}
}
When a command is showing (when clause returns true), the enablement
allows use of the command, perhaps when a cursor is over a line of text.
Example (from API Guides) of storing a value to use with a when
clause to check if number of cool open things is greater than 2:
vscode.commands.executeCommand('setContext', 'myExtension.showMyCommand', true);
vscode.commands.executeCommand(
'setContext',
'myExtension.numberOfCoolOpenThings',
4
);
Namespace for localization-related functionality is l10n
and must be definied in Extension Manifest and have bundle.l10n.json
files included. Does not apply to built-in Extensions like GitHub Authentication, Git, some Language Features, etc.
onCommand:helloworld.helloWorld
contribues.commands
.commands.regsiterCommand
and helloworld.helloWorld
.@types/vscode
: See Package.json, 'engines:vscode'. These provide IntelliSense and commands like 'Go to definition', etc to the Extension code.Check out Extension Anatomy Documentation for up-to-date info.
Program analyzes project to provide dynamic features.
Example: typescript-language-features
utilizes TS Language Service to offer features like Hover Info, Auto Completion, Formatting, etc.
LSP: Language Server Protocol
Language Server Extension Guide
The Workbench can be put into 'readonly' mode to prevent changes to specific files, however files that match cannot be edited in the Editor:
files.readonlyInclude
.VSCode Documentation on Testing Extensions.
Requirements:
Capabilities:
Electron is going to be the way to test VSCode Extensions going forward.
vscode
dependency.engines.vscode: 1.3
, install '@types/vscode': '^1.30.0'
to package.json dependencies.'postinstall': 'node ./node_modules/vscode/bin/install'
in package.json.test
script in package.json to the compiled output of runTest.ts
.mocha@4
and glob
will need to be in devDependencies if the above steps were taken.When targeting Linux in YAML, ensure Xvfb
enabled environment is targeted, otherwise test will fail.
See GitHub Actions subsection in Working With Extensions.
See GitHub Actions Automated Publishing subsection in Working With Extensions
Define the publisher
property in order to enable managing an Extension.
Publishing can be done 2 ways:
Packaging tool: vsce
the Visual Studio Code Extensions packaing and publishing tool.
npm install -g vsce
at the root of the project.vsce login {publister_name_from_step_11}
and the Publisher Token captured previously.{ ..., "publisher": "{publisher_name_created_previously}", ...}
.vsce publish
.Return to Conted Index.
Return to Root README.