Example Plugin
This is a complete example plugin that demonstrates all major plugin features. The "Cat Image Replacer" plugin is included in the Colab repository as a test plugin.
package.json
{
"name": "colab-cat-replacer",
"version": "1.0.0",
"description": "Replaces all images on web pages with adorable cat pictures",
"main": "index.ts",
"keywords": ["colab-plugin"],
"author": "Colab Team",
"license": "MIT",
"colab-plugin": {
"displayName": "Cat Image Replacer",
"description": "Replaces all images on web pages with random cat pictures",
"main": "index.ts",
"contributes": {
"commands": [
{
"id": "catReplacer.enable",
"title": "Enable Cat Mode"
},
{
"id": "catReplacer.disable",
"title": "Disable Cat Mode"
}
],
"webviewHooks": ["onLoad"]
},
"permissions": {
"network": "allow",
"notifications": true
},
"activationEvents": ["*"]
}
} index.ts
The full plugin implementation with all features:
/**
* Cat Image Replacer Plugin for Colab
*
* This is a test/demo plugin that demonstrates the plugin API.
* When enabled, it replaces all images on web pages with cat pictures.
*/
import type { PluginAPI, Disposable } from 'colab/src/main/plugins/types';
let catModeEnabled = false;
const disposables: Disposable[] = [];
/**
* The preload script that will be injected into web pages
* This runs in the webview context, not the plugin worker
*/
const preloadScript = `
(function() {
console.log('Cat Replacer preload script loaded!');
// Simple: wait 2 seconds then replace all images with cats
setTimeout(function() {
var images = document.querySelectorAll('img');
console.log('Replacing', images.length, 'images with cats...');
images.forEach(function(img, i) {
// Use cataas.com - Cat as a Service (reliable cat image API)
var catUrl = 'https://cataas.com/cat?t=' + Date.now() + '-' + i;
img.src = catUrl;
img.srcset = '';
});
console.log('Done! All images are now cats.');
}, 2000);
})();
`;
/**
* Called when the plugin is activated
*/
export async function activate(api: PluginAPI): Promise<void> {
api.log.info('Cat Image Replacer plugin activating...');
// ========================================
// 1. Webview Preload Script
// ========================================
const preloadDisposable = api.webview.registerPreloadScript(preloadScript);
disposables.push(preloadDisposable);
api.log.info('Preload script registered for webviews');
// ========================================
// 2. Commands
// ========================================
const enableDisposable = api.commands.registerCommand('catReplacer.enable', async () => {
catModeEnabled = true;
api.log.info('Cat mode enabled!');
api.notifications.showInfo('Cat Mode Enabled! All images are now cats.');
return { enabled: true };
});
disposables.push(enableDisposable);
const disableDisposable = api.commands.registerCommand('catReplacer.disable', async () => {
catModeEnabled = false;
api.log.info('Cat mode disabled!');
api.notifications.showInfo('Cat Mode Disabled. Images restored.');
return { enabled: false };
});
disposables.push(disableDisposable);
// ========================================
// 3. Terminal Command
// ========================================
const terminalDisposable = api.terminal.registerCommand('meow', async (ctx) => {
const { args, cwd, write } = ctx;
const count = parseInt(args[0]) || 1;
write('\x1b[33m'); // Yellow color
write('Cat Plugin Terminal Command\r\n');
write('\x1b[0m'); // Reset color
write('---\r\n\r\n');
write(`\x1b[90mCWD: ${cwd}\x1b[0m\r\n\r\n`);
// Stream multiple meows with a delay
for (let i = 0; i < count; i++) {
await new Promise(resolve => setTimeout(resolve, 200));
const catEmojis = ['cat', 'happy', 'grin', 'joy', 'heart', 'smirk', 'kiss', 'scream', 'cry', 'pout'];
const randomCat = catEmojis[Math.floor(Math.random() * catEmojis.length)];
write(`Meow ${i + 1}! (${randomCat})\r\n`);
}
write('\r\n\x1b[32mDone meowing!\x1b[0m\r\n');
});
disposables.push(terminalDisposable);
// ========================================
// 4. Editor Completion Provider
// ========================================
const completionDisposable = api.editor.registerCompletionProvider(
['typescript', 'javascript', 'typescriptreact', 'javascriptreact'],
{
triggerCharacters: ['.'],
provideCompletions(ctx) {
// Only trigger after "console."
if (!ctx.linePrefix.endsWith('console.')) {
return [];
}
return [
{
label: 'log (cat)',
insertText: "log('Cat: ', $1);$0",
detail: 'Cat-themed console.log',
documentation: 'Insert a console.log with a cat emoji prefix',
kind: 'snippet',
},
{
label: 'meow',
insertText: "log('Meow!', $1);$0",
detail: 'Log a meow',
documentation: 'Insert a meow log statement',
kind: 'snippet',
},
{
label: 'error (cat)',
insertText: "error('Error: ', $1);$0",
detail: 'Cat-themed console.error',
documentation: 'Insert a console.error with a surprised cat',
kind: 'snippet',
},
];
},
}
);
disposables.push(completionDisposable);
// ========================================
// 5. Status Bar Item
// ========================================
let catCount = 0;
const statusBarItem = api.statusBar.createItem({
id: 'cat-status',
text: 'Cat Mode',
tooltip: 'Cat Replacer Plugin is active',
color: '#ffcc00',
alignment: 'right',
priority: 100,
});
disposables.push(statusBarItem);
// Update the status bar periodically
const catEmojis = ['cat', 'happy', 'grin', 'joy', 'heart', 'smirk', 'kiss', 'scream', 'cry', 'pout'];
const statusInterval = setInterval(() => {
catCount++;
const randomCat = catEmojis[catCount % catEmojis.length];
statusBarItem.update({
text: `Cat Mode (${catCount}) - ${randomCat}`,
});
}, 5000);
disposables.push({ dispose: () => clearInterval(statusInterval) });
// ========================================
// 6. File Decoration Provider
// ========================================
const decorationDisposable = api.fileDecorations.registerProvider({
provideDecoration(filePath) {
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
return {
badge: 'TS',
tooltip: 'TypeScript file (cat approved!)',
};
}
return undefined;
},
});
disposables.push(decorationDisposable);
// ========================================
// 7. Context Menu Item
// ========================================
const contextMenuDisposable = api.contextMenu.registerItem(
{
id: 'catify-file',
label: 'Catify this file',
context: 'both',
shortcutHint: 'Ctrl+Shift+C',
},
async (ctx) => {
api.log.info(`Catify requested for: ${ctx.filePath || 'selection'}`);
api.notifications.showInfo(`Would catify: ${ctx.filePath || ctx.selection || 'nothing selected'}`);
}
);
disposables.push(contextMenuDisposable);
// ========================================
// 8. Keyboard Shortcut
// ========================================
const keybindingDisposable = api.keybindings.register({
key: 'ctrl+shift+m',
command: 'catReplacer.enable',
when: 'global',
});
disposables.push(keybindingDisposable);
// ========================================
// 9. Settings Panel
// ========================================
const settingsDisposable = api.settings.registerSchema({
title: 'Cat Replacer Settings',
description: 'Configure the Cat Image Replacer plugin',
fields: [
{
key: 'autoEnable',
label: 'Auto-enable Cat Mode',
type: 'boolean',
default: false,
description: 'Automatically enable cat mode when the plugin loads',
},
{
key: 'catService',
label: 'Cat Image Service',
type: 'select',
default: 'cataas',
description: 'Which service to use for cat images',
options: [
{ label: 'Cat as a Service (cataas.com)', value: 'cataas' },
{ label: 'The Cat API (thecatapi.com)', value: 'thecatapi' },
],
},
{
key: 'replaceDelay',
label: 'Replace Delay (ms)',
type: 'number',
default: 2000,
min: 500,
max: 10000,
step: 500,
description: 'How long to wait before replacing images',
},
{
key: 'statusBarColor',
label: 'Status Bar Color',
type: 'color',
default: '#ffcc00',
description: 'Color for the cat mode status bar indicator',
},
],
});
disposables.push(settingsDisposable);
// Listen for settings changes
const settingsChangeDisposable = api.settings.onChange((key, value) => {
api.log.info(`Setting changed: ${key} = ${value}`);
if (key === 'statusBarColor') {
statusBarItem.update({ color: value as string });
}
});
disposables.push(settingsChangeDisposable);
// Apply saved settings on startup
const savedColor = api.settings.get<string>('statusBarColor');
if (savedColor) {
statusBarItem.update({ color: savedColor });
}
api.log.info('Cat Image Replacer plugin activated! All features registered.');
}
/**
* Called when the plugin is deactivated
*/
export async function deactivate(): Promise<void> {
// Clean up all disposables
for (const disposable of disposables) {
disposable.dispose();
}
disposables.length = 0;
catModeEnabled = false;
} Features Demonstrated
- Webview Preload Scripts - Injects JavaScript that replaces images with cats
- Commands -
catReplacer.enableandcatReplacer.disable - Terminal Commands - Type
meowormeow 5in any terminal - Code Completions - Type
console.in JS/TS files for cat-themed suggestions - Status Bar Item - Shows "Cat Mode" and updates every 5 seconds
- File Decorations - Adds "TS" badge to TypeScript files
- Context Menu - Right-click "Catify this file" in editor or file tree
- Keyboard Shortcuts -
Ctrl+Shift+Menables cat mode - Settings Panel - Click status bar item to configure plugin options
Running the Example
The test plugin is located in the Colab repository at test-plugin/. To install it:
- Open Colab
- Click "Plugins" in the status bar
- Click "Install from folder"
- Navigate to and select the
test-pluginfolder - The plugin will be installed and activated automatically
Testing the Features
- Webview: Open a web browser tab and wait 2 seconds - images become cats!
- Terminal: Open a terminal and type
meowormeow 3 - Editor: Create a
.tsfile and typeconsole. - Status Bar: Look for "Cat Mode" on the right side
- File Tree: TypeScript files show a badge
- Context Menu: Right-click a file and look for "Catify this file"
- Keyboard: Press
Ctrl+Shift+Manywhere - Settings: Click on the "Cat Mode" status bar item to open settings