mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-21 17:22:55 -05:00
Rework how we handle custom editors (#5696)
* update how we handle editors * small edit * handle changing languages * implement generic language association * implement notebook serializers * fix tests * formatting * update how we handle editors * small edit * handle changing languages * implement generic language association * implement notebook serializers * fix tests * formatting * fix broken * fix compile * fix tests * add back in removed note book contributions * fix layering * fix compile errors * fix workbench * fix hanging promises * idk why these changed * fix change * add comments to language change code * fix a few bugs * add query plan association
This commit is contained in:
@@ -30,9 +30,10 @@ import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilit
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { notebookModeId } from 'sql/workbench/browser/customInputConverter';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
|
||||
import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput';
|
||||
import { find } from 'vs/base/common/arrays';
|
||||
|
||||
class MainThreadNotebookEditor extends Disposable {
|
||||
@@ -453,13 +454,18 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
};
|
||||
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
||||
|
||||
const fileInput = isUntitled ? this._untitledEditorService.createOrGet(uri, notebookModeId, options.initialContent) :
|
||||
this._editorService.createInput({ resource: uri, mode: notebookModeId });
|
||||
let input = this._instantiationService.createInstance(NotebookInput, path.basename(uri.fsPath), uri, fileInput);
|
||||
const fileInput = isUntitled ? this._untitledEditorService.createOrGet(uri, 'notebook', options.initialContent) :
|
||||
this._editorService.createInput({ resource: uri, mode: 'notebook' });
|
||||
let input: NotebookInput;
|
||||
if (isUntitled) {
|
||||
input = this._instantiationService.createInstance(UntitledNotebookInput, path.basename(uri.fsPath), uri, fileInput);
|
||||
} else {
|
||||
input = this._instantiationService.createInstance(FileNotebookInput, path.basename(uri.fsPath), uri, fileInput);
|
||||
}
|
||||
input.defaultKernel = options.defaultKernel;
|
||||
input.connectionProfile = new ConnectionProfile(this._capabilitiesService, options.connectionProfile);
|
||||
if (isUntitled) {
|
||||
let untitledModel = await input.textInput.resolve();
|
||||
let untitledModel = await (input as UntitledNotebookInput).textInput.resolve();
|
||||
await untitledModel.load();
|
||||
input.untitledEditorModel = untitledModel;
|
||||
if (options.initialDirtyState === false) {
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorInput, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { IQueryEditorOptions } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||
import { QueryPlanInput } from 'sql/workbench/contrib/queryPlan/common/queryPlanInput';
|
||||
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { find } from 'vs/base/common/arrays';
|
||||
|
||||
////// Exported public functions/vars
|
||||
|
||||
// prefix for untitled sql editors
|
||||
export const untitledFilePrefix = 'SQLQuery';
|
||||
|
||||
// mode identifier for SQL mode
|
||||
export const sqlModeId = 'sql';
|
||||
export const notebookModeId = 'notebook';
|
||||
|
||||
/**
|
||||
* Checks if the specified input is supported by one our custom input types, and if so convert it
|
||||
* to that type.
|
||||
* @param input The input to check for conversion
|
||||
* @param options Editor options for controlling the conversion
|
||||
* @param instantiationService The instantiation service to use to create the new input types
|
||||
*/
|
||||
export function convertEditorInput(input: EditorInput, options: IQueryEditorOptions, instantiationService: IInstantiationService): EditorInput {
|
||||
let denyQueryEditor: boolean = options && options.denyQueryEditor;
|
||||
let untitledEditorInput: UntitledEditorInput = input as UntitledEditorInput;
|
||||
let mode: string = (untitledEditorInput && untitledEditorInput.getMode) ? untitledEditorInput.getMode() : 'sql';
|
||||
if (input && !denyQueryEditor) {
|
||||
let uri: URI;
|
||||
if (mode === 'sql') {
|
||||
//QueryInput
|
||||
uri = getQueryEditorFileUri(input);
|
||||
if (uri) {
|
||||
const queryResultsInput: QueryResultsInput = instantiationService.createInstance(QueryResultsInput, uri.toString(true));
|
||||
let queryInput: QueryInput = instantiationService.createInstance(QueryInput, '', input, queryResultsInput, undefined);
|
||||
return queryInput;
|
||||
}
|
||||
|
||||
//QueryPlanInput
|
||||
uri = getQueryPlanEditorUri(input);
|
||||
if (uri) {
|
||||
return instantiationService.createInstance(QueryPlanInput, uri, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
//Notebook
|
||||
uri = getNotebookEditorUri(input, instantiationService);
|
||||
if (uri) {
|
||||
let notebookInput: NotebookInput = instantiationService.createInstance(NotebookInput, input.getName(), uri, input);
|
||||
return notebookInput;
|
||||
}
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resource of the input if it's one of the ones we support.
|
||||
* @param input The IEditorInput to get the resource of
|
||||
*/
|
||||
export function getSupportedInputResource(input: IEditorInput): URI {
|
||||
if (input instanceof UntitledEditorInput) {
|
||||
let untitledCast: UntitledEditorInput = <UntitledEditorInput>input;
|
||||
if (untitledCast) {
|
||||
return untitledCast.getResource();
|
||||
}
|
||||
}
|
||||
|
||||
if (input instanceof FileEditorInput) {
|
||||
let fileCast: FileEditorInput = <FileEditorInput>input;
|
||||
if (fileCast) {
|
||||
return fileCast.getResource();
|
||||
}
|
||||
}
|
||||
|
||||
if (input instanceof ResourceEditorInput) {
|
||||
let resourceCast: ResourceEditorInput = <ResourceEditorInput>input;
|
||||
if (resourceCast) {
|
||||
return resourceCast.getResource();
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
////// Non-Exported Private functions/vars
|
||||
|
||||
// file extensions for the inputs we support (should be all upper case for comparison)
|
||||
const sqlFileTypes = ['SQL'];
|
||||
const sqlPlanFileTypes = ['SQLPLAN'];
|
||||
|
||||
/**
|
||||
* If input is a supported query editor file, return it's URI. Otherwise return undefined.
|
||||
* @param input The EditorInput to retrieve the URI of
|
||||
*/
|
||||
function getQueryEditorFileUri(input: EditorInput): URI {
|
||||
if (!input || !input.getName()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If this editor is not already of type queryinput
|
||||
if (!(input instanceof QueryInput)) {
|
||||
|
||||
// If this editor has a URI
|
||||
let uri: URI = getSupportedInputResource(input);
|
||||
if (uri) {
|
||||
let isValidUri: boolean = !!uri && !!uri.toString;
|
||||
|
||||
if (isValidUri && (hasFileExtension(sqlFileTypes, input, true) || hasSqlFileMode(input))) {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* If input is a supported query plan editor file (.sqlplan), return it's URI. Otherwise return undefined.
|
||||
* @param input The EditorInput to get the URI of
|
||||
*/
|
||||
function getQueryPlanEditorUri(input: EditorInput): URI {
|
||||
if (!input || !input.getName()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If this editor is not already of type queryinput
|
||||
if (!(input instanceof QueryPlanInput)) {
|
||||
let uri: URI = getSupportedInputResource(input);
|
||||
if (uri) {
|
||||
if (hasFileExtension(sqlPlanFileTypes, input, false)) {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* If input is a supported notebook editor file (.ipynb), return it's URI. Otherwise return undefined.
|
||||
* @param input The EditorInput to get the URI of.
|
||||
*/
|
||||
function getNotebookEditorUri(input: EditorInput, instantiationService: IInstantiationService): URI {
|
||||
if (!input || !input.getName()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If this editor is not already of type notebook input
|
||||
if (!(input instanceof NotebookInput)) {
|
||||
let uri: URI = getSupportedInputResource(input);
|
||||
if (uri) {
|
||||
if (hasFileExtension(getNotebookFileExtensions(instantiationService), input, false) || hasNotebookFileMode(input)) {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getNotebookFileExtensions(instantiationService: IInstantiationService): string[] {
|
||||
return withService<INotebookService, string[]>(instantiationService, INotebookService, notebookService => {
|
||||
return notebookService.getSupportedFileExtensions();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given EditorInput is set to either undefined or notebook mode
|
||||
* @param input The EditorInput to check the mode of
|
||||
*/
|
||||
function hasNotebookFileMode(input: EditorInput): boolean {
|
||||
if (input instanceof UntitledEditorInput) {
|
||||
let untitledCast: UntitledEditorInput = <UntitledEditorInput>input;
|
||||
return (untitledCast && untitledCast.getMode() === notebookModeId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function withService<TService, TResult>(instantiationService: IInstantiationService, serviceId: ServiceIdentifier<TService>, action: (service: TService) => TResult, ): TResult {
|
||||
return instantiationService.invokeFunction(accessor => {
|
||||
let service = accessor.get(serviceId);
|
||||
return action(service);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given EditorInput is set to either undefined or sql mode
|
||||
* @param input The EditorInput to check the mode of
|
||||
*/
|
||||
function hasSqlFileMode(input: EditorInput): boolean {
|
||||
if (input instanceof UntitledEditorInput) {
|
||||
let untitledCast: UntitledEditorInput = <UntitledEditorInput>input;
|
||||
return untitledCast && (untitledCast.getMode() === undefined || untitledCast.getMode() === sqlModeId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the name of the specified input has an extension that is
|
||||
* @param extensions The extensions to check for
|
||||
* @param input The input to check for the specified extensions
|
||||
*/
|
||||
function hasFileExtension(extensions: string[], input: EditorInput, checkUntitledFileType: boolean): boolean {
|
||||
// Check the extension type
|
||||
let lastPeriodIndex = input.getName().lastIndexOf('.');
|
||||
if (lastPeriodIndex > -1) {
|
||||
let extension: string = input.getName().substr(lastPeriodIndex + 1).toUpperCase();
|
||||
return !!find(extensions, x => x === extension);
|
||||
}
|
||||
|
||||
// Check for untitled file type
|
||||
if (checkUntitledFileType && find(input.getName(), x => x === untitledFilePrefix)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return false if not a queryEditor file
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns file mode - notebookModeId or sqlModeId
|
||||
export function getFileMode(instantiationService: IInstantiationService, resource: URI): string {
|
||||
if (!resource) {
|
||||
return sqlModeId;
|
||||
}
|
||||
return withService<INotebookService, string>(instantiationService, INotebookService, notebookService => {
|
||||
for (const editor of notebookService.listNotebookEditors()) {
|
||||
if (editor.notebookParams.notebookUri === resource) {
|
||||
return notebookModeId;
|
||||
}
|
||||
}
|
||||
return sqlModeId;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IModeSupport, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
||||
import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/common/languageAssociation';
|
||||
|
||||
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
||||
|
||||
/**
|
||||
* Handles setting a mode from the editor status and converts inputs if necessary
|
||||
*/
|
||||
export async function setMode(accessor: ServicesAccessor, modeSupport: IModeSupport, activeEditor: IEditorInput, language: string): Promise<void> {
|
||||
const editorService = accessor.get(IEditorService);
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const activeWidget = getCodeEditor(editorService.activeTextEditorWidget);
|
||||
const activeControl = editorService.activeControl;
|
||||
const textModel = activeWidget.getModel();
|
||||
const oldLanguage = textModel.getLanguageIdentifier().language;
|
||||
if (language !== oldLanguage) {
|
||||
const oldInputCreator = languageAssociationRegistry.getAssociations().filter(e => e.language === oldLanguage)[0]; // who knows how to handle the current language
|
||||
const newInputCreator = languageAssociationRegistry.getAssociations().filter(e => e.language === language)[0]; // who knows how to handle the requested language
|
||||
if ((oldInputCreator || newInputCreator) && activeEditor.isDirty()) { // theres some issues with changing the language on a dirty file with one of our editors (we should look into this)
|
||||
const notificationService = accessor.get(INotificationService);
|
||||
notificationService.error(localize('languageChangeUnsupported', "Changing editor types on unsaved files is unsupported"));
|
||||
return;
|
||||
}
|
||||
modeSupport.setMode(language);
|
||||
let input: IEditorInput;
|
||||
if (oldInputCreator) { // only transform the input if we have someone who knows how to deal with it (e.x QueryInput -> UntitledInput, etc)
|
||||
input = oldInputCreator.baseInputCreator(activeEditor);
|
||||
}
|
||||
|
||||
if (newInputCreator) { // if we know how to handle the new language, tranform the input and replace the editor (e.x notebook, sql, etc)
|
||||
const newInput = instantiationService.invokeFunction(newInputCreator.creator, input || activeEditor);
|
||||
if (newInput) { // the factory will return undefined if it doesn't know how to handle the input
|
||||
await editorService.replaceEditors([{ editor: activeEditor, replacement: newInput }], activeControl.group);
|
||||
}
|
||||
} else if (oldInputCreator) { // if we don't know handle to handle the new language but we know how to handle the current language, replace the editor with the reverted input (e.x sql -> text)
|
||||
await editorService.replaceEditors([{ editor: activeEditor, replacement: input }], activeControl.group);
|
||||
} // otherwise we don't know the old language and we don't know the new langauge, so don't do anything and just let vscode handle it (e.x text -> powershell)
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,12 @@ import {
|
||||
import { EditDataInput } from 'sql/workbench/contrib/editData/browser/editDataInput';
|
||||
import { IInsightsDialogService } from 'sql/workbench/services/insights/browser/insightsDialogService';
|
||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { DashboardInput } from 'sql/workbench/contrib/dashboard/browser/dashboardInput';
|
||||
import { ProfilerInput } from 'sql/workbench/contrib/profiler/browser/profilerInput';
|
||||
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInsightsConfig } from 'sql/platform/dashboard/browser/insightRegistry';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
|
||||
export function replaceConnection(oldUri: string, newUri: string, connectionService: IConnectionManagementService): Promise<IConnectionResult> {
|
||||
return new Promise<IConnectionResult>((resolve, reject) => {
|
||||
@@ -87,7 +87,7 @@ export function getCurrentGlobalConnection(objectExplorerService: IObjectExplore
|
||||
|
||||
let activeInput = workbenchEditorService.activeEditor;
|
||||
if (activeInput) {
|
||||
if (activeInput instanceof QueryInput || activeInput instanceof EditDataInput || activeInput instanceof DashboardInput) {
|
||||
if (activeInput instanceof QueryEditorInput || activeInput instanceof EditDataInput || activeInput instanceof DashboardInput) {
|
||||
connection = connectionManagementService.getConnectionProfile(activeInput.uri);
|
||||
}
|
||||
else if (activeInput instanceof ProfilerInput) {
|
||||
|
||||
12
src/sql/workbench/common/editorReplacer.contribution.ts
Normal file
12
src/sql/workbench/common/editorReplacer.contribution.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EditorReplacementContribution } from 'sql/workbench/common/editorReplacerContribution';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
||||
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchContributionsRegistry.registerWorkbenchContribution(EditorReplacementContribution, LifecyclePhase.Starting);
|
||||
83
src/sql/workbench/common/editorReplacerContribution.ts
Normal file
83
src/sql/workbench/common/editorReplacerContribution.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
||||
import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/common/languageAssociation';
|
||||
|
||||
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
||||
|
||||
export class EditorReplacementContribution implements IWorkbenchContribution {
|
||||
private editorOpeningListener: IDisposable;
|
||||
|
||||
constructor(
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IModeService private readonly modeService: IModeService
|
||||
) {
|
||||
this.editorOpeningListener = this.editorService.overrideOpenEditor((editor, options, group) => this.onEditorOpening(editor, options, group));
|
||||
}
|
||||
|
||||
private onEditorOpening(editor: IEditorInput, options: IEditorOptions | ITextEditorOptions | undefined, group: IEditorGroup): IOpenEditorOverride | undefined {
|
||||
// If the resource was already opened before in the group, do not prevent
|
||||
// the opening of that resource. Otherwise we would have the same settings
|
||||
// opened twice (https://github.com/Microsoft/vscode/issues/36447)
|
||||
// if (group.isOpened(editor)) {
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
if (!(editor instanceof FileEditorInput) && !(editor instanceof UntitledEditorInput)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let language: string;
|
||||
if (editor instanceof FileEditorInput) {
|
||||
language = editor.getPreferredMode();
|
||||
} else if (editor instanceof UntitledEditorInput) {
|
||||
language = editor.getMode();
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!language) { // in the case the input doesn't have a preferred mode set we will attempt to guess the mode from the file path
|
||||
language = this.modeService.getModeIdByFilepathOrFirstLine(editor.getResource());
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
const defaultInputCreator = languageAssociationRegistry.getAssociations().filter(e => e.isDefault)[0];
|
||||
if (defaultInputCreator) {
|
||||
editor.setMode(defaultInputCreator.language);
|
||||
const newInput = this.instantiationService.invokeFunction(defaultInputCreator.creator, editor);
|
||||
if (newInput) {
|
||||
return { override: this.editorService.openEditor(newInput, options, group) };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const inputCreator = languageAssociationRegistry.getAssociations().filter(e => e.language === language)[0];
|
||||
if (inputCreator) {
|
||||
const newInput = this.instantiationService.invokeFunction(inputCreator.creator, editor);
|
||||
if (newInput) {
|
||||
return { override: this.editorService.openEditor(newInput, options, group) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this.editorOpeningListener);
|
||||
}
|
||||
}
|
||||
34
src/sql/workbench/common/languageAssociation.ts
Normal file
34
src/sql/workbench/common/languageAssociation.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export type InputCreator = (servicesAccessor: ServicesAccessor, activeEditor: IEditorInput) => IEditorInput | undefined;
|
||||
export type BaseInputCreator = (activeEditor: IEditorInput) => IEditorInput;
|
||||
|
||||
export interface ILanguageAssociationRegistry {
|
||||
registerLanguageAssociation(language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault?: boolean): void;
|
||||
getAssociations(): Array<{ language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean }>;
|
||||
}
|
||||
|
||||
class LanguageAssociationRegistry implements ILanguageAssociationRegistry {
|
||||
private associations = new Array<{ language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean }>();
|
||||
|
||||
registerLanguageAssociation(language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean = false): void {
|
||||
this.associations.push({ language, creator, baseInputCreator, isDefault });
|
||||
}
|
||||
|
||||
getAssociations(): Array<{ language: string, creator: InputCreator, baseInputCreator: BaseInputCreator, isDefault: boolean }> {
|
||||
return this.associations.slice();
|
||||
}
|
||||
}
|
||||
|
||||
export const Extensions = {
|
||||
LanguageAssociations: 'workbench.contributions.editor.languageAssociation'
|
||||
};
|
||||
|
||||
Registry.add(Extensions.LanguageAssociations, new LanguageAssociationRegistry());
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as ConnectionConstants from 'sql/platform/connection/common/constants';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -26,11 +26,8 @@ export function getSqlConfigValue<T>(workspaceConfigService: IConfigurationServi
|
||||
|
||||
export function getEditorUri(input: IEditorInput): string {
|
||||
let uri: URI;
|
||||
if (input instanceof QueryInput) {
|
||||
let queryCast: QueryInput = <QueryInput>input;
|
||||
if (queryCast) {
|
||||
uri = queryCast.getResource();
|
||||
}
|
||||
if (input instanceof QueryEditorInput) {
|
||||
uri = input.getResource();
|
||||
}
|
||||
|
||||
if (uri) {
|
||||
|
||||
@@ -13,9 +13,9 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { IInsightsConfig } from 'sql/platform/dashboard/browser/insightRegistry';
|
||||
import { IInsightOptions } from 'sql/workbench/contrib/charts/common/interfaces';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IFileDialogService, FileFilter } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
@@ -89,7 +89,7 @@ export class CreateInsightAction extends Action {
|
||||
|
||||
private getActiveUriString(): string {
|
||||
let editor = this.editorService.activeEditor;
|
||||
if (editor instanceof QueryInput) {
|
||||
if (editor instanceof QueryEditorInput) {
|
||||
return editor.uri;
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ipcRenderer as ipc } from 'electron';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { localize } from 'vs/nls';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
@@ -202,21 +202,18 @@ export class CommandLineWorkbenchContribution implements IWorkbenchContribution,
|
||||
// If an open and connectable query editor exists for the given URI, attach it to the connection profile
|
||||
private async processFile(uriString: string, profile: IConnectionProfile, warnOnConnectFailure: boolean): Promise<void> {
|
||||
let activeEditor = this._editorService.editors.filter(v => v.getResource().toString() === uriString).pop();
|
||||
if (activeEditor) {
|
||||
let queryInput = activeEditor as QueryInput;
|
||||
if (queryInput && queryInput.state.connected) {
|
||||
let options: IConnectionCompletionOptions = {
|
||||
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none, input: queryInput },
|
||||
saveTheConnection: false,
|
||||
showDashboard: false,
|
||||
showConnectionDialogOnError: warnOnConnectFailure,
|
||||
showFirewallRuleOnError: warnOnConnectFailure
|
||||
};
|
||||
if (this._notificationService) {
|
||||
this._notificationService.status(localize('connectingQueryLabel', "Connecting query file"), { hideAfter: 2500 });
|
||||
}
|
||||
await this._connectionManagementService.connect(profile, uriString, options);
|
||||
if (activeEditor instanceof QueryEditorInput && activeEditor.state.connected) {
|
||||
let options: IConnectionCompletionOptions = {
|
||||
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none, input: activeEditor },
|
||||
saveTheConnection: false,
|
||||
showDashboard: false,
|
||||
showConnectionDialogOnError: warnOnConnectFailure,
|
||||
showFirewallRuleOnError: warnOnConnectFailure
|
||||
};
|
||||
if (this._notificationService) {
|
||||
this._notificationService.status(localize('connectingQueryLabel', "Connecting query file"), { hideAfter: 2500 });
|
||||
}
|
||||
await this._connectionManagementService.connect(profile, uriString, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,16 @@ import { TestCommandService } from 'vs/editor/test/browser/editorTestServices';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { assertThrowsAsync } from 'sql/base/test/common/async';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestEditorService, TestDialogService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { QueryInput, QueryEditorState } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { TestEditorService, TestDialogService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { TestQueryModelService } from 'sql/platform/query/test/common/testQueryModelService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
@@ -129,6 +134,7 @@ suite('commandLineService tests', () => {
|
||||
function getConfigurationServiceMock(showConnectDialogOnStartup: boolean): TypeMoq.Mock<IConfigurationService> {
|
||||
let configurationService = TypeMoq.Mock.ofType<IConfigurationService>(TestConfigurationService);
|
||||
configurationService.setup((c) => c.getValue(TypeMoq.It.isAnyString())).returns((config: string) => showConnectDialogOnStartup);
|
||||
configurationService.object.onDidChangeConfiguration = Event.None;
|
||||
return configurationService;
|
||||
}
|
||||
|
||||
@@ -377,23 +383,26 @@ suite('commandLineService tests', () => {
|
||||
return Promise.resolve('unused');
|
||||
}).verifiable(TypeMoq.Times.once());
|
||||
connectionManagementService.setup(c => c.getConnectionProfileById(TypeMoq.It.isAnyString())).returns(() => originalProfile);
|
||||
connectionManagementService.setup(c => c.onDisconnect).returns(() => Event.None);
|
||||
connectionManagementService.setup(c => c.ensureDefaultLanguageFlavor(TypeMoq.It.isAny()));
|
||||
const configurationService = getConfigurationServiceMock(true);
|
||||
const queryInput: TypeMoq.Mock<QueryInput> = TypeMoq.Mock.ofType<QueryInput>(QueryInput);
|
||||
const querymodelService = TypeMoq.Mock.ofType<IQueryModelService>(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
||||
querymodelService.setup(c => c.onRunQueryStart).returns(() => Event.None);
|
||||
querymodelService.setup(c => c.onRunQueryComplete).returns(() => Event.None);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let uri = URI.file(args._[0]);
|
||||
const queryState = new QueryEditorState();
|
||||
queryState.connected = true;
|
||||
queryInput.setup(q => q.state).returns(() => queryState);
|
||||
queryInput.setup(q => q.getResource()).returns(() => uri).verifiable(TypeMoq.Times.once());
|
||||
const untitledEditorInput = new UntitledEditorInput(uri, false, '', '', '', instantiationService, undefined, undefined);
|
||||
const queryInput = new UntitledQueryEditorInput(undefined, untitledEditorInput, undefined, connectionManagementService.object, querymodelService.object, configurationService.object, undefined);
|
||||
queryInput.state.connected = true;
|
||||
const editorService: TypeMoq.Mock<IEditorService> = TypeMoq.Mock.ofType<IEditorService>(TestEditorService, TypeMoq.MockBehavior.Strict);
|
||||
editorService.setup(e => e.editors).returns(() => [queryInput.object]);
|
||||
editorService.setup(e => e.editors).returns(() => [queryInput]);
|
||||
connectionManagementService.setup(c =>
|
||||
c.connect(TypeMoq.It.is<ConnectionProfile>(p => p.serverName === 'myserver' && p.authenticationType === Constants.sqlLogin),
|
||||
uri.toString(),
|
||||
TypeMoq.It.is<IConnectionCompletionOptions>(i => i.params.input === queryInput.object && i.params.connectionType === ConnectionType.editor))
|
||||
TypeMoq.It.is<IConnectionCompletionOptions>(i => i.params.input === queryInput && i.params.connectionType === ConnectionType.editor))
|
||||
).verifiable(TypeMoq.Times.once());
|
||||
let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, editorService.object);
|
||||
await contribution.processCommandLine(args);
|
||||
queryInput.verifyAll();
|
||||
connectionManagementService.verifyAll();
|
||||
});
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { INotificationService, INotificationActions } from 'vs/platform/notifica
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IDialogService, IConfirmation, IConfirmationResult } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { EditDataInput } from 'sql/workbench/contrib/editData/browser/editDataInput';
|
||||
import { DashboardInput } from 'sql/workbench/contrib/dashboard/browser/dashboardInput';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
@@ -156,7 +156,7 @@ export class GetCurrentConnectionStringAction extends Action {
|
||||
public run(): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let activeInput = this._editorService.activeEditor;
|
||||
if (activeInput && (activeInput instanceof QueryInput || activeInput instanceof EditDataInput || activeInput instanceof DashboardInput)
|
||||
if (activeInput && (activeInput instanceof QueryEditorInput || activeInput instanceof EditDataInput || activeInput instanceof DashboardInput)
|
||||
&& this._connectionManagementService.isConnected(activeInput.uri)) {
|
||||
let includePassword = false;
|
||||
let connectionProfile = this._connectionManagementService.getConnectionProfile(activeInput.uri);
|
||||
|
||||
@@ -60,9 +60,7 @@ export class EditDataInput extends EditorInput implements IConnectableInput {
|
||||
// re-emit sql editor events through this editor if it exists
|
||||
if (this._sql) {
|
||||
this._register(this._sql.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
|
||||
this._sql.disableSaving();
|
||||
}
|
||||
this.disableSaving();
|
||||
|
||||
//TODO determine is this is a table or a view
|
||||
this._objectType = 'TABLE';
|
||||
|
||||
@@ -29,6 +29,9 @@ import { Deferred } from 'sql/base/common/promise';
|
||||
import { NotebookTextFileModel } from 'sql/workbench/contrib/notebook/browser/models/notebookTextFileModel';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
|
||||
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
|
||||
export type ModeViewSaveHandler = (handle: number) => Thenable<boolean>;
|
||||
|
||||
@@ -195,8 +198,9 @@ export class NotebookEditorModel extends EditorModel {
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookInput extends EditorInput {
|
||||
public static ID: string = 'workbench.editorinputs.notebookInput';
|
||||
type TextInput = ResourceEditorInput | UntitledEditorInput | FileEditorInput;
|
||||
|
||||
export abstract class NotebookInput extends EditorInput {
|
||||
private _providerId: string;
|
||||
private _providers: string[];
|
||||
private _standardKernels: IStandardKernelWithProvider[];
|
||||
@@ -217,7 +221,7 @@ export class NotebookInput extends EditorInput {
|
||||
|
||||
constructor(private _title: string,
|
||||
private resource: URI,
|
||||
private _textInput: UntitledEditorInput,
|
||||
private _textInput: TextInput,
|
||||
@ITextModelService private textModelService: ITextModelService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@INotebookService private notebookService: INotebookService,
|
||||
@@ -233,7 +237,7 @@ export class NotebookInput extends EditorInput {
|
||||
}
|
||||
}
|
||||
|
||||
public get textInput(): UntitledEditorInput {
|
||||
public get textInput(): TextInput {
|
||||
return this._textInput;
|
||||
}
|
||||
|
||||
@@ -319,9 +323,7 @@ export class NotebookInput extends EditorInput {
|
||||
this._layoutChanged.fire();
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return NotebookInput.ID;
|
||||
}
|
||||
public abstract getTypeId(): string;
|
||||
|
||||
getResource(): URI {
|
||||
return this.resource;
|
||||
@@ -352,7 +354,9 @@ export class NotebookInput extends EditorInput {
|
||||
textOrUntitledEditorModel = this._untitledEditorModel;
|
||||
} else {
|
||||
let resolvedInput = await this._textInput.resolve();
|
||||
resolvedInput.textEditorModel.onBeforeAttached();
|
||||
if (!(resolvedInput instanceof BinaryEditorModel)) {
|
||||
resolvedInput.textEditorModel.onBeforeAttached();
|
||||
}
|
||||
textOrUntitledEditorModel = resolvedInput;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -5,7 +5,17 @@
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IEditorInputFactoryRegistry, Extensions as EditorInputFactoryExtensions } from 'vs/workbench/common/editor';
|
||||
|
||||
import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/common/languageAssociation';
|
||||
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
|
||||
import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput';
|
||||
import { FileNoteBookEditorInputFactory, UntitledNoteBookEditorInputFactory } from 'sql/workbench/contrib/notebook/common/models/nodebookInputFactory';
|
||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionsExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor, registerAction, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
|
||||
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
@@ -14,7 +24,6 @@ import { NewNotebookAction } from 'sql/workbench/contrib/notebook/browser/notebo
|
||||
import { KeyMod } from 'vs/editor/common/standalone/standaloneBase';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import { GridOutputComponent } from 'sql/workbench/contrib/notebook/browser/outputs/gridOutput.component';
|
||||
import { PlotlyOutputComponent } from 'sql/workbench/contrib/notebook/browser/outputs/plotlyOutput.component';
|
||||
import { registerComponentType } from 'sql/workbench/contrib/notebook/browser/outputs/mimeRegistry';
|
||||
@@ -30,7 +39,6 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { TreeViewItemHandleArg } from 'sql/workbench/common/views';
|
||||
import { ConnectedContext } from 'azdata';
|
||||
import { TreeNodeContextKey } from 'sql/workbench/contrib/objectExplorer/common/treeNodeContextKey';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ObjectExplorerActionsContext } from 'sql/workbench/contrib/objectExplorer/browser/objectExplorerActions';
|
||||
import { ItemContextKey } from 'sql/workbench/contrib/dashboard/browser/widgets/explorer/explorerTreeContext';
|
||||
import { ManageActionContext } from 'sql/workbench/browser/actions';
|
||||
@@ -39,18 +47,30 @@ import { MarkdownOutputComponent } from 'sql/workbench/contrib/notebook/browser/
|
||||
import { registerCellComponent } from 'sql/platform/notebooks/common/outputRegistry';
|
||||
import { TextCellComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/textCell.component';
|
||||
|
||||
// Model View editor registration
|
||||
const viewModelEditorDescriptor = new EditorDescriptor(
|
||||
NotebookEditor,
|
||||
NotebookEditor.ID,
|
||||
'Notebook'
|
||||
);
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputFactoryExtensions.EditorInputFactories)
|
||||
.registerEditorInputFactory(FileNotebookInput.ID, FileNoteBookEditorInputFactory);
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputFactoryExtensions.EditorInputFactories)
|
||||
.registerEditorInputFactory(UntitledNotebookInput.ID, UntitledNoteBookEditorInputFactory);
|
||||
|
||||
Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations)
|
||||
.registerLanguageAssociation('notebook', (accessor, editor) => {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
if (editor instanceof FileEditorInput) {
|
||||
return instantiationService.createInstance(FileNotebookInput, editor.getName(), editor.getResource(), editor);
|
||||
} else if (editor instanceof UntitledEditorInput) {
|
||||
return instantiationService.createInstance(UntitledNotebookInput, editor.getName(), editor.getResource(), editor);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}, (editor: NotebookInput) => editor.textInput);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||
.registerEditor(viewModelEditorDescriptor, [new SyncDescriptor(NotebookInput)]);
|
||||
.registerEditor(new EditorDescriptor(NotebookEditor, NotebookEditor.ID, localize('notebookEditor.name', "Notebook Editor")), [new SyncDescriptor(UntitledNotebookInput), new SyncDescriptor(FileNotebookInput)]);
|
||||
|
||||
|
||||
// Global Actions
|
||||
let actionRegistry = <IWorkbenchActionRegistry>Registry.as(Extensions.WorkbenchActions);
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionsExtensions.WorkbenchActions);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(
|
||||
@@ -145,7 +165,7 @@ registerAction({
|
||||
}
|
||||
});
|
||||
|
||||
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigExtensions.Configuration);
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigExtensions.Configuration);
|
||||
configurationRegistry.registerConfiguration({
|
||||
'id': 'notebook',
|
||||
'title': 'Notebook',
|
||||
|
||||
@@ -14,7 +14,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
|
||||
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
||||
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||
import { RESULTS_GRID_DEFAULTS } from 'sql/workbench/contrib/query/common/resultsGridContribution';
|
||||
import { RESULTS_GRID_DEFAULTS } from 'sql/workbench/contrib/query/common/resultsGrid.contribution';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
|
||||
export class FileNotebookInput extends NotebookInput {
|
||||
public static ID: string = 'workbench.editorinputs.fileNotebookInput';
|
||||
|
||||
constructor(
|
||||
title: string,
|
||||
resource: URI,
|
||||
textInput: FileEditorInput,
|
||||
@ITextModelService textModelService: ITextModelService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@INotebookService notebookService: INotebookService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(title, resource, textInput, textModelService, instantiationService, notebookService, extensionService);
|
||||
}
|
||||
|
||||
public get textInput(): FileEditorInput {
|
||||
return super.textInput as FileEditorInput;
|
||||
}
|
||||
|
||||
public getPreferredMode(): string {
|
||||
return this.textInput.getPreferredMode();
|
||||
}
|
||||
|
||||
public setMode(mode: string): void {
|
||||
this.textInput.setMode(mode);
|
||||
}
|
||||
|
||||
public setPreferredMode(mode: string): void {
|
||||
this.textInput.setPreferredMode(mode);
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return FileNotebookInput.ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { FileNotebookInput } from 'sql/workbench/contrib/notebook/common/models/fileNotebookInput';
|
||||
import { UntitledNotebookInput } from 'sql/workbench/contrib/notebook/common/models/untitledNotebookInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
|
||||
const editorInputFactoryRegistry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
|
||||
export class FileNoteBookEditorInputFactory implements IEditorInputFactory {
|
||||
serialize(editorInput: FileNotebookInput): string {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(FILE_EDITOR_INPUT_ID);
|
||||
if (factory) {
|
||||
return factory.serialize(editorInput.textInput); // serialize based on the underlying input
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileNotebookInput | undefined {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(FILE_EDITOR_INPUT_ID);
|
||||
const fileEditorInput = factory.deserialize(instantiationService, serializedEditorInput) as FileEditorInput;
|
||||
return instantiationService.createInstance(FileNotebookInput, fileEditorInput.getName(), fileEditorInput.getResource(), fileEditorInput);
|
||||
}
|
||||
}
|
||||
|
||||
export class UntitledNoteBookEditorInputFactory implements IEditorInputFactory {
|
||||
serialize(editorInput: UntitledNotebookInput): string {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(UntitledEditorInput.ID);
|
||||
if (factory) {
|
||||
return factory.serialize(editorInput.textInput); // serialize based on the underlying input
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): UntitledNotebookInput | undefined {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(UntitledEditorInput.ID);
|
||||
const untitledEditorInput = factory.deserialize(instantiationService, serializedEditorInput) as UntitledEditorInput;
|
||||
return instantiationService.createInstance(UntitledNotebookInput, untitledEditorInput.getName(), untitledEditorInput.getResource(), untitledEditorInput);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
|
||||
export class UntitledNotebookInput extends NotebookInput {
|
||||
public static ID: string = 'workbench.editorinputs.untitledNotebookInput';
|
||||
|
||||
constructor(
|
||||
title: string,
|
||||
resource: URI,
|
||||
textInput: UntitledEditorInput,
|
||||
@ITextModelService textModelService: ITextModelService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@INotebookService notebookService: INotebookService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(title, resource, textInput, textModelService, instantiationService, notebookService, extensionService);
|
||||
}
|
||||
|
||||
public get textInput(): UntitledEditorInput {
|
||||
return super.textInput as UntitledEditorInput;
|
||||
}
|
||||
|
||||
public setMode(mode: string): void {
|
||||
this.textInput.setMode(mode);
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return UntitledNotebookInput.ID;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import * as ConnectionConstants from 'sql/platform/connection/common/constants';
|
||||
import { EditDataEditor } from 'sql/workbench/contrib/editData/browser/editDataEditor';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
|
||||
const singleQuote = '\'';
|
||||
@@ -199,7 +199,7 @@ export class RefreshIntellisenseKeyboardAction extends Action {
|
||||
|
||||
public run(): Promise<void> {
|
||||
const editor = this.editorService.activeEditor;
|
||||
if (editor instanceof QueryInput) {
|
||||
if (editor instanceof QueryEditorInput) {
|
||||
this.connectionManagementService.rebuildIntelliSenseCache(editor.uri);
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
|
||||
@@ -19,7 +19,6 @@ import { QueryEditor } from 'sql/workbench/contrib/query/browser/queryEditor';
|
||||
import { QueryResultsEditor } from 'sql/workbench/contrib/query/browser/queryResultsEditor';
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import {
|
||||
RunQueryKeyboardAction, RunCurrentQueryKeyboardAction, CancelQueryKeyboardAction, RefreshIntellisenseKeyboardAction, ToggleQueryResultsKeyboardAction,
|
||||
RunQueryShortcutAction, RunCurrentQueryWithActualPlanKeyboardAction, FocusOnCurrentQueryKeyboardAction, ParseSyntaxAction
|
||||
@@ -33,6 +32,14 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { TimeElapsedStatusBarContributions, RowCountStatusBarContributions, QueryStatusStatusBarContributions } from 'sql/workbench/contrib/query/browser/statusBarItems';
|
||||
import { SqlFlavorStatusbarItem } from 'sql/workbench/contrib/query/browser/flavorStatus';
|
||||
import { IEditorInputFactoryRegistry, Extensions as EditorInputFactoryExtensions } from 'vs/workbench/common/editor';
|
||||
import { FileQueryEditorInput } from 'sql/workbench/contrib/query/common/fileQueryEditorInput';
|
||||
import { FileQueryEditorInputFactory, UntitledQueryEditorInputFactory } from 'sql/workbench/contrib/query/common/queryInputFactory';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/common/languageAssociation';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { NewQueryTask, OE_NEW_QUERY_ACTION_ID, DE_NEW_QUERY_COMMAND_ID } from 'sql/workbench/contrib/query/browser/queryActions';
|
||||
import { TreeNodeContextKey } from 'sql/workbench/contrib/objectExplorer/common/treeNodeContextKey';
|
||||
import { MssqlNodeContext } from 'sql/workbench/contrib/dataExplorer/browser/mssqlNodeContext';
|
||||
@@ -44,25 +51,30 @@ export const QueryEditorVisibleCondition = ContextKeyExpr.has(queryContext.query
|
||||
export const ResultsGridFocusCondition = ContextKeyExpr.and(ContextKeyExpr.has(queryContext.resultsVisibleId), ContextKeyExpr.has(queryContext.resultsGridFocussedId));
|
||||
export const ResultsMessagesFocusCondition = ContextKeyExpr.and(ContextKeyExpr.has(queryContext.resultsVisibleId), ContextKeyExpr.has(queryContext.resultsMessagesFocussedId));
|
||||
|
||||
// Editor
|
||||
const queryResultsEditorDescriptor = new EditorDescriptor(
|
||||
QueryResultsEditor,
|
||||
QueryResultsEditor.ID,
|
||||
'QueryResults'
|
||||
);
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputFactoryExtensions.EditorInputFactories)
|
||||
.registerEditorInputFactory(FileQueryEditorInput.ID, FileQueryEditorInputFactory);
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputFactoryExtensions.EditorInputFactories)
|
||||
.registerEditorInputFactory(UntitledQueryEditorInput.ID, UntitledQueryEditorInputFactory);
|
||||
|
||||
Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations)
|
||||
.registerLanguageAssociation('sql', (accessor, editor) => {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
const queryResultsInput = instantiationService.createInstance(QueryResultsInput, editor.getResource().toString());
|
||||
if (editor instanceof FileEditorInput) {
|
||||
return instantiationService.createInstance(FileQueryEditorInput, '', editor, queryResultsInput);
|
||||
} else if (editor instanceof UntitledEditorInput) {
|
||||
return instantiationService.createInstance(UntitledQueryEditorInput, '', editor, queryResultsInput);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}, (editor: QueryEditorInput) => editor.text, true);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||
.registerEditor(queryResultsEditorDescriptor, [new SyncDescriptor(QueryResultsInput)]);
|
||||
|
||||
// Editor
|
||||
const queryEditorDescriptor = new EditorDescriptor(
|
||||
QueryEditor,
|
||||
QueryEditor.ID,
|
||||
'Query'
|
||||
);
|
||||
.registerEditor(new EditorDescriptor(QueryResultsEditor, QueryResultsEditor.ID, localize('queryResultsEditor.name', "Query Results")), [new SyncDescriptor(QueryResultsInput)]);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||
.registerEditor(queryEditorDescriptor, [new SyncDescriptor(QueryInput)]);
|
||||
.registerEditor(new EditorDescriptor(QueryEditor, QueryEditor.ID, localize('queryEditor.name', "Query Editor")), [new SyncDescriptor(FileQueryEditorInput), new SyncDescriptor(UntitledQueryEditorInput)]);
|
||||
|
||||
const actionRegistry = <IWorkbenchActionRegistry>Registry.as(Extensions.WorkbenchActions);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService, FileChangesEvent } from 'vs/platform/files/common/files';
|
||||
|
||||
import { QueryInput, IQueryEditorStateChange } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditorInput, IQueryEditorStateChange } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { QueryResultsEditor } from 'sql/workbench/contrib/query/browser/queryResultsEditor';
|
||||
import * as queryContext from 'sql/workbench/contrib/query/common/queryContext';
|
||||
import { Taskbar, ITaskbarContent } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
@@ -120,8 +120,8 @@ export class QueryEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
// PUBLIC METHODS ////////////////////////////////////////////////////////////
|
||||
public get input(): QueryInput | null {
|
||||
return this._input as QueryInput;
|
||||
public get input(): QueryEditorInput | null {
|
||||
return this._input as QueryEditorInput;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,7 +278,7 @@ export class QueryEditor extends BaseEditor {
|
||||
this.taskbar.setContent(content);
|
||||
}
|
||||
|
||||
public async setInput(newInput: QueryInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
public async setInput(newInput: QueryEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
|
||||
const oldInput = this.input;
|
||||
|
||||
if (newInput.matches(oldInput)) {
|
||||
@@ -293,7 +293,7 @@ export class QueryEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
// If we're switching editor types switch out the views
|
||||
const newTextEditor = newInput.sql instanceof FileEditorInput ? this.textFileEditor : this.textResourceEditor;
|
||||
const newTextEditor = newInput.text instanceof FileEditorInput ? this.textFileEditor : this.textResourceEditor;
|
||||
if (newTextEditor !== this.currentTextEditor) {
|
||||
this.currentTextEditor = newTextEditor;
|
||||
this.splitview.removeView(0, Sizing.Distribute);
|
||||
@@ -309,7 +309,7 @@ export class QueryEditor extends BaseEditor {
|
||||
|
||||
await Promise.all([
|
||||
super.setInput(newInput, options, token),
|
||||
this.currentTextEditor.setInput(newInput.sql, options, token),
|
||||
this.currentTextEditor.setInput(newInput.text, options, token),
|
||||
this.resultsEditor.setInput(newInput.results, options)
|
||||
]);
|
||||
|
||||
@@ -324,7 +324,7 @@ export class QueryEditor extends BaseEditor {
|
||||
}
|
||||
}
|
||||
|
||||
private saveQueryEditorViewState(input: QueryInput): void {
|
||||
private saveQueryEditorViewState(input: QueryEditorInput): void {
|
||||
if (!input) {
|
||||
return; // ensure we have an input to handle view state for
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResul
|
||||
import { QueryResultsView } from 'sql/workbench/contrib/query/browser/queryResultsView';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { RESULTS_GRID_DEFAULTS } from 'sql/workbench/contrib/query/common/resultsGridContribution';
|
||||
import { RESULTS_GRID_DEFAULTS } from 'sql/workbench/contrib/query/common/resultsGrid.contribution';
|
||||
|
||||
export const TextCompareEditorVisible = new RawContextKey<boolean>('textCompareEditorVisible', false);
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ import { IntervalTimer } from 'vs/base/common/async';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { localize } from 'vs/nls';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import QueryRunner from 'sql/platform/query/common/queryRunner';
|
||||
import { parseNumAsTimeString } from 'sql/platform/connection/common/utils';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { IStatusbarService, IStatusbarEntryAccessor, StatusbarAlignment } from 'vs/workbench/services/statusbar/common/statusbar';
|
||||
|
||||
export class TimeElapsedStatusBarContributions extends Disposable implements IWorkbenchContribution {
|
||||
@@ -56,7 +56,7 @@ export class TimeElapsedStatusBarContributions extends Disposable implements IWo
|
||||
this.disposable.clear();
|
||||
this.hide();
|
||||
const activeInput = this.editorService.activeEditor;
|
||||
if (activeInput && activeInput instanceof QueryInput && activeInput.uri) {
|
||||
if (activeInput && activeInput instanceof QueryEditorInput && activeInput.uri) {
|
||||
const uri = activeInput.uri;
|
||||
const runner = this.queryModelService.getQueryRunner(uri);
|
||||
if (runner) {
|
||||
@@ -148,7 +148,7 @@ export class RowCountStatusBarContributions extends Disposable implements IWorkb
|
||||
this.disposable.clear();
|
||||
this.hide();
|
||||
const activeInput = this.editorService.activeEditor;
|
||||
if (activeInput && activeInput instanceof QueryInput && activeInput.uri) {
|
||||
if (activeInput && activeInput instanceof QueryEditorInput && activeInput.uri) {
|
||||
const uri = activeInput.uri;
|
||||
const runner = this.queryModelService.getQueryRunner(uri);
|
||||
if (runner) {
|
||||
@@ -227,7 +227,7 @@ export class QueryStatusStatusBarContributions extends Disposable implements IWo
|
||||
this.hide();
|
||||
this.visisbleUri = undefined;
|
||||
const activeInput = this.editorService.activeEditor;
|
||||
if (activeInput && activeInput instanceof QueryInput && activeInput.uri) {
|
||||
if (activeInput && activeInput instanceof QueryEditorInput && activeInput.uri) {
|
||||
this.visisbleUri = activeInput.uri;
|
||||
const runner = this.queryModelService.getQueryRunner(this.visisbleUri);
|
||||
if (runner && runner.isExecuting) {
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
|
||||
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { EncodingMode } from 'vs/workbench/common/editor';
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
type PublicPart<T> = { [K in keyof T]: T[K] };
|
||||
|
||||
export class FileQueryEditorInput extends QueryEditorInput implements PublicPart<FileEditorInput> {
|
||||
|
||||
public static readonly ID = 'workbench.editorInput.fileQueryInput';
|
||||
|
||||
constructor(
|
||||
description: string,
|
||||
text: FileEditorInput,
|
||||
results: QueryResultsInput,
|
||||
@IConnectionManagementService connectionManagementService: IConnectionManagementService,
|
||||
@IQueryModelService queryModelService: IQueryModelService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IFileService fileService: IFileService
|
||||
) {
|
||||
super(description, text, results, connectionManagementService, queryModelService, configurationService, fileService);
|
||||
}
|
||||
|
||||
public resolve(): Promise<TextFileEditorModel | BinaryEditorModel> {
|
||||
return this.text.resolve();
|
||||
}
|
||||
|
||||
public get text(): FileEditorInput {
|
||||
return this._text as FileEditorInput;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return FileQueryEditorInput.ID;
|
||||
}
|
||||
|
||||
public getEncoding(): string {
|
||||
return this.text.getEncoding();
|
||||
}
|
||||
|
||||
public setEncoding(encoding: string, mode: EncodingMode) {
|
||||
this.text.setEncoding(encoding, mode);
|
||||
}
|
||||
|
||||
public getPreferredEncoding(): string {
|
||||
return this.text.getPreferredEncoding();
|
||||
}
|
||||
|
||||
public setPreferredEncoding(encoding: string) {
|
||||
this.text.setPreferredEncoding(encoding);
|
||||
}
|
||||
|
||||
public getPreferredMode(): string {
|
||||
return this.text.getPreferredMode();
|
||||
}
|
||||
|
||||
public setMode(mode: string) {
|
||||
this.text.setMode(mode);
|
||||
}
|
||||
|
||||
public setPreferredMode(mode: string) {
|
||||
this.text.setPreferredMode(mode);
|
||||
}
|
||||
|
||||
public setForceOpenAsText() {
|
||||
this.text.setForceOpenAsText();
|
||||
}
|
||||
|
||||
public setForceOpenAsBinary() {
|
||||
this.text.setForceOpenAsBinary();
|
||||
}
|
||||
|
||||
public isResolved(): boolean {
|
||||
return this.text.isResolved();
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,9 @@
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { EditorInput, ConfirmResult, EncodingMode, IEncodingSupport } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, ConfirmResult } from 'vs/workbench/common/editor';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
@@ -17,14 +16,10 @@ import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResul
|
||||
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
|
||||
|
||||
import { ISelectionData, ExecutionPlanOptions } from 'azdata';
|
||||
import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
|
||||
const MAX_SIZE = 13;
|
||||
|
||||
type PublicPart<T> = { [K in keyof T]: T[K] };
|
||||
|
||||
function trimTitle(title: string): string {
|
||||
const length = title.length;
|
||||
const diff = length - MAX_SIZE;
|
||||
@@ -115,79 +110,48 @@ export class QueryEditorState extends Disposable {
|
||||
* Input for the QueryEditor. This input is simply a wrapper around a QueryResultsInput for the QueryResultsEditor
|
||||
* and a UntitledEditorInput for the SQL File Editor.
|
||||
*/
|
||||
export class QueryInput extends EditorInput implements IEncodingSupport, IConnectableInput, PublicPart<UntitledEditorInput>, IDisposable {
|
||||
export abstract class QueryEditorInput extends EditorInput implements IConnectableInput, IDisposable {
|
||||
|
||||
public static ID: string = 'workbench.editorinputs.queryInput';
|
||||
public static SCHEMA: string = 'sql';
|
||||
|
||||
private _state = this._register(new QueryEditorState());
|
||||
public get state(): QueryEditorState { return this._state; }
|
||||
|
||||
private _updateSelection: Emitter<ISelectionData>;
|
||||
|
||||
constructor(
|
||||
private _description: string,
|
||||
private _sql: UntitledEditorInput,
|
||||
private _results: QueryResultsInput,
|
||||
private _connectionProviderName: string,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IQueryModelService private _queryModelService: IQueryModelService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService,
|
||||
protected _text: EditorInput,
|
||||
protected _results: QueryResultsInput,
|
||||
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
|
||||
@IQueryModelService private readonly queryModelService: IQueryModelService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IFileService private _fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
this._updateSelection = new Emitter<ISelectionData>();
|
||||
|
||||
this._register(this._sql);
|
||||
this._register(this._text);
|
||||
this._register(this._results);
|
||||
|
||||
// re-emit sql editor events through this editor if it exists
|
||||
if (this._sql) {
|
||||
this._register(this._sql.onDidChangeDirty(() => this._onDidChangeDirty.fire()));
|
||||
}
|
||||
this._text.onDidChangeDirty(() => this._onDidChangeDirty.fire());
|
||||
|
||||
// Attach to event callbacks
|
||||
if (this._queryModelService) {
|
||||
// Register callbacks for the Actions
|
||||
this._register(
|
||||
this._queryModelService.onRunQueryStart(uri => {
|
||||
if (this.uri === uri) {
|
||||
this.onRunQuery();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._register(
|
||||
this._queryModelService.onRunQueryComplete(uri => {
|
||||
if (this.uri === uri) {
|
||||
this.onQueryComplete();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (this._connectionManagementService) {
|
||||
this._register(this._connectionManagementService.onDisconnect(result => {
|
||||
if (result.connectionUri === this.uri) {
|
||||
this.onDisconnect();
|
||||
}
|
||||
}));
|
||||
if (this.uri) {
|
||||
if (this._connectionProviderName) {
|
||||
this._connectionManagementService.doChangeLanguageFlavor(this.uri, 'sql', this._connectionProviderName);
|
||||
} else {
|
||||
this._connectionManagementService.ensureDefaultLanguageFlavor(this.uri);
|
||||
this._register(
|
||||
this.queryModelService.onRunQueryComplete(uri => {
|
||||
if (this.uri === uri) {
|
||||
this.onQueryComplete();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._register(this.connectionManagementService.onDisconnect(result => {
|
||||
if (result.connectionUri === this.uri) {
|
||||
this.onDisconnect();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
if (this._configurationService) {
|
||||
this._register(this._configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('sql.showConnectionInfoInTitle')) {
|
||||
this._onDidChangeLabel.fire();
|
||||
}
|
||||
}));
|
||||
}
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectedKeys.indexOf('sql.showConnectionInfoInTitle') > -1) {
|
||||
this._onDidChangeLabel.fire();
|
||||
}
|
||||
}));
|
||||
|
||||
this.onDisconnect();
|
||||
this.onQueryComplete();
|
||||
@@ -195,47 +159,30 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
|
||||
// Getters for private properties
|
||||
public get uri(): string { return this.getResource().toString(true); }
|
||||
public get sql(): UntitledEditorInput { return this._sql; }
|
||||
public get text(): EditorInput { return this._text; }
|
||||
public get results(): QueryResultsInput { return this._results; }
|
||||
public updateSelection(selection: ISelectionData): void { this._updateSelection.fire(selection); }
|
||||
public getTypeId(): string { return QueryInput.ID; }
|
||||
// Description is shown beside the tab name in the combobox of open editors
|
||||
public getDescription(): string { return this._description; }
|
||||
public supportsSplitEditor(): boolean { return false; }
|
||||
public getMode(): string { return QueryInput.SCHEMA; }
|
||||
public revert(): Promise<boolean> { return this._sql.revert(); }
|
||||
public setMode(mode: string) {
|
||||
this._sql.setMode(mode);
|
||||
}
|
||||
public revert(): Promise<boolean> { return this._text.revert(); }
|
||||
|
||||
public matches(otherInput: any): boolean {
|
||||
if (otherInput instanceof QueryInput) {
|
||||
return this._sql.matches(otherInput.sql);
|
||||
// we want to be able to match against our underlying input as well, bascially we are our underlying input
|
||||
if (otherInput instanceof QueryEditorInput) {
|
||||
return this._text.matches(otherInput._text);
|
||||
} else {
|
||||
return this._text.matches(otherInput);
|
||||
}
|
||||
|
||||
return this._sql.matches(otherInput);
|
||||
}
|
||||
|
||||
// Forwarding resource functions to the inline sql file editor
|
||||
public get onDidModelChangeContent(): Event<void> { return this._sql.onDidModelChangeContent; }
|
||||
public get onDidModelChangeEncoding(): Event<void> { return this._sql.onDidModelChangeEncoding; }
|
||||
public resolve(): Promise<UntitledEditorModel & IResolvedTextEditorModel> { return this._sql.resolve(); }
|
||||
public save(): Promise<boolean> { return this._sql.save(); }
|
||||
public isDirty(): boolean { return this._sql.isDirty(); }
|
||||
public confirmSave(): Promise<ConfirmResult> { return this._sql.confirmSave(); }
|
||||
public getResource(): URI { return this._sql.getResource(); }
|
||||
public getEncoding(): string { return this._sql.getEncoding(); }
|
||||
public suggestFileName(): string { return this._sql.suggestFileName(); }
|
||||
hasBackup(): boolean {
|
||||
if (this.sql) {
|
||||
return this.sql.hasBackup();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public save(): Promise<boolean> { return this._text.save(); }
|
||||
public isDirty(): boolean { return this._text.isDirty(); }
|
||||
public confirmSave(): Promise<ConfirmResult> { return this._text.confirmSave(); }
|
||||
public getResource(): URI { return this._text.getResource(); }
|
||||
|
||||
public matchInputInstanceType(inputType: any): boolean {
|
||||
return (this._sql instanceof inputType);
|
||||
return (this._text instanceof inputType);
|
||||
}
|
||||
|
||||
public inputFileExists(): Promise<boolean> {
|
||||
@@ -243,8 +190,8 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
}
|
||||
|
||||
public getName(longForm?: boolean): string {
|
||||
if (this._configurationService.getValue('sql.showConnectionInfoInTitle')) {
|
||||
let profile = this._connectionManagementService.getConnectionProfile(this.uri);
|
||||
if (this.configurationService.getValue('sql.showConnectionInfoInTitle')) {
|
||||
let profile = this.connectionManagementService.getConnectionProfile(this.uri);
|
||||
let title = '';
|
||||
if (this._description && this._description !== '') {
|
||||
title = this._description + ' ';
|
||||
@@ -258,36 +205,30 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
} else {
|
||||
title += localize('disconnected', "disconnected");
|
||||
}
|
||||
return this._sql.getName() + (longForm ? (' - ' + title) : ` - ${trimTitle(title)}`);
|
||||
return this._text.getName() + (longForm ? (' - ' + title) : ` - ${trimTitle(title)}`);
|
||||
} else {
|
||||
return this._sql.getName();
|
||||
return this._text.getName();
|
||||
}
|
||||
}
|
||||
|
||||
// Called to get the tooltip of the tab
|
||||
public getTitle() {
|
||||
public getTitle(): string {
|
||||
return this.getName(true);
|
||||
}
|
||||
|
||||
public get hasAssociatedFilePath(): boolean { return this._sql.hasAssociatedFilePath; }
|
||||
|
||||
public setEncoding(encoding: string, mode: EncodingMode /* ignored, we only have Encode */): void {
|
||||
this._sql.setEncoding(encoding, mode);
|
||||
}
|
||||
|
||||
// State update funtions
|
||||
public runQuery(selection?: ISelectionData, executePlanOptions?: ExecutionPlanOptions): void {
|
||||
this._queryModelService.runQuery(this.uri, selection, this, executePlanOptions);
|
||||
this.queryModelService.runQuery(this.uri, selection, this, executePlanOptions);
|
||||
this.state.executing = true;
|
||||
}
|
||||
|
||||
public runQueryStatement(selection?: ISelectionData): void {
|
||||
this._queryModelService.runQueryStatement(this.uri, selection, this);
|
||||
this.queryModelService.runQueryStatement(this.uri, selection, this);
|
||||
this.state.executing = true;
|
||||
}
|
||||
|
||||
public runQueryString(text: string): void {
|
||||
this._queryModelService.runQueryString(this.uri, text, this);
|
||||
this.queryModelService.runQueryString(this.uri, text, this);
|
||||
this.state.executing = true;
|
||||
}
|
||||
|
||||
@@ -314,7 +255,7 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
this.state.connected = true;
|
||||
this.state.connecting = false;
|
||||
|
||||
let isRunningQuery = this._queryModelService.isRunningQuery(this.uri);
|
||||
let isRunningQuery = this.queryModelService.isRunningQuery(this.uri);
|
||||
if (!isRunningQuery && params && params.runQueryOnCompletion) {
|
||||
let selection: ISelectionData | undefined = params ? params.querySelection : undefined;
|
||||
if (params.runQueryOnCompletion === RunQueryOnConnectionMode.executeCurrentQuery) {
|
||||
@@ -345,10 +286,10 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this._queryModelService.disposeQuery(this.uri);
|
||||
this._connectionManagementService.disconnectEditor(this, true);
|
||||
this.queryModelService.disposeQuery(this.uri);
|
||||
this.connectionManagementService.disconnectEditor(this, true);
|
||||
|
||||
this._sql.close();
|
||||
this._text.close();
|
||||
this._results.close();
|
||||
super.close();
|
||||
}
|
||||
@@ -357,7 +298,7 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
* Get the color that should be displayed
|
||||
*/
|
||||
public get tabColor(): string {
|
||||
return this._connectionManagementService.getTabColorForUri(this.uri);
|
||||
return this.connectionManagementService.getTabColorForUri(this.uri);
|
||||
}
|
||||
|
||||
public get isSharedSession(): boolean {
|
||||
50
src/sql/workbench/contrib/query/common/queryInputFactory.ts
Normal file
50
src/sql/workbench/contrib/query/common/queryInputFactory.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import { FILE_EDITOR_INPUT_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { FileQueryEditorInput } from 'sql/workbench/contrib/query/common/fileQueryEditorInput';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
|
||||
const editorInputFactoryRegistry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
|
||||
export class FileQueryEditorInputFactory implements IEditorInputFactory {
|
||||
serialize(editorInput: FileQueryEditorInput): string {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(FILE_EDITOR_INPUT_ID);
|
||||
if (factory) {
|
||||
return factory.serialize(editorInput.text); // serialize based on the underlying input
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): FileQueryEditorInput | undefined {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(FILE_EDITOR_INPUT_ID);
|
||||
const fileEditorInput = factory.deserialize(instantiationService, serializedEditorInput) as FileEditorInput;
|
||||
const queryResultsInput = instantiationService.createInstance(QueryResultsInput, fileEditorInput.getResource().toString());
|
||||
return instantiationService.createInstance(FileQueryEditorInput, '', fileEditorInput, queryResultsInput);
|
||||
}
|
||||
}
|
||||
|
||||
export class UntitledQueryEditorInputFactory implements IEditorInputFactory {
|
||||
serialize(editorInput: UntitledQueryEditorInput): string {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(UntitledEditorInput.ID);
|
||||
if (factory) {
|
||||
return factory.serialize(editorInput.text); // serialize based on the underlying input
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): UntitledQueryEditorInput | undefined {
|
||||
const factory = editorInputFactoryRegistry.getEditorInputFactory(UntitledEditorInput.ID);
|
||||
const untitledEditorInput = factory.deserialize(instantiationService, serializedEditorInput) as UntitledEditorInput;
|
||||
const queryResultsInput = instantiationService.createInstance(QueryResultsInput, untitledEditorInput.getResource().toString());
|
||||
return instantiationService.createInstance(UntitledQueryEditorInput, '', untitledEditorInput, queryResultsInput);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
|
||||
|
||||
import { IEncodingSupport, EncodingMode } from 'vs/workbench/common/editor';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel';
|
||||
import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
type PublicPart<T> = { [K in keyof T]: T[K] };
|
||||
|
||||
export class UntitledQueryEditorInput extends QueryEditorInput implements IEncodingSupport, PublicPart<UntitledEditorInput> {
|
||||
|
||||
public static readonly ID = 'workbench.editorInput.untitledQueryInput';
|
||||
|
||||
public readonly onDidModelChangeContent = this.text.onDidModelChangeContent;
|
||||
public readonly onDidModelChangeEncoding = this.text.onDidModelChangeEncoding;
|
||||
|
||||
constructor(
|
||||
description: string,
|
||||
text: UntitledEditorInput,
|
||||
results: QueryResultsInput,
|
||||
@IConnectionManagementService connectionManagementService: IConnectionManagementService,
|
||||
@IQueryModelService queryModelService: IQueryModelService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IFileService fileService: IFileService
|
||||
) {
|
||||
super(description, text, results, connectionManagementService, queryModelService, configurationService, fileService);
|
||||
}
|
||||
|
||||
public resolve(): Promise<UntitledEditorModel & IResolvedTextEditorModel> {
|
||||
return this.text.resolve();
|
||||
}
|
||||
|
||||
public get text(): UntitledEditorInput {
|
||||
return this._text as UntitledEditorInput;
|
||||
}
|
||||
|
||||
public get hasAssociatedFilePath(): boolean {
|
||||
return this.text.hasAssociatedFilePath;
|
||||
}
|
||||
|
||||
public suggestFileName(): string {
|
||||
return this.text.suggestFileName();
|
||||
}
|
||||
|
||||
public setMode(mode: string): void {
|
||||
this.text.setMode(mode);
|
||||
}
|
||||
|
||||
public getMode(): string {
|
||||
return this.text.getMode();
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return UntitledQueryEditorInput.ID;
|
||||
}
|
||||
|
||||
public getEncoding(): string {
|
||||
return this.text.getEncoding();
|
||||
}
|
||||
|
||||
public setEncoding(encoding: string, mode: EncodingMode): void {
|
||||
this.text.setEncoding(encoding, mode);
|
||||
}
|
||||
|
||||
hasBackup(): boolean {
|
||||
if (this.text) {
|
||||
return this.text.hasBackup();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -3,50 +3,48 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
import { ISelectionData } from 'azdata';
|
||||
|
||||
import {
|
||||
IConnectionManagementService,
|
||||
IConnectionParams,
|
||||
INewConnectionParams,
|
||||
ConnectionType,
|
||||
RunQueryOnConnectionMode
|
||||
} from 'sql/platform/connection/common/connectionManagement';
|
||||
import { ConnectionDialogService } from 'sql/workbench/services/connection/browser/connectionDialogService';
|
||||
import {
|
||||
RunQueryAction, CancelQueryAction, ListDatabasesActionItem,
|
||||
DisconnectDatabaseAction, ConnectDatabaseAction, QueryTaskbarAction
|
||||
} from 'sql/workbench/contrib/query/browser/queryActions';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditor } from 'sql/workbench/contrib/query/browser/queryEditor';
|
||||
import { QueryModelService } from 'sql/platform/query/common/queryModelService';
|
||||
import { ConnectionManagementService } from 'sql/workbench/services/connection/browser/connectionManagementService';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as assert from 'assert';
|
||||
import { TestStorageService, TestFileService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
let none: void;
|
||||
import { TestQueryModelService } from 'sql/platform/query/test/common/testQueryModelService';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
|
||||
suite('SQL QueryAction Tests', () => {
|
||||
|
||||
let testUri: string = 'testURI';
|
||||
let editor: TypeMoq.Mock<QueryEditor>;
|
||||
let calledRunQueryOnInput: boolean = undefined;
|
||||
let testQueryInput: TypeMoq.Mock<QueryInput>;
|
||||
let configurationService: TypeMoq.Mock<IConfigurationService>;
|
||||
let testQueryInput: TypeMoq.Mock<UntitledQueryEditorInput>;
|
||||
let configurationService: TypeMoq.Mock<TestConfigurationService>;
|
||||
let queryModelService: TypeMoq.Mock<TestQueryModelService>;
|
||||
let connectionManagementService: TypeMoq.Mock<TestConnectionManagementService>;
|
||||
|
||||
setup(() => {
|
||||
// Setup a reusable mock QueryInput
|
||||
testQueryInput = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Strict);
|
||||
testQueryInput.setup(x => x.uri).returns(() => testUri);
|
||||
testQueryInput.setup(x => x.runQuery(undefined)).callback(() => { calledRunQueryOnInput = true; });
|
||||
|
||||
const contextkeyservice = new MockContextKeyService();
|
||||
|
||||
@@ -65,6 +63,17 @@ suite('SQL QueryAction Tests', () => {
|
||||
configurationService.setup(x => x.getValue(TypeMoq.It.isAny())).returns(() => {
|
||||
return {};
|
||||
});
|
||||
queryModelService = TypeMoq.Mock.ofType<TestQueryModelService>(TestQueryModelService);
|
||||
queryModelService.setup(q => q.onRunQueryStart).returns(() => Event.None);
|
||||
queryModelService.setup(q => q.onRunQueryComplete).returns(() => Event.None);
|
||||
connectionManagementService = TypeMoq.Mock.ofType<TestConnectionManagementService>(TestConnectionManagementService);
|
||||
connectionManagementService.setup(q => q.onDisconnect).returns(() => Event.None);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let fileInput = new UntitledEditorInput(URI.parse('file://testUri'), false, '', '', '', instantiationService, undefined, undefined);
|
||||
// Setup a reusable mock QueryInput
|
||||
testQueryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||
testQueryInput.setup(x => x.uri).returns(() => testUri);
|
||||
testQueryInput.setup(x => x.runQuery(undefined)).callback(() => { calledRunQueryOnInput = true; });
|
||||
});
|
||||
|
||||
test('setClass sets child CSS class correctly', (done) => {
|
||||
@@ -82,7 +91,6 @@ suite('SQL QueryAction Tests', () => {
|
||||
let isConnectedReturnValue: boolean = false;
|
||||
|
||||
// ... Mock "isConnected in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, new TestStorageService());
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnectedReturnValue);
|
||||
|
||||
const contextkeyservice = new MockContextKeyService();
|
||||
@@ -114,19 +122,15 @@ suite('SQL QueryAction Tests', () => {
|
||||
let connectionParams: INewConnectionParams = undefined;
|
||||
let countCalledShowDialog: number = 0;
|
||||
|
||||
// ... Mock "showDialog" ConnectionDialogService
|
||||
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
|
||||
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined, undefined))
|
||||
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
connectionManagementService.setup(x => x.showConnectionDialog(TypeMoq.It.isAny()))
|
||||
.callback((params: INewConnectionParams) => {
|
||||
connectionParams = params;
|
||||
countCalledShowDialog++;
|
||||
})
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
.returns(() => Promise.resolve());
|
||||
|
||||
// ... Mock QueryModelService
|
||||
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
|
||||
@@ -143,7 +147,6 @@ suite('SQL QueryAction Tests', () => {
|
||||
testQueryInput.verify(x => x.runQuery(undefined), TypeMoq.Times.never());
|
||||
|
||||
// and the connection dialog should open with the correct parameter details
|
||||
assert.equal(countCalledShowDialog, 1, 'run should call showDialog');
|
||||
assert.equal(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
|
||||
assert.equal(connectionParams.runQueryOnCompletion, RunQueryOnConnectionMode.executeQuery, 'runQueryOnCompletion should be true`');
|
||||
assert.equal(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
|
||||
@@ -166,9 +169,18 @@ suite('SQL QueryAction Tests', () => {
|
||||
let isSelectionEmpty: boolean = undefined;
|
||||
let countCalledRunQuery: number = 0;
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => true);
|
||||
|
||||
// ... Mock QueryModelService
|
||||
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
|
||||
queryModelService.setup(x => x.onRunQueryStart).returns(() => Event.None);
|
||||
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let fileInput = new UntitledEditorInput(URI.parse('file://testUri'), false, '', '', '', instantiationService, undefined, undefined);
|
||||
|
||||
// ... Mock "isSelectionEmpty" in QueryEditor
|
||||
let queryInput: TypeMoq.Mock<QueryInput> = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Strict);
|
||||
queryInput = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Strict);
|
||||
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Strict, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||
queryInput.setup(x => x.uri).returns(() => testUri);
|
||||
queryInput.setup(x => x.runQuery(undefined)).callback(() => {
|
||||
countCalledRunQuery++;
|
||||
@@ -183,14 +195,6 @@ suite('SQL QueryAction Tests', () => {
|
||||
queryEditor.setup(x => x.getSelection(false)).returns(() => undefined);
|
||||
queryEditor.setup(x => x.isSelectionEmpty()).returns(() => isSelectionEmpty);
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {});
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => true);
|
||||
|
||||
// ... Mock QueryModelService
|
||||
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
|
||||
|
||||
// If I call run on RunQueryAction when I have a non empty selection
|
||||
let queryAction: RunQueryAction = new RunQueryAction(queryEditor.object, queryModelService.object, connectionManagementService.object);
|
||||
isSelectionEmpty = false;
|
||||
@@ -221,17 +225,11 @@ suite('SQL QueryAction Tests', () => {
|
||||
let selectionToReturnInGetSelection: ISelectionData = undefined;
|
||||
let predefinedSelection: ISelectionData = { startLine: 1, startColumn: 2, endLine: 3, endColumn: 4 };
|
||||
|
||||
// ... Mock "showDialog" ConnectionDialogService
|
||||
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
|
||||
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined, undefined))
|
||||
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
|
||||
showDialogConnectionParams = params;
|
||||
countCalledShowDialog++;
|
||||
})
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "getSelection" in QueryEditor
|
||||
let queryInput = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Loose);
|
||||
const instantiationService = new TestInstantiationService();
|
||||
let fileInput = new UntitledEditorInput(URI.parse('file://testUri'), false, '', '', '', instantiationService, undefined, undefined);
|
||||
|
||||
let queryInput = TypeMoq.Mock.ofType(UntitledQueryEditorInput, TypeMoq.MockBehavior.Loose, undefined, fileInput, undefined, connectionManagementService.object, queryModelService.object, configurationService.object);
|
||||
queryInput.setup(x => x.uri).returns(() => testUri);
|
||||
queryInput.setup(x => x.runQuery(TypeMoq.It.isAny())).callback((selection: ISelectionData) => {
|
||||
runQuerySelection = selection;
|
||||
@@ -256,9 +254,13 @@ suite('SQL QueryAction Tests', () => {
|
||||
});
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
connectionManagementService.setup(x => x.showConnectionDialog(TypeMoq.It.isAny()))
|
||||
.callback((params: INewConnectionParams) => {
|
||||
showDialogConnectionParams = params;
|
||||
countCalledShowDialog++;
|
||||
})
|
||||
.returns(() => Promise.resolve());
|
||||
|
||||
/// End Setup Test ///
|
||||
|
||||
@@ -320,7 +322,6 @@ suite('SQL QueryAction Tests', () => {
|
||||
let calledCancelQuery: boolean = false;
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {});
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
|
||||
// ... Mock QueryModelService
|
||||
@@ -353,7 +354,6 @@ suite('SQL QueryAction Tests', () => {
|
||||
let countCalledDisconnectEditor: number = 0;
|
||||
|
||||
// ... Mock "isConnected" and "disconnectEditor" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {});
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
connectionManagementService.setup(x => x.disconnectEditor(TypeMoq.It.isAny())).callback(() => {
|
||||
countCalledDisconnectEditor++;
|
||||
@@ -382,19 +382,14 @@ suite('SQL QueryAction Tests', () => {
|
||||
let connectionParams: INewConnectionParams = undefined;
|
||||
let countCalledShowDialog: number = 0;
|
||||
|
||||
// ... Mock "showDialog" ConnectionDialogService
|
||||
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
|
||||
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined, undefined))
|
||||
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
connectionManagementService.setup(x => x.showConnectionDialog(TypeMoq.It.isAny()))
|
||||
.callback((params: INewConnectionParams) => {
|
||||
connectionParams = params;
|
||||
countCalledShowDialog++;
|
||||
})
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
.returns(() => Promise.resolve());
|
||||
|
||||
// If I call run on ConnectDatabaseAction when I am not connected
|
||||
let queryAction: ConnectDatabaseAction = new ConnectDatabaseAction(editor.object, false, connectionManagementService.object);
|
||||
@@ -428,19 +423,13 @@ suite('SQL QueryAction Tests', () => {
|
||||
let connectionParams: INewConnectionParams = undefined;
|
||||
let calledShowDialog: number = 0;
|
||||
|
||||
// ... Mock "showDialog" ConnectionDialogService
|
||||
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
|
||||
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined, undefined))
|
||||
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
connectionManagementService.setup(x => x.showConnectionDialog(TypeMoq.It.isAny()))
|
||||
.callback((params: INewConnectionParams) => {
|
||||
calledShowDialog++;
|
||||
connectionParams = params;
|
||||
})
|
||||
.returns(() => Promise.resolve(none));
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, undefined, connectionDialogService.object);
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
}).returns(() => Promise.resolve());
|
||||
|
||||
// If I call run on ChangeConnectionAction when I am not connected
|
||||
queryAction = new ConnectDatabaseAction(editor.object, false, connectionManagementService.object);
|
||||
@@ -473,9 +462,8 @@ suite('SQL QueryAction Tests', () => {
|
||||
let databaseName: string = undefined;
|
||||
|
||||
// ... Mock "isConnected" in ConnectionManagementService
|
||||
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {});
|
||||
connectionManagementService.callBase = true;
|
||||
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
|
||||
connectionManagementService.setup(x => x.onConnectionChanged).returns(() => Event.None);
|
||||
connectionManagementService.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{
|
||||
databaseName: databaseName
|
||||
});
|
||||
@@ -510,13 +498,11 @@ suite('SQL QueryAction Tests', () => {
|
||||
|
||||
// ... Create mock connection management service
|
||||
let databaseName = 'foobar';
|
||||
let cms = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {});
|
||||
cms.callBase = true;
|
||||
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
||||
connectionManagementService.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||
connectionManagementService.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
||||
|
||||
// ... Create a database dropdown that has been connected
|
||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, undefined, configurationService.object);
|
||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, connectionManagementService.object, undefined, configurationService.object);
|
||||
listItem.onConnected();
|
||||
|
||||
// If: I raise a connection changed event
|
||||
@@ -534,13 +520,11 @@ suite('SQL QueryAction Tests', () => {
|
||||
|
||||
// ... Create mock connection management service that will not claim it's connected
|
||||
let databaseName = 'foobar';
|
||||
let cms = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, new TestStorageService());
|
||||
cms.callBase = true;
|
||||
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
||||
connectionManagementService.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||
connectionManagementService.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
||||
|
||||
// ... Create a database dropdown that has been connected
|
||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, undefined, configurationService.object);
|
||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, connectionManagementService.object, undefined, configurationService.object);
|
||||
listItem.onConnected();
|
||||
|
||||
// If: I raise a connection changed event for the 'wrong' URI
|
||||
@@ -562,12 +546,10 @@ suite('SQL QueryAction Tests', () => {
|
||||
let dbChangedEmitter = new Emitter<IConnectionParams>();
|
||||
|
||||
// ... Create mock connection management service
|
||||
let cms = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, new TestStorageService());
|
||||
cms.callBase = true;
|
||||
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||
connectionManagementService.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||
|
||||
// ... Create a database dropdown
|
||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, undefined, configurationService.object);
|
||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, connectionManagementService.object, undefined, configurationService.object);
|
||||
|
||||
// If: I raise a connection changed event
|
||||
let eventParams = <IConnectionParams>{
|
||||
|
||||
@@ -10,8 +10,6 @@ import { Memento } from 'vs/workbench/common/memento';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import { QueryModelService } from 'sql/platform/query/common/queryModelService';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { INewConnectionParams, ConnectionType, RunQueryOnConnectionMode } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { ConnectionManagementService } from 'sql/workbench/services/connection/browser/connectionManagementService';
|
||||
import { RunQueryAction, ListDatabasesActionItem } from 'sql/workbench/contrib/query/browser/queryActions';
|
||||
@@ -23,6 +21,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
import { TestQueryModelService } from 'sql/platform/query/test/common/testQueryModelService';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
suite('SQL QueryEditor Tests', () => {
|
||||
let instantiationService: TypeMoq.Mock<InstantiationService>;
|
||||
@@ -247,8 +248,8 @@ suite('SQL QueryEditor Tests', () => {
|
||||
suite('Action Tests', () => {
|
||||
let queryActionInstantiationService: TypeMoq.Mock<InstantiationService>;
|
||||
let queryConnectionService: TypeMoq.Mock<ConnectionManagementService>;
|
||||
let queryModelService: TypeMoq.Mock<QueryModelService>;
|
||||
let queryInput: QueryInput;
|
||||
let queryModelService: TypeMoq.Mock<TestQueryModelService>;
|
||||
let queryInput: UntitledQueryEditorInput;
|
||||
setup(() => {
|
||||
|
||||
// Mock ConnectionManagementService but don't set connected state
|
||||
@@ -284,17 +285,17 @@ suite('SQL QueryEditor Tests', () => {
|
||||
});
|
||||
|
||||
let fileInput = new UntitledEditorInput(URI.parse('file://testUri'), false, '', '', '', instantiationService.object, undefined, undefined);
|
||||
queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose, undefined, undefined);
|
||||
queryModelService.callBase = true;
|
||||
queryModelService.setup(x => x.disposeQuery(TypeMoq.It.isAny())).returns(() => void 0);
|
||||
queryInput = new QueryInput(
|
||||
queryModelService = TypeMoq.Mock.ofType(TestQueryModelService, TypeMoq.MockBehavior.Strict);
|
||||
queryModelService.setup(x => x.disposeQuery(TypeMoq.It.isAny()));
|
||||
queryModelService.setup(x => x.onRunQueryComplete).returns(() => Event.None);
|
||||
queryModelService.setup(x => x.onRunQueryStart).returns(() => Event.None);
|
||||
queryInput = new UntitledQueryEditorInput(
|
||||
'',
|
||||
fileInput,
|
||||
undefined,
|
||||
undefined,
|
||||
connectionManagementService.object,
|
||||
queryModelService.object,
|
||||
undefined,
|
||||
configurationService.object,
|
||||
undefined
|
||||
);
|
||||
});
|
||||
@@ -311,8 +312,8 @@ suite('SQL QueryEditor Tests', () => {
|
||||
|
||||
test('Taskbar buttons are set correctly upon connect', () => {
|
||||
let params: INewConnectionParams = { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none };
|
||||
queryInput.onConnectSuccess(params);
|
||||
queryModelService.setup(x => x.isRunningQuery(TypeMoq.It.isAny())).returns(() => false);
|
||||
queryInput.onConnectSuccess(params);
|
||||
assert.equal(queryInput.state.connected, true, 'query state should be not connected');
|
||||
assert.equal(queryInput.state.executing, false, 'query state should be not executing');
|
||||
assert.equal(queryInput.state.connecting, false, 'query state should be not connecting');
|
||||
|
||||
@@ -8,6 +8,8 @@ import { EditorDescriptor, IEditorRegistry, Extensions } from 'vs/workbench/brow
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { QueryPlanEditor } from 'sql/workbench/contrib/queryPlan/browser/queryPlanEditor';
|
||||
import { ILanguageAssociationRegistry, Extensions as LanguageAssociationExtensions } from 'sql/workbench/common/languageAssociation';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
// Query Plan editor registration
|
||||
|
||||
@@ -19,3 +21,9 @@ const queryPlanEditorDescriptor = new EditorDescriptor(
|
||||
|
||||
Registry.as<IEditorRegistry>(Extensions.Editors)
|
||||
.registerEditor(queryPlanEditorDescriptor, [new SyncDescriptor(QueryPlanInput)]);
|
||||
|
||||
Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations)
|
||||
.registerLanguageAssociation('sqlplan', (accessor, editor) => {
|
||||
const instantiationService = accessor.get(IInstantiationService);
|
||||
return instantiationService.createInstance(QueryPlanInput, editor.getResource());
|
||||
}, (editor: QueryPlanInput) => undefined);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import { EditorInput, EditorModel } from 'vs/workbench/common/editor';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
@@ -19,7 +18,7 @@ export class QueryPlanInput extends EditorInput {
|
||||
private _xml: string;
|
||||
|
||||
constructor(
|
||||
private _uri: URI, private _connection: ConnectionManagementInfo,
|
||||
private _uri: URI,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
@@ -68,8 +67,4 @@ export class QueryPlanInput extends EditorInput {
|
||||
public get uniqueSelector(): string {
|
||||
return this._uniqueSelector;
|
||||
}
|
||||
|
||||
public getConnectionInfo(): ConnectionManagementInfo {
|
||||
return this._connection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,33 +4,23 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { QueryResultsInput } from 'sql/workbench/contrib/query/common/queryResultsInput';
|
||||
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
|
||||
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
|
||||
import { EditDataInput } from 'sql/workbench/contrib/editData/browser/editDataInput';
|
||||
import { IConnectableInput, IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { IQueryEditorService, IQueryEditorOptions } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||
import { sqlModeId, untitledFilePrefix, getSupportedInputResource } from 'sql/workbench/browser/customInputConverter';
|
||||
import * as TaskUtilities from 'sql/workbench/browser/taskUtilities';
|
||||
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
|
||||
import { UntitledQueryEditorInput } from 'sql/workbench/contrib/query/common/untitledQueryEditorInput';
|
||||
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import nls = require('vs/nls');
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import paths = require('vs/base/common/extpath');
|
||||
import * as paths from 'vs/base/common/extpath';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
||||
import { IEditorInput, IEditor } from 'vs/workbench/common/editor';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { ILanguageSelection } from 'vs/editor/common/services/modeService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||
import { replaceConnection } from 'sql/workbench/browser/taskUtilities';
|
||||
import { EditDataResultsInput } from 'sql/workbench/contrib/editData/browser/editDataResultsInput';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
|
||||
/**
|
||||
* Service wrapper for opening and creating SQL documents as sql editor inputs
|
||||
@@ -39,18 +29,7 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
private static CHANGE_UNSUPPORTED_ERROR_MESSAGE = nls.localize(
|
||||
'queryEditorServiceChangeUnsupportedError',
|
||||
"Change Language Mode is not supported for unsaved queries"
|
||||
);
|
||||
|
||||
private static CHANGE_ERROR_MESSAGE = nls.localize(
|
||||
'queryEditorServiceChangeError',
|
||||
"Please save or discard changes before switching to/from the SQL Language Mode"
|
||||
);
|
||||
|
||||
constructor(
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@IUntitledEditorService private _untitledEditorService: IUntitledEditorService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IEditorService private _editorService: IEditorService,
|
||||
@@ -83,12 +62,11 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
}
|
||||
|
||||
const queryResultsInput: QueryResultsInput = this._instantiationService.createInstance(QueryResultsInput, docUri.toString());
|
||||
let queryInput: QueryInput = this._instantiationService.createInstance(QueryInput, objectName, fileInput, queryResultsInput, connectionProviderName);
|
||||
let queryInput = this._instantiationService.createInstance(UntitledQueryEditorInput, objectName, fileInput, queryResultsInput);
|
||||
|
||||
this._editorService.openEditor(queryInput, { pinned: true })
|
||||
.then((editor) => {
|
||||
let params = <QueryInput>editor.input;
|
||||
resolve(params);
|
||||
resolve(editor.input as UntitledQueryEditorInput);
|
||||
}, (error) => {
|
||||
reject(error);
|
||||
});
|
||||
@@ -128,14 +106,14 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
let oldResourceString: string = oldResource.toString();
|
||||
|
||||
this._editorService.editors.forEach(input => {
|
||||
if (input instanceof QueryInput) {
|
||||
if (input instanceof QueryEditorInput) {
|
||||
const resource = input.getResource();
|
||||
|
||||
// Update Editor if file (or any parent of the input) got renamed or moved
|
||||
// Note: must check the new file name for this since this method is called after the rename is completed
|
||||
if (paths.isEqualOrParent(resource.fsPath, newResource.fsPath, !isLinux /* ignorecase */)) {
|
||||
// In this case, we know that this is a straight rename so support this as a rename / replace operation
|
||||
TaskUtilities.replaceConnection(oldResourceString, newResource.toString(), this._connectionManagementService).then(result => {
|
||||
replaceConnection(oldResourceString, newResource.toString(), this._connectionManagementService).then(result => {
|
||||
if (result && result.connected) {
|
||||
input.onConnectSuccess();
|
||||
} else {
|
||||
@@ -147,84 +125,10 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
});
|
||||
}
|
||||
|
||||
////// Public static functions
|
||||
// These functions are static to reduce extra lines needed in the vscode code base
|
||||
|
||||
/**
|
||||
* Checks if the Language Mode is being changed to/from SQL. If so, swaps out the input of the
|
||||
* given editor with a new input, opens a new editor, then returns the new editor's IModel.
|
||||
*
|
||||
* Returns an immediately resolved promise if the SQL Language mode is not involved. In this case,
|
||||
* the calling function in editorStatus.ts will handle the language change normally.
|
||||
*
|
||||
* Returns an immediately resolved promise with undefined if SQL is involved in the language change
|
||||
* and the editor is dirty. In this case, the calling function in editorStatus.ts will not perform
|
||||
* the language change. TODO: change this - tracked by issue #727
|
||||
*
|
||||
* In all other cases (when SQL is involved in the language change and the editor is not dirty),
|
||||
* returns a promise that will resolve when the old editor has been replaced by a new editor.
|
||||
*/
|
||||
public async sqlLanguageModeCheck(model: ITextModel, languageSelection: ILanguageSelection, editor: IEditor): Promise<ITextModel> {
|
||||
if (!model || !languageSelection || !editor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let newLanguage: string = languageSelection.languageIdentifier.language;
|
||||
let oldLanguage: string = model.getLanguageIdentifier().language;
|
||||
let changingToSql = sqlModeId === newLanguage;
|
||||
let changingFromSql = sqlModeId === oldLanguage;
|
||||
let changingLanguage = newLanguage !== oldLanguage;
|
||||
|
||||
if (!changingLanguage) {
|
||||
return model;
|
||||
}
|
||||
if (!changingFromSql && !changingToSql) {
|
||||
return model;
|
||||
}
|
||||
|
||||
let uri: URI = QueryEditorService._getEditorChangeUri(editor.input, changingToSql);
|
||||
if (uri.scheme === Schemas.untitled && (editor.input instanceof QueryInput || editor.input instanceof EditDataInput)) {
|
||||
this._notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: QueryEditorService.CHANGE_UNSUPPORTED_ERROR_MESSAGE
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Return undefined to notify the calling funciton to not perform the language change
|
||||
// TODO change this - tracked by issue #727
|
||||
if (editor.input.isDirty()) {
|
||||
this._notificationService.notify({
|
||||
severity: Severity.Error,
|
||||
message: QueryEditorService.CHANGE_ERROR_MESSAGE
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let group: IEditorGroup = editor.group;
|
||||
let index: number = group.editors.indexOf(editor.input);
|
||||
let options: IQueryEditorOptions = editor.options ? editor.options : {};
|
||||
options = assign(options, { index: index });
|
||||
|
||||
// Return a promise that will resovle when the old editor has been replaced by a new editor
|
||||
let newEditorInput = this.getNewEditorInput(changingToSql, editor.input, uri);
|
||||
|
||||
// Override queryEditorCheck to not open this file in a QueryEditor
|
||||
if (!changingToSql) {
|
||||
options.denyQueryEditor = true;
|
||||
}
|
||||
|
||||
await group.closeEditor(editor.input);
|
||||
// Reopen a new editor in the same position/index
|
||||
const newEditor = await this._editorService.openEditor(newEditorInput, options, group);
|
||||
|
||||
return QueryEditorService._onEditorOpened(newEditor, uri.toString(), undefined, options.pinned);
|
||||
}
|
||||
|
||||
////// Private functions
|
||||
|
||||
private createUntitledSqlFilePath(): Promise<string> {
|
||||
return this.createPrefixedSqlFilePath(untitledFilePrefix);
|
||||
return this.createPrefixedSqlFilePath('SQLQuery');
|
||||
}
|
||||
|
||||
private async createPrefixedSqlFilePath(prefix: string): Promise<string> {
|
||||
@@ -242,69 +146,4 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
////// Private static functions
|
||||
|
||||
/**
|
||||
* Returns a QueryInput if we are changingToSql. Returns a FileEditorInput if we are !changingToSql.
|
||||
*/
|
||||
private getNewEditorInput(changingToSql: boolean, input: IEditorInput, uri: URI): IEditorInput {
|
||||
if (!uri) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let newEditorInput: IEditorInput = undefined;
|
||||
if (changingToSql) {
|
||||
const queryResultsInput: QueryResultsInput = this._instantiationService.createInstance(QueryResultsInput, uri.toString());
|
||||
let queryInput: QueryInput = this._instantiationService.createInstance(QueryInput, '', input, queryResultsInput, undefined);
|
||||
newEditorInput = queryInput;
|
||||
} else {
|
||||
let uriCopy: URI = URI.from({ scheme: uri.scheme, authority: uri.authority, path: uri.path, query: uri.query, fragment: uri.fragment });
|
||||
newEditorInput = this._instantiationService.createInstance(FileEditorInput, uriCopy, undefined, undefined);
|
||||
}
|
||||
|
||||
return newEditorInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI for this IEditorInput or returns undefined if one does not exist.
|
||||
*/
|
||||
private static _getEditorChangeUri(input: IEditorInput, changingToSql: boolean): URI {
|
||||
let uriSource: IEditorInput = input;
|
||||
|
||||
// It is assumed that if we got here, !changingToSql is logically equivalent to changingFromSql
|
||||
let changingFromSql = !changingToSql;
|
||||
if (input instanceof QueryInput && changingFromSql) {
|
||||
let queryInput: QueryInput = <QueryInput>input;
|
||||
uriSource = queryInput.sql;
|
||||
}
|
||||
return getSupportedInputResource(uriSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle all cleanup actions that need to wait until the editor is fully open.
|
||||
*/
|
||||
private static _onEditorOpened(editor: IEditor, uri: string, position: Position, isPinned: boolean): ITextModel {
|
||||
|
||||
// Reset the editor pin state
|
||||
// TODO: change this so it happens automatically in openEditor in sqlLanguageModeCheck. Performing this here
|
||||
// causes the text on the tab to slightly flicker for unpinned files (from non-italic to italic to non-italic).
|
||||
// This is currently unavoidable because vscode ignores "pinned" on IEditorOptions if "index" is not undefined,
|
||||
// and we need to specify "index"" so the editor tab remains in the same place
|
||||
// let group: IEditorGroup = QueryEditorService.editorGroupService.getStacksModel().groupAt(position);
|
||||
// if (isPinned) {
|
||||
// QueryEditorService.editorGroupService.pinEditor(group, editor.input);
|
||||
// }
|
||||
|
||||
// @SQLTODO do we need the below
|
||||
// else {
|
||||
// QueryEditorService.editorGroupService.p .unpinEditor(group, editor.input);
|
||||
// }
|
||||
|
||||
// Grab and returns the IModel that will be used to resolve the sqlLanguageModeCheck promise.
|
||||
let control = editor.getControl();
|
||||
let codeEditor: ICodeEditor = <ICodeEditor>control;
|
||||
let newModel = codeEditor ? codeEditor.getModel() : undefined;
|
||||
return newModel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@ import { IConnectableInput } from 'sql/platform/connection/common/connectionMana
|
||||
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageSelection } from 'vs/editor/common/services/modeService';
|
||||
import { IEditor } from 'vs/workbench/common/editor';
|
||||
|
||||
export interface IQueryEditorOptions extends IEditorOptions {
|
||||
|
||||
@@ -38,6 +35,4 @@ export interface IQueryEditorService {
|
||||
* @param newResource URI of the file after the save as operation was completed
|
||||
*/
|
||||
onSaveAsCompleted(oldResource: URI, newResource: URI): void;
|
||||
|
||||
sqlLanguageModeCheck(model: ITextModel, languageSelection: ILanguageSelection, editor: IEditor): Promise<ITextModel>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user