@@ -7,8 +7,10 @@ import { File } from "./File";
7
7
import { fireOtherStudioAction , OtherStudioAction } from "../../commands/studio" ;
8
8
import { StudioOpenDialog } from "../../queries" ;
9
9
import { studioOpenDialogFromURI } from "../../utils/FileProviderUtil" ;
10
- import { outputChannel , redirectDotvscodeRoot , workspaceFolderOfUri } from "../../utils/index" ;
10
+ import { notNull , outputChannel , redirectDotvscodeRoot , workspaceFolderOfUri } from "../../utils/index" ;
11
11
import { workspaceState } from "../../extension" ;
12
+ import { DocumentContentProvider } from "../DocumentContentProvider" ;
13
+ import { Document } from "../../api/atelier" ;
12
14
13
15
declare function setTimeout ( callback : ( ...args : any [ ] ) => void , ms : number , ...args : any [ ] ) : NodeJS . Timeout ;
14
16
@@ -284,43 +286,98 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
284
286
) ;
285
287
}
286
288
287
- public delete ( uri : vscode . Uri , options : { recursive : boolean } ) : void | Thenable < void > {
289
+ /** Process a Document object that was successfully deleted. */
290
+ private async processDeletedDoc ( doc : Document , uri : vscode . Uri , csp : boolean ) : Promise < void > {
291
+ const events : vscode . FileChangeEvent [ ] = [ ] ;
292
+ try {
293
+ if ( doc . ext ) {
294
+ fireOtherStudioAction ( OtherStudioAction . DeletedDocument , uri , doc . ext ) ;
295
+ }
296
+ // Remove entry from our cache, plus any now-empty ancestor entries
297
+ let thisUri = vscode . Uri . parse ( uri . toString ( ) , true ) ;
298
+ while ( thisUri . path !== "/" ) {
299
+ events . push ( { type : vscode . FileChangeType . Deleted , uri : thisUri } ) ;
300
+ const parentDir = await this . _lookupParentDirectory ( thisUri ) ;
301
+ const name = path . basename ( thisUri . path ) ;
302
+ parentDir . entries . delete ( name ) ;
303
+ if ( ! csp && parentDir . entries . size === 0 ) {
304
+ thisUri = thisUri . with ( { path : path . posix . dirname ( thisUri . path ) } ) ;
305
+ } else {
306
+ break ;
307
+ }
308
+ }
309
+ } catch {
310
+ // Swallow all errors
311
+ } finally {
312
+ if ( events . length ) {
313
+ this . _fireSoon ( ...events ) ;
314
+ }
315
+ }
316
+ }
317
+
318
+ public async delete ( uri : vscode . Uri , options : { recursive : boolean } ) : Promise < void > {
288
319
const { query } = url . parse ( uri . toString ( true ) , true ) ;
289
320
const csp = query . csp === "" || query . csp === "1" ;
290
321
const fileName = csp ? uri . path : uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
322
+ const api = new AtelierAPI ( uri ) ;
291
323
if ( fileName . startsWith ( "." ) ) {
292
324
return ;
293
325
}
294
326
if ( ! fileName . includes ( "." ) ) {
295
- throw new Error ( `${ csp ? "Folder" : "Package" } deletion is not supported on server` ) ;
296
- }
297
- const api = new AtelierAPI ( uri ) ;
298
- return api . deleteDoc ( fileName ) . then (
299
- async ( response ) => {
300
- if ( response . result . ext ) {
301
- fireOtherStudioAction ( OtherStudioAction . DeletedDocument , uri , response . result . ext ) ;
302
- }
303
- // Remove entry from our cache, plus any now-empty ancestor entries
304
- let thisUri = vscode . Uri . parse ( uri . toString ( ) , true ) ;
305
- const events : vscode . FileChangeEvent [ ] = [ ] ;
306
- while ( thisUri . path !== "/" ) {
307
- events . push ( { type : vscode . FileChangeType . Deleted , uri : thisUri } ) ;
308
- const parentDir = await this . _lookupParentDirectory ( thisUri ) ;
309
- const name = path . basename ( thisUri . path ) ;
310
- parentDir . entries . delete ( name ) ;
311
- if ( ! csp && parentDir . entries . size === 0 ) {
312
- thisUri = thisUri . with ( { path : path . posix . dirname ( thisUri . path ) } ) ;
327
+ // Get the list of documents to delete
328
+ const toDelete : string [ ] = await studioOpenDialogFromURI (
329
+ uri ,
330
+ options . recursive ? { flat : true } : undefined
331
+ ) . then ( ( data ) =>
332
+ data . result . content
333
+ . map ( ( entry ) => {
334
+ if ( options . recursive ) {
335
+ return entry . Name ;
336
+ } else if ( entry . Name . includes ( "." ) ) {
337
+ return csp ? uri . path + entry . Name : uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) + entry . Name ;
338
+ }
339
+ return null ;
340
+ } )
341
+ . filter ( notNull )
342
+ ) ;
343
+ if ( toDelete . length == 0 ) {
344
+ // Nothing to delete
345
+ return ;
346
+ }
347
+ // Delete the documents
348
+ return api . deleteDocs ( toDelete ) . then ( ( data ) => {
349
+ let failed = 0 ;
350
+ for ( const doc of data . result ) {
351
+ if ( doc . status == "" ) {
352
+ this . processDeletedDoc ( doc , DocumentContentProvider . getUri ( doc . name , undefined , undefined , true , uri ) , csp ) ;
313
353
} else {
314
- break ;
354
+ // The document was not deleted, so log the error
355
+ failed ++ ;
356
+ outputChannel . appendLine ( `${ failed == 1 ? "\n" : "" } ${ doc . status } ` ) ;
315
357
}
316
358
}
317
- this . _fireSoon ( ...events ) ;
359
+ if ( failed > 0 ) {
360
+ outputChannel . show ( true ) ;
361
+ throw new vscode . FileSystemError (
362
+ `Failed to delete ${ failed } document${
363
+ failed > 1 ? "s" : ""
364
+ } . Check 'ObjectScript' Output channel for details.`
365
+ ) ;
366
+ }
367
+ } ) ;
368
+ }
369
+ return api . deleteDoc ( fileName ) . then (
370
+ ( response ) => {
371
+ this . processDeletedDoc ( response . result , uri , csp ) ;
318
372
} ,
319
373
( error ) => {
320
- if ( error . errorText !== "" ) {
321
- error . message = error . errorText ;
374
+ let message = `Failed to delete file '${ fileName } '.` ;
375
+ if ( error && error . errorText && error . errorText !== "" ) {
376
+ outputChannel . appendLine ( "\n" + error . errorText ) ;
377
+ outputChannel . show ( true ) ;
378
+ message += " Check 'ObjectScript' Output channel for details." ;
322
379
}
323
- throw error ;
380
+ throw new vscode . FileSystemError ( message ) ;
324
381
}
325
382
) ;
326
383
}
0 commit comments