CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-theia--workspace

Theia workspace extension providing workspace functionality and services for Eclipse Theia IDE framework

Pending
Overview
Eval results
Files

workspace-server.mddocs/

Workspace Server

The workspace server provides backend workspace management functionality including workspace persistence, recent workspace tracking, and server-side workspace operations. It operates over JSON-RPC and handles workspace state across application sessions.

Capabilities

Core Workspace Server Protocol

The main server interface for workspace operations exposed over JSON-RPC.

/**
 * JSON-RPC endpoint path for workspace service
 */
const workspacePath = '/services/workspace';

/**
 * Workspace server interface for backend workspace operations
 */
interface WorkspaceServer {
  /**
   * Returns the most recently used workspace folder URI as a string
   */
  getMostRecentlyUsedWorkspace(): Promise<string | undefined>;
  
  /**
   * Sets the desired URI as the most recently used workspace folder
   * @param uri - String representation of the workspace URI
   */
  setMostRecentlyUsedWorkspace(uri: string): Promise<void>;
  
  /**
   * Removes a workspace from the list of recently opened workspaces
   * @param uri - The workspace URI to remove
   */
  removeRecentWorkspace(uri: string): Promise<void>;
  
  /**
   * Returns list of recently opened workspaces as an array
   */
  getRecentWorkspaces(): Promise<string[]>;
}

Usage Example:

import { injectable, inject } from "@theia/core/shared/inversify";
import { WorkspaceServer } from "@theia/workspace/lib/common";

@injectable()
export class MyWorkspaceClient {
  
  @inject(WorkspaceServer)
  protected readonly workspaceServer: WorkspaceServer;

  async displayRecentWorkspaces(): Promise<void> {
    // Get recent workspaces
    const recentWorkspaces = await this.workspaceServer.getRecentWorkspaces();
    console.log("Recent workspaces:", recentWorkspaces);
    
    // Get most recently used
    const mostRecent = await this.workspaceServer.getMostRecentlyUsedWorkspace();
    if (mostRecent) {
      console.log("Most recent workspace:", mostRecent);
    }
  }

  async setCurrentWorkspace(workspaceUri: string): Promise<void> {
    // Set as most recently used
    await this.workspaceServer.setMostRecentlyUsedWorkspace(workspaceUri);
    console.log(`Set ${workspaceUri} as most recent workspace`);
  }

  async cleanupOldWorkspace(workspaceUri: string): Promise<void> {
    // Remove from recent list
    await this.workspaceServer.removeRecentWorkspace(workspaceUri);
    console.log(`Removed ${workspaceUri} from recent workspaces`);
  }
}

Default Workspace Server Implementation

Backend implementation that handles persistence and workspace lifecycle management.

class DefaultWorkspaceServer implements WorkspaceServer, BackendApplicationContribution {
  /**
   * Threshold for untitled workspace cleanup (days)
   */
  protected readonly untitledWorkspaceStaleThreshold: number;
  
  /**
   * Backend application lifecycle - called on server start
   */
  onStart(): void;
  
  /**
   * Get most recently used workspace (implements WorkspaceServer)
   */
  getMostRecentlyUsedWorkspace(): Promise<string | undefined>;
  
  /**
   * Set most recently used workspace and persist to storage
   */
  setMostRecentlyUsedWorkspace(rawUri: string): Promise<void>;
  
  /**
   * Remove workspace from recent list and update storage
   */
  removeRecentWorkspace(rawUri: string): Promise<void>;
  
  /**
   * Get filtered list of recent workspaces that still exist
   */
  getRecentWorkspaces(): Promise<string[]>;
}

Usage Example:

import { injectable, inject } from "@theia/core/shared/inversify";
import { DefaultWorkspaceServer } from "@theia/workspace/lib/node";

@injectable()
export class MyWorkspaceManager {
  
  @inject(DefaultWorkspaceServer)
  protected readonly workspaceServer: DefaultWorkspaceServer;

  async initializeWorkspace(): Promise<void> {
    // The server automatically handles:
    // - Loading recent workspaces from ~/.config/theia/recentworkspace.json
    // - Validating that workspaces still exist
    // - Cleaning up old untitled workspaces (older than 10 days by default)
    // - Processing CLI workspace arguments
    
    const mostRecent = await this.workspaceServer.getMostRecentlyUsedWorkspace();
    if (mostRecent) {
      console.log(`Restoring workspace: ${mostRecent}`);
    }
  }
}

CLI Integration

Service for handling workspace arguments from the command line.

class WorkspaceCliContribution implements CliContribution {
  /**
   * Deferred workspace root from CLI arguments
   */
  readonly workspaceRoot: Deferred<string | undefined>;
  
  /**
   * Configure CLI argument parsing for workspace options
   */
  configure(conf: yargs.Argv): void;
  
  /**
   * Process parsed CLI arguments and set workspace
   */
  setArguments(args: yargs.Arguments): Promise<void>;
  
  /**
   * Normalize workspace argument to proper format
   */
  protected normalizeWorkspaceArg(raw: string): string;
  
  /**
   * Build untitled workspace for multiple directory arguments
   */
  protected buildWorkspaceForMultipleArguments(workspaceArguments: string[]): Promise<string | undefined>;
}

Usage Example:

import { injectable, inject } from "@theia/core/shared/inversify";
import { WorkspaceCliContribution } from "@theia/workspace/lib/node";

@injectable()
export class MyApplicationContribution {
  
  @inject(WorkspaceCliContribution)
  protected readonly cliContribution: WorkspaceCliContribution;

  async handleStartup(): Promise<void> {
    // Wait for CLI processing to complete
    const workspaceFromCli = await this.cliContribution.workspaceRoot.promise;
    
    if (workspaceFromCli) {
      console.log(`Opening workspace from CLI: ${workspaceFromCli}`);
      // The CLI contribution handles:
      // - Single directory arguments
      // - Multiple directory arguments (creates untitled workspace)
      // - Workspace file arguments
      // - Legacy --root-dir flag
    }
  }
}

// CLI usage examples:
// theia /path/to/workspace
// theia /path/to/project1 /path/to/project2  # Creates untitled workspace
// theia workspace.theia-workspace
// theia --root-dir=/legacy/path  # Deprecated but supported

Extension Points

Interfaces for extending workspace server functionality with custom handlers.

/**
 * Extension point for custom workspace handlers
 */
interface WorkspaceHandlerContribution {
  /**
   * Check if this handler can handle the given URI scheme/format
   */
  canHandle(uri: URI): boolean;
  
  /**
   * Check if the workspace still exists and is accessible
   */
  workspaceStillExists(uri: URI): Promise<boolean>;
}

/**
 * Default file system workspace handler
 */
class FileWorkspaceHandlerContribution implements WorkspaceHandlerContribution {
  /**
   * Handles file:// scheme URIs
   */
  canHandle(uri: URI): boolean;
  
  /**
   * Check if file/directory exists on disk
   */
  workspaceStillExists(uri: URI): Promise<boolean>;
}

Usage Example:

import { injectable } from "@theia/core/shared/inversify";
import { WorkspaceHandlerContribution } from "@theia/workspace/lib/node";
import URI from "@theia/core/lib/common/uri";

@injectable()
export class RemoteWorkspaceHandler implements WorkspaceHandlerContribution {
  
  canHandle(uri: URI): boolean {
    // Handle custom remote workspace schemes
    return uri.scheme === 'ssh' || uri.scheme === 'ftp';
  }
  
  async workspaceStillExists(uri: URI): Promise<boolean> {
    // Custom logic to check remote workspace availability
    if (uri.scheme === 'ssh') {
      return this.checkSshWorkspace(uri);
    } else if (uri.scheme === 'ftp') {
      return this.checkFtpWorkspace(uri);
    }
    return false;
  }

  private async checkSshWorkspace(uri: URI): Promise<boolean> {
    // Implementation for SSH workspace validation
    try {
      // SSH connection logic here
      return true;
    } catch {
      return false;
    }
  }

  private async checkFtpWorkspace(uri: URI): Promise<boolean> {
    // Implementation for FTP workspace validation
    try {
      // FTP connection logic here
      return true;
    } catch {
      return false;
    }
  }
}

// Register the custom handler in your module:
// bind(WorkspaceHandlerContribution).to(RemoteWorkspaceHandler).inSingletonScope();

Recent Workspace Data Management

Data structures and utilities for managing workspace persistence.

interface RecentWorkspacePathsData {
  /** Array of recent workspace URI strings */
  recentRoots: string[];
}

namespace RecentWorkspacePathsData {
  /**
   * Create RecentWorkspacePathsData from unknown data with validation
   */
  function create(data: unknown): RecentWorkspacePathsData | undefined;
}

Usage Example:

import { RecentWorkspacePathsData } from "@theia/workspace/lib/node";
import * as fs from "fs-extra";

export class WorkspaceStorageManager {
  
  private readonly recentWorkspacesPath = "~/.config/theia/recentworkspace.json";

  async loadRecentWorkspaces(): Promise<string[]> {
    try {
      const data = await fs.readJson(this.recentWorkspacesPath);
      const workspaceData = RecentWorkspacePathsData.create(data);
      return workspaceData?.recentRoots || [];
    } catch {
      return [];
    }
  }

  async saveRecentWorkspaces(workspaces: string[]): Promise<void> {
    const data: RecentWorkspacePathsData = {
      recentRoots: workspaces
    };
    await fs.ensureDir(path.dirname(this.recentWorkspacesPath));
    await fs.writeJson(this.recentWorkspacesPath, data, { spaces: 2 });
  }

  async addRecentWorkspace(workspace: string): Promise<void> {
    const recent = await this.loadRecentWorkspaces();
    
    // Remove if already exists (to move to front)
    const filtered = recent.filter(w => w !== workspace);
    
    // Add to front and limit to reasonable number
    const updated = [workspace, ...filtered].slice(0, 10);
    
    await this.saveRecentWorkspaces(updated);
  }
}

Server Configuration and Lifecycle

The workspace server integrates with Theia's backend application lifecycle and provides automatic cleanup and maintenance.

Key Features:

  • Automatic Cleanup: Removes untitled workspaces older than configurable threshold (default: 10 days)
  • Persistence: Stores recent workspaces in user config directory
  • Validation: Checks workspace existence before returning in recent list
  • CLI Integration: Processes command-line workspace arguments
  • Extension Support: Pluggable workspace handlers for different URI schemes

Types

interface RecentWorkspacePathsData {
  recentRoots: string[];
}

interface WorkspaceHandlerContribution {
  canHandle(uri: URI): boolean;
  workspaceStillExists(uri: URI): Promise<boolean>;
}

interface CliContribution {
  configure(conf: yargs.Argv): void;
  setArguments(args: yargs.Arguments): Promise<void>;
}

interface BackendApplicationContribution {
  initialize?(): void;
  configure?(app: Application): void;
  onStart?(server?: http.Server): void;
  onStop?(app?: Application): void;
}

const workspacePath: string; // '/services/workspace'
const WorkspaceServer: symbol;
const WorkspaceHandlerContribution: symbol;

type Deferred<T> = {
  readonly promise: Promise<T>;
  resolve(value: T): void;
  reject(reason?: any): void;
};

Install with Tessl CLI

npx tessl i tessl/npm-theia--workspace

docs

extension-points.md

index.md

workspace-commands.md

workspace-file-handling.md

workspace-preferences.md

workspace-server.md

workspace-service.md

tile.json