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

  1. Webview Preload Scripts - Injects JavaScript that replaces images with cats
  2. Commands - catReplacer.enable and catReplacer.disable
  3. Terminal Commands - Type meow or meow 5 in any terminal
  4. Code Completions - Type console. in JS/TS files for cat-themed suggestions
  5. Status Bar Item - Shows "Cat Mode" and updates every 5 seconds
  6. File Decorations - Adds "TS" badge to TypeScript files
  7. Context Menu - Right-click "Catify this file" in editor or file tree
  8. Keyboard Shortcuts - Ctrl+Shift+M enables cat mode
  9. 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:

  1. Open Colab
  2. Click "Plugins" in the status bar
  3. Click "Install from folder"
  4. Navigate to and select the test-plugin folder
  5. 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 meow or meow 3
  • Editor: Create a .ts file and type console.
  • 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+M anywhere
  • Settings: Click on the "Cat Mode" status bar item to open settings