Skip to content

Commit 3d3e22e

Browse files
authored
Make clearing interactive sessions work better (microsoft#181851)
* Don't persist empty sessions when cleared * Make clearing interactive sessions work better Fixes possible infinite loop when clearing a session, and starting the next session fails
1 parent ee684a3 commit 3d3e22e

File tree

8 files changed

+47
-31
lines changed

8 files changed

+47
-31
lines changed

src/vs/workbench/contrib/interactiveSession/browser/actions/interactiveSessionActions.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis
1515
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
1616
import { ViewAction } from 'vs/workbench/browser/parts/views/viewPane';
1717
import { ActiveEditorContext } from 'vs/workbench/common/contextkeys';
18+
import { IViewsService } from 'vs/workbench/common/views';
1819
import { IInteractiveSessionEditorOptions, InteractiveSessionEditor } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditor';
1920
import { InteractiveSessionEditorInput } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditorInput';
2021
import { InteractiveSessionViewPane } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionViewPane';
2122
import { IInteractiveSessionWidgetService } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget';
2223
import { CONTEXT_IN_INTERACTIVE_INPUT, CONTEXT_IN_INTERACTIVE_SESSION } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionContextKeys';
2324
import { IInteractiveSessionDetail, IInteractiveSessionService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionService';
2425
import { IInteractiveSessionWidgetHistoryService } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionWidgetHistoryService';
26+
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
2527
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
2628

2729
export const INTERACTIVE_SESSION_CATEGORY = { value: localize('interactiveSession.category', "Interactive Session"), original: 'Interactive Session' };
@@ -70,10 +72,14 @@ export function registerInteractiveSessionActions() {
7072
});
7173
}
7274
async run(accessor: ServicesAccessor, ...args: any[]) {
75+
const widgetService = accessor.get(IInteractiveSessionWidgetService);
7376
const editorService = accessor.get(IEditorService);
74-
if (editorService.activeEditorPane instanceof InteractiveSessionEditor) {
75-
await editorService.activeEditorPane.clear();
76-
}
77+
const editorGroupsService = accessor.get(IEditorGroupsService);
78+
79+
editorService.replaceEditors([{
80+
editor: editorService.activeEditor!,
81+
replacement: { resource: InteractiveSessionEditorInput.getNewEditorUri(), options: <IInteractiveSessionEditorOptions>{ target: { providerId: widgetService.lastFocusedWidget!.providerId, pinned: true } } }
82+
}], editorGroupsService.activeGroup);
7783
}
7884
});
7985

@@ -156,10 +162,25 @@ export function registerInteractiveSessionActions() {
156162
}
157163
async run(accessor: ServicesAccessor, ...args: any[]) {
158164
const widgetService = accessor.get(IInteractiveSessionWidgetService);
159-
const interactiveSessionService = accessor.get(IInteractiveSessionService);
160-
const sessionId = widgetService.lastFocusedWidget?.viewModel?.sessionId;
161-
if (sessionId) {
162-
interactiveSessionService.clearSession(sessionId);
165+
const viewsService = accessor.get(IViewsService);
166+
const editorService = accessor.get(IEditorService);
167+
const editorGroupsService = accessor.get(IEditorGroupsService);
168+
169+
const widget = widgetService.lastFocusedWidget;
170+
if (!widget) {
171+
return;
172+
}
173+
174+
if ('viewId' in widget.viewContext) {
175+
const view = viewsService.getViewWithId(widget.viewContext.viewId);
176+
if (view instanceof InteractiveSessionViewPane) {
177+
view.clear();
178+
}
179+
} else {
180+
editorService.replaceEditors([{
181+
editor: editorService.activeEditor!,
182+
replacement: { resource: InteractiveSessionEditorInput.getNewEditorUri(), options: <IInteractiveSessionEditorOptions>{ target: { providerId: widgetService.lastFocusedWidget!.providerId, pinned: true } } }
183+
}], editorGroupsService.activeGroup);
163184
}
164185
}
165186
});

src/vs/workbench/contrib/interactiveSession/browser/interactiveSession.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ import { IInteractiveSlashCommand } from 'vs/workbench/contrib/interactiveSessio
88
import { IInteractiveSessionViewModel } from 'vs/workbench/contrib/interactiveSession/common/interactiveSessionViewModel';
99
import { Event } from 'vs/base/common/event';
1010

11+
export type IInteractiveSessionWidgetViewContext = { viewId: string } | { resource: boolean };
12+
1113
export interface IInteractiveSessionWidget {
1214
readonly onDidChangeViewModel: Event<void>;
15+
readonly viewContext: IInteractiveSessionWidgetViewContext;
1316
readonly viewModel: IInteractiveSessionViewModel | undefined;
1417
readonly inputEditor: ICodeEditor;
1518
readonly providerId: string;

src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditor.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

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

43-
private _modelDisposables = this._register(new DisposableStore());
44-
4542
constructor(
4643
@ITelemetryService telemetryService: ITelemetryService,
4744
@IThemeService themeService: IThemeService,
@@ -104,19 +101,9 @@ export class InteractiveSessionEditor extends EditorPane {
104101
}
105102

106103
private updateModel(model: IInteractiveSessionModel): void {
107-
this._modelDisposables.clear();
108-
109104
this._memento = new Memento('interactive-session-editor-' + model.sessionId, this.storageService);
110105
this._viewState = this._memento.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE) as IViewState;
111106
this.widget.setModel(model, { ...this._viewState });
112-
this._modelDisposables.add(model.onDidDispose(() => {
113-
// TODO go back to swapping out the EditorInput when the session is restarted instead of this listener
114-
const newModel = this.interactiveSessionService.startSession(model.providerId, CancellationToken.None);
115-
if (newModel) {
116-
(this.input as InteractiveSessionEditorInput).sessionId = newModel.sessionId;
117-
this.updateModel(newModel);
118-
}
119-
}));
120107
}
121108

122109
protected override saveState(): void {

src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionEditorInput.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export class InteractiveSessionEditorInput extends EditorInput {
2222
static count = 0;
2323

2424
private readonly inputCount: number;
25-
public model: IInteractiveSessionModel | undefined;
2625
public sessionId: string | undefined;
2726
public providerId: string | undefined;
2827

@@ -77,9 +76,9 @@ export class InteractiveSessionEditorInput extends EditorInput {
7776
return null;
7877
}
7978

80-
await model.waitForInitialization();
8179
this.sessionId = model.sessionId;
82-
return new InteractiveSessionEditorModel(model);
80+
await model.waitForInitialization();
81+
return this._register(new InteractiveSessionEditorModel(model));
8382
}
8483

8584
override dispose(): void {

src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionViewPane.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,6 @@ export class InteractiveSessionViewPane extends ViewPane {
7575

7676
this._widget.setModel(model, { ...this.viewState });
7777
this.viewState.sessionId = model.sessionId;
78-
this.modelDisposables.add(model.onDidDispose(() => {
79-
this.updateModel();
80-
}));
8178
}
8279

8380
protected override renderBody(parent: HTMLElement): void {
@@ -110,6 +107,7 @@ export class InteractiveSessionViewPane extends ViewPane {
110107
async clear(): Promise<void> {
111108
if (this.widget.viewModel) {
112109
this.interactiveSessionService.clearSession(this.widget.viewModel.sessionId);
110+
this.updateModel();
113111
}
114112
}
115113

src/vs/workbench/contrib/interactiveSession/browser/interactiveSessionWidget.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { IInstantiationService, createDecorator } from 'vs/platform/instantiatio
2020
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
2121
import { WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
2222
import { IViewsService } from 'vs/workbench/common/views';
23-
import { IInteractiveSessionWidget } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSession';
23+
import { IInteractiveSessionWidget, IInteractiveSessionWidgetViewContext } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSession';
2424
import { InteractiveSessionInputPart } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionInputPart';
2525
import { IInteractiveSessionRendererDelegate, InteractiveListItemRenderer, InteractiveSessionAccessibilityProvider, InteractiveSessionListDelegate, InteractiveTreeItem } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionListRenderer';
2626
import { InteractiveSessionEditorOptions } from 'vs/workbench/contrib/interactiveSession/browser/interactiveSessionOptions';
@@ -68,8 +68,6 @@ export interface IInteractiveSessionWidgetStyles {
6868
resultEditorBackground: string;
6969
}
7070

71-
export type IInteractiveSessionWidgetViewContext = { viewId: string } | { resource: boolean };
72-
7371
export class InteractiveSessionWidget extends Disposable implements IInteractiveSessionWidget {
7472
public static readonly CONTRIBS: { new(...args: [IInteractiveSessionWidget, ...any]): any }[] = [];
7573

src/vs/workbench/contrib/interactiveSession/common/interactiveSessionModel.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ export class InteractiveSessionModel extends Disposable implements IInteractiveS
330330
}
331331

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

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

354+
setInitializationError(error: Error): void {
355+
if (!this._isInitializedDeferred.isSettled) {
356+
this._isInitializedDeferred.error(error);
357+
}
358+
}
359+
354360
waitForInitialization(): Promise<void> {
355361
return this._isInitializedDeferred.p;
356362
}

src/vs/workbench/contrib/interactiveSession/common/interactiveSessionServiceImpl.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
243243
}
244244
}).catch(err => {
245245
this.trace('startSession', `initializeSession failed: ${err}`);
246+
model.setInitializationError(err);
246247
model.dispose();
247248
this._sessionModels.delete(model.sessionId);
248249
});
@@ -520,7 +521,10 @@ export class InteractiveSessionService extends Disposable implements IInteractiv
520521
throw new Error(`Unknown session: ${sessionId}`);
521522
}
522523

523-
this._persistedSessions[sessionId] = model.toJSON();
524+
if (model.getRequests().length) {
525+
this._persistedSessions[sessionId] = model.toJSON();
526+
}
527+
524528
model.dispose();
525529
this._sessionModels.delete(sessionId);
526530
this._pendingRequests.get(sessionId)?.cancel();

0 commit comments

Comments
 (0)