@@ -7,8 +7,10 @@ import { File } from "./File";
77import { fireOtherStudioAction , OtherStudioAction } from "../../commands/studio" ;
88import { StudioOpenDialog } from "../../queries" ;
99import { studioOpenDialogFromURI } from "../../utils/FileProviderUtil" ;
10- import { outputChannel , redirectDotvscodeRoot , workspaceFolderOfUri } from "../../utils/index" ;
10+ import { notNull , outputChannel , redirectDotvscodeRoot , workspaceFolderOfUri } from "../../utils/index" ;
1111import { workspaceState } from "../../extension" ;
12+ import { DocumentContentProvider } from "../DocumentContentProvider" ;
13+ import { Document } from "../../api/atelier" ;
1214
1315declare function setTimeout ( callback : ( ...args : any [ ] ) => void , ms : number , ...args : any [ ] ) : NodeJS . Timeout ;
1416
@@ -284,43 +286,98 @@ export class FileSystemProvider implements vscode.FileSystemProvider {
284286 ) ;
285287 }
286288
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 > {
288319 const { query } = url . parse ( uri . toString ( true ) , true ) ;
289320 const csp = query . csp === "" || query . csp === "1" ;
290321 const fileName = csp ? uri . path : uri . path . slice ( 1 ) . replace ( / \/ / g, "." ) ;
322+ const api = new AtelierAPI ( uri ) ;
291323 if ( fileName . startsWith ( "." ) ) {
292324 return ;
293325 }
294326 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 ) ;
313353 } else {
314- break ;
354+ // The document was not deleted, so log the error
355+ failed ++ ;
356+ outputChannel . appendLine ( `${ failed == 1 ? "\n" : "" } ${ doc . status } ` ) ;
315357 }
316358 }
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 ) ;
318372 } ,
319373 ( 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." ;
322379 }
323- throw error ;
380+ throw new vscode . FileSystemError ( message ) ;
324381 }
325382 ) ;
326383 }
0 commit comments