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:
Anthony Dresser
2019-11-24 19:22:11 -08:00
committed by GitHub
parent f3a6fc6f88
commit 43387f0d0b
50 changed files with 988 additions and 873 deletions

View File

@@ -124,11 +124,6 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
const untitledEditorInput = <UntitledEditorInput>editorInput;
// {{SQL CARBON EDIT}} @todo anthonydresser 4/12/19 investigate
if (!untitledEditorInput.getResource()) {
return undefined;
}
let resource = untitledEditorInput.getResource();
if (untitledEditorInput.hasAssociatedFilePath) {
resource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority); // untitled with associated file path use the local schema

View File

@@ -32,7 +32,7 @@ import { RunOnceWorker } from 'vs/base/common/async';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl';
import { IEditorGroupsAccessor, IEditorGroupView, IEditorPartOptionsChangeEvent, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor';
// import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ActionRunner, IAction, Action } from 'vs/base/common/actions';
@@ -42,10 +42,6 @@ import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
// {{SQL CARBON EDIT}}
import { ICommandService } from 'vs/platform/commands/common/commands';
import { GlobalNewUntitledFileAction } from 'vs/workbench/contrib/files/browser/fileActions';
// {{SQL CARBON EDIT}} - End
import { isErrorWithActions, IErrorWithActions } from 'vs/base/common/errorsWithActions';
import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService';
import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
@@ -132,12 +128,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
@INotificationService private readonly notificationService: INotificationService,
@IDialogService private readonly dialogService: IDialogService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
// @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, {{SQL CARBON EDIT}} no unused
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
// {{SQL CARBON EDIT}}
@ICommandService private commandService: ICommandService
@IContextMenuService private readonly contextMenuService: IContextMenuService
) {
super(themeService);
@@ -260,8 +254,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this._register(addDisposableListener(this.element, EventType.DBLCLICK, e => {
if (this.isEmpty) {
EventHelper.stop(e);
// {{SQL CARBON EDIT}}
this.commandService.executeCommand(GlobalNewUntitledFileAction.ID).then(undefined, err => this.notificationService.warn(err));
this.openEditor(this.untitledEditorService.createOrGet(), EditorOptions.create({ pinned: true }));
}
}));
@@ -1463,7 +1457,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
inactiveReplacements.forEach(({ editor, replacement, options }) => {
// Open inactive editor
this.doOpenEditor(replacement, options);
this.openEditor(replacement, options); // {{SQL CARBON EDIT}} use this.openEditor to allow us to override the open, we could potentially add this to vscode but i don't think they would care
// Close replaced inactive editor unless they match
if (!editor.matches(replacement)) {
@@ -1476,7 +1470,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
if (activeReplacement) {
// Open replacement as active editor
const openEditorResult = this.doOpenEditor(activeReplacement.replacement, activeReplacement.options);
const openEditorResult = this.openEditor(activeReplacement.replacement, activeReplacement.options); // {{SQL CARBON EDIT}} use this.openEditor to allow us to override the open, we could potentially add this to vscode but i don't think they would care
// Close replaced active editor unless they match
if (!activeReplacement.editor.matches(activeReplacement.replacement)) {

View File

@@ -50,9 +50,7 @@ import { Event } from 'vs/base/common/event';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
// {{SQL CARBON EDIT}}
import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService';
import { setMode } from 'sql/workbench/browser/parts/editor/editorStatusModeSelect'; // {{SQL CARBON EDIT}}
class SideBySideEditorEncodingSupport implements IEncodingSupport {
constructor(private master: IEncodingSupport, private details: IEncodingSupport) { }
@@ -872,8 +870,7 @@ export class ChangeModeAction extends Action {
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IQueryEditorService private readonly queryEditorService: IQueryEditorService // {{ SQL CARBON EDIT }}
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService
) {
super(actionId, actionLabel);
}
@@ -973,16 +970,16 @@ export class ChangeModeAction extends Action {
}
// Change mode for active editor
const activeEditor = this.editorService.activeControl; // {{SQL CARBON EDIT}} @anthonydresser change to activeControl from active editor
const activeEditor = this.editorService.activeEditor;
if (activeEditor) {
const modeSupport = toEditorWithModeSupport(activeEditor.input); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly
const modeSupport = toEditorWithModeSupport(activeEditor);
if (modeSupport) {
// Find mode
let languageSelection: ILanguageSelection | undefined;
if (pick === autoDetectMode) {
if (textModel) {
const resource = toResource(activeEditor.input, { supportSideBySide: SideBySideEditor.MASTER }); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
if (resource) {
languageSelection = this.modeService.createByFilepathOrFirstLine(resource, textModel.getLineContent(1));
}
@@ -991,14 +988,9 @@ export class ChangeModeAction extends Action {
languageSelection = this.modeService.createByLanguageName(pick.label);
}
// {{SQL CARBON EDIT}} @anthonydresser preform a check before we actuall set the mode
// Change mode
if (typeof languageSelection !== 'undefined') {
this.queryEditorService.sqlLanguageModeCheck(textModel, languageSelection, activeEditor).then(newTextModel => {
if (newTextModel) {
modeSupport.setMode(languageSelection.languageIdentifier.language);
}
});
return this.instantiationService.invokeFunction(setMode, modeSupport, activeEditor, languageSelection.languageIdentifier.language); // {{SQL CARBON EDIT}} @anthonydresser use custom setMode
}
}
}

View File

@@ -32,7 +32,7 @@ import { Color } from 'vs/base/common/color';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MergeGroupMode, IMergeGroupOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
// import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { addClass, addDisposableListener, hasClass, EventType, EventHelper, removeClass, Dimension, scheduleAtNextAnimationFrame, findParentWithClass, clearNode } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { IEditorGroupsAccessor, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
@@ -44,10 +44,8 @@ import { withNullAsUndefined, assertAllDefined, assertIsDefined } from 'vs/base/
import { ILabelService } from 'vs/platform/label/common/label';
// {{SQL CARBON EDIT}} -- Display the editor's tab color
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as QueryConstants from 'sql/workbench/contrib/query/common/constants';
import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
import { GlobalNewUntitledFileAction } from 'vs/workbench/contrib/files/browser/fileActions';
// {{SQL CARBON EDIT}} -- End
interface IEditorInputLabel {
@@ -81,7 +79,7 @@ export class TabsTitleControl extends TitleControl {
group: IEditorGroupView,
@IContextMenuService contextMenuService: IContextMenuService,
@IInstantiationService instantiationService: IInstantiationService,
// @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, {{SQL CARBON EDIT}} comment out inject
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IKeybindingService keybindingService: IKeybindingService,
@ITelemetryService telemetryService: ITelemetryService,
@@ -92,9 +90,6 @@ export class TabsTitleControl extends TitleControl {
@IExtensionService extensionService: IExtensionService,
@IConfigurationService configurationService: IConfigurationService,
@IFileService fileService: IFileService,
// {{SQL CARBON EDIT}} -- Display the editor's tab color
@ICommandService private commandService: ICommandService,
// {{SQL CARBON EDIT}} -- End
@ILabelService labelService: ILabelService
) {
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService, labelService);
@@ -186,8 +181,8 @@ export class TabsTitleControl extends TitleControl {
this._register(addDisposableListener(tabsContainer, EventType.DBLCLICK, e => {
if (e.target === tabsContainer) {
EventHelper.stop(e);
// {{SQL CARBON EDIT}}
this.commandService.executeCommand(GlobalNewUntitledFileAction.ID).then(undefined, err => this.notificationService.warn(err));
this.group.openEditor(this.untitledEditorService.createOrGet(), { pinned: true /* untitled is always pinned */, index: this.group.count /* always at the end */ });
}
}));

View File

@@ -447,8 +447,7 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
* Subclasses can set this to false if it does not make sense to split the editor input.
*/
supportsSplitEditor(): boolean {
// {{SQL CARBON EDIT}} @anthonydresser 05/19/2019 investigate
return false; // TODO reenable when multiple Angular components of the same type can be open simultaneously
return true;
}
/**
@@ -475,16 +474,6 @@ export abstract class EditorInput extends Disposable implements IEditorInput {
super.dispose();
}
// {{SQL CARBON EDIT}} @anthonydresser 05/19/2019 investigate
// Saving is not supported in the EditData query editor, so this can be overriden in its Input.
private _savingSupported: boolean = true;
public get savingSupported(): boolean {
return this._savingSupported;
}
public disableSaving() {
this._savingSupported = false;
}
}
export const enum ConfirmResult {

View File

@@ -14,11 +14,9 @@ import { ResourceMap } from 'vs/base/common/map';
import { coalesce, firstIndex } from 'vs/base/common/arrays';
// {{SQL CARBON EDIT}}
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
import * as CustomInputConverter from 'sql/workbench/browser/customInputConverter';
import { NotebookInput } from 'sql/workbench/contrib/notebook/browser/models/notebookInput';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
const EditorOpenPositioning = {
LEFT: 'left',
@@ -643,16 +641,7 @@ export class EditorGroup extends Disposable {
let serializableEditors: EditorInput[] = [];
let serializedEditors: ISerializedEditorInput[] = [];
let serializablePreviewIndex: number | undefined;
// {{SQL CARBON EDIT}}
const editors = this.editors.map(e => {
if (e instanceof QueryInput) {
return e.sql;
} else if (e instanceof NotebookInput) {
return e.textInput;
}
return e;
});
editors.forEach(e => {
this.editors.forEach(e => {
const factory = registry.getEditorInputFactory(e.getTypeId());
if (factory) {
// {{SQL CARBON EDIT}}
@@ -675,16 +664,7 @@ export class EditorGroup extends Disposable {
}
});
// {{SQL CARBON EDIT}}
let mru = this.mru.map(e => {
if (e instanceof QueryInput) {
return e.sql;
} else if (e instanceof NotebookInput) {
return e.textInput;
}
return e;
});
const serializableMru = mru.map(e => this.indexOf(e, serializableEditors)).filter(i => i >= 0);
const serializableMru = this.mru.map(e => this.indexOf(e, serializableEditors)).filter(i => i >= 0);
return {
id: this.id,
@@ -714,8 +694,7 @@ export class EditorGroup extends Disposable {
this.updateResourceMap(editor, false /* add */);
}
// {{SQL CARBON EDIT}}
return CustomInputConverter.convertEditorInput(editor, undefined, this.instantiationService);
return editor;
}
return null;
@@ -737,7 +716,7 @@ export class EditorGroup extends Disposable {
let n = 0;
while (n < this.editors.length) {
let editor = this.editors[n];
if (editor instanceof QueryInput && editor.matchInputInstanceType(FileEditorInput) && !editor.isDirty() && await editor.inputFileExists() === false && this.editors.length > 1) {
if (editor instanceof QueryEditorInput && editor.matchInputInstanceType(FileEditorInput) && !editor.isDirty() && await editor.inputFileExists() === false && this.editors.length > 1) {
// remove from editors list so that they do not get restored
this.editors.splice(n, 1);
let index = firstIndex(this.mru, e => e.matches(editor));

View File

@@ -125,11 +125,6 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
}
isDirty(): boolean {
// {{SQL CARBON EDIT}}
if (!this.savingSupported) {
return false;
}
if (this.cachedModel) {
return this.cachedModel.isDirty();
}

View File

@@ -30,7 +30,7 @@ import { withNullAsUndefined } from 'vs/base/common/types';
import { EditorActivation } from 'vs/platform/editor/common/editor';
// {{SQL CARBON EDIT}}
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
import { QueryEditorInput } from 'sql/workbench/contrib/query/common/queryEditorInput';
export class FileEditorTracker extends Disposable implements IWorkbenchContribution {
@@ -186,12 +186,12 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
}
// {{SQL CARBON EDIT}} - Support FileEditorInput or QueryInput
private getOpenedFileEditors(dirtyState: boolean): (FileEditorInput | QueryInput)[] {
const editors: (FileEditorInput | QueryInput)[] = [];
private getOpenedFileEditors(dirtyState: boolean): (FileEditorInput | QueryEditorInput)[] {
const editors: (FileEditorInput | QueryEditorInput)[] = [];
this.editorService.editors.forEach(editor => {
// {{SQL CARBON EDIT}} - Support FileEditorInput or QueryInput
if (editor instanceof FileEditorInput || editor instanceof QueryInput) {
if (editor instanceof FileEditorInput || editor instanceof QueryEditorInput) {
if (!!editor.isDirty() === dirtyState) {
editors.push(editor);
}
@@ -220,7 +220,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
this.editorGroupService.groups.forEach(group => {
group.editors.forEach(editor => {
// {{SQL CARBON EDIT}} - Support FileEditorInput or QueryInput
if (editor instanceof FileEditorInput || editor instanceof QueryInput) {
if (editor instanceof FileEditorInput || editor instanceof QueryEditorInput) {
const resource = editor.getResource();
// Update Editor if file (or any parent of the input) got renamed or moved

View File

@@ -46,9 +46,6 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel';
import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors';
// {{SQL CARBON EDIT}}
import { openNewQuery } from 'sql/workbench/contrib/query/browser/queryActions';
export const NEW_FILE_COMMAND_ID = 'explorer.newFile';
export const NEW_FILE_LABEL = nls.localize('newFile', "New File");
@@ -155,15 +152,13 @@ export class GlobalNewUntitledFileAction extends Action {
constructor(
id: string,
label: string,
// {{SQL CARBON EDIT}} - Make editorService protected and add other services
@IEditorService protected readonly editorService: IEditorService,
@IInstantiationService private readonly instantiationService: IInstantiationService
@IEditorService private readonly editorService: IEditorService
) {
super(id, label);
}
run(): Promise<any> {
return this.instantiationService.invokeFunction(openNewQuery); // {{SQL CARBON EDIT}}
return this.editorService.openEditor({ options: { pinned: true } }); // untitled are always pinned
}
}

View File

@@ -5,7 +5,7 @@
import * as nls from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { toResource, IEditorCommandsContext, SideBySideEditor, EditorInput } from 'vs/workbench/common/editor'; // {{SQL CARBON EDIT}} add edit input
import { toResource, IEditorCommandsContext, SideBySideEditor } from 'vs/workbench/common/editor';
import { IWindowOpenable, IOpenWindowOptions, isWorkspaceToOpen, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -128,14 +128,6 @@ async function save(
return doSaveAs(resource, isSaveAs, options, editorService, fileService, untitledEditorService, textFileService, editorGroupService, queryEditorService, environmentService); // {{SQL CARBON EDIT}} add paramater
}
if (resource && (fileService.canHandleResource(resource) || resource.scheme === Schemas.untitled)) {
// {{SQL CARBON EDIT}}
let editorInput = editorService.activeEditor;
if (editorInput instanceof EditorInput && !(<EditorInput>editorInput).savingSupported) {
return;
}
}
// Save
return doSave(resource, options, editorService, textFileService);
}

View File

@@ -28,7 +28,6 @@ import { IEditorGroupView, IEditorOpeningEvent, EditorServiceImpl } from 'vs/wor
import { ILabelService } from 'vs/platform/label/common/label';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { withNullAsUndefined } from 'vs/base/common/types';
import { convertEditorInput, getFileMode } from 'sql/workbench/browser/customInputConverter'; //{{SQL CARBON EDIT}}
type CachedEditorInput = ResourceEditorInput | IFileEditorInput | DataUriEditorInput;
type OpenInEditorGroup = IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE;
@@ -571,10 +570,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
// Untitled file support
const untitledInput = input as IUntitledResourceInput;
if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource && untitledInput.resource.scheme === Schemas.untitled)) {
// {{SQL CARBON EDIT}}
// Need to get mode for QueryEditor and Notebook
let mode: string = untitledInput.mode ? untitledInput.mode : getFileMode(this.instantiationService, untitledInput.resource);
return convertEditorInput(this.untitledEditorService.createOrGet(untitledInput.resource, mode, untitledInput.contents, untitledInput.encoding), undefined, this.instantiationService);
return this.untitledEditorService.createOrGet(untitledInput.resource, untitledInput.mode, untitledInput.contents, untitledInput.encoding);
}
// Resource Editor Support
@@ -585,9 +581,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
label = basename(resourceInput.resource); // derive the label from the path (but not for data URIs)
}
// {{SQL CARBON EDIT}}
return convertEditorInput(this.createOrGet(resourceInput.resource, this.instantiationService, label, resourceInput.description, resourceInput.encoding, resourceInput.mode, resourceInput.forceFile) as EditorInput,
undefined, this.instantiationService);
return this.createOrGet(resourceInput.resource, this.instantiationService, label, resourceInput.description, resourceInput.encoding, resourceInput.mode, resourceInput.forceFile) as EditorInput;
}
throw new Error('Unknown input type');

View File

@@ -363,13 +363,16 @@ import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution';
// query
import 'sql/workbench/contrib/query/browser/query.contribution';
import 'sql/workbench/contrib/query/common/resultsGridContribution';
import 'sql/workbench/contrib/query/common/resultsGrid.contribution';
// data explorer
import 'sql/workbench/contrib/dataExplorer/browser/dataExplorer.contribution';
import 'sql/workbench/contrib/dataExplorer/browser/nodeActions.common.contribution';
// {{SQL CARBON EDIT}}
//editor replacement
import 'sql/workbench/common/editorReplacer.contribution';
// tasks
import 'sql/workbench/contrib/tasks/browser/tasks.contribution';
import 'sql/workbench/browser/actions.contribution';