DevelopersPlugin DevelopmentAPI Quick Reference

API Quick Reference

Note: This page provides a quick overview of the Lokus Plugin API. For comprehensive documentation with detailed examples, method signatures, and advanced usage, visit the API Reference section.

This is a condensed quick reference. Plugins receive a PluginContext during construction with access to all APIs.

Plugin Structure

import { PluginContext } from 'lokus-plugin-sdk';
 
export default class MyPlugin {
  private context: PluginContext;
 
  constructor(context: PluginContext) {
    this.context = context;
  }
 
  async activate(activationContext: any): Promise<void> {
    // Register commands via activationContext
    activationContext.commands.registerCommand('myPlugin.cmd', {
      callback: () => {}
    });
 
    // Access other APIs via this.context
    this.context.ui.showInformationMessage('Plugin activated!');
  }
 
  async deactivate(): Promise<void> {
    // Cleanup
  }
}

API Overview

Lokus provides 14 comprehensive APIs for complete extensibility:

APIAccessPurposeFull Docs
EditorAPIcontext.editorTipTap editor (95+ methods)View
UIAPIcontext.uiUI components & notificationsView
CommandsAPIcontext.commandsCommand registrationView
WorkspaceAPIcontext.workspaceFile and editor accessView
ConfigurationAPIcontext.configPlugin settingsView
LanguagesAPIcontext.languagesLanguage featuresView
TerminalAPIcontext.terminalTerminal managementView
TaskAPIcontext.tasksTask executionView
DebugAPIcontext.debugDebugging sessionsView
ThemeAPIcontext.themesTheme managementView
StorageAPIcontext.storageData persistenceView
FilesystemAPIcontext.fsFile operationsView
NetworkAPIcontext.networkHTTP requestsView
ClipboardAPIcontext.clipboardClipboard accessView
Loggercontext.loggerLogging and debuggingBuilt-in

Logger API

Access: context.logger

Log messages for debugging. Logs appear in Lokus Developer Tools console.

Methods

// Information message
context.logger.info(message: string, ...args: any[]): void
 
// Warning message
context.logger.warn(message: string, ...args: any[]): void
 
// Error message
context.logger.error(message: string, ...args: any[]): void
 
// Debug message (only shown in dev mode)
context.logger.debug(message: string, ...args: any[]): void

Example

constructor(context: PluginContext) {
  this.context = context;
  this.context.logger.info('Plugin initialized');
}
 
async activate() {
  try {
    // ... setup
    this.context.logger.info('Plugin activated successfully');
  } catch (error) {
    this.context.logger.error('Activation failed:', error);
  }
}

UI API

Access: context.ui

Display notifications and dialogs to the user.

showInformationMessage()

Show an info notification.

context.ui.showInformationMessage(message: string): void

showWarningMessage()

Show a warning notification.

context.ui.showWarningMessage(message: string): void

showErrorMessage()

Show an error notification.

context.ui.showErrorMessage(message: string): void

showInputBox()

Show an input dialog and get user input.

context.ui.showInputBox(options?: InputBoxOptions): Promise<string | null>
 
interface InputBoxOptions {
  title?: string;
  prompt?: string;
  placeholder?: string;
  value?: string;  // Default value
  validateInput?: (value: string) => string | null;  // Return error message or null
}

showConfirm()

Show a confirmation dialog.

context.ui.showConfirm(options: ConfirmOptions): Promise<boolean>
 
interface ConfirmOptions {
  title: string;
  message: string;
  confirmText?: string;  // Default: "OK"
  cancelText?: string;   // Default: "Cancel"
}

registerPanel()

Register a custom UI panel.

context.ui.registerPanel(panel: PanelDefinition): Disposable
 
interface PanelDefinition {
  id: string;
  title: string;
  location: 'sidebar' | 'bottom';
  icon?: string;
  component?: React.ComponentType;
  initialState?: Record<string, any>;
}

addPanel()

Add a panel to the UI.

context.ui.addPanel(panel: AddPanelOptions): Panel
 
interface AddPanelOptions {
  id: string;
  title: string;
  position: 'sidebar-left' | 'sidebar-right' | 'bottom' | 'modal';
  icon?: string;
  component?: React.ComponentType;
  props?: Record<string, any>;
}

createOutputChannel()

Create an output channel for logging.

context.ui.createOutputChannel(name: string): OutputChannel
 
interface OutputChannel {
  name: string;
  append(value: string): void;
  appendLine(value: string): void;
  clear(): void;
  show(preserveFocus?: boolean): void;
  hide(): void;
  dispose(): void;
}

Example

async activate() {
  // Show notification
  this.context.ui.showInformationMessage('Plugin loaded!');
 
  // Get user input
  const name = await this.context.ui.showInputBox({
    title: 'Enter Name',
    prompt: 'What is your name?',
    placeholder: 'John Doe'
  });
 
  if (name) {
    this.context.ui.showInformationMessage(`Hello, ${name}!`);
  }
 
  // Confirm action
  const confirmed = await this.context.ui.showConfirm({
    title: 'Confirm',
    message: 'Are you sure you want to continue?'
  });
 
  if (confirmed) {
    // proceed...
  }
}

Editor API

Access: context.editor

Interact with the TipTap-based editor.

addSlashCommand()

Add a slash command to the editor.

context.editor.addSlashCommand(command: SlashCommand): Promise<string>
 
interface SlashCommand {
  name: string;
  description: string;
  icon?: string;
  aliases?: string[];
  execute: () => void | Promise<void>;
}

addToolbarItem()

Add a button to the editor toolbar.

context.editor.addToolbarItem(item: ToolbarItem): string
 
interface ToolbarItem {
  id: string;
  title: string;
  icon: string;
  group?: string;  // Default: 'plugin'
  handler: () => void;
  isActive?: () => boolean;
  isDisabled?: () => boolean;
}

addContextMenuItem()

Add an item to the right-click context menu.

context.editor.addContextMenuItem(item: ContextMenuItem): string
 
interface ContextMenuItem {
  id: string;
  name: string;
  icon?: string;
  condition?: () => boolean;
  execute: () => void;
}

addKeyboardShortcut()

Register a keyboard shortcut.

context.editor.addKeyboardShortcut(shortcut: KeyboardShortcut): string
 
interface KeyboardShortcut {
  key: string;  // e.g., 'Mod-Shift-K' (Mod = Cmd on Mac, Ctrl elsewhere)
  handler: () => boolean;  // Return true to prevent default
  description?: string;
}

addDropHandler()

Handle drag & drop events.

context.editor.addDropHandler(handler: DropHandler): string
 
interface DropHandler {
  accept: string | string[];  // MIME types, e.g., 'image/*'
  handler: (files: File[]) => void | Promise<void>;
}

addExtension()

Add a TipTap extension to the editor.

context.editor.addExtension(extension: ExtensionConfig): Promise<string>
 
interface ExtensionConfig {
  name: string;
  type?: 'extension' | 'node' | 'mark';
  schema?: object;
  view?: object;
  commands?: object;
  inputRules?: any[];
  keyboardShortcuts?: object;
}

getSelection()

Get the current text selection.

context.editor.getSelection(): Promise<Selection | null>
 
interface Selection {
  from: number;
  to: number;
  text: string;
  empty: boolean;
}

replaceSelection()

Replace the current selection with new content.

context.editor.replaceSelection(content: string): Promise<void>

getText()

Get the editor content as plain text.

context.editor.getText(): Promise<string>

insertNode()

Insert a node at the current cursor position.

context.editor.insertNode(
  type: string,
  attrs?: Record<string, any>,
  content?: string
): Promise<void>

onUpdate()

Subscribe to editor content changes.

context.editor.onUpdate(callback: (content: string) => void): Disposable

Example

async activate() {
  const editor = this.context.editor;
 
  // Add slash command
  await editor.addSlashCommand({
    name: 'greeting',
    description: 'Insert a greeting',
    icon: 'đź‘‹',
    execute: async () => {
      await editor.insertNode('paragraph', {}, 'Hello, World!');
    }
  });
 
  // Add toolbar button
  editor.addToolbarItem({
    id: 'my-button',
    title: 'Insert Date',
    icon: 'calendar',
    handler: async () => {
      const date = new Date().toLocaleDateString();
      await editor.replaceSelection(date);
    }
  });
 
  // Add keyboard shortcut
  editor.addKeyboardShortcut({
    key: 'Mod-Shift-D',
    description: 'Insert current date',
    handler: async () => {
      const date = new Date().toLocaleDateString();
      await editor.replaceSelection(date);
      return true;
    }
  });
}

Commands API

Access: activationContext.commands (in activate method)

Register commands that appear in the command palette.

registerCommand()

Register a command.

activationContext.commands.registerCommand(
  id: string,
  options: CommandOptions
): Disposable
 
interface CommandOptions {
  name?: string;
  description?: string;
  shortcut?: string;
  callback: (...args: any[]) => void | Promise<void>;
  // Alternative property name (both work)
  execute?: (...args: any[]) => void | Promise<void>;
}

Example

async activate(activationContext: any) {
  // Register a simple command
  activationContext.commands.registerCommand('myPlugin.hello', {
    name: 'Say Hello',
    description: 'Shows a greeting',
    callback: () => {
      this.context.ui.showInformationMessage('Hello!');
    }
  });
 
  // Register command with arguments
  activationContext.commands.registerCommand('myPlugin.greet', {
    name: 'Greet User',
    callback: (name: string) => {
      this.context.ui.showInformationMessage(`Hello, ${name}!`);
    }
  });
 
  // Register with shortcut
  activationContext.commands.registerCommand('myPlugin.quickAction', {
    name: 'Quick Action',
    shortcut: 'Ctrl+Shift+Q',
    callback: () => {
      // Action...
    }
  });
}

Filesystem API

Access: context.fs

File operations scoped to the plugin’s directory for security.

readFile()

Read a file from the plugin directory.

context.fs.readFile(relativePath: string): Promise<Uint8Array>

writeFile()

Write content to a file in the plugin directory.

context.fs.writeFile(relativePath: string, content: string | Uint8Array): Promise<void>

exists()

Check if a file exists.

context.fs.exists(relativePath: string): Promise<boolean>

readdir()

List files in a directory.

context.fs.readdir(relativePath: string): Promise<string[]>

mkdir()

Create a directory.

context.fs.mkdir(relativePath: string): Promise<void>

delete()

Delete a file or directory.

context.fs.delete(relativePath: string): Promise<void>

rename()

Rename a file or directory.

context.fs.rename(oldPath: string, newPath: string): Promise<void>

copy()

Copy a file.

context.fs.copy(source: string, destination: string): Promise<void>

stat()

Get file information.

context.fs.stat(path: string): Promise<FileStat>
 
interface FileStat {
  isFile: boolean;
  isDirectory: boolean;
  size: number;
  mtime: Date;
}

openFileDialog()

Open a file picker dialog.

context.fs.openFileDialog(options: FileDialogOptions): Promise<string[]>
 
interface FileDialogOptions {
  accept?: string[];  // File extensions, e.g., ['.txt', '.md']
  multiple?: boolean;
  title?: string;
}

Example

async saveData() {
  const data = JSON.stringify({ count: 42 });
  await this.context.fs.writeFile('data.json', data);
}
 
async loadData() {
  if (await this.context.fs.exists('data.json')) {
    const content = await this.context.fs.readFile('data.json');
    const text = new TextDecoder().decode(content);
    return JSON.parse(text);
  }
  return null;
}

Network API

Access: context.network

Make HTTP requests. Requires network permission.

fetch()

Make an HTTP request.

context.network.fetch(url: string, options?: RequestInit): Promise<Response>

Example

async fetchData() {
  try {
    const response = await this.context.network.fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    this.context.logger.error('Network request failed:', error);
    throw error;
  }
}

Note: Network access requires the network permission in your manifest:

{
  "permissions": ["network:fetch"]
}

Storage API

Access: context.storage

Persistent key-value storage for plugin data.

getDatabase()

Get a database instance for storing data.

context.storage.getDatabase(name: string): Promise<Database>
 
interface Database {
  get(key: string): Promise<any>;
  set(key: string, value: any): Promise<void>;
  delete(key: string): Promise<void>;
  keys(): Promise<string[]>;
  clear(): Promise<void>;
}

Example

async saveSettings(settings: Record<string, any>) {
  const db = await this.context.storage.getDatabase('settings');
  for (const [key, value] of Object.entries(settings)) {
    await db.set(key, value);
  }
}
 
async loadSettings() {
  const db = await this.context.storage.getDatabase('settings');
  const keys = await db.keys();
  const settings: Record<string, any> = {};
  for (const key of keys) {
    settings[key] = await db.get(key);
  }
  return settings;
}

Clipboard API

Access: context.clipboard

Read and write to the system clipboard.

writeText()

Write text to the clipboard.

context.clipboard.writeText(text: string): Promise<void>

read()

Read from the clipboard.

context.clipboard.read(): Promise<ClipboardItems>

Example

async copyToClipboard() {
  const selection = await this.context.editor.getSelection();
  if (selection && selection.text) {
    await this.context.clipboard.writeText(selection.text);
    this.context.ui.showInformationMessage('Copied to clipboard!');
  }
}

Disposable Pattern

Many API methods return a Disposable object. Call dispose() to clean up resources.

interface Disposable {
  dispose(): void;
}

Example

class MyPlugin {
  private disposables: Disposable[] = [];
 
  async activate(activationContext: any) {
    // Store disposables for cleanup
    this.disposables.push(
      activationContext.commands.registerCommand('myPlugin.cmd', {
        callback: () => {}
      })
    );
 
    this.disposables.push(
      this.context.editor.onUpdate((content) => {
        console.log('Content changed');
      })
    );
  }
 
  async deactivate() {
    // Dispose all resources
    for (const disposable of this.disposables) {
      disposable.dispose();
    }
    this.disposables = [];
  }
}

Permissions

Declare required permissions in your plugin.json:

{
  "permissions": [
    "editor:read",
    "editor:write",
    "commands:register",
    "ui:notifications",
    "filesystem:read",
    "filesystem:write",
    "network:fetch",
    "storage:read",
    "storage:write",
    "clipboard:read",
    "clipboard:write"
  ]
}

Permission Categories

CategoryPermissions
Editoreditor:read, editor:write
Commandscommands:register, commands:execute
UIui:notifications, ui:create
Filesystemfilesystem:read, filesystem:write, filesystem:delete
Networknetwork:fetch, network:websocket
Storagestorage:read, storage:write
Clipboardclipboard:read, clipboard:write

Error Handling

Always wrap API calls in try-catch blocks:

async doSomething() {
  try {
    const content = await this.context.editor.getText();
    // process content...
  } catch (error) {
    this.context.logger.error('Operation failed:', error);
    this.context.ui.showErrorMessage('Operation failed. Please try again.');
  }
}

Workspace API

Access: context.workspace

Access workspace files, folders, and active editors.

const rootPath = context.workspace?.rootPath;
const activeEditor = context.workspace?.activeTextEditor;
 
context.workspace?.onDidChangeActiveTextEditor((editor) => {
  console.log(`Editor changed: $\\{editor?.document.fileName\\}`);
});

See WorkspaceAPI Reference for complete documentation.


Configuration API

Access: context.config

Read and write plugin configuration settings.

const theme = await context.config.get('theme') ?? 'dark';
await context.config.set('theme', 'light');
 
context.config.onDidChange((e) => {
  console.log(`Config changed: ${e.key} = $\\{e.value\\}`);
});

See ConfigurationAPI Reference.


Languages API

Access: context.languages

Register language features like completion providers and formatters.

context.languages.registerCompletionProvider('markdown', {
  async provideCompletionItems(document, position) {
    return [
      { label: 'todo', insertText: '- [ ] ', detail: 'Todo item' }
    ];
  }
});

See LanguagesAPI Reference.


Terminal API

Access: context.terminal

Create and manage virtual terminals.

const terminal = context.terminal.createTerminal({
  name: 'Build',
  cwd: context.workspace?.rootPath
});
terminal.show();
terminal.sendText('npm run build');

See TerminalAPI Reference.


Task API

Access: context.tasks

Register task providers and execute automated tasks.

context.tasks.registerTaskProvider('npm', {
  async provideTasks() {
    return [
      { type: 'npm', name: 'build', command: 'npm run build' }
    ];
  }
});

See TaskAPI Reference.


Debug API

Access: context.debug

Register debug adapters and manage debugging sessions.

await context.debug.startDebugging({
  type: 'node',
  name: 'Launch App',
  request: 'launch',
  program: '${workspaceFolder}/index.js'
});

See DebugAPI Reference.


Theme API

Access: context.themes

Register custom themes and manage theme settings.

context.themes.registerTheme({
  id: 'my-theme',
  label: 'My Theme',
  uiTheme: 'vs-dark',
  colors: {
    'editor.background': '#1a1a1a',
    'editor.foreground': '#e0e0e0'
  }
});

See ThemeAPI Reference.


Next Steps