diff --git a/package.json b/package.json index 54444451..e2d4dae9 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,11 @@ "title": "Execute Query", "category": "SQL" }, + { + "command": "extension.cancelQuery", + "title": "Cancel executing T-SQL query", + "category": "SQL" + }, { "command": "extension.connect", "title": "Connect", diff --git a/src/controllers/mainController.ts b/src/controllers/mainController.ts index 06e1f023..0876221d 100644 --- a/src/controllers/mainController.ts +++ b/src/controllers/mainController.ts @@ -98,6 +98,8 @@ export default class MainController implements vscode.Disposable { this._event.on(Constants.cmdChooseDatabase, () => { self.onChooseDatabase(); } ); this.registerCommand(Constants.cmdShowReleaseNotes); this._event.on(Constants.cmdShowReleaseNotes, () => { self.launchReleaseNotesPage(); } ); + this.registerCommand(Constants.cmdCancelQuery); + this._event.on(Constants.cmdCancelQuery, () => { self.onCancelQuery(); }); this._vscodeWrapper = new VscodeWrapper(); @@ -156,6 +158,14 @@ export default class MainController implements vscode.Disposable { }); } + /** + * Handles the command to cancel queries + */ + private onCancelQuery(): void { + let uri = this._vscodeWrapper.activeTextEditorUri; + this._outputContentProvider.cancelQuery(uri); + } + /** * Choose a new database from the current server */ diff --git a/src/models/SqlOutputContentProvider.ts b/src/models/SqlOutputContentProvider.ts index 1366db4f..6910cf45 100644 --- a/src/models/SqlOutputContentProvider.ts +++ b/src/models/SqlOutputContentProvider.ts @@ -236,12 +236,19 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi public cancelQuery(uri: string): void { let self = this; - // Cancel the query + // If there isn't a query for this uri, then return an info message let resultsUri = this.getResultsUri(uri).toString(); - this._queryResultsMap.get(resultsUri).cancel().then(success => { - // On success, dispose of the query runner - self._queryResultsMap.delete(resultsUri); - }, error => { + let queryRunner = this._queryResultsMap.get(resultsUri); + if (queryRunner === undefined || !queryRunner.isExecutingQuery) { + self._vscodeWrapper.showInformationMessage(Constants.msgCancelQueryNotRunning); + return; + } + + // Switch the spinner to canceling, which will be reset when the query execute sends back its completed event + this._statusView.cancelingQuery(queryRunner.uri); + + // Cancel the query + queryRunner.cancel().then(success => undefined, error => { // On error, show error message self._vscodeWrapper.showErrorMessage(Utils.formatString(Constants.msgCancelQueryFailed, error)); }); @@ -272,7 +279,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi /** * Executed from the MainController when a text document (that already exists on disk) was - * closed. If the query is in progress, it will be cancelled. If there is a query at all, + * closed. If the query is in progress, it will be canceled. If there is a query at all, * the query will be disposed. * @param doc The document that was closed */ diff --git a/src/models/constants.ts b/src/models/constants.ts index 08ccf6ea..4cd42e6b 100644 --- a/src/models/constants.ts +++ b/src/models/constants.ts @@ -65,6 +65,8 @@ export const msgRunQueryNoConnection = 'runQuery: no active connection - prompti export const msgRunQueryInProgress = 'A query is already executing for this editor session. Please cancel this query or wait for its completion.'; export const msgCancelQueryFailed = 'Failed to cancel query: {0}'; +export const msgCancelQueryNotRunning = 'Cannot cancel query, no query is executing'; +export const msgCancelQuerySuccess = 'Query successfully canceled'; export const msgContentProviderOnContentUpdated = 'Content provider: onContentUpdated called'; export const msgContentProviderAssociationFailure = 'Content provider: Unable to associate status view for current file'; @@ -158,6 +160,7 @@ export const connectErrorTooltip = 'Error connecting to: '; export const connectErrorCode = 'Errorcode: '; export const connectErrorMessage = 'ErrorMessage: '; export const executeQueryLabel = 'Executing query '; +export const cancelingQueryLabel = 'Canceling query '; export const serviceCompatibleVersion = '1.0.0'; export const serviceNotCompatibleError = 'Client is not compatiable with the service layer'; diff --git a/src/views/statusView.ts b/src/views/statusView.ts index 089d1694..5658a6fe 100644 --- a/src/views/statusView.ts +++ b/src/views/statusView.ts @@ -135,6 +135,16 @@ export default class StatusView implements vscode.Disposable { bar.statusQuery.hide(); } + public cancelingQuery(fileUri: string): void { + let bar = this.getStatusBar(fileUri); + bar.statusQuery.hide(); + + bar.statusQuery.command = undefined; + bar.statusQuery.tooltip = Constants.cancelingQueryLabel; + this.showStatusBarItem(fileUri, bar.statusQuery); + this.showProgress(fileUri, Constants.cancelingQueryLabel, bar.statusQuery); + } + public installingService(fileUri: string): void { let bar = this.getStatusBar(fileUri); bar.statusConnection.command = undefined;