Skip to content

Commit

Permalink
Add vscode API DebugSessionOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew committed Jul 5, 2021
1 parent 3bd43c9 commit 2ee44b4
Show file tree
Hide file tree
Showing 21 changed files with 359 additions and 53 deletions.
107 changes: 107 additions & 0 deletions packages/console/src/browser/console-session-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/********************************************************************************
* Copyright (C) 2021 TypeFox 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 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable } from '@theia/core/shared/inversify';
import { Emitter, Disposable, DisposableCollection } from '@theia/core';
import { ConsoleSession } from './console-session';
import { Severity } from '@theia/core/lib/common/severity';

@injectable()
export class ConsoleSessionManager implements Disposable {

protected readonly sessions = new Map<string, ConsoleSession>();
protected _selectedSession: ConsoleSession | undefined;
protected _severity: Severity | undefined;

protected readonly sessionAddedEmitter = new Emitter<ConsoleSession>();
protected readonly sessionDeletedEmitter = new Emitter<ConsoleSession>();
protected readonly sessionWasShownEmitter = new Emitter<ConsoleSession>();
protected readonly sessionWasHiddenEmitter = new Emitter<ConsoleSession>();
protected readonly selectedSessionChangedEmitter = new Emitter<ConsoleSession | undefined>();
protected readonly severityChangedEmitter = new Emitter<void>();

readonly onSessionAdded = this.sessionAddedEmitter.event;
readonly onSessionDeleted = this.sessionDeletedEmitter.event;
readonly onSessionWasShown = this.sessionWasShownEmitter.event;
readonly onSessionWasHidden = this.sessionWasHiddenEmitter.event;
readonly onSelectedSessionChanged = this.selectedSessionChangedEmitter.event;
readonly onSeverityChanged = this.severityChangedEmitter.event;

protected readonly toDispose = new DisposableCollection();
protected readonly toDisposeOnSessionDeletion = new Map<string, Disposable>();

dispose(): void {
this.toDispose.dispose();
}

get severity(): Severity | undefined {
return this._severity;
}

set severity(value: Severity | undefined) {
value = value || Severity.Ignore;
this._severity = value;
for (const session of this.sessions.values()) {
session.severity = value;
}
this.severityChangedEmitter.fire(undefined);
}

get all(): ConsoleSession[] {
return Array.from(this.sessions.values());
}

get selectedSession(): ConsoleSession | undefined {
return this._selectedSession;
}

set selectedSession(session: ConsoleSession | undefined) {
const oldSession = this.selectedSession;
this._selectedSession = session;
this.selectedSessionChangedEmitter.fire(session);
if (oldSession !== session) {
if (oldSession) {
this.sessionWasHiddenEmitter.fire(oldSession);
}
if (session) {
this.sessionWasShownEmitter.fire(session);
}
}
}

get(id: string): ConsoleSession | undefined {
return this.sessions.get(id);
}

add(session: ConsoleSession): void {
this.sessions.set(session.id, session);
this.sessionAddedEmitter.fire(session);
if (this.sessions.size === 1) {
this.selectedSession = session;
}
}

delete(id: string): void {
const session = this.sessions.get(id);
if (this.sessions.delete(id) && session) {
this.sessionDeletedEmitter.fire(session);
if (this.sessions.size === 0) {
this.selectedSessionChangedEmitter.fire(undefined);
}
}
}

}
1 change: 1 addition & 0 deletions packages/console/src/browser/console-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export abstract class ConsoleSession extends TreeSource {
protected selectedSeverity?: Severity;
protected readonly selectionEmitter: Emitter<void> = new Emitter<void>();
readonly onSelectionChange = this.selectionEmitter.event;
id: string;

get severity(): Severity | undefined {
return this.selectedSeverity;
Expand Down
11 changes: 11 additions & 0 deletions packages/console/src/browser/console-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { MonacoEditorProvider } from '@theia/monaco/lib/browser/monaco-editor-pr
import { ConsoleHistory } from './console-history';
import { ConsoleContentWidget } from './console-content-widget';
import { ConsoleSession } from './console-session';
import { ConsoleSessionManager } from './console-session-manager';

export const ConsoleOptions = Symbol('ConsoleWidgetOptions');
export interface ConsoleOptions {
Expand Down Expand Up @@ -67,6 +68,9 @@ export class ConsoleWidget extends BaseWidget implements StatefulWidget {
@inject(ConsoleHistory)
protected readonly history: ConsoleHistory;

@inject(ConsoleSessionManager)
protected readonly sessionManager: ConsoleSessionManager;

@inject(MonacoEditorProvider)
protected readonly editorProvider: MonacoEditorProvider;

Expand Down Expand Up @@ -109,6 +113,13 @@ export class ConsoleWidget extends BaseWidget implements StatefulWidget {
}
}));

this.toDispose.push(this.sessionManager.onSelectedSessionChanged(session => {
// Don't delete the last session by overriding it with 'undefined'
if (session) {
this.session = session;
}
}));

this.updateFont();
if (inputFocusContextKey) {
this.toDispose.push(input.onFocusChanged(() => inputFocusContextKey.set(this.hasInputFocus())));
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ button.secondary[disabled], .theia-button.secondary[disabled] {
border: 1px solid var(--theia-dropdown-border);
background: var(--theia-dropdown-background);
outline: none;
margin-left: calc(var(--theia-ui-padding));
}

.theia-select option {
Expand Down
98 changes: 85 additions & 13 deletions packages/debug/src/browser/console/debug-console-contribution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { ConsoleSessionManager } from '@theia/console/lib/browser/console-session-manager';
import { ConsoleOptions, ConsoleWidget } from '@theia/console/lib/browser/console-widget';
import { AbstractViewContribution, bindViewContribution, Widget, WidgetFactory } from '@theia/core/lib/browser';
import { ContextKey, ContextKeyService } from '@theia/core/lib/browser/context-key-service';
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { Command, CommandRegistry } from '@theia/core/lib/common/command';
import { Severity } from '@theia/core/lib/common/severity';
import { inject, injectable, interfaces } from '@theia/core/shared/inversify';
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { DebugConsoleSession } from './debug-console-session';
import { DebugConsoleMode } from '../../common/debug-configuration';
import { DebugSession } from '../debug-session';
import { DebugSessionManager } from '../debug-session-manager';
import { DebugConsoleSession, DebugConsoleSessionFactory } from './debug-console-session';

export type InDebugReplContextKey = ContextKey<boolean>;
export const InDebugReplContextKey = Symbol('inDebugReplContextKey');
Expand All @@ -40,8 +44,14 @@ export namespace DebugConsoleCommands {
@injectable()
export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWidget> implements TabBarToolbarContribution {

@inject(DebugConsoleSession)
protected debugConsoleSession: DebugConsoleSession;
@inject(ConsoleSessionManager)
protected consoleSessionManager: ConsoleSessionManager;

@inject(DebugConsoleSessionFactory)
protected debugConsoleSessionFactory: DebugConsoleSessionFactory;

@inject(DebugSessionManager)
protected debugSessionManager: DebugSessionManager;

constructor() {
super({
Expand All @@ -55,6 +65,37 @@ export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWi
});
}

@postConstruct()
protected init(): void {
this.debugSessionManager.onDidCreateDebugSession(session => {
const topParent = this.findParentSession(session);
if (topParent) {
const parentConsoleSession = this.consoleSessionManager.get(topParent.id);
if (parentConsoleSession instanceof DebugConsoleSession) {
session.on('output', event => parentConsoleSession.logOutput(parentConsoleSession.debugSession, event));
}
} else {
const consoleSession = this.debugConsoleSessionFactory(session);
this.consoleSessionManager.add(consoleSession);
session.on('output', event => consoleSession.logOutput(session, event));
}
});
this.debugSessionManager.onDidDestroyDebugSession(session => {
this.consoleSessionManager.delete(session.id);
});
}

protected findParentSession(session: DebugSession): DebugSession | undefined {
if (session.configuration.consoleMode !== DebugConsoleMode.MergeWithParent) {
return undefined;
}
let debugSession: DebugSession | undefined = session;
do {
debugSession = debugSession.parentSession;
} while (debugSession?.parentSession && debugSession.configuration.consoleMode === DebugConsoleMode.MergeWithParent);
return debugSession;
}

registerCommands(commands: CommandRegistry): void {
super.registerCommands(commands);
commands.registerCommand(DebugConsoleCommands.CLEAR, {
Expand All @@ -71,7 +112,13 @@ export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWi
id: 'debug-console-severity',
render: widget => this.renderSeveritySelector(widget),
isVisible: widget => this.withWidget(widget, () => true),
onDidChange: this.debugConsoleSession.onSelectionChange
onDidChange: this.consoleSessionManager.onSeverityChanged
});

toolbarRegistry.registerItem({
id: 'debug-console-session-selector',
render: widget => this.renderDebugConsoleSelector(widget),
isVisible: widget => this.withWidget(widget, () => this.consoleSessionManager.all.length > 1)
});

toolbarRegistry.registerItem({
Expand Down Expand Up @@ -105,20 +152,21 @@ export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWi
inputFocusContextKey
});
const widget = child.get(ConsoleWidget);
widget.session = child.get(DebugConsoleSession);
return widget;
}

static bindContribution(bind: interfaces.Bind): void {
bind(InDebugReplContextKey).toDynamicValue(({ container }) =>
container.get(ContextKeyService).createKey('inDebugRepl', false)
).inSingletonScope();
bind(DebugConsoleSession).toSelf().inSingletonScope();
bindViewContribution(bind, DebugConsoleContribution).onActivation((context, _) => {
// eagerly initialize the debug console session
context.container.get(DebugConsoleSession);
return _;
bind(DebugConsoleSession).toSelf().inRequestScope();
bind(DebugConsoleSessionFactory).toFactory(context => (session: DebugSession) => {
const consoleSession = context.container.get(DebugConsoleSession);
consoleSession.debugSession = session;
return consoleSession;
});
bind(ConsoleSessionManager).toSelf().inSingletonScope();
bindViewContribution(bind, DebugConsoleContribution);
bind(TabBarToolbarContribution).toService(DebugConsoleContribution);
bind(WidgetFactory).toDynamicValue(({ container }) => ({
id: DebugConsoleContribution.options.id,
Expand All @@ -129,7 +177,7 @@ export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWi
protected renderSeveritySelector(widget: Widget | undefined): React.ReactNode {
const severityElements: React.ReactNode[] = [];
Severity.toArray().forEach(s => severityElements.push(<option value={s} key={s}>{s}</option>));
const selectedValue = Severity.toString(this.debugConsoleSession.severity || Severity.Ignore);
const selectedValue = Severity.toString(this.consoleSessionManager.severity || Severity.Ignore);

return <select
className='theia-select'
Expand All @@ -142,8 +190,32 @@ export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWi
</select>;
}

protected renderDebugConsoleSelector(widget: Widget | undefined): React.ReactNode {
const availableConsoles: React.ReactNode[] = [];
this.consoleSessionManager.all.forEach(e => {
if (e instanceof DebugConsoleSession) {
availableConsoles.push(<option value={e.id} key={e.id}>{e.debugSession.label}</option>);
}
});
return <select
className='theia-select'
id='debugConsoleSelector'
key='debugConsoleSelector'
value={undefined}
onChange={this.changeDebugConsole}
>
{availableConsoles}
</select>;
}

protected changeDebugConsole = (event: React.ChangeEvent<HTMLSelectElement>) => {
const id = event.target.value;
const session = this.consoleSessionManager.get(id);
this.consoleSessionManager.selectedSession = session;
};

protected changeSeverity = (event: React.ChangeEvent<HTMLSelectElement>) => {
this.debugConsoleSession.severity = Severity.fromValue(event.target.value);
this.consoleSessionManager.severity = Severity.fromValue(event.target.value);
};

protected withWidget<T>(widget: Widget | undefined = this.tryGetWidget(), fn: (widget: ConsoleWidget) => T): T | false {
Expand Down
Loading

0 comments on commit 2ee44b4

Please sign in to comment.