Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make clearing interactive sessions work better #181851

Merged
merged 2 commits into from May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -15,13 +15,15 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
import { IViewsService } from 'vs/workbench/common/views';
import { IInteractiveSessionEditorOptions, InteractiveSessionEditor } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditor';
import { InteractiveSessionEditorInput } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditorInput';
import { InteractiveSessionViewPane } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionViewPane';
import { IInteractiveSessionWidgetService } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget';
import { CONTEXT_IN_INTERACTIVE_INPUT, CONTEXT_IN_INTERACTIVE_SESSION } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionContextKeys';
import { IInteractiveSessionDetail, IInteractiveSessionService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
import { IInteractiveSessionWidgetHistoryService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionWidgetHistoryService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';

export const INTERACTIVE_SESSION_CATEGORY = { value: localize('interactiveSession.category', "Interactive Session"), original: 'Interactive Session' };
Expand Down Expand Up @@ -70,10 +72,14 @@ export function registerInteractiveSessionActions() {
});
}
async run(accessor: ServicesAccessor, ...args: any[]) {
const widgetService = accessor.get(IInteractiveSessionWidgetService);
const editorService = accessor.get(IEditorService);
if (editorService.activeEditorPane instanceof InteractiveSessionEditor) {
await editorService.activeEditorPane.clear();
}
const editorGroupsService = accessor.get(IEditorGroupsService);

editorService.replaceEditors([{
editor: editorService.activeEditor!,
replacement: { resource: InteractiveSessionEditorInput.getNewEditorUri(), options: <IInteractiveSessionEditorOptions>{ target: { providerId: widgetService.lastFocusedWidget!.providerId, pinned: true } } }
}], editorGroupsService.activeGroup);
}
});

Expand Down Expand Up @@ -156,10 +162,25 @@ export function registerInteractiveSessionActions() {
}
async run(accessor: ServicesAccessor, ...args: any[]) {
const widgetService = accessor.get(IInteractiveSessionWidgetService);
const interactiveSessionService = accessor.get(IInteractiveSessionService);
const sessionId = widgetService.lastFocusedWidget?.viewModel?.sessionId;
if (sessionId) {
interactiveSessionService.clearSession(sessionId);
const viewsService = accessor.get(IViewsService);
const editorService = accessor.get(IEditorService);
const editorGroupsService = accessor.get(IEditorGroupsService);

const widget = widgetService.lastFocusedWidget;
if (!widget) {
return;
}

if ('viewId' in widget.viewContext) {
const view = viewsService.getViewWithId(widget.viewContext.viewId);
if (view instanceof InteractiveSessionViewPane) {
view.clear();
}
} else {
editorService.replaceEditors([{
editor: editorService.activeEditor!,
replacement: { resource: InteractiveSessionEditorInput.getNewEditorUri(), options: <IInteractiveSessionEditorOptions>{ target: { providerId: widgetService.lastFocusedWidget!.providerId, pinned: true } } }
}], editorGroupsService.activeGroup);
}
}
});
Expand Down
Expand Up @@ -8,8 +8,11 @@ import { IInteractiveSlashCommand } from 'vs/workbench/contrib/interactiveSessio
import { IInteractiveSessionViewModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionViewModel';
import { Event } from 'vs/base/common/event';

export type IInteractiveSessionWidgetViewContext = { viewId: string } | { resource: boolean };

export interface IInteractiveSessionWidget {
readonly onDidChangeViewModel: Event<void>;
readonly viewContext: IInteractiveSessionWidgetViewContext;
readonly viewModel: IInteractiveSessionViewModel | undefined;
readonly inputEditor: ICodeEditor;
readonly providerId: string;
Expand Down
Expand Up @@ -5,7 +5,6 @@

import * as dom from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IContextKeyService, IScopedContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IEditorOptions } from 'vs/platform/editor/common/editor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
Expand Down Expand Up @@ -40,8 +39,6 @@ export class InteractiveSessionEditor extends EditorPane {
private _memento: Memento | undefined;
private _viewState: IViewState | undefined;

private _modelDisposables = this._register(new DisposableStore());

constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService,
Expand Down Expand Up @@ -104,19 +101,9 @@ export class InteractiveSessionEditor extends EditorPane {
}

private updateModel(model: IInteractiveSessionModel): void {
this._modelDisposables.clear();

this._memento = new Memento('interactive-session-editor-' + model.sessionId, this.storageService);
this._viewState = this._memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewState;
this.widget.setModel(model, { ...this._viewState });
this._modelDisposables.add(model.onDidDispose(() => {
// TODO go back to swapping out the EditorInput when the session is restarted instead of this listener
const newModel = this.interactiveSessionService.startSession(model.providerId, CancellationToken.None);
if (newModel) {
(this.input as InteractiveSessionEditorInput).sessionId = newModel.sessionId;
this.updateModel(newModel);
}
}));
}

protected override saveState(): void {
Expand Down
Expand Up @@ -22,7 +22,6 @@ export class InteractiveSessionEditorInput extends EditorInput {
static count = 0;

private readonly inputCount: number;
public model: IInteractiveSessionModel | undefined;
public sessionId: string | undefined;
public providerId: string | undefined;

Expand Down Expand Up @@ -77,9 +76,9 @@ export class InteractiveSessionEditorInput extends EditorInput {
return null;
}

await model.waitForInitialization();
this.sessionId = model.sessionId;
return new InteractiveSessionEditorModel(model);
await model.waitForInitialization();
return this._register(new InteractiveSessionEditorModel(model));
}

override dispose(): void {
Expand Down
Expand Up @@ -75,9 +75,6 @@ export class InteractiveSessionViewPane extends ViewPane {

this._widget.setModel(model, { ...this.viewState });
this.viewState.sessionId = model.sessionId;
this.modelDisposables.add(model.onDidDispose(() => {
this.updateModel();
}));
}

protected override renderBody(parent: HTMLElement): void {
Expand Down Expand Up @@ -110,6 +107,7 @@ export class InteractiveSessionViewPane extends ViewPane {
async clear(): Promise<void> {
if (this.widget.viewModel) {
this.interactiveSessionService.clearSession(this.widget.viewModel.sessionId);
this.updateModel();
}
}

Expand Down
Expand Up @@ -20,7 +20,7 @@ import { IInstantiationService, createDecorator } from 'vs/platform/instantiatio
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
import { IViewsService } from 'vs/workbench/common/views';
import { IInteractiveSessionWidget } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSession';
import { IInteractiveSessionWidget, IInteractiveSessionWidgetViewContext } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSession';
import { InteractiveSessionInputPart } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionInputPart';
import { IInteractiveSessionRendererDelegate, InteractiveListItemRenderer, InteractiveSessionAccessibilityProvider, InteractiveSessionListDelegate, InteractiveTreeItem } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer';
import { InteractiveSessionEditorOptions } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionOptions';
Expand Down Expand Up @@ -68,8 +68,6 @@ export interface IInteractiveSessionWidgetStyles {
resultEditorBackground: string;
}

export type IInteractiveSessionWidgetViewContext = { viewId: string } | { resource: boolean };

export class InteractiveSessionWidget extends Disposable implements IInteractiveSessionWidget {
public static readonly CONTRIBS: { new(...args: [IInteractiveSessionWidget, ...any]): any }[] = [];

Expand Down
Expand Up @@ -330,7 +330,7 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS
}

initialize(session: IInteractiveSession, welcomeMessage: InteractiveSessionWelcomeMessageModel | undefined): void {
if (this._session) {
if (this._session || this._isInitializedDeferred.isSettled) {
throw new Error('InteractiveSessionModel is already initialized');
}

Expand All @@ -351,6 +351,12 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS
this._onDidChange.fire({ kind: 'initialize' });
}

setInitializationError(error: Error): void {
if (!this._isInitializedDeferred.isSettled) {
this._isInitializedDeferred.error(error);
}
}

waitForInitialization(): Promise<void> {
return this._isInitializedDeferred.p;
}
Expand Down
Expand Up @@ -243,6 +243,7 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
}
}).catch(err => {
this.trace('startSession', `initializeSession failed: ${err}`);
model.setInitializationError(err);
model.dispose();
this._sessionModels.delete(model.sessionId);
});
Expand Down Expand Up @@ -520,7 +521,10 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
throw new Error(`Unknown session: ${sessionId}`);
}

this._persistedSessions[sessionId] = model.toJSON();
if (model.getRequests().length) {
this._persistedSessions[sessionId] = model.toJSON();
}

model.dispose();
this._sessionModels.delete(sessionId);
this._pendingRequests.get(sessionId)?.cancel();
Expand Down