deploy: current vibn theia state
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled

Made-with: Cursor
This commit is contained in:
2026-02-27 12:01:08 -08:00
commit 8bb5110148
3782 changed files with 640947 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
// *****************************************************************************
// Copyright (C) 2018 Red Hat, Inc. and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Some entities copied and modified from https://github.com/Microsoft/vscode-debugadapter-node/blob/master/adapter/src/protocol.ts
import * as net from 'net';
import { injectable, inject } from '@theia/core/shared/inversify';
import {
RawProcessFactory,
ProcessManager,
RawProcess,
RawForkOptions,
RawProcessOptions
} from '@theia/process/lib/node';
import {
DebugAdapterExecutable,
DebugAdapterSession,
DebugAdapterSessionFactory,
DebugAdapterFactory,
DebugAdapterForkExecutable,
DebugAdapter
} from '../common/debug-model';
import { DebugAdapterSessionImpl } from '../common/debug-adapter-session';
import { environment } from '@theia/core/shared/@theia/application-package';
import { ProcessDebugAdapter, SocketDebugAdapter } from './stream-debug-adapter';
import { isObject } from '@theia/core/lib/common';
/**
* [DebugAdapterFactory](#DebugAdapterFactory) implementation based on
* launching the debug adapter as separate process.
*/
@injectable()
export class LaunchBasedDebugAdapterFactory implements DebugAdapterFactory {
@inject(RawProcessFactory)
protected readonly processFactory: RawProcessFactory;
@inject(ProcessManager)
protected readonly processManager: ProcessManager;
start(executable: DebugAdapterExecutable): DebugAdapter {
const process = this.childProcess(executable);
if (!process.process) {
throw new Error(`Could not start debug adapter process: ${JSON.stringify(executable)}`);
}
// FIXME: propagate onError + onExit
const provider = new ProcessDebugAdapter(process.process);
return provider;
}
private childProcess(executable: DebugAdapterExecutable): RawProcess {
const isForkOptions = (forkOptions: unknown): forkOptions is RawForkOptions =>
isObject(forkOptions) && 'modulePath' in forkOptions;
const processOptions: RawProcessOptions | RawForkOptions = { ...executable };
const options: { stdio: (string | number)[], env?: object, execArgv?: string[] } = { stdio: ['pipe', 'pipe', 2] };
if (isForkOptions(processOptions)) {
options.stdio.push('ipc');
options.env = environment.electron.runAsNodeEnv();
options.execArgv = (executable as DebugAdapterForkExecutable).execArgv;
}
processOptions.options = options;
return this.processFactory(processOptions);
}
connect(debugServerPort: number): DebugAdapter {
const socket = net.createConnection(debugServerPort);
// FIXME: propagate socket.on('error', ...) + socket.on('close', ...)
const provider = new SocketDebugAdapter(socket);
return provider;
}
}
/**
* [DebugAdapterSessionFactory](#DebugAdapterSessionFactory) implementation.
*/
@injectable()
export class DebugAdapterSessionFactoryImpl implements DebugAdapterSessionFactory {
get(sessionId: string, debugAdapter: DebugAdapter): DebugAdapterSession {
return new DebugAdapterSessionImpl(
sessionId,
debugAdapter
);
}
}

View File

@@ -0,0 +1,106 @@
// *****************************************************************************
// Copyright (C) 2018 Red Hat, Inc. and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { UUID } from '@theia/core/shared/@lumino/coreutils';
import { injectable, inject } from '@theia/core/shared/inversify';
import { MessagingService } from '@theia/core/lib/node/messaging/messaging-service';
import { DebugAdapterPath, ForwardingDebugChannel } from '../common/debug-service';
import { DebugConfiguration } from '../common/debug-configuration';
import { DebugAdapterSession, DebugAdapterSessionFactory, DebugAdapterFactory } from '../common/debug-model';
import { DebugAdapterContributionRegistry } from '../common/debug-adapter-contribution-registry';
/**
* Debug adapter session manager.
*/
@injectable()
export class DebugAdapterSessionManager implements MessagingService.Contribution {
protected readonly sessions = new Map<string, DebugAdapterSession>();
@inject(DebugAdapterSessionFactory)
protected readonly debugAdapterSessionFactory: DebugAdapterSessionFactory;
@inject(DebugAdapterFactory)
protected readonly debugAdapterFactory: DebugAdapterFactory;
configure(service: MessagingService): void {
service.registerChannelHandler(`${DebugAdapterPath}/:id`, ({ id }: { id: string }, wsChannel) => {
const session = this.find(id);
if (!session) {
wsChannel.close();
return;
}
session.start(new ForwardingDebugChannel(wsChannel));
});
}
/**
* Creates a new [debug adapter session](#DebugAdapterSession).
* @param config The [DebugConfiguration](#DebugConfiguration)
* @returns The debug adapter session
*/
async create(config: DebugConfiguration, registry: DebugAdapterContributionRegistry): Promise<DebugAdapterSession> {
const sessionId = UUID.uuid4();
let communicationProvider;
if ('debugServer' in config) {
communicationProvider = this.debugAdapterFactory.connect(config.debugServer);
} else {
const executable = await registry.provideDebugAdapterExecutable(config);
communicationProvider = this.debugAdapterFactory.start(executable);
}
const sessionFactory = registry.debugAdapterSessionFactory(config.type) || this.debugAdapterSessionFactory;
const session = sessionFactory.get(sessionId, communicationProvider);
this.sessions.set(sessionId, session);
if (config.parentSession) {
const parentSession = this.sessions.get(config.parentSession.id);
if (parentSession) {
session.parentSession = parentSession;
}
}
return session;
}
/**
* Removes [debug adapter session](#DebugAdapterSession) from the list of the instantiated sessions.
* Is invoked when session is terminated and isn't needed anymore.
* @param sessionId The session identifier
*/
remove(sessionId: string): void {
this.sessions.delete(sessionId);
}
/**
* Finds the debug adapter session by its id.
* Returning the value 'undefined' means the session isn't found.
* @param sessionId The session identifier
* @returns The debug adapter session
*/
find(sessionId: string): DebugAdapterSession | undefined {
return this.sessions.get(sessionId);
}
/**
* Returns all instantiated debug adapter sessions.
* @returns An array of debug adapter sessions
*/
getAll(): IterableIterator<DebugAdapterSession> {
return this.sessions.values();
}
}

View File

@@ -0,0 +1,57 @@
// *****************************************************************************
// Copyright (C) 2018 Red Hat, Inc. and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { bindContributionProvider } from '@theia/core/lib/common';
import { ContainerModule } from '@theia/core/shared/inversify';
import {
DebugPath,
DebugService
} from '../common/debug-service';
import {
LaunchBasedDebugAdapterFactory,
DebugAdapterSessionFactoryImpl
} from './debug-adapter-factory';
import { MessagingService } from '@theia/core/lib/node/messaging/messaging-service';
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
import {
DebugAdapterContribution,
DebugAdapterSessionFactory,
DebugAdapterFactory
} from '../common/debug-model';
import { DebugServiceImpl } from './debug-service-impl';
import { DebugAdapterContributionRegistry } from '../common/debug-adapter-contribution-registry';
import { DebugAdapterSessionManager } from './debug-adapter-session-manager';
import { bindDebugPreferences } from '../common/debug-preferences';
import { bindLaunchPreferences } from '../common/launch-preferences';
const debugConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
bindContributionProvider(bind, DebugAdapterContribution);
bind(DebugAdapterContributionRegistry).toSelf().inSingletonScope();
bind(DebugService).to(DebugServiceImpl).inSingletonScope();
bindBackendService(DebugPath, DebugService);
});
export default new ContainerModule(bind => {
bind(ConnectionContainerModule).toConstantValue(debugConnectionModule);
bind(DebugAdapterSessionFactory).to(DebugAdapterSessionFactoryImpl).inSingletonScope();
bind(DebugAdapterFactory).to(LaunchBasedDebugAdapterFactory).inSingletonScope();
bind(DebugAdapterSessionManager).toSelf().inSingletonScope();
bind(MessagingService.Contribution).toService(DebugAdapterSessionManager);
bindDebugPreferences(bind);
bindLaunchPreferences(bind);
});

View File

@@ -0,0 +1,119 @@
// *****************************************************************************
// Copyright (C) 2018 Red Hat, Inc. and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { injectable, inject } from '@theia/core/shared/inversify';
import { DebugConfiguration } from '../common/debug-configuration';
import { DebugService, DebuggerDescription } from '../common/debug-service';
import { IJSONSchema, IJSONSchemaSnippet } from '@theia/core/lib/common/json-schema';
import { CommandIdVariables } from '@theia/variable-resolver/lib/common/variable-types';
import { DebugAdapterSessionManager } from './debug-adapter-session-manager';
import { DebugAdapterContributionRegistry } from '../common/debug-adapter-contribution-registry';
import { Event } from '@theia/core';
/**
* DebugService implementation.
*/
@injectable()
export class DebugServiceImpl implements DebugService {
@inject(DebugAdapterSessionManager)
protected readonly sessionManager: DebugAdapterSessionManager;
@inject(DebugAdapterContributionRegistry)
protected readonly registry: DebugAdapterContributionRegistry;
get onDidChangeDebugConfigurationProviders(): Event<void> {
return Event.None;
}
dispose(): void {
this.terminateDebugSession();
}
async debugTypes(): Promise<string[]> {
return this.registry.debugTypes();
}
getDebuggersForLanguage(language: string): Promise<DebuggerDescription[]> {
return this.registry.getDebuggersForLanguage(language);
}
getSchemaAttributes(debugType: string): Promise<IJSONSchema[]> {
return this.registry.getSchemaAttributes(debugType);
}
getConfigurationSnippets(): Promise<IJSONSchemaSnippet[]> {
return this.registry.getConfigurationSnippets();
}
async provideDebuggerVariables(debugType: string): Promise<CommandIdVariables> {
// TODO: Support resolution of variables map through Theia extensions?
return {};
}
async provideDebugConfigurations(debugType: string, workspaceFolderUri?: string): Promise<DebugConfiguration[]> {
return this.registry.provideDebugConfigurations(debugType, workspaceFolderUri);
}
async provideDynamicDebugConfigurations(): Promise<Record<string, DebugConfiguration[]>> {
// TODO: Support dynamic debug configurations through Theia extensions?
return {};
}
fetchDynamicDebugConfiguration(name: string, type: string, folder?: string): Promise<DebugConfiguration | undefined> {
// TODO: Support dynamic debug configurations through Theia extensions?
return Promise.resolve(undefined);
}
async resolveDebugConfiguration(config: DebugConfiguration, workspaceFolderUri?: string): Promise<DebugConfiguration> {
return this.registry.resolveDebugConfiguration(config, workspaceFolderUri);
}
async resolveDebugConfigurationWithSubstitutedVariables(config: DebugConfiguration, workspaceFolderUri?: string): Promise<DebugConfiguration> {
return this.registry.resolveDebugConfigurationWithSubstitutedVariables(config, workspaceFolderUri);
}
protected readonly sessions = new Set<string>();
async createDebugSession(config: DebugConfiguration, _workspaceFolderUri?: string): Promise<string> {
const session = await this.sessionManager.create(config, this.registry);
this.sessions.add(session.id);
return session.id;
}
async terminateDebugSession(sessionId?: string): Promise<void> {
if (sessionId) {
await this.doStop(sessionId);
} else {
const promises: Promise<void>[] = [];
const sessions = [...this.sessions];
this.sessions.clear();
for (const session of sessions) {
promises.push((async () => {
try {
await this.doStop(session);
} catch (e) {
console.error('terminateDebugSession failed:', e);
}
})());
}
await Promise.all(promises);
}
}
protected async doStop(sessionId: string): Promise<void> {
const debugSession = this.sessionManager.find(sessionId);
if (debugSession) {
this.sessionManager.remove(sessionId);
this.sessions.delete(sessionId);
await debugSession.stop();
}
}
}

View File

@@ -0,0 +1,126 @@
// *****************************************************************************
// Copyright (C) 2021 Red Hat, Inc. and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { Emitter, Event } from '@theia/core/lib/common/event';
import { ChildProcess } from 'child_process';
import * as stream from 'stream';
import * as net from 'net';
import { DebugAdapter } from '../common/debug-model';
abstract class StreamDebugAdapter extends DisposableCollection {
private messageReceivedEmitter = new Emitter<string>();
onMessageReceived: Event<string> = this.messageReceivedEmitter.event;
private errorEmitter = new Emitter<Error>();
onError: Event<Error> = this.errorEmitter.event;
private closeEmitter = new Emitter<void>();
onClose: Event<void> = this.closeEmitter.event;
// these constants are for the message header, see: https://microsoft.github.io/debug-adapter-protocol/overview#header-part
private static TWO_CRLF = '\r\n\r\n';
private static CONTENT_LENGTH = 'Content-Length';
private contentLength: number = -1;
private buffer: Buffer = Buffer.alloc(0);
constructor(private fromAdapter: stream.Readable, private toAdapter: stream.Writable) {
super();
this.fromAdapter.on('data', (data: Buffer) => this.handleData(data));
this.fromAdapter.on('close', () => this.handleClosed()); // FIXME pass a proper exit code
this.fromAdapter.on('error', error => this.errorEmitter.fire(error));
this.toAdapter.on('error', error => this.errorEmitter.fire(error));
}
handleClosed(): void {
this.closeEmitter.fire();
}
send(message: string): void {
const msg = `${StreamDebugAdapter.CONTENT_LENGTH}: ${Buffer.byteLength(message, 'utf8')}${StreamDebugAdapter.TWO_CRLF}${message}`;
this.toAdapter.write(msg, 'utf8');
}
protected handleData(data: Buffer): void {
this.buffer = Buffer.concat([this.buffer, data]);
while (true) {
if (this.contentLength >= 0) {
if (this.buffer.length >= this.contentLength) {
const message = this.buffer.toString('utf8', 0, this.contentLength);
this.buffer = this.buffer.slice(this.contentLength);
this.contentLength = -1;
if (message.length > 0) {
this.messageReceivedEmitter.fire(message);
}
continue; // there may be more complete messages to process
}
} else {
let idx = this.buffer.indexOf(StreamDebugAdapter.CONTENT_LENGTH);
if (idx > 0) {
// log unrecognized output
const output = this.buffer.slice(0, idx);
console.log(output.toString('utf-8'));
this.buffer = this.buffer.slice(idx);
}
idx = this.buffer.indexOf(StreamDebugAdapter.TWO_CRLF);
if (idx !== -1) {
const header = this.buffer.toString('utf8', 0, idx);
const lines = header.split('\r\n');
for (let i = 0; i < lines.length; i++) {
const pair = lines[i].split(/: +/);
if (pair[0] === StreamDebugAdapter.CONTENT_LENGTH) {
this.contentLength = +pair[1];
}
}
this.buffer = this.buffer.slice(idx + StreamDebugAdapter.TWO_CRLF.length);
continue;
}
}
break;
}
}
}
export class ProcessDebugAdapter extends StreamDebugAdapter implements DebugAdapter {
protected readonly process: ChildProcess;
constructor(process: ChildProcess) {
super(process.stdout!, process.stdin!);
this.process = process;
}
async stop(): Promise<void> {
this.process.kill();
this.process.stdin?.end();
}
}
export class SocketDebugAdapter extends StreamDebugAdapter implements DebugAdapter {
private readonly socket: net.Socket;
constructor(socket: net.Socket) {
super(socket, socket);
this.socket = socket;
}
stop(): Promise<void> {
return new Promise<void>(resolve => {
this.socket.end(() => resolve());
});
}
}