@@ -14,8 +14,9 @@ import { isFalsyOrWhitespace } from 'vs/base/common/strings';
14
14
import { assertIsDefined } from 'vs/base/common/types' ;
15
15
import { URI , UriComponents } from 'vs/base/common/uri' ;
16
16
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' ;
17
+ import * as files from 'vs/platform/files/common/files' ;
17
18
import { Cache } from 'vs/workbench/api/common/cache' ;
18
- import { ExtHostNotebookShape , IMainContext , IModelAddedData , INotebookCellStatusBarListDto , INotebookDocumentsAndEditorsDelta , INotebookDocumentShowOptions , INotebookEditorAddData , MainContext , MainThreadNotebookDocumentsShape , MainThreadNotebookEditorsShape , MainThreadNotebookShape , NotebookDataDto } from 'vs/workbench/api/common/extHost.protocol' ;
19
+ import { ExtHostNotebookShape , IMainContext , IModelAddedData , INotebookCellStatusBarListDto , INotebookDocumentsAndEditorsDelta , INotebookDocumentShowOptions , INotebookEditorAddData , INotebookPartialFileStatsWithMetadata , MainContext , MainThreadNotebookDocumentsShape , MainThreadNotebookEditorsShape , MainThreadNotebookShape , NotebookDataDto } from 'vs/workbench/api/common/extHost.protocol' ;
19
20
import { ApiCommand , ApiCommandArgument , ApiCommandResult , CommandsConverter , ExtHostCommands } from 'vs/workbench/api/common/extHostCommands' ;
20
21
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments' ;
21
22
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors' ;
@@ -27,6 +28,9 @@ import type * as vscode from 'vscode';
27
28
import { ExtHostCell , ExtHostNotebookDocument } from './extHostNotebookDocument' ;
28
29
import { ExtHostNotebookEditor } from './extHostNotebookEditor' ;
29
30
import { onUnexpectedExternalError } from 'vs/base/common/errors' ;
31
+ import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer' ;
32
+ import { basename } from 'vs/base/common/resources' ;
33
+ import { filter } from 'vs/base/common/objects' ;
30
34
31
35
32
36
@@ -69,6 +73,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
69
73
commands : ExtHostCommands ,
70
74
private _textDocumentsAndEditors : ExtHostDocumentsAndEditors ,
71
75
private _textDocuments : ExtHostDocuments ,
76
+ private _extHostFileSystem : IExtHostConsumerFileSystem
72
77
) {
73
78
this . _notebookProxy = mainContext . getProxy ( MainContext . MainThreadNotebook ) ;
74
79
this . _notebookDocumentsProxy = mainContext . getProxy ( MainContext . MainThreadNotebookDocuments ) ;
@@ -263,14 +268,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
263
268
// --- serialize/deserialize
264
269
265
270
private _handlePool = 0 ;
266
- private readonly _notebookSerializer = new Map < number , vscode . NotebookSerializer > ( ) ;
271
+ private readonly _notebookSerializer = new Map < number , { viewType : string ; serializer : vscode . NotebookSerializer ; options : vscode . NotebookDocumentContentOptions | undefined } > ( ) ;
267
272
268
273
registerNotebookSerializer ( extension : IExtensionDescription , viewType : string , serializer : vscode . NotebookSerializer , options ?: vscode . NotebookDocumentContentOptions , registration ?: vscode . NotebookRegistrationData ) : vscode . Disposable {
269
274
if ( isFalsyOrWhitespace ( viewType ) ) {
270
275
throw new Error ( `viewType cannot be empty or just whitespace` ) ;
271
276
}
272
277
const handle = this . _handlePool ++ ;
273
- this . _notebookSerializer . set ( handle , serializer ) ;
278
+ this . _notebookSerializer . set ( handle , { viewType , serializer, options } ) ;
274
279
this . _notebookProxy . $registerNotebookSerializer (
275
280
handle ,
276
281
{ id : extension . identifier , location : extension . extensionLocation } ,
@@ -288,7 +293,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
288
293
if ( ! serializer ) {
289
294
throw new Error ( 'NO serializer found' ) ;
290
295
}
291
- const data = await serializer . deserializeNotebook ( bytes . buffer , token ) ;
296
+ const data = await serializer . serializer . deserializeNotebook ( bytes . buffer , token ) ;
292
297
return new SerializableObjectWithBuffers ( typeConverters . NotebookData . from ( data ) ) ;
293
298
}
294
299
@@ -297,10 +302,67 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
297
302
if ( ! serializer ) {
298
303
throw new Error ( 'NO serializer found' ) ;
299
304
}
300
- const bytes = await serializer . serializeNotebook ( typeConverters . NotebookData . to ( data . value ) , token ) ;
305
+ const bytes = await serializer . serializer . serializeNotebook ( typeConverters . NotebookData . to ( data . value ) , token ) ;
301
306
return VSBuffer . wrap ( bytes ) ;
302
307
}
303
308
309
+ async $saveNotebook ( handle : number , uriComponents : UriComponents , versionId : number , options : files . IWriteFileOptions , token : CancellationToken ) : Promise < INotebookPartialFileStatsWithMetadata > {
310
+ const uri = URI . revive ( uriComponents ) ;
311
+ const serializer = this . _notebookSerializer . get ( handle ) ;
312
+ if ( ! serializer ) {
313
+ throw new Error ( 'NO serializer found' ) ;
314
+ }
315
+
316
+ const document = this . _documents . get ( uri ) ;
317
+ if ( ! document ) {
318
+ throw new Error ( 'Document NOT found' ) ;
319
+ }
320
+
321
+ if ( document . versionId !== versionId ) {
322
+ throw new Error ( 'Document version mismatch' ) ;
323
+ }
324
+
325
+ const data : vscode . NotebookData = {
326
+ metadata : filter ( document . apiNotebook . metadata , key => ! ( serializer . options ?. transientDocumentMetadata ?? { } ) [ key ] ) ,
327
+ cells : [ ] ,
328
+ } ;
329
+
330
+ for ( const cell of document . apiNotebook . getCells ( ) ) {
331
+ const cellData = new extHostTypes . NotebookCellData (
332
+ cell . kind ,
333
+ cell . document . getText ( ) ,
334
+ cell . document . languageId ,
335
+ cell . mime ,
336
+ ! ( serializer . options ?. transientOutputs ) ? [ ...cell . outputs ] : [ ] ,
337
+ cell . metadata ,
338
+ cell . executionSummary
339
+ ) ;
340
+
341
+ cellData . metadata = filter ( cell . metadata , key => ! ( serializer . options ?. transientCellMetadata ?? { } ) [ key ] ) ;
342
+ data . cells . push ( cellData ) ;
343
+ }
344
+
345
+ const bytes = await serializer . serializer . serializeNotebook ( data , token ) ;
346
+ await this . _extHostFileSystem . value . writeFile ( uri , bytes ) ;
347
+ const stat = await this . _extHostFileSystem . value . stat ( uri ) ;
348
+
349
+ const fileStats = {
350
+ name : basename ( uri ) , // providerExtUri.basename(resource)
351
+ isFile : ( stat . type & files . FileType . File ) !== 0 ,
352
+ isDirectory : ( stat . type & files . FileType . Directory ) !== 0 ,
353
+ isSymbolicLink : ( stat . type & files . FileType . SymbolicLink ) !== 0 ,
354
+ mtime : stat . mtime ,
355
+ ctime : stat . ctime ,
356
+ size : stat . size ,
357
+ readonly : Boolean ( ( stat . permissions ?? 0 ) & files . FilePermission . Readonly ) || ! this . _extHostFileSystem . value . isWritableFileSystem ( uri . scheme ) ,
358
+ locked : Boolean ( ( stat . permissions ?? 0 ) & files . FilePermission . Locked ) ,
359
+ etag : files . etag ( { mtime : stat . mtime , size : stat . size } ) ,
360
+ children : undefined
361
+ } ;
362
+
363
+ return fileStats ;
364
+ }
365
+
304
366
// --- open, save, saveAs, backup
305
367
306
368
0 commit comments