CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-theia--core

Core framework for building cloud and desktop IDE applications using modern web technologies with TypeScript and dependency injection.

Pending
Overview
Eval results
Files

events-messaging.mddocs/

Events and Messaging

Theia's event system provides type-safe event handling with emitters, async event support, cancellation tokens, and disposable subscriptions for building reactive applications.

Capabilities

Event Interface

Core event subscription interface for type-safe event handling.

/**
 * Represents an event that can be subscribed to
 */
interface Event<T> {
    /**
     * Subscribe to the event
     * @param listener - Function to call when event fires
     * @param thisArgs - Optional 'this' context for listener
     * @param disposables - Optional array to add subscription disposable to
     * @returns Disposable to unsubscribe
     */
    (listener: (e: T) => any, thisArgs?: any, disposables?: Disposable[]): Disposable;
}

Event Emitter

Creates and manages events with type safety and subscription management.

/**
 * Event emitter for firing events to subscribers
 */
class Emitter<T> {
    /**
     * The event that subscribers can listen to
     */
    readonly event: Event<T>;
    
    /**
     * Create emitter with optional configuration
     * @param options - Emitter configuration options
     */
    constructor(options?: EmitterOptions);
    
    /**
     * Fire the event to all subscribers
     * @param event - Event data to send
     */
    fire(event: T): void;
    
    /**
     * Process each listener one by one
     * @param processor - Function that processes each listener, returns false to stop
     * @returns Promise that resolves when processing is complete
     */
    sequence(processor: (listener: (e: T) => any) => MaybePromise<boolean>): Promise<void>;
    
    /**
     * Dispose the emitter and all subscriptions
     */
    dispose(): void;
}

/**
 * Configuration options for event emitters
 */
interface EmitterOptions {
    /** Called when first listener is added */
    onFirstListenerAdd?: Function;
    /** Called when last listener is removed */
    onLastListenerRemove?: Function;
    /** Threshold for memory leak warnings */
    leakWarningThreshold?: number;
}

Usage Example:

import { Emitter, Event } from "@theia/core";

class FileWatcher {
    private readonly onDidChangeEmitter = new Emitter<string>();
    
    /** Event fired when file changes */
    readonly onDidChange: Event<string> = this.onDidChangeEmitter.event;
    
    private watchFile(path: string): void {
        // File watching logic
        // When file changes:
        this.onDidChangeEmitter.fire(path);
    }
    
    dispose(): void {
        this.onDidChangeEmitter.dispose();
    }
}

// Usage
const watcher = new FileWatcher();
const subscription = watcher.onDidChange(path => {
    console.log(`File changed: ${path}`);
});

// Later: subscription.dispose();

Async Event Emitter

Handles asynchronous event processing with Promise support.

/**
 * Emitter for async events that return promises
 */
class AsyncEmitter<T> {
    readonly event: Event<T>;
    
    constructor(options?: EmitterOptions);
    
    /**
     * Fire async event and wait for all handlers
     * @param event - Event data
     * @returns Promise that resolves when all handlers complete
     */
    fireAndAwait(event: T): Promise<void>;
    
    dispose(): void;
}

Queueable Emitter

Emitter that queues events and fires them in batches.

/**
 * Emitter that can queue events and fire them as arrays
 */
class QueueableEmitter<T> extends Emitter<T[]> {
    /** Current queue of events to fire */
    currentQueue?: T[];
    
    constructor(options?: EmitterOptions);
    
    /**
     * Queue events to be fired together
     * @param arg - Events to queue
     */
    queue(...arg: T[]): void;
    
    /**
     * Fire all queued events as an array
     */
    fire(): void;
    
    dispose(): void;
}

Wait Until Event

Special event type for handling async operations with wait semantics.

/**
 * Event that allows listeners to delay completion
 */
interface WaitUntilEvent {
    /**
     * Register a promise that must complete before event finishes
     * @param thenable - Promise to wait for
     */
    waitUntil(thenable: Promise<any>): void;
}

namespace WaitUntilEvent {
    /**
     * Fire a wait-until event
     * @param emitter - Event emitter
     * @param event - Event data
     * @returns Promise that waits for all waitUntil promises
     */
    function fire<T>(emitter: Emitter<T & WaitUntilEvent>, event: T): Promise<void>;
}

Usage Example:

import { Emitter, WaitUntilEvent } from "@theia/core";

interface BeforeSaveEvent extends WaitUntilEvent {
    readonly uri: string;
}

class DocumentManager {
    private readonly onWillSaveEmitter = new Emitter<BeforeSaveEvent>();
    
    async save(uri: string): Promise<void> {
        // Fire event and wait for all handlers
        await WaitUntilEvent.fire(this.onWillSaveEmitter, { uri });
        
        // Now perform actual save
        await this.doSave(uri);
    }
    
    private async doSave(uri: string): Promise<void> {
        // Actual save implementation
    }
}

// Extensions can delay save
documentManager.onWillSave(event => {
    if (event.uri.endsWith('.ts')) {
        // Format before save
        event.waitUntil(this.formatTypeScript(event.uri));
    }
});

Cancellation System

Provides cancellation tokens for long-running operations.

/**
 * Token that signals when operation should be cancelled
 */
interface CancellationToken {
    /** True if cancellation has been requested */
    readonly isCancellationRequested: boolean;
    
    /** Event fired when cancellation is requested */
    readonly onCancellationRequested: Event<any>;
}

/**
 * Creates cancellation tokens
 */
class CancellationTokenSource {
    /** The cancellation token */
    readonly token: CancellationToken;
    
    /** Request cancellation */
    cancel(): void;
    
    /** Dispose the token source */
    dispose(): void;
}

/**
 * Error thrown when operation is cancelled
 */
class CancellationError extends Error {
    constructor();
}

/**
 * Pre-defined tokens
 */
namespace CancellationToken {
    /** Token that is never cancelled */
    const None: CancellationToken;
    
    /** Token that is already cancelled */
    const Cancelled: CancellationToken;
}

Usage Example:

import { CancellationToken, CancellationTokenSource, CancellationError } from "@theia/core";

class SearchService {
    async search(query: string, token: CancellationToken): Promise<string[]> {
        const results: string[] = [];
        
        for (let i = 0; i < 1000; i++) {
            // Check for cancellation
            if (token.isCancellationRequested) {
                throw new CancellationError();
            }
            
            // Simulate work
            await this.searchChunk(query, i);
            results.push(`result-${i}`);
        }
        
        return results;
    }
    
    private async searchChunk(query: string, chunk: number): Promise<void> {
        // Simulate async work
        await new Promise(resolve => setTimeout(resolve, 10));
    }
}

// Usage with timeout
async function searchWithTimeout(service: SearchService, query: string): Promise<string[]> {
    const source = new CancellationTokenSource();
    
    // Cancel after 5 seconds
    setTimeout(() => source.cancel(), 5000);
    
    try {
        return await service.search(query, source.token);
    } finally {
        source.dispose();
    }
}

Event Utilities

Utility functions for working with events.

namespace Event {
    /** Event that never fires */
    const None: Event<any>;
    
    /**
     * Get the maximum number of listeners for an event
     * @param event - Event to check
     * @returns Maximum listeners count
     */
    function getMaxListeners(event: Event<unknown>): number;
    
    /**
     * Set the maximum number of listeners for an event
     * @param event - Event to configure
     * @param maxListeners - Maximum listeners count
     * @returns The set maximum listeners count
     */
    function setMaxListeners<N extends number>(event: Event<unknown>, maxListeners: N): N;
    
    /**
     * Add to the maximum number of listeners for an event
     * @param event - Event to configure
     * @param add - Number to add to current max
     * @returns New maximum listeners count
     */
    function addMaxListeners(event: Event<unknown>, add: number): number;
    
    /**
     * Create event that fires only once
     * @param event - Source event
     * @returns Event that fires once then disposes
     */
    function once<T>(event: Event<T>): Event<T>;
    
    /**
     * Convert event to promise that resolves on first emission
     * @param event - Source event
     * @returns Promise that resolves with event data
     */
    function toPromise<T>(event: Event<T>): Promise<T>;
    
    /**
     * Transform event data
     * @param event - Source event
     * @param map - Transformation function
     * @returns Event with transformed data
     */
    function map<I, O>(event: Event<I>, map: (i: I) => O): Event<O>;
    
    /**
     * Filter event data
     * @param event - Source event
     * @param filter - Filter predicate
     * @returns Event that only fires when filter returns true
     */
    function filter<T>(event: Event<T>, filter: (e: T) => boolean): Event<T>;
    
    /**
     * Combine multiple events into single event
     * @param events - Array of events to combine
     * @returns Event that fires when any source event fires
     */
    function any<T>(...events: Event<T>[]): Event<T>;
    function any(...events: Event<any>[]): Event<void>;
    
    /**
     * Debounce event firing
     * @param event - Source event
     * @param delay - Debounce delay in milliseconds
     * @returns Debounced event
     */
    function debounce<T>(event: Event<T>, delay: number): Event<T>;
}

Usage Example:

import { Event } from "@theia/core";

class ConfigurationWatcher {
    private readonly onDidChangeEmitter = new Emitter<string>();
    
    // Transform and filter events
    readonly onImportantConfigChange = Event.filter(
        Event.map(this.onDidChangeEmitter.event, path => path.toLowerCase()),
        path => path.includes('important')
    );
    
    // Debounced events for high-frequency changes
    readonly onConfigChangeDebounced = Event.debounce(
        this.onDidChangeEmitter.event,
        500 // 500ms debounce
    );
}

Message Service

High-level service for displaying user messages and dialogs.

/**
 * Service for showing messages to users
 */
interface MessageService {
    /**
     * Show info message
     * @param message - Message text
     * @param actions - Optional actions
     * @returns Promise resolving to selected action
     */
    info(message: string, ...actions: string[]): Promise<string | undefined>;
    
    /**
     * Show warning message
     * @param message - Message text
     * @param actions - Optional actions
     * @returns Promise resolving to selected action
     */
    warn(message: string, ...actions: string[]): Promise<string | undefined>;
    
    /**
     * Show error message
     * @param message - Message text
     * @param actions - Optional actions
     * @returns Promise resolving to selected action
     */
    error(message: string, ...actions: string[]): Promise<string | undefined>;
}

/**
 * Service token for MessageService
 */
const MessageService: symbol;

Types

type EventListener<T> = (e: T) => any;

type MaybePromise<T> = T | Promise<T>;

interface Disposable {
    dispose(): void;
}

interface DisposableCollection extends Disposable {
    push(disposable: Disposable): Disposable;
}

Install with Tessl CLI

npx tessl i tessl/npm-theia--core

docs

application-framework.md

commands.md

dependency-injection.md

events-messaging.md

index.md

keybindings.md

menus.md

preferences-configuration.md

resources-files.md

widgets-ui.md

tile.json