Kogito Tooling Examples — How to create a VS Code Extension for the custom Editor

Protograph by Taylor Rees

This is part of a series of blog posts, and this one covers “How to create a VS Code Extension for a custom Editor”.

You can navigate through the series by clicking on the following topics:

Creating a VS Code Extension is pretty similar to the Chrome Extension creation process. It’s recommended to access the VS Code Extension API reference to be aware of the VS Code Extension capabilities.

Starting

Here we’re going to show how to use our custom Base64Png Editor on a VS Code Extension, so when we open a base64png file on it, it’ll render our Editor. Here’s how it’ll look like.

The Base64Png Editor running inside VS Code

Obs: This example requires the VS Code version 1.46 or later.

Code

It’s necessary to create some files to have a VS Code Extension:

  • package.json
  • src/envelope/index.ts
  • src/extension.ts

package.json

The package.json is the manifest file of the VS Code Extension and has fundamental setups. You can find the package.json file here.

It’s important to specify the published and name properties because both create the extension name.

"publisher": "kogito-tooling-examples",
"name": "base64png-editor-vscode-extension"
view raw package.json hosted with ❤ by GitHub

As mentioned before, we need to specify the VS Code version, and we do that with the engine property.

"engines": {
"vscode": "^1.46.0"
},
view raw package.json hosted with ❤ by GitHub

Also, it’s required to tell the extension entry point file.

"main": "./dist/extension.js",
view raw package.json hosted with ❤ by GitHub

Now we must inform some other properties which will register our custom Editor and some new commands.

To start, we need to register our custom Editor and some commands:

  • A custom editor with the id kieKogitoWebviewBase64PNGEditor to be opened with a *.base64png file.
  • A command with the id extension.kogito.createBase64Png and the command icons.
  • A command with the id extension.kogito.getPreviewSvg and the command icons.
"contributes": {
"customEditors": [
{
"viewType": "kieKogitoWebviewBase64PNGEditor",
"displayName": "Kogito Base64Png React Editor",
"selector": [
{
"filenamePattern": "*.base64png"
}
]
}
],
"commands": [
{
"command": "extension.kogito.createBase64Png",
"title": "Create Base64 PNG",
"icon": {
"light": "./static/kogito-logo-128×128.png",
"dark": "./static/kogito-logo-128×128.png"
}
},
{
"command": "extension.kogito.getPreviewSvg",
"title": "Save Preview SVG",
"icon": {
"light": "./static/svg-icon-light.png",
"dark": "./static/svg-icon-dark.png"
}
}
]
}
view raw package.json hosted with ❤ by GitHub

We inform the places where the command will be registered on the menus property and which file extension can access the command. In this case, we register both commands on the command palette (CTRL + SHIFT + P) and in the editor title area. The extension.kogito.createBase64Png only works with .png files, and the extension.kogito.getPreviewSvg only works with .base64png files.

The getPreviewSvg icon command on the editor title area. (It just appears on base64png files)
The createBase64Png icon command on the editor title area. (It just appears on PNG files)

The example of both title commands. The transform a PNG to base64png command, and the transform a base64png to SVG.

"contributes": {
"menus": {
"commandPalette": [
{
"when": "resourceLangId == png",
"command": "extension.kogito.createBase64Png"
},
{
"when": "resourceLangId == base64png",
"command": "extension.kogito.getPreviewSvg"
}
],
"editor/title": [
{
"when": "resourceLangId == png",
"command": "extension.kogito.createBase64Png",
"group": "navigation"
},
{
"when": "resourceLangId == base64png",
"command": "extension.kogito.getPreviewSvg",
"group": "navigation"
}
]
}
}
view raw package.json hosted with ❤ by GitHub

It’s important to define the language property to help VS Code know for what kind of file your Extension works.

"contributes": {
"languages": [
{
"id": "base64png",
"extensions": [
".base64png"
],
"aliases": [
"base64png",
"Base64 PNG"
]
},
{
"id": "png",
"extensions": [
".png"
],
"aliases": [
"png",
"Png"
]
}
]
}
view raw package.json hosted with ❤ by GitHub

Now we need to inform when the Extension is going to be activated. In this example, the Extension is going to be active (activationEvent)when we open a custom editor (onCustomEditor) with the id kieKogitoWebviewBase64PNGEditor or when we execute a command (onCommand) with the id extension.kogito.createBase64Png.

"activationEvents": [
"onCustomEditor:kieKogitoWebviewBase64PNGEditor",
"onCommand:extension.kogito.createBase64Png"
]
view raw package.json hosted with ❤ by GitHub

src/extension.ts

This file is the entry point of the Extension as mentioned in the package.json and we must register two functions here:

  • activate
  • deactivate
import * as vscode from "vscode";
export function activate(context: vscode.ExtensionContext) {
console.info("Extension is alive.");
// activate code here
}
export function deactivate() {
console.info("Extension is deactivating");
// deactivate code here
}
view raw extension.ts hosted with ❤ by GitHub

activate

Here’s the code that will run when one of the options informed on the activationEvent is fulfilled. Inside the activate function, we are going to initialize the custom Editor (kieKogitoWebviewBase64PNGEditor) and the create Base64Png command (extension.kogito.createBase64Png).

To initialize our custom Editor, we’re going to use the startExtension method located on @kogito-tooling/vscode-extension.

  • extensionName: As informed before, the extension name is formed by the publisher and name properties.
  • context: VS Code creates this context.
  • viewType: Is the id of our custom Editor.
  • getPreviewCommandId: The id of our get preview command.
  • editorEnvelopeLocator: A map correlating the supported file extension with the Envelope location.
  • backendProxy: A VS Code backend service to be enabled on the package.json(Not covered on this example).
import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";
let backendProxy: VsCodeBackendProxy;
export function activate(context: vscode.ExtensionContext) {
// …
context.subscriptions.push(
vscode.commands.registerCommand("extension.kogito.createBase64Png", (file: { fsPath: string }) => {
const buffer = fs.readFileSync(file.fsPath);
const parsedPath = path.parse(file.fsPath);
const base64FileName = `${parsedPath.name}${parsedPath.ext}.base64png`;
const base64AbsoluteFilePath = path.join(parsedPath.dir, base64FileName);
fs.writeFileSync(base64AbsoluteFilePath, buffer.toString("base64"));
vscode.window.showInformationMessage("Generated the Base64 file with success!", "Open").then((selected) => {
if (!selected) {
return;
}
vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(base64AbsoluteFilePath));
});
})
);
}
view raw extension.ts hosted with ❤ by GitHub

We register and create our createBase64Png callback using the VS Code context. This command was made to convert a PNG image into a base64png, making it easy to test the Editor!

import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";
let backendProxy: VsCodeBackendProxy;
export function activate(context: vscode.ExtensionContext) {
// …
context.subscriptions.push(
vscode.commands.registerCommand("extension.kogito.createBase64Png", (file: { fsPath: string }) => {
const buffer = fs.readFileSync(file.fsPath);
const parsedPath = path.parse(file.fsPath);
const base64FileName = `${parsedPath.name}${parsedPath.ext}.base64png`;
const base64AbsoluteFilePath = path.join(parsedPath.dir, base64FileName);
fs.writeFileSync(base64AbsoluteFilePath, buffer.toString("base64"));
vscode.window.showInformationMessage("Generated the Base64 file with success!", "Open").then((selected) => {
if (!selected) {
return;
}
vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(base64AbsoluteFilePath));
});
})
);
}
view raw extension.ts hosted with ❤ by GitHub

deactivate

We just deactivate our backend proxy.

export function deactivate() {
console.info("Extension is deactivating");
backendProxy?.stopServices();
}
view raw extension.ts hosted with ❤ by GitHub

src/envelope/index.ts

This file is responsible for the initialization of the Envelope. Here we use the Base64EditorFactory to create a Base64Png Editor, and then we specify the editor context. It’s important to generate an output from this file using Webpack or any other module bundler of your choice.

Our Envelope will start on the “envelope-app” container (an HTML div) available inside the init method. The bus method is used by the Envelope to communicate with the Channel, in this case, we utilize the acquireVsCodeApi.

import { init } from "@kogito-tooling/editor/dist/envelope";
import { Base64PngEditorFactory } from "base64png-editor";
import { ChannelType, getOperatingSystem } from "@kogito-tooling/channel-common-api";
declare global {
export const acquireVsCodeApi: any;
}
init({
container: document.getElementById("envelope-app")!,
bus: acquireVsCodeApi(),
editorFactory: new Base64PngEditorFactory(),
editorContext: { channel: ChannelType.VSCODE, operatingSystem: getOperatingSystem() },
});
view raw index.ts hosted with ❤ by GitHub

Running

To run this Extension, you can use the vsce package to generate a vsix file and manually install it (read more about here), or you can run it in debug mode.

To run in debug mode, we need to create two files in the .vscode directory. The launch.json, which is the primary file used for debugging, and task.json, create a task used by the launch.json. The launch.json is executed when you open the VS Code Extension folder on utilizing the VS Code Editor and start the debug mode (use the F5 shortcut). You can check our setup on the repository used by this example.

Wrapping up

Now you can create your own VS Code extension to render an Editor ontop of base64png files. This finishes this section, in the next one we’ll see how to create custom Views!

Thanks for reading, and see you in the next section.

This post was original published on here.
0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments