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:
| API | Access | Purpose | Full Docs |
|---|---|---|---|
| EditorAPI | context.editor | TipTap editor (95+ methods) | View |
| UIAPI | context.ui | UI components & notifications | View |
| CommandsAPI | context.commands | Command registration | View |
| WorkspaceAPI | context.workspace | File and editor access | View |
| ConfigurationAPI | context.config | Plugin settings | View |
| LanguagesAPI | context.languages | Language features | View |
| TerminalAPI | context.terminal | Terminal management | View |
| TaskAPI | context.tasks | Task execution | View |
| DebugAPI | context.debug | Debugging sessions | View |
| ThemeAPI | context.themes | Theme management | View |
| StorageAPI | context.storage | Data persistence | View |
| FilesystemAPI | context.fs | File operations | View |
| NetworkAPI | context.network | HTTP requests | View |
| ClipboardAPI | context.clipboard | Clipboard access | View |
| Logger | context.logger | Logging and debugging | Built-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[]): voidExample
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): voidshowWarningMessage()
Show a warning notification.
context.ui.showWarningMessage(message: string): voidshowErrorMessage()
Show an error notification.
context.ui.showErrorMessage(message: string): voidshowInputBox()
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): DisposableExample
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
| Category | Permissions |
|---|---|
| Editor | editor:read, editor:write |
| Commands | commands:register, commands:execute |
| UI | ui:notifications, ui:create |
| Filesystem | filesystem:read, filesystem:write, filesystem:delete |
| Network | network:fetch, network:websocket |
| Storage | storage:read, storage:write |
| Clipboard | clipboard: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' }
];
}
});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');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
- Complete API Reference - Detailed documentation for all APIs
- Getting Started - Create your first plugin
- Plugin Manifest - Manifest reference
- Plugin Lifecycle - Activation and resource management
- Publishing - Publish to the marketplace