Skip to content

Commit cc725b7

Browse files
committed
Clone static plot for editor
1 parent 40816a0 commit cc725b7

File tree

4 files changed

+51
-36
lines changed

4 files changed

+51
-36
lines changed

src/vs/workbench/contrib/positronPlots/browser/positronPlots.tsx

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ import React, { PropsWithChildren, useCallback, useEffect, useState } from 'reac
1313
import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js';
1414
import { PositronPlotsServices } from './positronPlotsState.js';
1515
import { PositronPlotsContextProvider } from './positronPlotsContext.js';
16-
import { HistoryPolicy, IPositronPlotsService, ZoomLevel } from '../../../services/positronPlots/common/positronPlots.js';
16+
import { HistoryPolicy, IPositronPlotsService, isZoomablePlotClient, ZoomLevel } from '../../../services/positronPlots/common/positronPlots.js';
1717
import { DisposableStore } from '../../../../base/common/lifecycle.js';
1818
import { PlotsContainer } from './components/plotsContainer.js';
1919
import { ActionBars } from './components/actionBars.js';
2020
import { INotificationService } from '../../../../platform/notification/common/notification.js';
2121
import { PositronPlotsViewPane } from './positronPlotsView.js';
2222
import { IPreferencesService } from '../../../services/preferences/common/preferences.js';
23-
import { PlotClientInstance } from '../../../services/languageRuntime/common/languageRuntimePlotClient.js';
2423

2524
/**
2625
* PositronPlotsProps interface.
@@ -66,18 +65,16 @@ export const PositronPlots = (props: PropsWithChildren<PositronPlotsProps>) => {
6665
}, [props.positronPlotsService.positronPlotInstances.length, props.reactComponentContainer.height, props.reactComponentContainer.width]);
6766

6867
const zoomHandler = (zoom: number) => {
69-
setZoom(zoom);
7068
const currentPlotId = props.positronPlotsService.selectedPlotId;
7169
if (!currentPlotId) {
7270
return;
7371
}
7472

7573
const plot = props.positronPlotsService.positronPlotInstances.find(plot => plot.id === currentPlotId);
76-
if (!plot || !(plot instanceof PlotClientInstance)) {
77-
return;
74+
if (isZoomablePlotClient(plot)) {
75+
// Update the zoom level in the plot metadata.
76+
plot.zoomLevel = zoom;
7877
}
79-
// Update the zoom level in the plot metadata.
80-
plot.zoomLevel = zoom;
8178
};
8279

8380
// Hooks.
@@ -142,30 +139,29 @@ export const PositronPlots = (props: PropsWithChildren<PositronPlotsProps>) => {
142139

143140
useEffect(() => {
144141
// Set the initial zoom level for the current plot.
145-
const currentPlot = props.positronPlotsService.selectedPlotId;
146-
147-
if (currentPlot) {
148-
const plot = props.positronPlotsService.positronPlotInstances.find(plot => plot.id === currentPlot);
149-
if (plot) {
150-
setZoom(plot.metadata.zoom_level || ZoomLevel.Fit);
151-
}
152-
}
153-
}, [props.positronPlotsService.positronPlotInstances, props.positronPlotsService.selectedPlotId]);
142+
const disposableStore = new DisposableStore();
154143

155-
useEffect(() => {
156-
const disposable = props.positronPlotsService.onDidSelectPlot((selectedPlotId) => {
157-
const plot = props.positronPlotsService.positronPlotInstances.find(plot => plot.id === selectedPlotId);
158-
if (plot) {
159-
setZoom(plot.metadata.zoom_level || ZoomLevel.Fit);
160-
} else {
161-
setZoom(ZoomLevel.Fit);
144+
disposableStore.add(props.positronPlotsService.onDidSelectPlot(plotId => {
145+
const currentPlot = props.positronPlotsService.selectedPlotId;
146+
147+
if (currentPlot) {
148+
const plot = props.positronPlotsService.positronPlotInstances.find(plot => plot.id === currentPlot);
149+
if (isZoomablePlotClient(plot)) {
150+
disposableStore.add(plot.onDidChangeZoomLevel((zoomLevel) => {
151+
setZoom(zoomLevel);
152+
}));
153+
setZoom(plot.zoomLevel);
154+
} else {
155+
setZoom(ZoomLevel.Fit);
156+
}
162157
}
163-
});
158+
}));
164159

165160
return () => {
166-
disposable.dispose();
167-
};
168-
}, [props.positronPlotsService])
161+
// Dispose of the disposable store to clean up event handlers.
162+
disposableStore.dispose();
163+
}
164+
}, [props.positronPlotsService]);
169165

170166
// Render.
171167
return (

src/vs/workbench/contrib/positronPlots/browser/positronPlotsActions.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { IQuickInputService, IQuickPick, IQuickPickItem } from '../../../../plat
1616
import { PLOT_IS_ACTIVE_EDITOR } from '../../positronPlotsEditor/browser/positronPlotsEditor.contribution.js';
1717
import { PositronPlotsEditorInput } from '../../positronPlotsEditor/browser/positronPlotsEditorInput.js';
1818
import { IEditorService } from '../../../services/editor/common/editorService.js';
19-
import { IPositronPlotClient, IPositronPlotsService, ZoomLevel } from '../../../services/positronPlots/common/positronPlots.js';
19+
import { IPositronPlotClient, IPositronPlotsService, isZoomablePlotClient, ZoomLevel } from '../../../services/positronPlots/common/positronPlots.js';
2020
import { PlotClientInstance } from '../../../services/languageRuntime/common/languageRuntimePlotClient.js';
2121
import { ThemeIcon } from '../../../../base/common/themables.js';
2222
import { Uri } from 'vscode';
@@ -664,7 +664,10 @@ abstract class PlotsEditorZoomAction extends Action2 {
664664
*/
665665
async run(accessor: ServicesAccessor, plotId: Uri): Promise<void> {
666666
const plotsService = accessor.get(IPositronPlotsService);
667-
plotsService.setEditorPlotZoom(plotId.path, this.zoomLevel);
667+
const plotInstance = plotsService.getEditorInstance(plotId.path);
668+
if (isZoomablePlotClient(plotInstance)) {
669+
plotInstance.zoomLevel = this.zoomLevel;
670+
}
668671
}
669672
}
670673

src/vs/workbench/contrib/positronPlots/browser/positronPlotsService.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ export class PositronPlotsService extends Disposable implements IPositronPlotsSe
890890
const code = this._recentExecutions.get(message.parent_id) ?? '';
891891

892892
if (message.kind === RuntimeOutputKind.StaticImage) {
893-
return new StaticPlotClient(this._storageService, session.sessionId, message, code);
893+
return StaticPlotClient.fromMessage(this._storageService, session.sessionId, message, code);
894894
} else if (message.kind === RuntimeOutputKind.PlotWidget) {
895895
return new NotebookOutputPlotClient(this._notebookOutputWebviewService, session, message, code);
896896
}
@@ -1423,7 +1423,10 @@ export class PositronPlotsService extends Disposable implements IPositronPlotsSe
14231423
}
14241424

14251425
if (plotClient instanceof StaticPlotClient) {
1426-
this._editorPlots.set(plotClient.id, plotClient);
1426+
// Create a copy of the StaticPlotClient for the editor
1427+
const plotCopy = StaticPlotClient.fromMetadata(this._storageService, plotClient.metadata, plotClient.mimeType, plotClient.data);
1428+
this._editorPlots.set(plotClient.id, plotCopy);
1429+
this._register(plotCopy);
14271430
}
14281431

14291432
// Create a new plot client instance for the editor

src/vs/workbench/services/positronPlots/common/staticPlotClient.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@ export class StaticPlotClient extends Disposable implements IPositronPlotClient,
1717
public readonly metadata: IPositronPlotMetadata;
1818
public readonly mimeType;
1919
public readonly data;
20+
public readonly code?: string;
2021

2122
// Zoom level emitter
2223
public onDidChangeZoomLevel: Event<ZoomLevel>;
2324

2425
private readonly _zoomLevelEventEmitter = new Emitter<ZoomLevel>();
2526

26-
constructor(storageService: IStorageService, sessionId: string, message: ILanguageRuntimeMessageOutput,
27-
public readonly code?: string) {
28-
super();
27+
static fromMetadata(storageService: IStorageService, metadata: IPositronPlotMetadata, mimeType: string, data: string): StaticPlotClient {
28+
// Create a new StaticPlotClient instance from the provided metadata, MIME type, and data.
29+
return new StaticPlotClient(storageService, metadata.session_id, metadata, mimeType, data);
30+
}
2931

32+
static fromMessage(storageService: IStorageService, sessionId: string, message: ILanguageRuntimeMessageOutput, code?: string): StaticPlotClient {
3033
// Create the metadata for the plot.
31-
this.metadata = {
34+
const metadata = {
3235
id: message.id,
3336
parent_id: message.parent_id,
3437
created: Date.parse(message.when),
@@ -52,8 +55,18 @@ export class StaticPlotClient extends Disposable implements IPositronPlotClient,
5255
}
5356

5457
// Save the MIME type and data for the image.
55-
this.mimeType = imageKey;
58+
const mimeType = imageKey;
59+
60+
return new StaticPlotClient(storageService, sessionId, metadata, mimeType, data);
61+
}
62+
63+
private constructor(storageService: IStorageService, sessionId: string, metadata: IPositronPlotMetadata, mimeType: string, data: string) {
64+
super();
65+
66+
this.metadata = metadata;
67+
this.mimeType = mimeType;
5668
this.data = data;
69+
this.code = metadata.code;
5770

5871
// Set up the zoom level event emitter.
5972
this.onDidChangeZoomLevel = this._zoomLevelEventEmitter.event;

0 commit comments

Comments
 (0)