import * as fse from 'fs-extra' ; import * as path from 'path' ; import * as vscode from 'vscode' ; import { DialogResponses , IActionContext , UserCancelledError } from 'vscode-azureextensionui' ; import { ext } from '../../extensionVariables' ; import { localize } from "../../localize" ; import { createTemporaryFile } from '../../utils/fsUtil' ; import { writeToEditor } from '../../utils/vscodeUtils' ; export abstract class Editor < ContextT > implements vscode . Disposable { private fileMap : { [ key ] : [ vscode . TextDocument , ContextT ] ; } = { } ; private ignoreSave : boolean = false ; constructor ( private readonly showSavePromptKey ) { } public abstract getData ( context ) ; public abstract updateData ( context , data ) ; public abstract getFilename ( context ) ; public abstract getDiffFilename ( context ) ; public abstract getSaveConfirmationText ( context ) ; public abstract getSize ( context ) ; public async showEditor ( context , sizeLimit ? ) { const fileName = await this . getFilename ( context ) ; const originFileName = await this . getDiffFilename ( context ) ; this . appendLineToOutput ( localize ( 'opening' , 'Opening "{0}"...' , fileName ) ) ; if ( sizeLimit !== undefined ) { const size = await this . getSize ( context ) ; if ( size > sizeLimit ) { const message = localize ( 'tooLargeError' , '"{0}" is too large to download.' , fileName ) ; throw new Error ( message ) ; } } const localFilePath = await createTemporaryFile ( fileName ) ; const localOriginPath = await createTemporaryFile ( originFileName ) ; const document = await vscode . workspace . openTextDocument ( localFilePath ) ; if ( document . isDirty ) { const overwriteFlag = await vscode . window . showWarningMessage ( localize ( "" , `You are about to overwrite "${ fileName }", which has unsaved changes. Do you want to continue?` ) , { modal : true } , DialogResponses . yes , DialogResponses . cancel ) ; if ( overwriteFlag !== DialogResponses . yes ) { throw new UserCancelledError ( ) ; } } this . fileMap [ localFilePath ] = [ document , context ] ; const data = await this . getData ( context ) ; await fse . writeFile ( localOriginPath , data ) ; const textEditor = await vscode . window . showTextDocument ( document ) ; await this . updateEditor ( data , textEditor ) ; } public async updateMatchingContext ( doc ) { const filePath = Object . keys ( this . fileMap ) . find ( ( fsPath ) => path . relative ( doc . fsPath , fsPath ) === '' ) ; if ( filePath ) { const [ textDocument , context ] = this . fileMap [ filePath ] ; await this . updateRemote ( context , textDocument ) ; } } public async dispose ( ) { Object . keys ( this . fileMap ) . forEach ( async ( key ) => await fse . remove ( path . dirname ( key ) ) ) ; } public async onDidSaveTextDocument ( actionContext , globalState , doc ) { actionContext . telemetry . suppressIfSuccessful = true ; const filePath = Object . keys ( this . fileMap ) . find ( ( fsPath ) => path . relative ( doc . uri . fsPath , fsPath ) === '' ) ; if ( ! this . ignoreSave && filePath ) { actionContext . telemetry . suppressIfSuccessful = false ; const context = this . fileMap [ filePath ] [ 1 ] ; const showSaveWarning = vscode . workspace . getConfiguration ( ) . get ( this . showSavePromptKey ) ; if ( showSaveWarning ) { const message = await this . getSaveConfirmationText ( context ) ; const result = await vscode . window . showWarningMessage ( message , DialogResponses . upload , DialogResponses . alwaysUpload , DialogResponses . dontUpload ) ; if ( result === DialogResponses . alwaysUpload ) { await vscode . workspace . getConfiguration ( ) . update ( this . showSavePromptKey , false , vscode . ConfigurationTarget . Global ) ; await globalState . update ( this . showSavePromptKey , true ) ; } else if ( result === DialogResponses . dontUpload ) { throw new UserCancelledError ( ) ; } else if ( ! result ) { throw new UserCancelledError ( ) ; } } await this . updateRemote ( context , doc ) ; } } protected appendLineToOutput ( value ) { ext . outputChannel . appendLine ( value ) ; ext . outputChannel . show ( true ) ; } private async updateRemote ( context , doc ) { const filename = await this . getFilename ( context ) ; this . appendLineToOutput ( localize ( 'updating' , 'Updating "{0}" ...' , filename ) ) ; const updatedData = await this . updateData ( context , doc . getText ( ) ) ; this . appendLineToOutput ( localize ( 'done' , 'Updated "{0}".' , filename ) ) ; await this . updateEditor ( updatedData , vscode . window . activeTextEditor ) ; } private async updateEditor ( data , textEditor ? ) { if ( ! ! textEditor ) { await writeToEditor ( textEditor , data ) ; this . ignoreSave = true ; try { await textEditor . document . save ( ) ; } finally { this . ignoreSave = false ; } } } }