Skip to content

Commit 0eff78f

Browse files
committed
Merge branch 'notebook/dev' into main
2 parents 7f9ea94 + 07879df commit 0eff78f

25 files changed

+685
-249
lines changed

src/vs/platform/actions/common/actions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export class MenuId {
140140
static readonly CommentThreadActions = new MenuId('CommentThreadActions');
141141
static readonly CommentTitle = new MenuId('CommentTitle');
142142
static readonly CommentActions = new MenuId('CommentActions');
143+
static readonly NotebookToolbar = new MenuId('NotebookToolbar');
143144
static readonly NotebookCellTitle = new MenuId('NotebookCellTitle');
144145
static readonly NotebookCellInsert = new MenuId('NotebookCellInsert');
145146
static readonly NotebookCellBetween = new MenuId('NotebookCellBetween');

src/vs/vscode.proposed.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,8 +1402,25 @@ declare module 'vscode' {
14021402

14031403
//#endregion
14041404

1405+
//#region https://github.com/microsoft/vscode/issues/106744, NotebookSerializer
1406+
1407+
export interface NotebookSerializer {
1408+
dataToNotebook(data: Uint8Array): NotebookData | Thenable<NotebookData>;
1409+
notebookToData(data: NotebookData): Uint8Array | Thenable<Uint8Array>;
1410+
}
1411+
1412+
export namespace notebook {
1413+
1414+
// TODO@api use NotebookDocumentFilter instead of just notebookType:string?
1415+
// TODO@API options duplicates the more powerful variant on NotebookContentProvider
1416+
export function registerNotebookSerializer(notebookType: string, provider: NotebookSerializer, options?: NotebookDocumentContentOptions): Disposable;
1417+
}
1418+
1419+
//#endregion
1420+
14051421
//#region https://github.com/microsoft/vscode/issues/106744, NotebookContentProvider
14061422

1423+
14071424
interface NotebookDocumentBackup {
14081425
/**
14091426
* Unique identifier for the backup.

src/vs/workbench/api/browser/mainThreadNotebook.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/no
2424
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
2525
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
2626
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
27-
import { ICellEditOperation, ICellRange, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
27+
import { ICellEditOperation, ICellRange, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, INotebookKernel, NotebookCellsChangeType, NotebookDataDto, TransientMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
2828
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
2929
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
3030
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -107,6 +107,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
107107

108108
private readonly _proxy: ExtHostNotebookShape;
109109
private readonly _notebookProviders = new Map<string, { controller: IMainNotebookController, disposable: IDisposable }>();
110+
private readonly _notebookSerializer = new Map<number, IDisposable>();
110111
private readonly _notebookKernelProviders = new Map<number, { extension: NotebookExtensionDescription, emitter: Emitter<URI | undefined>, provider: IDisposable }>();
111112
private readonly _editorEventListenersMapping = new Map<string, DisposableStore>();
112113
private readonly _documentEventListenersMapping = new ResourceMap<DisposableStore>();
@@ -124,7 +125,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
124125
@IEditorService private readonly _editorService: IEditorService,
125126
@ILogService private readonly _logService: ILogService,
126127
@INotebookCellStatusBarService private readonly _cellStatusBarService: INotebookCellStatusBarService,
127-
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
128+
@INotebookEditorModelResolverService private readonly _notebookEditorModelResolverService: INotebookEditorModelResolverService,
128129
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService
129130
) {
130131
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
@@ -147,6 +148,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
147148
item.emitter.dispose();
148149
item.provider.dispose();
149150
}
151+
dispose(this._notebookSerializer.values());
150152
dispose(this._editorEventListenersMapping.values());
151153
dispose(this._documentEventListenersMapping.values());
152154
dispose(this._cellStatusBarEntries.values());
@@ -323,7 +325,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
323325
this._proxy.$acceptNotebookActiveKernelChange(e);
324326
}));
325327

326-
this._disposables.add(this._notebookService.onNotebookDocumentSaved(e => {
328+
this._disposables.add(this._notebookEditorModelResolverService.onDidSaveNotebook(e => {
327329
this._proxy.$acceptModelSaved(e);
328330
}));
329331

@@ -403,8 +405,8 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
403405
contentOptions.transientOutputs = newOptions.transientOutputs;
404406
},
405407
viewOptions: options.viewOptions,
406-
openNotebook: async (viewType: string, uri: URI, backupId: string | undefined, token: CancellationToken, untitledDocumentData?: VSBuffer) => {
407-
const data = await this._proxy.$openNotebook(viewType, uri, backupId, token, untitledDocumentData);
408+
open: async (uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken) => {
409+
const data = await this._proxy.$openNotebook(viewType, uri, backupId, untitledDocumentData, token);
408410
return {
409411
data,
410412
transientOptions: contentOptions
@@ -452,6 +454,24 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
452454
}
453455
}
454456

457+
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void {
458+
const registration = this._notebookService.registerNotebookSerializer(viewType, extension, {
459+
options,
460+
dataToNotebook: (data: VSBuffer): Promise<NotebookDataDto> => {
461+
return this._proxy.$dataToNotebook(handle, data);
462+
},
463+
notebookToData: (data: NotebookDataDto): Promise<VSBuffer> => {
464+
return this._proxy.$notebookToData(handle, data);
465+
}
466+
});
467+
this._notebookSerializer.set(handle, registration);
468+
}
469+
470+
$unregisterNotebookSerializer(handle: number): void {
471+
this._notebookSerializer.get(handle)?.dispose();
472+
this._notebookSerializer.delete(handle);
473+
}
474+
455475
async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
456476
const emitter = new Emitter<URI | undefined>();
457477
const that = this;
@@ -585,15 +605,15 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
585605

586606
async $tryOpenDocument(uriComponents: UriComponents): Promise<URI> {
587607
const uri = URI.revive(uriComponents);
588-
const ref = await this._notebookModelResolverService.resolve(uri, undefined);
608+
const ref = await this._notebookEditorModelResolverService.resolve(uri, undefined);
589609
this._modelReferenceCollection.add(uri, ref);
590610
return uri;
591611
}
592612

593613
async $trySaveDocument(uriComponents: UriComponents) {
594614
const uri = URI.revive(uriComponents);
595615

596-
const ref = await this._notebookModelResolverService.resolve(uri);
616+
const ref = await this._notebookEditorModelResolverService.resolve(uri);
597617
const saveResult = await ref.object.save();
598618
ref.dispose();
599619
return saveResult;

src/vs/workbench/api/common/extHost.api.impl.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
10511051
checkProposedApiEnabled(extension);
10521052
return extHostNotebook.onDidChangeActiveNotebookKernel;
10531053
},
1054+
registerNotebookSerializer(viewType, serializer, options) {
1055+
checkProposedApiEnabled(extension);
1056+
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options);
1057+
},
10541058
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: {
10551059
transientOutputs: boolean;
10561060
transientMetadata: { [K in keyof vscode.NotebookCellMetadata]?: boolean }

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
5050
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel';
5151
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
5252
import { revive } from 'vs/base/common/marshalling';
53-
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
53+
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
5454
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
5555
import { Dto } from 'vs/base/common/types';
5656
import { DebugConfigurationProviderTriggerKind, WorkspaceTrustState } from 'vs/workbench/api/common/extHostTypes';
@@ -840,6 +840,10 @@ export interface MainThreadNotebookShape extends IDisposable {
840840
}): Promise<void>;
841841
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise<void>;
842842
$unregisterNotebookProvider(viewType: string): Promise<void>;
843+
844+
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void;
845+
$unregisterNotebookSerializer(handle: number): void;
846+
843847
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
844848
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
845849
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
@@ -1863,10 +1867,15 @@ export interface ExtHostNotebookShape {
18631867
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
18641868
$cancelNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
18651869
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
1866-
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, token: CancellationToken, untitledDocumentData?: VSBuffer): Promise<NotebookDataDto>;
1870+
1871+
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto>;
18671872
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
18681873
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
18691874
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
1875+
1876+
$dataToNotebook(handle: number, data: VSBuffer): Promise<NotebookDataDto>;
1877+
$notebookToData(handle: number, data: NotebookDataDto): Promise<VSBuffer>;
1878+
18701879
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
18711880
$acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void;
18721881
$acceptModelSaved(uriComponents: UriComponents): void;

src/vs/workbench/api/common/extHostNotebook.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
77
import { Emitter, Event } from 'vs/base/common/event';
8-
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
8+
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
99
import { URI, UriComponents } from 'vs/base/common/uri';
1010
import * as UUID from 'vs/base/common/uuid';
1111
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -17,7 +17,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
1717
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
1818
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
1919
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
20-
import { CellStatusbarAlignment, CellUri, INotebookCellStatusBarEntry, INotebookExclusiveDocumentFilter, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
20+
import { CellStatusbarAlignment, CellUri, INotebookCellStatusBarEntry, INotebookExclusiveDocumentFilter, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
2121
import * as vscode from 'vscode';
2222
import { ResourceMap } from 'vs/base/common/map';
2323
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
@@ -209,6 +209,7 @@ export class NotebookEditorDecorationType {
209209
}
210210
}
211211

212+
212213
type NotebookContentProviderData = {
213214
readonly provider: vscode.NotebookContentProvider;
214215
readonly extension: IExtensionDescription;
@@ -496,9 +497,52 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
496497
});
497498
}
498499

500+
// --- serialize/deserialize
501+
502+
private _handlePool = 0;
503+
private readonly _notebookSerializer = new Map<number, vscode.NotebookSerializer>();
504+
505+
registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: vscode.NotebookSerializer, options?: TransientOptions): vscode.Disposable {
506+
const handle = this._handlePool++;
507+
this._notebookSerializer.set(handle, serializer);
508+
this._proxy.$registerNotebookSerializer(
509+
handle,
510+
{ id: extension.identifier, location: extension.extensionLocation, description: extension.description },
511+
viewType,
512+
options ?? { transientOutputs: false, transientMetadata: {} }
513+
);
514+
return toDisposable(() => {
515+
this._proxy.$unregisterNotebookSerializer(handle);
516+
});
517+
}
518+
519+
async $dataToNotebook(handle: number, bytes: VSBuffer): Promise<NotebookDataDto> {
520+
const serializer = this._notebookSerializer.get(handle);
521+
if (!serializer) {
522+
throw new Error('NO serializer found');
523+
}
524+
const data = await serializer.dataToNotebook(bytes.buffer);
525+
return {
526+
metadata: typeConverters.NotebookDocumentMetadata.from(data.metadata),
527+
cells: data.cells.map(typeConverters.NotebookCellData.from),
528+
};
529+
}
530+
531+
async $notebookToData(handle: number, data: NotebookDataDto): Promise<VSBuffer> {
532+
const serializer = this._notebookSerializer.get(handle);
533+
if (!serializer) {
534+
throw new Error('NO serializer found');
535+
}
536+
const bytes = await serializer.notebookToData({
537+
metadata: typeConverters.NotebookDocumentMetadata.to(data.metadata),
538+
cells: data.cells.map(typeConverters.NotebookCellData.to)
539+
});
540+
return VSBuffer.wrap(bytes);
541+
}
542+
499543
// --- open, save, saveAs, backup
500544

501-
async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, token: CancellationToken, untitledDocumentData?: VSBuffer): Promise<NotebookDataDto> {
545+
async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto> {
502546
const { provider } = this._getProviderData(viewType);
503547
const data = await provider.openNotebook(URI.revive(uri), { backupId, untitledDocumentData: untitledDocumentData?.buffer }, token);
504548
return {

src/vs/workbench/api/common/extHostTypeConverters.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,16 @@ export namespace NotebookCellData {
14691469
outputs: data.outputs ? data.outputs.map(NotebookCellOutput.from) : []
14701470
};
14711471
}
1472+
1473+
export function to(data: notebooks.ICellDto2): vscode.NotebookCellData {
1474+
return new types.NotebookCellData(
1475+
NotebookCellKind.to(data.cellKind),
1476+
data.source,
1477+
data.language,
1478+
data.outputs ? data.outputs.map(NotebookCellOutput.to) : undefined,
1479+
data.metadata ? NotebookCellMetadata.to(data.metadata) : undefined,
1480+
);
1481+
}
14721482
}
14731483

14741484
export namespace NotebookCellOutputItem {

src/vs/workbench/api/common/menusExtensionPoint.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ const apiMenus: IAPIMenu[] = [
170170
description: localize('comment.actions', "The contributed comment context menu, rendered as buttons below the comment editor"),
171171
supportsSubmenus: false
172172
},
173+
{
174+
key: 'notebook/toolbar',
175+
id: MenuId.NotebookToolbar,
176+
description: localize('notebook.toolbar', "The contributed notebook toolbar menu"),
177+
proposed: true
178+
},
173179
{
174180
key: 'notebook/cell/title',
175181
id: MenuId.NotebookCellTitle,

src/vs/workbench/contrib/notebook/browser/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
// Scrollable Element
77

8-
export const SCROLLABLE_ELEMENT_PADDING_TOP = 22;
8+
export const SCROLLABLE_ELEMENT_PADDING_TOP = 20;
9+
// export const SCROLLABLE_ELEMENT_PADDING_TOP_WITH_TOOLBAR = 8;
910

1011
// Cell sizing related
1112
export const CELL_MARGIN = 8;

src/vs/workbench/contrib/notebook/browser/contrib/cellOperations/cellOperations.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ registerAction2(class extends NotebookCellAction {
173173
primary: KeyMod.Alt | KeyMod.Shift | KeyCode.DownArrow,
174174
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, InputFocusedContext.toNegated()),
175175
weight: KeybindingWeight.WorkbenchContrib
176+
},
177+
menu: {
178+
id: MenuId.NotebookCellTitle,
179+
when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_CELL_EDITABLE),
180+
group: CellOverflowToolbarGroups.Edit,
181+
order: 12
176182
}
177183
});
178184
}

0 commit comments

Comments
 (0)