55
66import * as vscode from 'vscode' ;
77import { ATTACHMENT_CLEANUP_COMMANDID , JUPYTER_NOTEBOOK_MARKDOWN_SELECTOR } from './constants' ;
8- import { DebounceTrigger , deepClone , objectEquals } from './helper' ;
8+ import { deepClone , objectEquals , Delayer } from './helper' ;
99
1010interface AttachmentCleanRequest {
1111 notebook : vscode . NotebookDocument ;
@@ -32,15 +32,10 @@ export class AttachmentCleaner implements vscode.CodeActionProvider {
3232
3333 private _disposables : vscode . Disposable [ ] ;
3434 private _imageDiagnosticCollection : vscode . DiagnosticCollection ;
35+ private readonly _delayer = new Delayer ( 750 ) ;
36+
3537 constructor ( ) {
3638 this . _disposables = [ ] ;
37- const debounceTrigger = new DebounceTrigger < AttachmentCleanRequest > ( {
38- callback : ( change : AttachmentCleanRequest ) => {
39- this . cleanNotebookAttachments ( change ) ;
40- } ,
41- delay : 500
42- } ) ;
43-
4439 this . _imageDiagnosticCollection = vscode . languages . createDiagnosticCollection ( 'Notebook Image Attachment' ) ;
4540 this . _disposables . push ( this . _imageDiagnosticCollection ) ;
4641
@@ -57,23 +52,66 @@ export class AttachmentCleaner implements vscode.CodeActionProvider {
5752 } ) ) ;
5853
5954 this . _disposables . push ( vscode . workspace . onDidChangeNotebookDocument ( e => {
60- e . cellChanges . forEach ( change => {
61- if ( ! change . document ) {
62- return ;
63- }
55+ this . _delayer . trigger ( ( ) => {
6456
65- if ( change . cell . kind !== vscode . NotebookCellKind . Markup ) {
66- return ;
67- }
57+ e . cellChanges . forEach ( change => {
58+ if ( ! change . document ) {
59+ return ;
60+ }
6861
69- debounceTrigger . trigger ( {
70- notebook : e . notebook ,
71- cell : change . cell ,
72- document : change . document
62+ if ( change . cell . kind !== vscode . NotebookCellKind . Markup ) {
63+ return ;
64+ }
65+
66+ const metadataEdit = this . cleanNotebookAttachments ( {
67+ notebook : e . notebook ,
68+ cell : change . cell ,
69+ document : change . document
70+ } ) ;
71+ if ( metadataEdit ) {
72+ const workspaceEdit = new vscode . WorkspaceEdit ( ) ;
73+ workspaceEdit . set ( e . notebook . uri , [ metadataEdit ] ) ;
74+ vscode . workspace . applyEdit ( workspaceEdit ) ;
75+ }
7376 } ) ;
7477 } ) ;
7578 } ) ) ;
7679
80+
81+ this . _disposables . push ( vscode . workspace . onWillSaveNotebookDocument ( e => {
82+ if ( e . reason === vscode . TextDocumentSaveReason . Manual ) {
83+ this . _delayer . dispose ( ) ;
84+
85+ e . waitUntil ( new Promise ( ( resolve ) => {
86+ if ( e . notebook . getCells ( ) . length === 0 ) {
87+ return ;
88+ }
89+
90+ const notebookEdits : vscode . NotebookEdit [ ] = [ ] ;
91+ for ( const cell of e . notebook . getCells ( ) ) {
92+ if ( cell . kind !== vscode . NotebookCellKind . Markup ) {
93+ continue ;
94+ }
95+
96+ const metadataEdit = this . cleanNotebookAttachments ( {
97+ notebook : e . notebook ,
98+ cell : cell ,
99+ document : cell . document
100+ } ) ;
101+
102+ if ( metadataEdit ) {
103+ notebookEdits . push ( metadataEdit ) ;
104+ }
105+ }
106+
107+ const workspaceEdit = new vscode . WorkspaceEdit ( ) ;
108+ workspaceEdit . set ( e . notebook . uri , notebookEdits ) ;
109+
110+ resolve ( workspaceEdit ) ;
111+ } ) ) ;
112+ }
113+ } ) ) ;
114+
77115 this . _disposables . push ( vscode . workspace . onDidCloseNotebookDocument ( e => {
78116 this . _attachmentCache . delete ( e . uri . toString ( ) ) ;
79117 } ) ) ;
@@ -134,8 +172,10 @@ export class AttachmentCleaner implements vscode.CodeActionProvider {
134172 /**
135173 * take in a NotebookDocumentChangeEvent, and clean the attachment data for the cell(s) that have had their markdown source code changed
136174 * @param e NotebookDocumentChangeEvent from the onDidChangeNotebookDocument listener
175+ * @returns vscode.NotebookEdit, the metadata alteration performed on the json behind the ipynb
137176 */
138- private cleanNotebookAttachments ( e : AttachmentCleanRequest ) {
177+ private cleanNotebookAttachments ( e : AttachmentCleanRequest ) : vscode . NotebookEdit | undefined {
178+
139179 if ( e . notebook . isClosed ) {
140180 return ;
141181 }
@@ -187,16 +227,16 @@ export class AttachmentCleaner implements vscode.CodeActionProvider {
187227 }
188228 }
189229
230+ this . updateDiagnostics ( cell . document . uri , diagnostics ) ;
231+
190232 if ( cell . index > - 1 && ! objectEquals ( markdownAttachmentsInUse , cell . metadata . attachments ) ) {
191233 const updateMetadata : { [ key : string ] : any } = deepClone ( cell . metadata ) ;
192234 updateMetadata . attachments = markdownAttachmentsInUse ;
193235 const metadataEdit = vscode . NotebookEdit . updateCellMetadata ( cell . index , updateMetadata ) ;
194- const workspaceEdit = new vscode . WorkspaceEdit ( ) ;
195- workspaceEdit . set ( e . notebook . uri , [ metadataEdit ] ) ;
196- vscode . workspace . applyEdit ( workspaceEdit ) ;
197- }
198236
199- this . updateDiagnostics ( cell . document . uri , diagnostics ) ;
237+ return metadataEdit ;
238+ }
239+ return ;
200240 }
201241
202242 private analyzeMissingAttachments ( document : vscode . TextDocument ) : void {
@@ -345,6 +385,7 @@ export class AttachmentCleaner implements vscode.CodeActionProvider {
345385
346386 dispose ( ) {
347387 this . _disposables . forEach ( d => d . dispose ( ) ) ;
388+ this . _delayer . dispose ( ) ;
348389 }
349390}
350391
0 commit comments