Skip to content

Commit

Permalink
Properly handle completion and evaluation in debug session (#10469)
Browse files Browse the repository at this point in the history
- Ensure console session is disposed when debug session is destroyed
-- Remove  monaco completion item provider on disposal

- Only trigger console session functionality for matching debug session
-- Consider child sessions when searching for valid parents
-- Ensure we provide completion items for our own session
-- Ensure we provide evaluation for our own session

- Sync debug console with the currently selected session

Fixes #10468
Fixes #10648
  • Loading branch information
martin-fleck-at authored Feb 2, 2022
1 parent d5bb4e8 commit a3b025a
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 19 deletions.
29 changes: 16 additions & 13 deletions packages/debug/src/browser/console/debug-console-contribution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ import { Command, CommandRegistry } from '@theia/core/lib/common/command';
import { Severity } from '@theia/core/lib/common/severity';
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { DebugConsoleMode } from '../../common/debug-configuration';
import { DebugSession } from '../debug-session';
import { DebugSessionManager } from '../debug-session-manager';
import { DebugSessionManager, DidChangeActiveDebugSession } from '../debug-session-manager';
import { DebugConsoleSession, DebugConsoleSessionFactory } from './debug-console-session';

export type InDebugReplContextKey = ContextKey<boolean>;
Expand Down Expand Up @@ -71,9 +70,9 @@ 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);
const consoleParent = session.findConsoleParent();
if (consoleParent) {
const parentConsoleSession = this.consoleSessionManager.get(consoleParent.id);
if (parentConsoleSession instanceof DebugConsoleSession) {
session.on('output', event => parentConsoleSession.logOutput(parentConsoleSession.debugSession, event));
}
Expand All @@ -83,20 +82,24 @@ export class DebugConsoleContribution extends AbstractViewContribution<ConsoleWi
session.on('output', event => consoleSession.logOutput(session, event));
}
});
this.debugSessionManager.onDidChangeActiveDebugSession(event => this.handleActiveDebugSessionChanged(event));
this.debugSessionManager.onDidDestroyDebugSession(session => {
this.consoleSessionManager.delete(session.id);
});
}

protected findParentSession(session: DebugSession): DebugSession | undefined {
if (session.configuration.consoleMode !== DebugConsoleMode.MergeWithParent) {
return undefined;
protected handleActiveDebugSessionChanged(event: DidChangeActiveDebugSession): void {
if (!event.current) {
this.consoleSessionManager.selectedSession = undefined;
} else {
const topSession = event.current.findConsoleParent() || event.current;
const consoleSession = topSession ? this.consoleSessionManager.get(topSession.id) : undefined;
this.consoleSessionManager.selectedSession = consoleSession;
const consoleSelector = document.getElementById('debugConsoleSelector');
if (consoleSession && consoleSelector instanceof HTMLSelectElement) {
consoleSelector.value = consoleSession.id;
}
}
let debugSession: DebugSession | undefined = session;
do {
debugSession = debugSession.parentSession;
} while (debugSession?.parentSession && debugSession.configuration.consoleMode === DebugConsoleMode.MergeWithParent);
return debugSession;
}

registerCommands(commands: CommandRegistry): void {
Expand Down
41 changes: 36 additions & 5 deletions packages/debug/src/browser/console/debug-console-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { DebugSession } from '../debug-session';
import URI from '@theia/core/lib/common/uri';
import { ExpressionContainer, ExpressionItem } from './debug-console-items';
import { Severity } from '@theia/core/lib/common/severity';
import { injectable, postConstruct } from '@theia/core/shared/inversify';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import { DebugSessionManager } from '../debug-session-manager';

export const DebugConsoleSessionFactory = Symbol('DebugConsoleSessionFactory');

Expand All @@ -33,6 +34,8 @@ export class DebugConsoleSession extends ConsoleSession {

static uri = new URI().withScheme('debugconsole');

@inject(DebugSessionManager) protected readonly sessionManager: DebugSessionManager;

protected items: ConsoleItem[] = [];

protected _debugSession: DebugSession;
Expand Down Expand Up @@ -86,20 +89,48 @@ export class DebugConsoleSession extends ConsoleSession {
}

protected async completions(model: monaco.editor.ITextModel, position: monaco.Position): Promise<monaco.languages.CompletionList | undefined> {
const session = this.debugSession;
if (session && session.capabilities.supportsCompletionsRequest) {
const completionSession = this.findCompletionSession();
if (completionSession) {
const column = position.column;
const lineNumber = position.lineNumber;
const word = model.getWordAtPosition({ column, lineNumber });
const overwriteBefore = word ? word.word.length : 0;
const text = model.getValue();
const items = await session.completions(text, column, lineNumber);
const items = await completionSession.completions(text, column, lineNumber);
const suggestions = items.map(item => this.asCompletionItem(text, position, overwriteBefore, item));
return { suggestions };
}
return undefined;
}

protected findCurrentSession(): DebugSession | undefined {
const currentSession = this.sessionManager.currentSession;
if (!currentSession) {
return undefined;
}
if (currentSession.id === this.debugSession.id) {
// perfect match
return this.debugSession;
}
const parentSession = currentSession.findConsoleParent();
if (parentSession?.id === this.debugSession.id) {
// child of our session
return currentSession;
}
return undefined;
}

protected findCompletionSession(): DebugSession | undefined {
let completionSession: DebugSession | undefined = this.findCurrentSession();
while (completionSession !== undefined) {
if (completionSession.capabilities.supportsCompletionsRequest) {
return completionSession;
}
completionSession = completionSession.parentSession;
}
return completionSession;
}

protected asCompletionItem(text: string, position: monaco.Position, overwriteBefore: number, item: DebugProtocol.CompletionItem): monaco.languages.CompletionItem {
return {
label: item.label,
Expand All @@ -112,7 +143,7 @@ export class DebugConsoleSession extends ConsoleSession {
}

async execute(value: string): Promise<void> {
const expression = new ExpressionItem(value, () => this.debugSession);
const expression = new ExpressionItem(value, () => this.findCurrentSession());
this.items.push(expression);
await expression.evaluate();
this.fireDidChange();
Expand Down
17 changes: 16 additions & 1 deletion packages/debug/src/browser/debug-session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import debounce = require('p-debounce');
import URI from '@theia/core/lib/common/uri';
import { BreakpointManager } from './breakpoint/breakpoint-manager';
import { DebugSessionOptions, InternalDebugSessionOptions } from './debug-session-options';
import { DebugConfiguration } from '../common/debug-common';
import { DebugConfiguration, DebugConsoleMode } from '../common/debug-common';
import { SourceBreakpoint, ExceptionBreakpoint } from './breakpoint/breakpoint-marker';
import { TerminalWidgetOptions, TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
import { DebugFunctionBreakpoint } from './model/debug-function-breakpoint';
Expand Down Expand Up @@ -817,4 +817,19 @@ export class DebugSession implements CompositeTreeElement {
contrib.register(configType, connection);
}
};

/**
* Returns the top-most parent session that is responsible for the console. If this session uses a {@link DebugConsoleMode.Separate separate console}
* or does not have any parent session, undefined is returned.
*/
public findConsoleParent(): DebugSession | undefined {
if (this.configuration.consoleMode !== DebugConsoleMode.MergeWithParent) {
return undefined;
}
let debugSession: DebugSession | undefined = this;
do {
debugSession = this.parentSession;
} while (debugSession?.parentSession && debugSession.configuration.consoleMode === DebugConsoleMode.MergeWithParent);
return debugSession;
}
}

0 comments on commit a3b025a

Please sign in to comment.