mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-04-01 01:20:31 -04:00
Refresh master with initial release/0.24 snapshot (#332)
* Initial port of release/0.24 source code * Fix additional headers * Fix a typo in launch.json
This commit is contained in:
@@ -5,14 +5,10 @@
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import types = require('vs/base/common/types');
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Panel } from 'vs/workbench/browser/panel';
|
||||
import { EditorInput, EditorOptions, IEditorDescriptor, IEditorInputFactory, IEditorRegistry, Extensions, IFileInputFactory } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { IEditor, Position } from 'vs/platform/editor/common/editor';
|
||||
import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { SyncDescriptor, AsyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
@@ -123,183 +119,4 @@ export abstract class BaseEditor extends Panel implements IEditor {
|
||||
// Super Dispose
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A lightweight descriptor of an editor. The descriptor is deferred so that heavy editors
|
||||
* can load lazily in the workbench.
|
||||
*/
|
||||
export class EditorDescriptor extends AsyncDescriptor<BaseEditor> implements IEditorDescriptor {
|
||||
private id: string;
|
||||
private name: string;
|
||||
|
||||
constructor(id: string, name: string, moduleId: string, ctorName: string) {
|
||||
super(moduleId, ctorName);
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public describes(obj: any): boolean {
|
||||
return obj instanceof BaseEditor && (<BaseEditor>obj).getId() === this.id;
|
||||
}
|
||||
}
|
||||
|
||||
const INPUT_DESCRIPTORS_PROPERTY = '__$inputDescriptors';
|
||||
|
||||
class EditorRegistry implements IEditorRegistry {
|
||||
private editors: EditorDescriptor[];
|
||||
private instantiationService: IInstantiationService;
|
||||
private fileInputFactory: IFileInputFactory;
|
||||
private editorInputFactoryConstructors: { [editorInputId: string]: IConstructorSignature0<IEditorInputFactory> } = Object.create(null);
|
||||
private editorInputFactoryInstances: { [editorInputId: string]: IEditorInputFactory } = Object.create(null);
|
||||
|
||||
constructor() {
|
||||
this.editors = [];
|
||||
}
|
||||
|
||||
public setInstantiationService(service: IInstantiationService): void {
|
||||
this.instantiationService = service;
|
||||
|
||||
for (let key in this.editorInputFactoryConstructors) {
|
||||
const element = this.editorInputFactoryConstructors[key];
|
||||
this.createEditorInputFactory(key, element);
|
||||
}
|
||||
|
||||
this.editorInputFactoryConstructors = {};
|
||||
}
|
||||
|
||||
private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0<IEditorInputFactory>): void {
|
||||
const instance = this.instantiationService.createInstance(ctor);
|
||||
this.editorInputFactoryInstances[editorInputId] = instance;
|
||||
}
|
||||
|
||||
public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput>): void;
|
||||
public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: SyncDescriptor<EditorInput>[]): void;
|
||||
public registerEditor(descriptor: EditorDescriptor, editorInputDescriptor: any): void {
|
||||
|
||||
// Support both non-array and array parameter
|
||||
let inputDescriptors: SyncDescriptor<EditorInput>[] = [];
|
||||
if (!types.isArray(editorInputDescriptor)) {
|
||||
inputDescriptors.push(editorInputDescriptor);
|
||||
} else {
|
||||
inputDescriptors = editorInputDescriptor;
|
||||
}
|
||||
|
||||
// Register (Support multiple Editors per Input)
|
||||
descriptor[INPUT_DESCRIPTORS_PROPERTY] = inputDescriptors;
|
||||
this.editors.push(descriptor);
|
||||
}
|
||||
|
||||
public getEditor(input: EditorInput): EditorDescriptor {
|
||||
const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => {
|
||||
const matchingDescriptors: EditorDescriptor[] = [];
|
||||
|
||||
for (let i = 0; i < this.editors.length; i++) {
|
||||
const editor = this.editors[i];
|
||||
const inputDescriptors = <SyncDescriptor<EditorInput>[]>editor[INPUT_DESCRIPTORS_PROPERTY];
|
||||
for (let j = 0; j < inputDescriptors.length; j++) {
|
||||
const inputClass = inputDescriptors[j].ctor;
|
||||
|
||||
// Direct check on constructor type (ignores prototype chain)
|
||||
if (!byInstanceOf && input.constructor === inputClass) {
|
||||
matchingDescriptors.push(editor);
|
||||
break;
|
||||
}
|
||||
|
||||
// Normal instanceof check
|
||||
else if (byInstanceOf && input instanceof inputClass) {
|
||||
matchingDescriptors.push(editor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no descriptors found, continue search using instanceof and prototype chain
|
||||
if (!byInstanceOf && matchingDescriptors.length === 0) {
|
||||
return findEditorDescriptors(input, true);
|
||||
}
|
||||
|
||||
if (byInstanceOf) {
|
||||
return matchingDescriptors;
|
||||
}
|
||||
|
||||
return matchingDescriptors;
|
||||
};
|
||||
|
||||
const descriptors = findEditorDescriptors(input);
|
||||
if (descriptors && descriptors.length > 0) {
|
||||
|
||||
// Ask the input for its preferred Editor
|
||||
const preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId()));
|
||||
if (preferredEditorId) {
|
||||
return this.getEditorById(preferredEditorId);
|
||||
}
|
||||
|
||||
// Otherwise, first come first serve
|
||||
return descriptors[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public getEditorById(editorId: string): EditorDescriptor {
|
||||
for (let i = 0; i < this.editors.length; i++) {
|
||||
const editor = this.editors[i];
|
||||
if (editor.getId() === editorId) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public getEditors(): EditorDescriptor[] {
|
||||
return this.editors.slice(0);
|
||||
}
|
||||
|
||||
public setEditors(editorsToSet: EditorDescriptor[]): void {
|
||||
this.editors = editorsToSet;
|
||||
}
|
||||
|
||||
public getEditorInputs(): any[] {
|
||||
const inputClasses: any[] = [];
|
||||
for (let i = 0; i < this.editors.length; i++) {
|
||||
const editor = this.editors[i];
|
||||
const editorInputDescriptors = <SyncDescriptor<EditorInput>[]>editor[INPUT_DESCRIPTORS_PROPERTY];
|
||||
inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor));
|
||||
}
|
||||
|
||||
return inputClasses;
|
||||
}
|
||||
|
||||
public registerFileInputFactory(factory: IFileInputFactory): void {
|
||||
this.fileInputFactory = factory;
|
||||
}
|
||||
|
||||
public getFileInputFactory(): IFileInputFactory {
|
||||
return this.fileInputFactory;
|
||||
}
|
||||
|
||||
public registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0<IEditorInputFactory>): void {
|
||||
if (!this.instantiationService) {
|
||||
this.editorInputFactoryConstructors[editorInputId] = ctor;
|
||||
} else {
|
||||
this.createEditorInputFactory(editorInputId, ctor);
|
||||
}
|
||||
}
|
||||
|
||||
public getEditorInputFactory(editorInputId: string): IEditorInputFactory {
|
||||
return this.editorInputFactoryInstances[editorInputId];
|
||||
}
|
||||
}
|
||||
|
||||
Registry.add(Extensions.Editors, new EditorRegistry());
|
||||
}
|
||||
@@ -64,48 +64,46 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
public setInput(input: EditorInput, options?: EditorOptions): TPromise<void> {
|
||||
const oldInput = this.input;
|
||||
super.setInput(input, options);
|
||||
|
||||
// Detect options
|
||||
// Return early for same input unless we force to open
|
||||
const forceOpen = options && options.forceOpen;
|
||||
|
||||
// Same Input
|
||||
if (!forceOpen && input.matches(oldInput)) {
|
||||
if (!forceOpen && input.matches(this.input)) {
|
||||
return TPromise.as<void>(null);
|
||||
}
|
||||
|
||||
// Different Input (Reload)
|
||||
return input.resolve(true).then((resolvedModel: EditorModel) => {
|
||||
// Otherwise set input and resolve
|
||||
return super.setInput(input, options).then(() => {
|
||||
return input.resolve(true).then((resolvedModel: EditorModel) => {
|
||||
|
||||
// Assert Model instance
|
||||
if (!(resolvedModel instanceof BinaryEditorModel)) {
|
||||
return TPromise.wrapError<void>(new Error('Unable to open file as binary'));
|
||||
}
|
||||
// Assert Model instance
|
||||
if (!(resolvedModel instanceof BinaryEditorModel)) {
|
||||
return TPromise.wrapError<void>(new Error('Unable to open file as binary'));
|
||||
}
|
||||
|
||||
// Assert that the current input is still the one we expect. This prevents a race condition when loading takes long and another input was set meanwhile
|
||||
if (!this.input || this.input !== input) {
|
||||
return null;
|
||||
}
|
||||
// Assert that the current input is still the one we expect. This prevents a race condition when loading takes long and another input was set meanwhile
|
||||
if (!this.input || this.input !== input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Render Input
|
||||
const model = <BinaryEditorModel>resolvedModel;
|
||||
ResourceViewer.show(
|
||||
{ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag() },
|
||||
this.binaryContainer,
|
||||
this.scrollbar,
|
||||
(resource: URI) => {
|
||||
this.windowsService.openExternal(resource.toString()).then(didOpen => {
|
||||
if (!didOpen) {
|
||||
return this.windowsService.showItemInFolder(resource.fsPath);
|
||||
}
|
||||
// Render Input
|
||||
const model = <BinaryEditorModel>resolvedModel;
|
||||
ResourceViewer.show(
|
||||
{ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag() },
|
||||
this.binaryContainer,
|
||||
this.scrollbar,
|
||||
(resource: URI) => {
|
||||
this.windowsService.openExternal(resource.toString()).then(didOpen => {
|
||||
if (!didOpen) {
|
||||
return this.windowsService.showItemInFolder(resource.fsPath);
|
||||
}
|
||||
|
||||
return void 0;
|
||||
});
|
||||
},
|
||||
(meta) => this.handleMetadataChanged(meta));
|
||||
return void 0;
|
||||
});
|
||||
},
|
||||
(meta) => this.handleMetadataChanged(meta));
|
||||
|
||||
return TPromise.as<void>(null);
|
||||
return TPromise.as<void>(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ import URI from 'vs/base/common/uri';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { IEditorQuickOpenEntry, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
|
||||
import { StatusbarItemDescriptor, StatusbarAlignment, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorInput, IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, SideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor';
|
||||
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
|
||||
import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
@@ -22,15 +22,15 @@ import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
|
||||
import { ChangeEncodingAction, ChangeEOLAction, ChangeModeAction, EditorStatus } from 'vs/workbench/browser/parts/editor/editorStatus';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import {
|
||||
CloseEditorsInGroupAction, CloseEditorsInOtherGroupsAction, CloseAllEditorsAction, MoveGroupLeftAction, MoveGroupRightAction, SplitEditorAction, JoinTwoGroupsAction, KeepEditorAction, CloseOtherEditorsInGroupAction, OpenToSideAction, RevertAndCloseEditorAction,
|
||||
NavigateBetweenGroupsAction, FocusActiveGroupAction, FocusFirstGroupAction, FocusSecondGroupAction, FocusThirdGroupAction, EvenGroupWidthsAction, MaximizeGroupAction, MinimizeOtherGroupsAction, FocusPreviousGroup, FocusNextGroup, ShowEditorsInGroupOneAction,
|
||||
toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, CloseUnmodifiedEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, ReopenClosedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, NAVIGATE_IN_GROUP_ONE_PREFIX,
|
||||
toEditorQuickOpenEntry, CloseLeftEditorsInGroupAction, CloseRightEditorsInGroupAction, CloseUnmodifiedEditorsInGroupAction, OpenNextEditor, OpenPreviousEditor, NavigateBackwardsAction, NavigateForwardAction, NavigateLastAction, ReopenClosedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, NAVIGATE_IN_GROUP_ONE_PREFIX,
|
||||
OpenPreviousEditorFromHistoryAction, ShowAllEditorsAction, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, ClearEditorHistoryAction, ShowEditorsInGroupTwoAction, MoveEditorRightInGroupAction, OpenNextEditorInGroup, OpenPreviousEditorInGroup, OpenNextRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorAction,
|
||||
NAVIGATE_IN_GROUP_TWO_PREFIX, ShowEditorsInGroupThreeAction, NAVIGATE_IN_GROUP_THREE_PREFIX, FocusLastEditorInStackAction, OpenNextRecentlyUsedEditorInGroupAction, MoveEditorToPreviousGroupAction, MoveEditorToNextGroupAction, MoveEditorLeftInGroupAction, ClearRecentFilesAction
|
||||
} from 'vs/workbench/browser/parts/editor/editorActions';
|
||||
@@ -39,14 +39,15 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
|
||||
import { getQuickNavigateHandler, inQuickOpenContext } from 'vs/workbench/browser/parts/quickopen/quickopen';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { GroupOnePicker, GroupTwoPicker, GroupThreePicker, AllEditorsPicker } from 'vs/workbench/browser/parts/editor/editorPicker';
|
||||
|
||||
// Register String Editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
TextResourceEditor,
|
||||
TextResourceEditor.ID,
|
||||
nls.localize('textEditor', "Text Editor"),
|
||||
'vs/workbench/browser/parts/editor/textResourceEditor',
|
||||
'TextResourceEditor'
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(UntitledEditorInput),
|
||||
@@ -57,10 +58,9 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
// Register Text Diff Editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
TextDiffEditor,
|
||||
TextDiffEditor.ID,
|
||||
nls.localize('textDiffEditor', "Text Diff Editor"),
|
||||
'vs/workbench/browser/parts/editor/textDiffEditor',
|
||||
'TextDiffEditor'
|
||||
nls.localize('textDiffEditor', "Text Diff Editor")
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(DiffEditorInput)
|
||||
@@ -70,10 +70,9 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
// Register Binary Resource Diff Editor
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
BinaryResourceDiffEditor,
|
||||
BinaryResourceDiffEditor.ID,
|
||||
nls.localize('binaryDiffEditor', "Binary Diff Editor"),
|
||||
'vs/workbench/browser/parts/editor/binaryDiffEditor',
|
||||
'BinaryResourceDiffEditor'
|
||||
nls.localize('binaryDiffEditor', "Binary Diff Editor")
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(DiffEditorInput)
|
||||
@@ -82,10 +81,9 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
|
||||
new EditorDescriptor(
|
||||
SideBySideEditor,
|
||||
SideBySideEditor.ID,
|
||||
nls.localize('sideBySideEditor', "Side by Side Editor"),
|
||||
'vs/workbench/browser/parts/editor/sideBySideEditor',
|
||||
'SideBySideEditor'
|
||||
nls.localize('sideBySideEditor', "Side by Side Editor")
|
||||
),
|
||||
[
|
||||
new SyncDescriptor(SideBySideEditorInput)
|
||||
@@ -115,7 +113,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
|
||||
const untitledEditorInput = <UntitledEditorInput>editorInput;
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
if (!untitledEditorInput.getResource) {
|
||||
if (!untitledEditorInput.getResource()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -147,7 +145,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditorInputFactory(UntitledEditorInput.ID, UntitledEditorInputFactory);
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(UntitledEditorInput.ID, UntitledEditorInputFactory);
|
||||
|
||||
interface ISerializedSideBySideEditorInput {
|
||||
name: string;
|
||||
@@ -167,7 +165,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory {
|
||||
const input = <SideBySideEditorInput>editorInput;
|
||||
|
||||
if (input.details && input.master) {
|
||||
const registry = Registry.as<IEditorRegistry>(EditorExtensions.Editors);
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
const detailsInputFactory = registry.getEditorInputFactory(input.details.getTypeId());
|
||||
const masterInputFactory = registry.getEditorInputFactory(input.master.getTypeId());
|
||||
|
||||
@@ -194,7 +192,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory {
|
||||
public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput {
|
||||
const deserialized: ISerializedSideBySideEditorInput = JSON.parse(serializedEditorInput);
|
||||
|
||||
const registry = Registry.as<IEditorRegistry>(EditorExtensions.Editors);
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
const detailsInputFactory = registry.getEditorInputFactory(deserialized.detailsTypeId);
|
||||
const masterInputFactory = registry.getEditorInputFactory(deserialized.masterTypeId);
|
||||
|
||||
@@ -211,7 +209,7 @@ class SideBySideEditorInputFactory implements IEditorInputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditorInputFactory(SideBySideEditorInput.ID, SideBySideEditorInputFactory);
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(SideBySideEditorInput.ID, SideBySideEditorInputFactory);
|
||||
|
||||
// Register Editor Status
|
||||
const statusBar = Registry.as<IStatusbarRegistry>(StatusExtensions.Statusbar);
|
||||
@@ -270,8 +268,8 @@ const editorPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExp
|
||||
|
||||
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
|
||||
new QuickOpenHandlerDescriptor(
|
||||
'vs/workbench/browser/parts/editor/editorPicker',
|
||||
'GroupOnePicker',
|
||||
GroupOnePicker,
|
||||
GroupOnePicker.ID,
|
||||
NAVIGATE_IN_GROUP_ONE_PREFIX,
|
||||
editorPickerContextKey,
|
||||
[
|
||||
@@ -296,8 +294,8 @@ Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpen
|
||||
|
||||
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
|
||||
new QuickOpenHandlerDescriptor(
|
||||
'vs/workbench/browser/parts/editor/editorPicker',
|
||||
'GroupTwoPicker',
|
||||
GroupTwoPicker,
|
||||
GroupTwoPicker.ID,
|
||||
NAVIGATE_IN_GROUP_TWO_PREFIX,
|
||||
editorPickerContextKey,
|
||||
[]
|
||||
@@ -306,8 +304,8 @@ Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpen
|
||||
|
||||
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
|
||||
new QuickOpenHandlerDescriptor(
|
||||
'vs/workbench/browser/parts/editor/editorPicker',
|
||||
'GroupThreePicker',
|
||||
GroupThreePicker,
|
||||
GroupThreePicker.ID,
|
||||
NAVIGATE_IN_GROUP_THREE_PREFIX,
|
||||
editorPickerContextKey,
|
||||
[]
|
||||
@@ -316,8 +314,8 @@ Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpen
|
||||
|
||||
Registry.as<IQuickOpenRegistry>(QuickOpenExtensions.Quickopen).registerQuickOpenHandler(
|
||||
new QuickOpenHandlerDescriptor(
|
||||
'vs/workbench/browser/parts/editor/editorPicker',
|
||||
'AllEditorsPicker',
|
||||
AllEditorsPicker,
|
||||
AllEditorsPicker.ID,
|
||||
NAVIGATE_ALL_EDITORS_GROUP_PREFIX,
|
||||
editorPickerContextKey,
|
||||
[
|
||||
@@ -343,7 +341,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ShowEditorsInGroupThre
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextEditor, OpenNextEditor.ID, OpenNextEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageDown, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.RightArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET] } }), 'View: Open Next Editor', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditor, OpenPreviousEditor.ID, OpenPreviousEditor.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.PageUp, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.LeftArrow, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET] } }), 'View: Open Previous Editor', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ReopenClosedEditorAction, ReopenClosedEditorAction.ID, ReopenClosedEditorAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_T }), 'View: Reopen Closed Editor', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'View: Clear Recently Opened', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearRecentFilesAction, ClearRecentFilesAction.ID, ClearRecentFilesAction.LABEL), 'File: Clear Recently Opened', nls.localize('file', "File"));
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(KeepEditorAction, KeepEditorAction.ID, KeepEditorAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.Enter) }), 'View: Keep Editor', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseAllEditorsAction, CloseAllEditorsAction.ID, CloseAllEditorsAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_W) }), 'View: Close All Editors', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(CloseLeftEditorsInGroupAction, CloseLeftEditorsInGroupAction.ID, CloseLeftEditorsInGroupAction.LABEL), 'View: Close Editors to the Left', category);
|
||||
@@ -373,6 +371,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousGroup, Fo
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextGroup, FocusNextGroup.ID, FocusNextGroup.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.RightArrow) }), 'View: Focus Next Group', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateForwardAction, NavigateForwardAction.ID, NavigateForwardAction.LABEL, { primary: null, win: { primary: KeyMod.Alt | KeyCode.RightArrow }, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS } }), 'Go Forward');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateBackwardsAction, NavigateBackwardsAction.ID, NavigateBackwardsAction.LABEL, { primary: null, win: { primary: KeyMod.Alt | KeyCode.LeftArrow }, mac: { primary: KeyMod.WinCtrl | KeyCode.US_MINUS }, linux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.US_MINUS } }), 'Go Back');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLastAction, NavigateLastAction.ID, NavigateLastAction.LABEL), 'Go Last');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousEditorFromHistoryAction, OpenPreviousEditorFromHistoryAction.ID, OpenPreviousEditorFromHistoryAction.LABEL), 'Open Previous Editor from History');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(ClearEditorHistoryAction, ClearEditorHistoryAction.ID, ClearEditorHistoryAction.LABEL), 'Clear Editor History');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(RevertAndCloseEditorAction, RevertAndCloseEditorAction.ID, RevertAndCloseEditorAction.LABEL), 'View: Revert and Close Editor', category);
|
||||
@@ -380,8 +379,8 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(RevertAndCloseEditorAc
|
||||
// Register Editor Picker Actions including quick navigate support
|
||||
const openNextEditorKeybinding = { primary: KeyMod.CtrlCmd | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyCode.Tab } };
|
||||
const openPreviousEditorKeybinding = { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Tab, mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.Tab } };
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, openNextEditorKeybinding), 'Open Next Recently Used Editor in Group');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, openPreviousEditorKeybinding), 'Open Previous Recently Used Editor in Group');
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNextRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction.ID, OpenNextRecentlyUsedEditorInGroupAction.LABEL, openNextEditorKeybinding), 'View: Open Next Recently Used Editor in Group', category);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPreviousRecentlyUsedEditorInGroupAction, OpenPreviousRecentlyUsedEditorInGroupAction.ID, OpenPreviousRecentlyUsedEditorInGroupAction.LABEL, openPreviousEditorKeybinding), 'View: Open Previous Recently Used Editor in Group', category);
|
||||
|
||||
const quickOpenNavigateNextInEditorPickerId = 'workbench.action.quickOpenNavigateNextInEditorPicker';
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
@@ -405,4 +404,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
||||
|
||||
// Editor Commands
|
||||
editorCommands.setup();
|
||||
editorCommands.setup();
|
||||
|
||||
// Touch Bar
|
||||
if (isMacintosh) {
|
||||
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
|
||||
command: { id: NavigateBackwardsAction.ID, title: NavigateBackwardsAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/back-tb.png')).fsPath },
|
||||
group: 'navigation'
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.TouchBarContext, {
|
||||
command: { id: NavigateForwardAction.ID, title: NavigateForwardAction.LABEL, iconPath: URI.parse(require.toUrl('vs/workbench/browser/parts/editor/media/forward-tb.png')).fsPath },
|
||||
group: 'navigation'
|
||||
});
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import nls = require('vs/nls');
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { getCodeEditor } from 'vs/editor/common/services/codeEditorService';
|
||||
import { EditorInput, hasResource, TextEditorOptions, EditorOptions, IEditorIdentifier, IEditorContext, ActiveEditorMoveArguments, ActiveEditorMovePositioning, EditorCommands, ConfirmResult } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, TextEditorOptions, EditorOptions, IEditorIdentifier, IEditorContext, ActiveEditorMoveArguments, ActiveEditorMovePositioning, EditorCommands, ConfirmResult } from 'vs/workbench/common/editor';
|
||||
import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
|
||||
import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -255,16 +255,13 @@ export class FocusFirstGroupAction extends Action {
|
||||
|
||||
// Since no editor is currently opened, try to open last history entry to the target side
|
||||
const history = this.historyService.getHistory();
|
||||
for (let input of history) {
|
||||
|
||||
// For now only support to open files from history to the side
|
||||
if (history.length > 0) {
|
||||
const input = history[0];
|
||||
if (input instanceof EditorInput) {
|
||||
if (hasResource(input, { filter: ['file', 'untitled'] })) {
|
||||
return this.editorService.openEditor(input, null, Position.ONE);
|
||||
}
|
||||
} else {
|
||||
return this.editorService.openEditor(input as IResourceInput, Position.ONE);
|
||||
return this.editorService.openEditor(input, null, Position.ONE);
|
||||
}
|
||||
|
||||
return this.editorService.openEditor(input as IResourceInput, Position.ONE);
|
||||
}
|
||||
|
||||
return TPromise.as(true);
|
||||
@@ -327,15 +324,11 @@ export abstract class BaseFocusSideGroupAction extends Action {
|
||||
else if (referenceEditor) {
|
||||
const history = this.historyService.getHistory();
|
||||
for (let input of history) {
|
||||
|
||||
// For now only support to open files from history to the side
|
||||
if (input instanceof EditorInput) {
|
||||
if (hasResource(input, { filter: ['file', 'untitled'] })) {
|
||||
return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide());
|
||||
}
|
||||
} else {
|
||||
return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide());
|
||||
if (input instanceof EditorInput && input.supportsSplitEditor()) {
|
||||
return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide());
|
||||
}
|
||||
|
||||
return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,6 +1109,22 @@ export class NavigateBackwardsAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class NavigateLastAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.navigateLast';
|
||||
public static LABEL = nls.localize('navigateLast', "Go Last");
|
||||
|
||||
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
this.historyService.last();
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReopenClosedEditorAction extends Action {
|
||||
|
||||
public static ID = 'workbench.action.reopenClosedEditor';
|
||||
|
||||
@@ -199,7 +199,7 @@ function handleCommandDeprecations(): void {
|
||||
};
|
||||
|
||||
Object.keys(mapDeprecatedCommands).forEach(deprecatedCommandId => {
|
||||
const newCommandId = mapDeprecatedCommands[deprecatedCommandId];
|
||||
const newCommandId: string = mapDeprecatedCommands[deprecatedCommandId];
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: deprecatedCommandId,
|
||||
|
||||
@@ -20,7 +20,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Position, POSITIONS } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorGroupService, ITabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IEditorGroupService, IEditorTabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
@@ -73,6 +73,7 @@ export interface IEditorGroupsControl {
|
||||
getInstantiationService(position: Position): IInstantiationService;
|
||||
getProgressBar(position: Position): ProgressBar;
|
||||
updateProgress(position: Position, state: ProgressState): void;
|
||||
updateTitleAreas(refreshActive?: boolean): void;
|
||||
|
||||
layout(dimension: Dimension): void;
|
||||
layout(position: Position): void;
|
||||
@@ -115,7 +116,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
|
||||
|
||||
private layoutVertically: boolean;
|
||||
|
||||
private tabOptions: ITabOptions;
|
||||
private tabOptions: IEditorTabOptions;
|
||||
|
||||
private silos: Builder[];
|
||||
private silosSize: number[];
|
||||
@@ -225,7 +226,7 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
|
||||
this.extensionService.onReady().then(() => this.onExtensionsReady());
|
||||
}
|
||||
|
||||
private updateTabOptions(tabOptions: ITabOptions, refresh?: boolean): void {
|
||||
private updateTabOptions(tabOptions: IEditorTabOptions, refresh?: boolean): void {
|
||||
const tabCloseButton = this.tabOptions ? this.tabOptions.tabCloseButton : 'right';
|
||||
this.tabOptions = tabOptions;
|
||||
|
||||
@@ -443,6 +444,9 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
|
||||
|
||||
// Log this fact in telemetry
|
||||
if (this.telemetryService) {
|
||||
/* __GDPR__
|
||||
"workbenchEditorMaximized" : {}
|
||||
*/
|
||||
this.telemetryService.publicLog('workbenchEditorMaximized');
|
||||
}
|
||||
|
||||
@@ -2077,6 +2081,32 @@ export class EditorGroupsControl extends Themable implements IEditorGroupsContro
|
||||
return silo ? silo.child().getProperty(key) : void 0;
|
||||
}
|
||||
|
||||
public updateTitleAreas(refreshActive?: boolean): void {
|
||||
POSITIONS.forEach(position => {
|
||||
const group = this.stacks.groupAt(position);
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
const titleControl = this.getTitleAreaControl(position);
|
||||
if (!titleControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the active group is shown in the title
|
||||
// and refresh it if we are instructed to refresh it
|
||||
if (refreshActive && group.isActive) {
|
||||
titleControl.setContext(group);
|
||||
titleControl.refresh(true);
|
||||
}
|
||||
|
||||
// Otherwise, just refresh the toolbar
|
||||
else {
|
||||
titleControl.updateEditorActionsToolbar();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public updateProgress(position: Position, state: ProgressState): void {
|
||||
const progressbar = this.getProgressBar(position);
|
||||
if (!progressbar) {
|
||||
|
||||
@@ -20,17 +20,17 @@ import { getCodeEditor } from 'vs/editor/common/services/codeEditorService';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { Scope as MementoScope } from 'vs/workbench/common/memento';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { IEditorRegistry, Extensions as EditorExtensions, EditorInput, EditorOptions, ConfirmResult, IWorkbenchEditorConfiguration, IEditorDescriptor, TextEditorOptions, SideBySideEditorInput, TextCompareEditorVisible, TEXT_DIFF_EDITOR_ID } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorInput, EditorOptions, ConfirmResult, IWorkbenchEditorConfiguration, TextEditorOptions, SideBySideEditorInput, TextCompareEditorVisible, TEXT_DIFF_EDITOR_ID, EditorOpeningEvent, IEditorOpeningEvent } from 'vs/workbench/common/editor';
|
||||
import { EditorGroupsControl, Rochade, IEditorGroupsControl, ProgressState } from 'vs/workbench/browser/parts/editor/editorGroupsControl';
|
||||
import { WorkbenchProgressService } from 'vs/workbench/services/progress/browser/progressService';
|
||||
import { IEditorGroupService, GroupOrientation, GroupArrangement, ITabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorPart } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { IEditorGroupService, GroupOrientation, GroupArrangement, IEditorTabOptions, IMoveOptions } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { IEditorPart } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { Position, POSITIONS, Direction } from 'vs/platform/editor/common/editor';
|
||||
import { Position, POSITIONS, Direction, IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IMessageService, IMessageWithAction, Severity } from 'vs/platform/message/common/message';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -44,10 +44,13 @@ import { EDITOR_GROUP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { createCSSRule } from 'vs/base/browser/dom';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { join } from 'vs/base/common/paths';
|
||||
import { isCommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { IEditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { convertEditorInput } from 'sql/parts/common/customInputConverter';
|
||||
|
||||
|
||||
class ProgressMonitor {
|
||||
|
||||
constructor(private _token: number, private progressPromise: TPromise<void>) { }
|
||||
@@ -94,23 +97,23 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
private editorGroupsControl: IEditorGroupsControl;
|
||||
private memento: object;
|
||||
private stacks: EditorStacksModel;
|
||||
private tabOptions: ITabOptions;
|
||||
private tabOptions: IEditorTabOptions;
|
||||
private forceHideTabs: boolean;
|
||||
private doNotFireTabOptionsChanged: boolean;
|
||||
private revealIfOpen: boolean;
|
||||
|
||||
private _onEditorsChanged: Emitter<void>;
|
||||
private _onEditorsMoved: Emitter<void>;
|
||||
private _onEditorOpening: Emitter<IEditorOpeningEvent>;
|
||||
private _onEditorGroupMoved: Emitter<void>;
|
||||
private _onEditorOpenFail: Emitter<EditorInput>;
|
||||
private _onGroupOrientationChanged: Emitter<void>;
|
||||
private _onTabOptionsChanged: Emitter<ITabOptions>;
|
||||
private _onTabOptionsChanged: Emitter<IEditorTabOptions>;
|
||||
|
||||
private textCompareEditorVisible: IContextKey<boolean>;
|
||||
|
||||
// The following data structures are partitioned into array of Position as provided by Services.POSITION array
|
||||
private visibleEditors: BaseEditor[];
|
||||
private instantiatedEditors: BaseEditor[][];
|
||||
private mapEditorInstantiationPromiseToEditor: { [editorId: string]: TPromise<BaseEditor>; }[];
|
||||
private editorOpenToken: number[];
|
||||
private pendingEditorInputsToClose: EditorIdentifier[];
|
||||
private pendingEditorInputCloseTimeout: number;
|
||||
@@ -134,10 +137,11 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
super(id, { hasTitle: false }, themeService);
|
||||
|
||||
this._onEditorsChanged = new Emitter<void>();
|
||||
this._onEditorsMoved = new Emitter<void>();
|
||||
this._onEditorOpening = new Emitter<IEditorOpeningEvent>();
|
||||
this._onEditorGroupMoved = new Emitter<void>();
|
||||
this._onEditorOpenFail = new Emitter<EditorInput>();
|
||||
this._onGroupOrientationChanged = new Emitter<void>();
|
||||
this._onTabOptionsChanged = new Emitter<ITabOptions>();
|
||||
this._onTabOptionsChanged = new Emitter<IEditorTabOptions>();
|
||||
|
||||
this.visibleEditors = [];
|
||||
|
||||
@@ -145,8 +149,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
|
||||
this.instantiatedEditors = arrays.fill(POSITIONS.length, () => []);
|
||||
|
||||
this.mapEditorInstantiationPromiseToEditor = arrays.fill(POSITIONS.length, () => Object.create(null));
|
||||
|
||||
this.pendingEditorInputsToClose = [];
|
||||
this.pendingEditorInputCloseTimeout = null;
|
||||
|
||||
@@ -162,18 +164,27 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
previewEditors: editorConfig.enablePreview,
|
||||
showIcons: editorConfig.showIcons,
|
||||
showTabs: editorConfig.showTabs,
|
||||
tabCloseButton: editorConfig.tabCloseButton
|
||||
tabCloseButton: editorConfig.tabCloseButton,
|
||||
labelFormat: editorConfig.labelFormat,
|
||||
};
|
||||
|
||||
this.revealIfOpen = editorConfig.revealIfOpen;
|
||||
|
||||
/* __GDPR__
|
||||
"workbenchEditorConfiguration" : {
|
||||
"${include}": [
|
||||
"${IWorkbenchEditorConfiguration}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('workbenchEditorConfiguration', editorConfig);
|
||||
} else {
|
||||
this.tabOptions = {
|
||||
previewEditors: true,
|
||||
showIcons: false,
|
||||
showTabs: true,
|
||||
tabCloseButton: 'right'
|
||||
tabCloseButton: 'right',
|
||||
labelFormat: 'default',
|
||||
};
|
||||
|
||||
this.revealIfOpen = false;
|
||||
@@ -199,40 +210,44 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
this.toUnbind.push(this.stacks.onEditorClosed(event => this.onEditorClosed(event)));
|
||||
this.toUnbind.push(this.stacks.onGroupOpened(event => this.onEditorGroupOpenedOrClosed()));
|
||||
this.toUnbind.push(this.stacks.onGroupClosed(event => this.onEditorGroupOpenedOrClosed()));
|
||||
this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(this.configurationService.getConfiguration<IWorkbenchEditorConfiguration>())));
|
||||
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
|
||||
}
|
||||
|
||||
private onEditorGroupOpenedOrClosed(): void {
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
private onConfigurationUpdated(configuration: IWorkbenchEditorConfiguration): void {
|
||||
if (configuration && configuration.workbench && configuration.workbench.editor) {
|
||||
const editorConfig = configuration.workbench.editor;
|
||||
private onConfigurationUpdated(event: IConfigurationChangeEvent): void {
|
||||
if (event.affectsConfiguration('workbench.editor')) {
|
||||
const configuration = this.configurationService.getConfiguration<IWorkbenchEditorConfiguration>();
|
||||
if (configuration && configuration.workbench && configuration.workbench.editor) {
|
||||
const editorConfig = configuration.workbench.editor;
|
||||
|
||||
// Pin all preview editors of the user chose to disable preview
|
||||
const newPreviewEditors = editorConfig.enablePreview;
|
||||
if (this.tabOptions.previewEditors !== newPreviewEditors && !newPreviewEditors) {
|
||||
this.stacks.groups.forEach(group => {
|
||||
if (group.previewEditor) {
|
||||
this.pinEditor(group, group.previewEditor);
|
||||
}
|
||||
});
|
||||
// Pin all preview editors of the user chose to disable preview
|
||||
const newPreviewEditors = editorConfig.enablePreview;
|
||||
if (this.tabOptions.previewEditors !== newPreviewEditors && !newPreviewEditors) {
|
||||
this.stacks.groups.forEach(group => {
|
||||
if (group.previewEditor) {
|
||||
this.pinEditor(group, group.previewEditor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const oldTabOptions = objects.clone(this.tabOptions);
|
||||
this.tabOptions = {
|
||||
previewEditors: newPreviewEditors,
|
||||
showIcons: editorConfig.showIcons,
|
||||
tabCloseButton: editorConfig.tabCloseButton,
|
||||
showTabs: this.forceHideTabs ? false : editorConfig.showTabs,
|
||||
labelFormat: editorConfig.labelFormat,
|
||||
};
|
||||
|
||||
if (!this.doNotFireTabOptionsChanged && !objects.equals(oldTabOptions, this.tabOptions)) {
|
||||
this._onTabOptionsChanged.fire(this.tabOptions);
|
||||
}
|
||||
|
||||
this.revealIfOpen = editorConfig.revealIfOpen;
|
||||
}
|
||||
|
||||
const oldTabOptions = objects.clone(this.tabOptions);
|
||||
this.tabOptions = {
|
||||
previewEditors: newPreviewEditors,
|
||||
showIcons: editorConfig.showIcons,
|
||||
tabCloseButton: editorConfig.tabCloseButton,
|
||||
showTabs: this.forceHideTabs ? false : editorConfig.showTabs
|
||||
};
|
||||
|
||||
if (!this.doNotFireTabOptionsChanged && !objects.equals(oldTabOptions, this.tabOptions)) {
|
||||
this._onTabOptionsChanged.fire(this.tabOptions);
|
||||
}
|
||||
|
||||
this.revealIfOpen = editorConfig.revealIfOpen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,10 +263,24 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
}
|
||||
|
||||
private onEditorOpened(identifier: EditorIdentifier): void {
|
||||
/* __GDPR__
|
||||
"editorOpened" : {
|
||||
"${include}": [
|
||||
"${EditorTelemetryDescriptor}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('editorOpened', identifier.editor.getTelemetryDescriptor());
|
||||
}
|
||||
|
||||
private onEditorClosed(event: EditorCloseEvent): void {
|
||||
/* __GDPR__
|
||||
"editorClosed" : {
|
||||
"${include}": [
|
||||
"${EditorTelemetryDescriptor}"
|
||||
]
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('editorClosed', event.editor.getTelemetryDescriptor());
|
||||
}
|
||||
|
||||
@@ -270,8 +299,12 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
return this._onEditorsChanged.event;
|
||||
}
|
||||
|
||||
public get onEditorsMoved(): Event<void> {
|
||||
return this._onEditorsMoved.event;
|
||||
public get onEditorOpening(): Event<IEditorOpeningEvent> {
|
||||
return this._onEditorOpening.event;
|
||||
}
|
||||
|
||||
public get onEditorGroupMoved(): Event<void> {
|
||||
return this._onEditorGroupMoved.event;
|
||||
}
|
||||
|
||||
public get onEditorOpenFail(): Event<EditorInput> {
|
||||
@@ -282,39 +315,52 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
return this._onGroupOrientationChanged.event;
|
||||
}
|
||||
|
||||
public get onTabOptionsChanged(): Event<ITabOptions> {
|
||||
public get onTabOptionsChanged(): Event<IEditorTabOptions> {
|
||||
return this._onTabOptionsChanged.event;
|
||||
}
|
||||
|
||||
public getTabOptions(): ITabOptions {
|
||||
public getTabOptions(): IEditorTabOptions {
|
||||
return this.tabOptions;
|
||||
}
|
||||
|
||||
public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<BaseEditor>;
|
||||
public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, ratio?: number[]): TPromise<BaseEditor>;
|
||||
public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, ratio?: number[]): TPromise<BaseEditor> {
|
||||
|
||||
// Normalize some values
|
||||
if (!options) { options = null; }
|
||||
public openEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<IEditor>;
|
||||
public openEditor(input: EditorInput, options?: EditorOptions, position?: Position, ratio?: number[]): TPromise<IEditor>;
|
||||
public openEditor(input: EditorInput, options?: EditorOptions, arg3?: any, ratio?: number[]): TPromise<IEditor> {
|
||||
if (!options) {
|
||||
options = null;
|
||||
}
|
||||
|
||||
// Determine position to open editor in (one, two, three)
|
||||
const position = this.findPosition(input, options, arg3, ratio);
|
||||
|
||||
// Some conditions under which we prevent the request
|
||||
if (
|
||||
!input || // no input
|
||||
position === null || // invalid position
|
||||
Object.keys(this.mapEditorInstantiationPromiseToEditor[position]).length > 0 || // pending editor load
|
||||
!this.editorGroupsControl || // too early
|
||||
this.editorGroupsControl.isDragging() // pending editor DND
|
||||
!input || // no input
|
||||
position === null || // invalid position
|
||||
!this.editorGroupsControl || // too early
|
||||
this.editorGroupsControl.isDragging() // pending editor DND
|
||||
) {
|
||||
return TPromise.as<BaseEditor>(null);
|
||||
}
|
||||
|
||||
// Editor opening event (can be prevented and overridden)
|
||||
const event = new EditorOpeningEvent(input, options, position);
|
||||
this._onEditorOpening.fire(event);
|
||||
const prevented = event.isPrevented();
|
||||
if (prevented) {
|
||||
return prevented();
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// Convert input into custom type if it's one of the ones we support
|
||||
input = convertEditorInput(input, options, this.instantiationService);
|
||||
|
||||
// Open through UI
|
||||
return this.doOpenEditor(position, input, options, ratio);
|
||||
}
|
||||
|
||||
private doOpenEditor(position: Position, input: EditorInput, options: EditorOptions, ratio: number[]): TPromise<BaseEditor> {
|
||||
|
||||
// We need an editor descriptor for the input
|
||||
const descriptor = Registry.as<IEditorRegistry>(EditorExtensions.Editors).getEditor(input);
|
||||
if (!descriptor) {
|
||||
@@ -323,15 +369,14 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
|
||||
// Opened to the side
|
||||
if (position !== Position.ONE) {
|
||||
/* __GDPR__
|
||||
"workbenchSideEditorOpened" : {
|
||||
"position" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('workbenchSideEditorOpened', { position: position });
|
||||
}
|
||||
|
||||
// Open through UI
|
||||
return this.doOpenEditor(position, descriptor, input, options, ratio);
|
||||
}
|
||||
|
||||
private doOpenEditor(position: Position, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[]): TPromise<BaseEditor> {
|
||||
|
||||
// Update stacks: We do this early on before the UI is there because we want our stacks model to have
|
||||
// a consistent view of the editor world and updating it later async after the UI is there will cause
|
||||
// issues (e.g. when a closeEditor call is made that expects the openEditor call to have updated the
|
||||
@@ -339,7 +384,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
// This can however cause a race condition where the stacks model indicates the opened editor is there
|
||||
// while the UI is not yet ready. Clients have to deal with this fact and we have to make sure that the
|
||||
// stacks model gets updated if any of the UI updating fails with an error.
|
||||
const group = this.ensureGroup(position, !options || !options.preserveFocus);
|
||||
const [group, newGroupOpened] = this.ensureGroup(position, !options || !options.preserveFocus);
|
||||
const pinned = !this.tabOptions.previewEditors || (options && (options.pinned || typeof options.index === 'number')) || input.isDirty();
|
||||
|
||||
const active = (group.count === 0) || !options || !options.inactive;
|
||||
@@ -362,23 +407,34 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
}));
|
||||
|
||||
// Show editor
|
||||
return this.doShowEditor(group, descriptor, input, options, ratio, monitor).then(editor => {
|
||||
if (!editor) {
|
||||
return TPromise.as<BaseEditor>(null); // canceled or other error
|
||||
}
|
||||
const editor = this.doShowEditor(group, descriptor, input, options, ratio, monitor);
|
||||
if (!editor) {
|
||||
return TPromise.as<BaseEditor>(null); // canceled or other error
|
||||
}
|
||||
|
||||
// Set input to editor
|
||||
return this.doSetInput(group, editor, input, options, monitor);
|
||||
});
|
||||
// Set input to editor
|
||||
const inputPromise = this.doSetInput(group, editor, input, options, monitor);
|
||||
|
||||
// A new active group got opened. Since this involves updating the title area controls to show
|
||||
// the new editor and actions we trigger a direct update of title controls from here to avoid
|
||||
// some UI flickering if we rely on the event handlers that all use schedulers.
|
||||
// The reason we can trigger this now is that after the input is set to the editor group, the
|
||||
// resource context is updated and the correct number of actions will be resolved from the title
|
||||
// area.
|
||||
if (newGroupOpened && this.stacks.isActive(group)) {
|
||||
this.editorGroupsControl.updateTitleAreas(true /* refresh new active group */);
|
||||
}
|
||||
|
||||
return inputPromise;
|
||||
}
|
||||
|
||||
private doShowEditor(group: EditorGroup, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[], monitor: ProgressMonitor): TPromise<BaseEditor> {
|
||||
const position = this.stacks.positionOfGroup(group);
|
||||
private doShowEditor(group: EditorGroup, descriptor: IEditorDescriptor, input: EditorInput, options: EditorOptions, ratio: number[], monitor: ProgressMonitor): BaseEditor {
|
||||
let position = this.stacks.positionOfGroup(group);
|
||||
const editorAtPosition = this.visibleEditors[position];
|
||||
|
||||
// Return early if the currently visible editor can handle the input
|
||||
if (editorAtPosition && descriptor.describes(editorAtPosition)) {
|
||||
return TPromise.as(editorAtPosition);
|
||||
return editorAtPosition;
|
||||
}
|
||||
|
||||
// Hide active one first
|
||||
@@ -387,107 +443,77 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
}
|
||||
|
||||
// Create Editor
|
||||
return this.doCreateEditor(group, descriptor, monitor).then(editor => {
|
||||
const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile
|
||||
const editor = this.doCreateEditor(group, descriptor, monitor);
|
||||
position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile
|
||||
|
||||
// Make sure that the user meanwhile did not open another editor or something went wrong
|
||||
if (!editor || !this.visibleEditors[position] || editor.getId() !== this.visibleEditors[position].getId()) {
|
||||
monitor.cancel();
|
||||
// Make sure that the user meanwhile did not open another editor or something went wrong
|
||||
if (!editor || !this.visibleEditors[position] || editor.getId() !== this.visibleEditors[position].getId()) {
|
||||
monitor.cancel();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Show in side by side control
|
||||
this.editorGroupsControl.show(editor, position, options && options.preserveFocus, ratio);
|
||||
|
||||
// Indicate to editor that it is now visible
|
||||
editor.setVisible(true, position);
|
||||
|
||||
// Update text compare editor visible context
|
||||
this.updateTextCompareEditorVisible();
|
||||
|
||||
// Make sure the editor is layed out
|
||||
this.editorGroupsControl.layout(position);
|
||||
|
||||
return editor;
|
||||
|
||||
}, e => {
|
||||
this.messageService.show(Severity.Error, types.isString(e) ? new Error(e) : e);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
// Show in side by side control
|
||||
this.editorGroupsControl.show(editor, position, options && options.preserveFocus, ratio);
|
||||
|
||||
// Indicate to editor that it is now visible
|
||||
editor.setVisible(true, position);
|
||||
|
||||
// Update text compare editor visible context
|
||||
this.updateTextCompareEditorVisible();
|
||||
|
||||
// Make sure the editor is layed out
|
||||
this.editorGroupsControl.layout(position);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
private doCreateEditor(group: EditorGroup, descriptor: IEditorDescriptor, monitor: ProgressMonitor): TPromise<BaseEditor> {
|
||||
private doCreateEditor(group: EditorGroup, descriptor: IEditorDescriptor, monitor: ProgressMonitor): BaseEditor {
|
||||
|
||||
// Instantiate editor
|
||||
return this.doInstantiateEditor(group, descriptor).then(editor => {
|
||||
const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile
|
||||
const editor = this.doInstantiateEditor(group, descriptor);
|
||||
const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile
|
||||
|
||||
// Make sure that the user meanwhile did not open another editor
|
||||
if (monitor.token !== this.editorOpenToken[position]) {
|
||||
monitor.cancel();
|
||||
// Make sure that the user meanwhile did not open another editor
|
||||
if (monitor.token !== this.editorOpenToken[position]) {
|
||||
monitor.cancel();
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remember Editor at position
|
||||
this.visibleEditors[position] = editor;
|
||||
// Remember Editor at position
|
||||
this.visibleEditors[position] = editor;
|
||||
|
||||
// Create editor as needed
|
||||
if (!editor.getContainer()) {
|
||||
editor.create($().div({
|
||||
'class': 'editor-container',
|
||||
'role': 'tabpanel',
|
||||
id: descriptor.getId()
|
||||
}));
|
||||
}
|
||||
// Create editor as needed
|
||||
if (!editor.getContainer()) {
|
||||
editor.create($().div({
|
||||
'class': 'editor-container',
|
||||
'role': 'tabpanel',
|
||||
id: descriptor.getId()
|
||||
}));
|
||||
}
|
||||
|
||||
return editor;
|
||||
});
|
||||
return editor;
|
||||
}
|
||||
|
||||
private doInstantiateEditor(group: EditorGroup, descriptor: IEditorDescriptor): TPromise<BaseEditor> {
|
||||
private doInstantiateEditor(group: EditorGroup, descriptor: IEditorDescriptor): BaseEditor {
|
||||
const position = this.stacks.positionOfGroup(group);
|
||||
|
||||
// Return early if already instantiated
|
||||
const instantiatedEditor = this.instantiatedEditors[position].filter(e => descriptor.describes(e))[0];
|
||||
if (instantiatedEditor) {
|
||||
return TPromise.as(instantiatedEditor);
|
||||
}
|
||||
|
||||
// Return early if editor is being instantiated at the same time from a previous call
|
||||
const pendingEditorInstantiate = this.mapEditorInstantiationPromiseToEditor[position][descriptor.getId()];
|
||||
if (pendingEditorInstantiate) {
|
||||
return pendingEditorInstantiate;
|
||||
return instantiatedEditor;
|
||||
}
|
||||
|
||||
// Otherwise instantiate
|
||||
const progressService = this.instantiationService.createInstance(WorkbenchProgressService, this.editorGroupsControl.getProgressBar(position), descriptor.getId(), true);
|
||||
const editorInstantiationService = this.editorGroupsControl.getInstantiationService(position).createChild(new ServiceCollection([IProgressService, progressService]));
|
||||
let loaded = false;
|
||||
|
||||
const onInstantiate = (arg: BaseEditor): TPromise<BaseEditor> => {
|
||||
const position = this.stacks.positionOfGroup(group); // might have changed due to a rochade meanwhile
|
||||
const editor = descriptor.instantiate(editorInstantiationService);
|
||||
|
||||
loaded = true;
|
||||
delete this.mapEditorInstantiationPromiseToEditor[position][descriptor.getId()];
|
||||
this.instantiatedEditors[position].push(editor);
|
||||
|
||||
this.instantiatedEditors[position].push(arg);
|
||||
|
||||
return TPromise.as(arg);
|
||||
};
|
||||
|
||||
const instantiateEditorPromise = editorInstantiationService.createInstance(<EditorDescriptor>descriptor).then(onInstantiate);
|
||||
|
||||
if (!loaded) {
|
||||
this.mapEditorInstantiationPromiseToEditor[position][descriptor.getId()] = instantiateEditorPromise;
|
||||
}
|
||||
|
||||
return instantiateEditorPromise.then(result => {
|
||||
progressService.dispose();
|
||||
|
||||
return result;
|
||||
});
|
||||
return editor;
|
||||
}
|
||||
|
||||
private doSetInput(group: EditorGroup, editor: BaseEditor, input: EditorInput, options: EditorOptions, monitor: ProgressMonitor): TPromise<BaseEditor> {
|
||||
@@ -641,6 +667,9 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
// Explicitly trigger the focus changed handler because the side by side control will not trigger it unless
|
||||
// the user is actively changing focus with the mouse from left/top to right/bottom.
|
||||
this.onGroupFocusChanged();
|
||||
|
||||
// Update title area sync to avoid some flickering with actions
|
||||
this.editorGroupsControl.updateTitleAreas();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,7 +696,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
|
||||
// Emit Editor move event
|
||||
if (rochade !== Rochade.NONE) {
|
||||
this._onEditorsMoved.fire();
|
||||
this._onEditorGroupMoved.fire();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,14 +904,13 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
// Move data structures
|
||||
arrays.move(this.visibleEditors, fromPosition, toPosition);
|
||||
arrays.move(this.editorOpenToken, fromPosition, toPosition);
|
||||
arrays.move(this.mapEditorInstantiationPromiseToEditor, fromPosition, toPosition);
|
||||
arrays.move(this.instantiatedEditors, fromPosition, toPosition);
|
||||
|
||||
// Restore focus
|
||||
this.focusGroup(fromGroup);
|
||||
|
||||
// Events
|
||||
this._onEditorsMoved.fire();
|
||||
this._onEditorGroupMoved.fire();
|
||||
}
|
||||
|
||||
public moveEditor(input: EditorInput, from: EditorGroup, to: EditorGroup, moveOptions?: IMoveOptions): void;
|
||||
@@ -1020,7 +1048,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
}
|
||||
}
|
||||
|
||||
public replaceEditors(editors: { toReplace: EditorInput, replaceWith: EditorInput, options?: EditorOptions }[], position?: Position): TPromise<BaseEditor[]> {
|
||||
public replaceEditors(editors: { toReplace: EditorInput, replaceWith: EditorInput, options?: EditorOptions }[], position?: Position): TPromise<IEditor[]> {
|
||||
const activeReplacements: IEditorReplacement[] = [];
|
||||
const hiddenReplacements: IEditorReplacement[] = [];
|
||||
|
||||
@@ -1079,9 +1107,9 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
return res;
|
||||
}
|
||||
|
||||
public openEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[]): TPromise<BaseEditor[]> {
|
||||
public openEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[]): TPromise<IEditor[]> {
|
||||
if (!editors.length) {
|
||||
return TPromise.as<BaseEditor[]>([]);
|
||||
return TPromise.as<IEditor[]>([]);
|
||||
}
|
||||
|
||||
let activePosition: Position;
|
||||
@@ -1098,7 +1126,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
return this.stacks.groups.some(g => g.count > 0);
|
||||
}
|
||||
|
||||
public restoreEditors(): TPromise<BaseEditor[]> {
|
||||
public restoreEditors(): TPromise<IEditor[]> {
|
||||
const editors = this.stacks.groups.map((group, index) => {
|
||||
return {
|
||||
input: group.activeEditor,
|
||||
@@ -1108,7 +1136,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
});
|
||||
|
||||
if (!editors.length) {
|
||||
return TPromise.as<BaseEditor[]>([]);
|
||||
return TPromise.as<IEditor[]>([]);
|
||||
}
|
||||
|
||||
let activePosition: Position;
|
||||
@@ -1121,7 +1149,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
return this.doOpenEditors(editors, activePosition, editorState && editorState.ratio);
|
||||
}
|
||||
|
||||
private doOpenEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[], activePosition?: number, ratio?: number[]): TPromise<BaseEditor[]> {
|
||||
private doOpenEditors(editors: { input: EditorInput, position: Position, options?: EditorOptions }[], activePosition?: number, ratio?: number[]): TPromise<IEditor[]> {
|
||||
const positionOneEditors = editors.filter(e => e.position === Position.ONE);
|
||||
const positionTwoEditors = editors.filter(e => e.position === Position.TWO);
|
||||
const positionThreeEditors = editors.filter(e => e.position === Position.THREE);
|
||||
@@ -1168,7 +1196,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
|
||||
// Open each input respecting the options. Since there can only be one active editor in each
|
||||
// position, we have to pick the first input from each position and add the others as inactive
|
||||
const promises: TPromise<BaseEditor>[] = [];
|
||||
const promises: TPromise<IEditor>[] = [];
|
||||
[positionOneEditors.shift(), positionTwoEditors.shift(), positionThreeEditors.shift()].forEach((editor, position) => {
|
||||
if (!editor) {
|
||||
return; // unused position
|
||||
@@ -1177,7 +1205,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
const input = editor.input;
|
||||
|
||||
// Resolve editor options
|
||||
const preserveFocus = (activePosition !== position);
|
||||
const preserveFocus = (activePosition !== position && ratio && ratio.length > 0); // during restore, preserve focus to reduce flicker
|
||||
let options: EditorOptions;
|
||||
if (editor.options) {
|
||||
options = editor.options;
|
||||
@@ -1202,7 +1230,12 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
[positionOneEditors, positionTwoEditors, positionThreeEditors].forEach((editors, index) => {
|
||||
const group = this.stacks.groupAt(index);
|
||||
if (group) {
|
||||
editors.forEach(editor => group.openEditor(editor.input, { pinned: true })); // group could be null if one openeditor call failed!
|
||||
|
||||
// Make sure we are keeping the order as the editors are passed to us. We have to set
|
||||
// an explicit index because otherwise we would put editors in the wrong order
|
||||
// (see https://github.com/Microsoft/vscode/issues/30364)
|
||||
const startingIndex = group.indexOf(group.activeEditor) + 1;
|
||||
editors.forEach((editor, offset) => group.openEditor(editor.input, { pinned: true, index: (startingIndex + offset) }));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1298,6 +1331,20 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
}
|
||||
}
|
||||
|
||||
public invokeWithinEditorContext<T>(fn: (accessor: ServicesAccessor) => T): T {
|
||||
const activeEditor = this.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const activeEditorControl = activeEditor.getControl();
|
||||
if (isCommonCodeEditor(activeEditorControl)) {
|
||||
return activeEditorControl.invokeWithinContext(fn);
|
||||
}
|
||||
|
||||
return this.editorGroupsControl.getInstantiationService(activeEditor.position).invokeFunction(fn);
|
||||
}
|
||||
|
||||
return this.instantiationService.invokeFunction(fn);
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): Dimension[] {
|
||||
|
||||
// Pass to super
|
||||
@@ -1337,7 +1384,8 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
|
||||
// Emitters
|
||||
this._onEditorsChanged.dispose();
|
||||
this._onEditorsMoved.dispose();
|
||||
this._onEditorOpening.dispose();
|
||||
this._onEditorGroupMoved.dispose();
|
||||
this._onEditorOpenFail.dispose();
|
||||
|
||||
// Reset Tokens
|
||||
@@ -1493,7 +1541,6 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
|
||||
this.doRochade(this.visibleEditors, from, to, null);
|
||||
this.doRochade(this.editorOpenToken, from, to, null);
|
||||
this.doRochade(this.mapEditorInstantiationPromiseToEditor, from, to, Object.create(null));
|
||||
this.doRochade(this.instantiatedEditors, from, to, []);
|
||||
}
|
||||
}
|
||||
@@ -1503,9 +1550,11 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
array[from] = empty;
|
||||
}
|
||||
|
||||
private ensureGroup(position: Position, activate = true): EditorGroup {
|
||||
private ensureGroup(position: Position, activate = true): [EditorGroup, boolean /* new group opened */] {
|
||||
let newGroupOpened = false;
|
||||
let group = this.stacks.groupAt(position);
|
||||
if (!group) {
|
||||
newGroupOpened = true;
|
||||
|
||||
// Race condition: it could be that someone quickly opens editors one after
|
||||
// the other and we are asked to open an editor in position 2 before position
|
||||
@@ -1528,7 +1577,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService
|
||||
this.stacks.setActive(group);
|
||||
}
|
||||
|
||||
return group;
|
||||
return [group, newGroupOpened];
|
||||
}
|
||||
|
||||
private modifyGroups(modification: () => void) {
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
import 'vs/css!./media/editorpicker';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import nls = require('vs/nls');
|
||||
import labels = require('vs/base/common/labels');
|
||||
import URI from 'vs/base/common/uri';
|
||||
import errors = require('vs/base/common/errors');
|
||||
import strings = require('vs/base/common/strings');
|
||||
import { IIconLabelOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IAutoFocus, Mode, IEntryRunContext, IQuickNavigateConfiguration, IModel } from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import { QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
|
||||
import scorer = require('vs/base/common/scorer');
|
||||
import { QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup, QuickOpenItemAccessor } from 'vs/base/parts/quickopen/browser/quickOpenModel';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { getIconClasses } from 'vs/workbench/browser/labels';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
@@ -25,6 +22,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { EditorInput, toResource, IEditorGroup, IEditorStacksModel } from 'vs/workbench/common/editor';
|
||||
import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer';
|
||||
|
||||
export class EditorPickerEntry extends QuickOpenEntryGroup {
|
||||
private stacks: IEditorStacksModel;
|
||||
@@ -89,7 +87,7 @@ export class EditorPickerEntry extends QuickOpenEntryGroup {
|
||||
}
|
||||
|
||||
export abstract class BaseEditorPicker extends QuickOpenHandler {
|
||||
private scorerCache: { [key: string]: number };
|
||||
private scorerCache: ScorerCache;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService protected instantiationService: IInstantiationService,
|
||||
@@ -103,41 +101,38 @@ export abstract class BaseEditorPicker extends QuickOpenHandler {
|
||||
}
|
||||
|
||||
public getResults(searchValue: string): TPromise<QuickOpenModel> {
|
||||
searchValue = searchValue.trim();
|
||||
const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase();
|
||||
|
||||
const editorEntries = this.getEditorEntries();
|
||||
if (!editorEntries.length) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
const stacks = this.editorGroupService.getStacksModel();
|
||||
// Prepare search for scoring
|
||||
const query = prepareQuery(searchValue);
|
||||
|
||||
const entries = editorEntries.filter(e => {
|
||||
if (!searchValue) {
|
||||
if (!query.value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const resource = e.getResource();
|
||||
const targetToMatch = resource ? labels.getPathLabel(e.getResource(), this.contextService) : e.getLabel();
|
||||
if (!scorer.matches(targetToMatch, normalizedSearchValueLowercase)) {
|
||||
const itemScore = scoreItem(e, query, true, QuickOpenItemAccessor, this.scorerCache);
|
||||
if (!itemScore.score) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { labelHighlights, descriptionHighlights } = QuickOpenEntry.highlight(e, searchValue, true /* fuzzy highlight */);
|
||||
e.setHighlights(labelHighlights, descriptionHighlights);
|
||||
e.setHighlights(itemScore.labelMatch, itemScore.descriptionMatch);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// Sorting
|
||||
if (searchValue) {
|
||||
const stacks = this.editorGroupService.getStacksModel();
|
||||
if (query.value) {
|
||||
entries.sort((e1, e2) => {
|
||||
if (e1.group !== e2.group) {
|
||||
return stacks.positionOfGroup(e1.group) - stacks.positionOfGroup(e2.group);
|
||||
}
|
||||
|
||||
return QuickOpenEntry.compareByScore(e1, e2, searchValue, normalizedSearchValueLowercase, this.scorerCache);
|
||||
return compareItemsByScore(e1, e2, query, true, QuickOpenItemAccessor, this.scorerCache);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -220,6 +215,8 @@ export abstract class EditorGroupPicker extends BaseEditorPicker {
|
||||
|
||||
export class GroupOnePicker extends EditorGroupPicker {
|
||||
|
||||
public static readonly ID = 'workbench.picker.editors.one';
|
||||
|
||||
protected getPosition(): Position {
|
||||
return Position.ONE;
|
||||
}
|
||||
@@ -227,6 +224,8 @@ export class GroupOnePicker extends EditorGroupPicker {
|
||||
|
||||
export class GroupTwoPicker extends EditorGroupPicker {
|
||||
|
||||
public static readonly ID = 'workbench.picker.editors.two';
|
||||
|
||||
protected getPosition(): Position {
|
||||
return Position.TWO;
|
||||
}
|
||||
@@ -234,6 +233,8 @@ export class GroupTwoPicker extends EditorGroupPicker {
|
||||
|
||||
export class GroupThreePicker extends EditorGroupPicker {
|
||||
|
||||
public static readonly ID = 'workbench.picker.editors.three';
|
||||
|
||||
protected getPosition(): Position {
|
||||
return Position.THREE;
|
||||
}
|
||||
@@ -241,6 +242,8 @@ export class GroupThreePicker extends EditorGroupPicker {
|
||||
|
||||
export class AllEditorsPicker extends BaseEditorPicker {
|
||||
|
||||
public static readonly ID = 'workbench.picker.editors';
|
||||
|
||||
protected getEditorEntries(): EditorPickerEntry[] {
|
||||
const entries: EditorPickerEntry[] = [];
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import 'vs/css!./media/editorstatus';
|
||||
import nls = require('vs/nls');
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { $, append, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
|
||||
import { $, append, runAtThisOrScheduleAtNextAnimationFrame, addDisposableListener } from 'vs/base/browser/dom';
|
||||
import strings = require('vs/base/common/strings');
|
||||
import paths = require('vs/base/common/paths');
|
||||
import types = require('vs/base/common/types');
|
||||
@@ -17,12 +17,12 @@ import errors = require('vs/base/common/errors');
|
||||
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { language, LANGUAGE_DEFAULT, AccessibilitySupport } from 'vs/base/common/platform';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { IMode } from 'vs/editor/common/modes';
|
||||
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
|
||||
import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing';
|
||||
import { IEditorAction, ICommonCodeEditor, EndOfLineSequence, IModel } from 'vs/editor/common/editorCommon';
|
||||
import { IModelLanguageChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents';
|
||||
import { TrimTrailingWhitespaceAction } from 'vs/editor/contrib/linesOperations/common/linesOperations';
|
||||
@@ -33,7 +33,7 @@ import { IEditor as IBaseEditor, IEditorInput } from 'vs/platform/editor/common/
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { SUPPORTED_ENCODINGS, IFileService } from 'vs/platform/files/common/files';
|
||||
import { SUPPORTED_ENCODINGS, IFileService, IFilesConfiguration, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
@@ -43,13 +43,19 @@ import { TabFocus } from 'vs/editor/common/config/commonEditorConfig';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { getCodeEditor as getEditorWidget } from 'vs/editor/common/services/codeEditorService';
|
||||
import { getCodeEditor as getEditorWidget, getCodeOrDiffEditor } from 'vs/editor/common/services/codeEditorService';
|
||||
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { IConfigurationChangedEvent, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
|
||||
import { widgetShadow, editorWidgetBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
// TODO@Sandeep layer breaker
|
||||
// tslint:disable-next-line:import-patterns
|
||||
import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { QueryEditorService } from 'sql/parts/query/services/queryEditorService';
|
||||
@@ -233,7 +239,7 @@ const nlsMultiSelection = nls.localize('multiSelection', "{0} selections");
|
||||
const nlsEOLLF = nls.localize('endOfLineLineFeed', "LF");
|
||||
const nlsEOLCRLF = nls.localize('endOfLineCarriageReturnLineFeed', "CRLF");
|
||||
const nlsTabFocusMode = nls.localize('tabFocusModeEnabled', "Tab Moves Focus");
|
||||
const nlsScreenReaderDetected = nls.localize('screenReaderDetected', "Screen Reader Detected");
|
||||
const nlsScreenReaderDetected = nls.localize('screenReaderDetected', "Screen Reader Optimized");
|
||||
const nlsScreenReaderDetectedTitle = nls.localize('screenReaderDetectedExtra', "If you are not using a Screen Reader, please change the setting `editor.accessibilitySupport` to \"off\".");
|
||||
|
||||
function _setDisplay(el: HTMLElement, desiredValue: string): void {
|
||||
@@ -264,6 +270,7 @@ export class EditorStatus implements IStatusbarItem {
|
||||
private activeEditorListeners: IDisposable[];
|
||||
private delayedRender: IDisposable;
|
||||
private toRender: StateChange;
|
||||
private lastScreenReaderExplanation: ScreenReaderDetectedExplanation;
|
||||
|
||||
constructor(
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@@ -272,11 +279,13 @@ export class EditorStatus implements IStatusbarItem {
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
|
||||
@IModeService private modeService: IModeService,
|
||||
@ITextFileService private textFileService: ITextFileService
|
||||
@ITextFileService private textFileService: ITextFileService,
|
||||
@IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService,
|
||||
) {
|
||||
this.toDispose = [];
|
||||
this.activeEditorListeners = [];
|
||||
this.state = new State();
|
||||
this.lastScreenReaderExplanation = null;
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): IDisposable {
|
||||
@@ -291,6 +300,7 @@ export class EditorStatus implements IStatusbarItem {
|
||||
this.screenRedearModeElement = append(this.element, $('a.editor-status-screenreadermode.status-bar-info'));
|
||||
this.screenRedearModeElement.textContent = nlsScreenReaderDetected;
|
||||
this.screenRedearModeElement.title = nlsScreenReaderDetectedTitle;
|
||||
this.screenRedearModeElement.onclick = () => this.onScreenReaderModeClick();
|
||||
hide(this.screenRedearModeElement);
|
||||
|
||||
this.selectionElement = append(this.element, $('a.editor-status-selection'));
|
||||
@@ -472,6 +482,10 @@ export class EditorStatus implements IStatusbarItem {
|
||||
action.dispose();
|
||||
}
|
||||
|
||||
private onScreenReaderModeClick(): void {
|
||||
this.lastScreenReaderExplanation = this.instantiationService.createInstance(ScreenReaderDetectedExplanation, this.screenRedearModeElement);
|
||||
}
|
||||
|
||||
private onSelectionClick(): void {
|
||||
this.quickOpenService.show(':'); // "Go to line"
|
||||
}
|
||||
@@ -610,15 +624,35 @@ export class EditorStatus implements IStatusbarItem {
|
||||
this.updateState(update);
|
||||
}
|
||||
|
||||
private _promptedScreenReader: boolean = false;
|
||||
|
||||
private onScreenReaderModeChange(editorWidget: ICommonCodeEditor): void {
|
||||
let screenReaderMode = false;
|
||||
|
||||
// We only support text based editors
|
||||
if (editorWidget) {
|
||||
const screenReaderDetected = (browser.getAccessibilitySupport() === AccessibilitySupport.Enabled);
|
||||
if (screenReaderDetected) {
|
||||
const screenReaderConfiguration = this.configurationService.getConfiguration<IEditorOptions>('editor').accessibilitySupport;
|
||||
if (screenReaderConfiguration === 'auto') {
|
||||
// show explanation
|
||||
if (!this._promptedScreenReader) {
|
||||
this._promptedScreenReader = true;
|
||||
setTimeout(() => {
|
||||
this.onScreenReaderModeClick();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
screenReaderMode = (editorWidget.getConfiguration().accessibilitySupport === AccessibilitySupport.Enabled);
|
||||
}
|
||||
|
||||
if (screenReaderMode === false && this.lastScreenReaderExplanation) {
|
||||
this.lastScreenReaderExplanation.hide();
|
||||
this.lastScreenReaderExplanation = null;
|
||||
}
|
||||
|
||||
this.updateState({ screenReaderMode: screenReaderMode });
|
||||
}
|
||||
|
||||
@@ -699,7 +733,7 @@ export class EditorStatus implements IStatusbarItem {
|
||||
private onResourceEncodingChange(resource: uri): void {
|
||||
const activeEditor = this.editorService.getActiveEditor();
|
||||
if (activeEditor) {
|
||||
const activeResource = toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] });
|
||||
const activeResource = toResource(activeEditor.input, { supportSideBySide: true });
|
||||
if (activeResource && activeResource.toString() === resource.toString()) {
|
||||
return this.onEncodingChange(<IBaseEditor>activeEditor); // only update if the encoding changed for the active resource
|
||||
}
|
||||
@@ -755,21 +789,18 @@ export class ChangeModeAction extends Action {
|
||||
public static ID = 'workbench.action.editor.changeLanguageMode';
|
||||
public static LABEL = nls.localize('changeMode', "Change Language Mode");
|
||||
|
||||
private static FILE_ASSOCIATION_KEY = 'files.associations';
|
||||
|
||||
constructor(
|
||||
actionId: string,
|
||||
actionLabel: string,
|
||||
@IModeService private modeService: IModeService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IConfigurationEditingService private configurationEditingService: IConfigurationEditingService,
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IConfigurationEditingService private configurationEditService: IConfigurationEditingService
|
||||
@IUntitledEditorService private untitledEditorService: IUntitledEditorService
|
||||
) {
|
||||
super(actionId, actionLabel);
|
||||
}
|
||||
@@ -782,11 +813,16 @@ export class ChangeModeAction extends Action {
|
||||
}
|
||||
|
||||
const textModel = editorWidget.getModel();
|
||||
const fileResource = toResource(activeEditor.input, { supportSideBySide: true, filter: 'file' });
|
||||
const resource = toResource(activeEditor.input, { supportSideBySide: true });
|
||||
|
||||
let hasLanguageSupport = !!resource;
|
||||
if (resource.scheme === 'untitled' && !this.untitledEditorService.hasAssociatedFilePath(resource)) {
|
||||
hasLanguageSupport = false; // no configuration for untitled resources (e.g. "Untitled-1")
|
||||
}
|
||||
|
||||
// Compute mode
|
||||
let currentModeId: string;
|
||||
let modeId;
|
||||
let modeId: string;
|
||||
if (textModel) {
|
||||
modeId = textModel.getLanguageIdentifier().language;
|
||||
currentModeId = this.modeService.getLanguageName(modeId);
|
||||
@@ -821,7 +857,7 @@ export class ChangeModeAction extends Action {
|
||||
};
|
||||
});
|
||||
|
||||
if (fileResource) {
|
||||
if (hasLanguageSupport) {
|
||||
picks[0].separator = { border: true, label: nls.localize('languagesPicks', "languages (identifier)") };
|
||||
}
|
||||
|
||||
@@ -829,15 +865,14 @@ export class ChangeModeAction extends Action {
|
||||
let configureModeAssociations: IPickOpenEntry;
|
||||
let configureModeSettings: IPickOpenEntry;
|
||||
let galleryAction: Action;
|
||||
if (fileResource) {
|
||||
const ext = paths.extname(fileResource.fsPath) || paths.basename(fileResource.fsPath);
|
||||
if (hasLanguageSupport) {
|
||||
const ext = paths.extname(resource.fsPath) || paths.basename(resource.fsPath);
|
||||
|
||||
galleryAction = this.instantiationService.createInstance(ShowLanguageExtensionsAction, ext);
|
||||
if (galleryAction.enabled) {
|
||||
picks.unshift(galleryAction);
|
||||
}
|
||||
|
||||
|
||||
configureModeSettings = { label: nls.localize('configureModeSettings', "Configure '{0}' language based settings...", currentModeId) };
|
||||
picks.unshift(configureModeSettings);
|
||||
configureModeAssociations = { label: nls.localize('configureAssociationsExt', "Configure File Association for '{0}'...", ext) };
|
||||
@@ -848,7 +883,8 @@ export class ChangeModeAction extends Action {
|
||||
const autoDetectMode: IPickOpenEntry = {
|
||||
label: nls.localize('autoDetect', "Auto Detect")
|
||||
};
|
||||
if (fileResource) {
|
||||
|
||||
if (hasLanguageSupport) {
|
||||
picks.unshift(autoDetectMode);
|
||||
}
|
||||
|
||||
@@ -864,7 +900,7 @@ export class ChangeModeAction extends Action {
|
||||
|
||||
// User decided to permanently configure associations, return right after
|
||||
if (pick === configureModeAssociations) {
|
||||
this.configureFileAssociation(fileResource);
|
||||
this.configureFileAssociation(resource);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -876,36 +912,46 @@ export class ChangeModeAction extends Action {
|
||||
|
||||
// Change mode for active editor
|
||||
activeEditor = this.editorService.getActiveEditor();
|
||||
const editorWidget = getEditorWidget(activeEditor);
|
||||
if (editorWidget) {
|
||||
const models: IModel[] = [];
|
||||
|
||||
const textModel = editorWidget.getModel();
|
||||
if (textModel) {
|
||||
models.push(textModel);
|
||||
const codeOrDiffEditor = getCodeOrDiffEditor(activeEditor);
|
||||
const models: IModel[] = [];
|
||||
if (codeOrDiffEditor.codeEditor) {
|
||||
const codeEditorModel = codeOrDiffEditor.codeEditor.getModel();
|
||||
if (codeEditorModel) {
|
||||
models.push(codeEditorModel);
|
||||
}
|
||||
|
||||
// Find mode
|
||||
let mode: TPromise<IMode>;
|
||||
if (pick === autoDetectMode) {
|
||||
mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(toResource(activeEditor.input, { supportSideBySide: true, filter: ['file', 'untitled'] }).fsPath, textModel.getLineContent(1));
|
||||
} else {
|
||||
mode = this.modeService.getOrCreateModeByLanguageName(pick.label);
|
||||
}
|
||||
if (codeOrDiffEditor.diffEditor) {
|
||||
const diffEditorModel = codeOrDiffEditor.diffEditor.getModel();
|
||||
if (diffEditorModel) {
|
||||
if (diffEditorModel.original) {
|
||||
models.push(diffEditorModel.original);
|
||||
}
|
||||
if (diffEditorModel.modified) {
|
||||
models.push(diffEditorModel.modified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// Change mode
|
||||
models.forEach(textModel => {
|
||||
let self = this;
|
||||
mode.then((modeValue) => {
|
||||
QueryEditorService.sqlLanguageModeCheck(textModel, modeValue, activeEditor).then((newTextModel) => {
|
||||
if (newTextModel) {
|
||||
self.modelService.setMode(newTextModel, modeValue);
|
||||
}
|
||||
});
|
||||
// Find mode
|
||||
let mode: TPromise<IMode>;
|
||||
if (pick === autoDetectMode) {
|
||||
mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(toResource(activeEditor.input, { supportSideBySide: true }).fsPath, textModel.getLineContent(1));
|
||||
} else {
|
||||
mode = this.modeService.getOrCreateModeByLanguageName(pick.label);
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
// Change mode
|
||||
models.forEach(textModel => {
|
||||
let self = this;
|
||||
mode.then((modeValue) => {
|
||||
QueryEditorService.sqlLanguageModeCheck(textModel, modeValue, activeEditor).then((newTextModel) => {
|
||||
if (newTextModel) {
|
||||
self.modelService.setMode(newTextModel, modeValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -928,7 +974,7 @@ export class ChangeModeAction extends Action {
|
||||
TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).done(() => {
|
||||
this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || basename) }).done(language => {
|
||||
if (language) {
|
||||
const fileAssociationsConfig = this.configurationService.lookup(ChangeModeAction.FILE_ASSOCIATION_KEY);
|
||||
const fileAssociationsConfig = this.configurationService.inspect(FILES_ASSOCIATIONS_CONFIG);
|
||||
|
||||
let associationKey: string;
|
||||
if (extension && basename[0] !== '.') {
|
||||
@@ -951,8 +997,7 @@ export class ChangeModeAction extends Action {
|
||||
|
||||
currentAssociations[associationKey] = language.id;
|
||||
|
||||
// Write config
|
||||
this.configurationEditingService.writeConfiguration(target, { key: ChangeModeAction.FILE_ASSOCIATION_KEY, value: currentAssociations });
|
||||
this.configurationService.updateValue(FILES_ASSOCIATIONS_CONFIG, currentAssociations, target);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1070,7 +1115,7 @@ export class ChangeEncodingAction extends Action {
|
||||
actionLabel: string,
|
||||
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
|
||||
@ITextResourceConfigurationService private textResourceConfigurationService: ITextResourceConfigurationService,
|
||||
@IFileService private fileService: IFileService
|
||||
) {
|
||||
super(actionId, actionLabel);
|
||||
@@ -1112,19 +1157,22 @@ export class ChangeEncodingAction extends Action {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
const resource = toResource(activeEditor.input, { filter: ['file', 'untitled'], supportSideBySide: true });
|
||||
const resource = toResource(activeEditor.input, { supportSideBySide: true });
|
||||
|
||||
return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */)
|
||||
.then(() => {
|
||||
if (!resource || resource.scheme !== 'file') {
|
||||
return TPromise.as(null); // encoding detection only possible for file resources
|
||||
if (!resource || !this.fileService.canHandleResource(resource)) {
|
||||
return TPromise.as(null); // encoding detection only possible for resources the file service can handle
|
||||
}
|
||||
|
||||
return this.fileService.resolveContent(resource, { autoGuessEncoding: true, acceptTextOnly: true }).then(content => content.encoding, err => null);
|
||||
})
|
||||
.then((guessedEncoding: string) => {
|
||||
const isReopenWithEncoding = (action === reopenWithEncodingPick);
|
||||
const configuredEncoding = this.configurationService.lookup('files.encoding', { resource }).value;
|
||||
|
||||
const config = this.textResourceConfigurationService.getConfiguration(resource) as IFilesConfiguration;
|
||||
const configuredEncoding = config && config.files && config.files.encoding;
|
||||
|
||||
let directMatchIndex: number;
|
||||
let aliasMatchIndex: number;
|
||||
|
||||
@@ -1153,7 +1201,7 @@ export class ChangeEncodingAction extends Action {
|
||||
aliasMatchIndex = index;
|
||||
}
|
||||
|
||||
return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong };
|
||||
return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong, description: key };
|
||||
});
|
||||
|
||||
// If we have a guessed encoding, show it first unless it matches the configured encoding
|
||||
@@ -1178,3 +1226,107 @@ export class ChangeEncodingAction extends Action {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenReaderDetectedExplanation {
|
||||
|
||||
private _isDisposed: boolean;
|
||||
private _toDispose: IDisposable[];
|
||||
|
||||
constructor(
|
||||
anchorElement: HTMLElement,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IContextViewService private readonly contextViewService: IContextViewService,
|
||||
@IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService,
|
||||
) {
|
||||
this._isDisposed = false;
|
||||
this._toDispose = [];
|
||||
|
||||
this.contextViewService.showContextView({
|
||||
getAnchor: () => anchorElement,
|
||||
|
||||
render: (container) => {
|
||||
return this.renderContents(container);
|
||||
},
|
||||
|
||||
onDOMEvent: (e, activeElement) => {
|
||||
},
|
||||
|
||||
onHide: () => {
|
||||
this.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._isDisposed = true;
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
if (this._isDisposed) {
|
||||
return;
|
||||
}
|
||||
this.contextViewService.hideContextView();
|
||||
}
|
||||
|
||||
protected renderContents(container: HTMLElement): IDisposable {
|
||||
const domNode = $('div.screen-reader-detected-explanation', {
|
||||
'aria-hidden': 'true'
|
||||
});
|
||||
|
||||
const title = $('h2.title', {}, nls.localize('screenReaderDetectedExplanation.title', "Screen Reader Optimized"));
|
||||
domNode.appendChild(title);
|
||||
|
||||
const closeBtn = $('div.cancel');
|
||||
this._toDispose.push(addDisposableListener(closeBtn, 'click', () => {
|
||||
this.contextViewService.hideContextView();
|
||||
}));
|
||||
domNode.appendChild(closeBtn);
|
||||
|
||||
const question = $('p.question', {}, nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate VS Code?"));
|
||||
domNode.appendChild(question);
|
||||
|
||||
const yesBtn = $('div.button', {}, nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"));
|
||||
this._toDispose.push(addDisposableListener(yesBtn, 'click', () => {
|
||||
this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER);
|
||||
this.contextViewService.hideContextView();
|
||||
}));
|
||||
domNode.appendChild(yesBtn);
|
||||
|
||||
const noBtn = $('div.button', {}, nls.localize('screenReaderDetectedExplanation.answerNo', "No"));
|
||||
this._toDispose.push(addDisposableListener(noBtn, 'click', () => {
|
||||
this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER);
|
||||
this.contextViewService.hideContextView();
|
||||
}));
|
||||
domNode.appendChild(noBtn);
|
||||
|
||||
const clear = $('div');
|
||||
clear.style.clear = 'both';
|
||||
domNode.appendChild(clear);
|
||||
|
||||
const br = $('br');
|
||||
domNode.appendChild(br);
|
||||
|
||||
const hr = $('hr');
|
||||
domNode.appendChild(hr);
|
||||
|
||||
const explanation1 = $('p.body1', {}, nls.localize('screenReaderDetectedExplanation.body1', "VS Code is now optimized for usage with a screen reader."));
|
||||
domNode.appendChild(explanation1);
|
||||
|
||||
const explanation2 = $('p.body2', {}, nls.localize('screenReaderDetectedExplanation.body2', "Some editor features will have different behaviour: e.g. word wrapping, folding, etc."));
|
||||
domNode.appendChild(explanation2);
|
||||
|
||||
container.appendChild(domNode);
|
||||
|
||||
this._toDispose.push(attachStylerCallback(this.themeService, { widgetShadow, editorWidgetBackground }, colors => {
|
||||
domNode.style.backgroundColor = colors.editorWidgetBackground;
|
||||
if (colors.widgetShadow) {
|
||||
domNode.style.boxShadow = `0 2px 8px ${colors.widgetShadow}`;
|
||||
}
|
||||
}));
|
||||
|
||||
return {
|
||||
dispose: () => { this.dispose(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/vs/workbench/browser/parts/editor/media/back-tb.png
Normal file
BIN
src/vs/workbench/browser/parts/editor/media/back-tb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#C5C5C5" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
|
||||
|
After Width: | Height: | Size: 307 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="3 3 16 16" enable-background="new 3 3 16 16"><polygon fill="#424242" points="12.597,11.042 15.4,13.845 13.844,15.4 11.042,12.598 8.239,15.4 6.683,13.845 9.485,11.042 6.683,8.239 8.238,6.683 11.042,9.486 13.845,6.683 15.4,8.239"/></svg>
|
||||
|
After Width: | Height: | Size: 307 B |
@@ -18,7 +18,78 @@
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
|
||||
.monaco-workbench .editor-statusbar-item > .editor-status-metadata,
|
||||
.monaco-workbench > .part.statusbar > .statusbar-item > .editor-statusbar-item > a.editor-status-screenreadermode {
|
||||
.monaco-workbench .editor-statusbar-item > .editor-status-metadata {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
|
||||
.monaco-shell .screen-reader-detected-explanation {
|
||||
width: 420px;
|
||||
top: 30px;
|
||||
right: 6px;
|
||||
padding: 1em;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.monaco-shell .screen-reader-detected-explanation .cancel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: .5em 0 0;
|
||||
padding: .5em;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.monaco-shell .screen-reader-detected-explanation h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: 400;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.monaco-shell .screen-reader-detected-explanation p {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.monaco-shell .screen-reader-detected-explanation p.question {
|
||||
font-size: 1.4em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.monaco-shell .screen-reader-detected-explanation .button {
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background-color: #007ACC;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
border: 4px solid #007ACC;
|
||||
border-radius: 4px;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.monaco-shell.vs .screen-reader-detected-explanation .cancel {
|
||||
background: url('close-big.svg') center center no-repeat;
|
||||
}
|
||||
.monaco-shell.vs .screen-reader-detected-explanation .cancel:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
.monaco-shell.vs-dark .screen-reader-detected-explanation .cancel,
|
||||
.monaco-shell.hc-black .screen-reader-detected-explanation .cancel {
|
||||
background: url('close-big-dark.svg') center center no-repeat;
|
||||
}
|
||||
.monaco-shell.vs-dark .screen-reader-detected-explanation .cancel:hover {
|
||||
background-color: rgba(30,30,30,0.8);
|
||||
}
|
||||
|
||||
.monaco-shell.hc-black .screen-reader-detected-explanation .cancel {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.monaco-shell.hc-black .screen-reader-detected-explanation .cancel:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
BIN
src/vs/workbench/browser/parts/editor/media/forward-tb.png
Normal file
BIN
src/vs/workbench/browser/parts/editor/media/forward-tb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
@@ -10,13 +10,15 @@ import errors = require('vs/base/common/errors');
|
||||
import { IEditorGroup, toResource } from 'vs/workbench/common/editor';
|
||||
import DOM = require('vs/base/browser/dom');
|
||||
import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl';
|
||||
import { EditorLabel } from 'vs/workbench/browser/labels';
|
||||
import { ResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { Verbosity } from 'vs/platform/editor/common/editor';
|
||||
import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
|
||||
|
||||
export class NoTabsTitleControl extends TitleControl {
|
||||
private titleContainer: HTMLElement;
|
||||
private editorLabel: EditorLabel;
|
||||
private editorLabel: ResourceLabel;
|
||||
private titleTouchSupport: Gesture;
|
||||
|
||||
public setContext(group: IEditorGroup): void {
|
||||
super.setContext(group);
|
||||
@@ -29,17 +31,22 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
|
||||
this.titleContainer = parent;
|
||||
|
||||
// Gesture Support
|
||||
this.titleTouchSupport = new Gesture(this.titleContainer);
|
||||
|
||||
// Pin on double click
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.DBLCLICK, (e: MouseEvent) => this.onTitleDoubleClick(e)));
|
||||
|
||||
// Detect mouse click
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleClick(e)));
|
||||
|
||||
// Detect touch
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, TouchEventType.Tap, (e: GestureEvent) => this.onTitleClick(e)));
|
||||
|
||||
// Editor Label
|
||||
this.editorLabel = this.instantiationService.createInstance(EditorLabel, this.titleContainer, void 0);
|
||||
this.editorLabel = this.instantiationService.createInstance(ResourceLabel, this.titleContainer, void 0);
|
||||
this.toUnbind.push(this.editorLabel);
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.editorLabel.labelElement, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleLabelClick(e)));
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.editorLabel.descriptionElement, DOM.EventType.CLICK, (e: MouseEvent) => this.onTitleLabelClick(e)));
|
||||
this.toUnbind.push(this.editorLabel.onClick(e => this.onTitleLabelClick(e)));
|
||||
|
||||
// Right Actions Container
|
||||
const actionsContainer = document.createElement('div');
|
||||
@@ -51,6 +58,7 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
|
||||
// Context Menu
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, DOM.EventType.CONTEXT_MENU, (e: Event) => this.onContextMenu({ group: this.context, editor: this.context.activeEditor }, e, this.titleContainer)));
|
||||
this.toUnbind.push(DOM.addDisposableListener(this.titleContainer, TouchEventType.Contextmenu, (e: Event) => this.onContextMenu({ group: this.context, editor: this.context.activeEditor }, e, this.titleContainer)));
|
||||
}
|
||||
|
||||
private onTitleLabelClick(e: MouseEvent): void {
|
||||
@@ -71,7 +79,7 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
this.editorGroupService.pinEditor(group, group.activeEditor);
|
||||
}
|
||||
|
||||
private onTitleClick(e: MouseEvent): void {
|
||||
private onTitleClick(e: MouseEvent | GestureEvent): void {
|
||||
if (!this.context) {
|
||||
return;
|
||||
}
|
||||
@@ -79,7 +87,7 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
const group = this.context;
|
||||
|
||||
// Close editor on middle mouse click
|
||||
if (e.button === 1 /* Middle Button */) {
|
||||
if (e instanceof MouseEvent && e.button === 1 /* Middle Button */) {
|
||||
this.closeEditorAction.run({ group, editor: group.activeEditor }).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
|
||||
@@ -119,7 +127,15 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
// Editor Label
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
const name = editor.getName() || '';
|
||||
const description = isActive ? (editor.getDescription() || '') : '';
|
||||
|
||||
const labelFormat = this.editorGroupService.getTabOptions().labelFormat;
|
||||
let description: string;
|
||||
if (labelFormat === 'default' && !isActive) {
|
||||
description = ''; // hide description when group is not active and style is 'default'
|
||||
} else {
|
||||
description = editor.getDescription(this.getVerbosity(labelFormat)) || '';
|
||||
}
|
||||
|
||||
let title = editor.getTitle(Verbosity.LONG);
|
||||
if (description === title) {
|
||||
title = ''; // dont repeat what is already shown
|
||||
@@ -135,4 +151,18 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
// Update Editor Actions Toolbar
|
||||
this.updateEditorActionsToolbar();
|
||||
}
|
||||
|
||||
private getVerbosity(style: string): Verbosity {
|
||||
switch (style) {
|
||||
case 'short': return Verbosity.SHORT;
|
||||
case 'long': return Verbosity.LONG;
|
||||
default: return Verbosity.MEDIUM;
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.titleTouchSupport.dispose();
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Dimension, Builder } from 'vs/base/browser/builder';
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IEditorRegistry, Extensions as EditorExtensions, EditorInput, EditorOptions, SideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor, EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { EditorInput, EditorOptions, SideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { IEditorControl, Position, IEditor } from 'vs/platform/editor/common/editor';
|
||||
import { VSash } from 'vs/base/browser/ui/sash/sash';
|
||||
|
||||
@@ -18,6 +17,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { scrollbarShadow } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
|
||||
export class SideBySideEditor extends BaseEditor {
|
||||
|
||||
@@ -110,7 +110,7 @@ export class SideBySideEditor extends BaseEditor {
|
||||
return this.detailsEditor;
|
||||
}
|
||||
|
||||
private updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options?: EditorOptions): TPromise<void> {
|
||||
private updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options?: EditorOptions): void {
|
||||
if (!newInput.matches(oldInput)) {
|
||||
if (oldInput) {
|
||||
this.disposeEditors();
|
||||
@@ -126,24 +126,21 @@ export class SideBySideEditor extends BaseEditor {
|
||||
}
|
||||
}
|
||||
|
||||
private setNewInput(newInput: SideBySideEditorInput, options?: EditorOptions): TPromise<void> {
|
||||
return TPromise.join([
|
||||
this._createEditor(<EditorInput>newInput.details, this.detailsEditorContainer),
|
||||
this._createEditor(<EditorInput>newInput.master, this.masterEditorContainer)
|
||||
]).then(result => this.onEditorsCreated(result[0], result[1], newInput.details, newInput.master, options));
|
||||
private setNewInput(newInput: SideBySideEditorInput, options?: EditorOptions): void {
|
||||
const detailsEditor = this._createEditor(<EditorInput>newInput.details, this.detailsEditorContainer);
|
||||
const masterEditor = this._createEditor(<EditorInput>newInput.master, this.masterEditorContainer);
|
||||
|
||||
this.onEditorsCreated(detailsEditor, masterEditor, newInput.details, newInput.master, options);
|
||||
}
|
||||
|
||||
private _createEditor(editorInput: EditorInput, container: HTMLElement): TPromise<BaseEditor> {
|
||||
private _createEditor(editorInput: EditorInput, container: HTMLElement): BaseEditor {
|
||||
const descriptor = Registry.as<IEditorRegistry>(EditorExtensions.Editors).getEditor(editorInput);
|
||||
if (!descriptor) {
|
||||
return TPromise.wrapError<BaseEditor>(new Error(strings.format('Can not find a registered editor for the input {0}', editorInput)));
|
||||
}
|
||||
return this.instantiationService.createInstance(<EditorDescriptor>descriptor)
|
||||
.then((editor: BaseEditor) => {
|
||||
editor.create(new Builder(container));
|
||||
editor.setVisible(this.isVisible(), this.position);
|
||||
return editor;
|
||||
});
|
||||
|
||||
const editor = descriptor.instantiate(this.instantiationService);
|
||||
editor.create(new Builder(container));
|
||||
editor.setVisible(this.isVisible(), this.position);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
private onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions): TPromise<void> {
|
||||
|
||||
@@ -17,10 +17,11 @@ import { ActionRunner, IAction } from 'vs/base/common/actions';
|
||||
import { Position, IEditorInput, Verbosity, IUntitledResourceInput } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorGroup, toResource } from 'vs/workbench/common/editor';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { EditorLabel } from 'vs/workbench/browser/labels';
|
||||
import { ResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
@@ -37,7 +38,6 @@ import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElemen
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { extractResources } from 'vs/base/browser/dnd';
|
||||
import { getOrSet } from 'vs/base/common/map';
|
||||
import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_BORDER, TAB_ACTIVE_BORDER } from 'vs/workbench/common/theme';
|
||||
@@ -47,16 +47,17 @@ import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||
|
||||
interface IEditorInputLabel {
|
||||
name: string;
|
||||
hasAmbiguousName?: boolean;
|
||||
description?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
type AugmentedLabel = IEditorInputLabel & { editor: IEditorInput };
|
||||
|
||||
export class TabsTitleControl extends TitleControl {
|
||||
private titleContainer: HTMLElement;
|
||||
private tabsContainer: HTMLElement;
|
||||
private activeTab: HTMLElement;
|
||||
private editorLabels: EditorLabel[];
|
||||
private editorLabels: ResourceLabel[];
|
||||
private scrollbar: ScrollableElement;
|
||||
private tabDisposeables: IDisposable[];
|
||||
private blockRevealActiveTab: boolean;
|
||||
@@ -264,7 +265,7 @@ export class TabsTitleControl extends TitleControl {
|
||||
|
||||
// Compute labels and protect against duplicates
|
||||
const editorsOfGroup = this.context.getEditors();
|
||||
const labels = this.getUniqueTabLabels(editorsOfGroup);
|
||||
const labels = this.getTabLabels(editorsOfGroup);
|
||||
|
||||
// Tab label and styles
|
||||
editorsOfGroup.forEach((editor, index) => {
|
||||
@@ -276,7 +277,7 @@ export class TabsTitleControl extends TitleControl {
|
||||
|
||||
const label = labels[index];
|
||||
const name = label.name;
|
||||
const description = label.hasAmbiguousName && label.description ? label.description : '';
|
||||
const description = label.description || '';
|
||||
const title = label.title || '';
|
||||
|
||||
// Container
|
||||
@@ -294,7 +295,8 @@ export class TabsTitleControl extends TitleControl {
|
||||
|
||||
// Label
|
||||
const tabLabel = this.editorLabels[index];
|
||||
tabLabel.setLabel({ name, description, resource: toResource(editor, { supportSideBySide: true }) }, { extraClasses: ['tab-label'], italic: !isPinned });
|
||||
// {{SQL CARBON EDIT}} -- add title in options passed
|
||||
tabLabel.setLabel({ name, description, resource: toResource(editor, { supportSideBySide: true }) }, { extraClasses: ['tab-label'], italic: !isPinned, title });
|
||||
|
||||
// Active state
|
||||
if (isTabActive) {
|
||||
@@ -338,56 +340,108 @@ export class TabsTitleControl extends TitleControl {
|
||||
this.layout();
|
||||
}
|
||||
|
||||
private getUniqueTabLabels(editors: IEditorInput[]): IEditorInputLabel[] {
|
||||
const labels: IEditorInputLabel[] = [];
|
||||
|
||||
const mapLabelToDuplicates = new Map<string, IEditorInputLabel[]>();
|
||||
const mapLabelAndDescriptionToDuplicates = new Map<string, IEditorInputLabel[]>();
|
||||
private getTabLabels(editors: IEditorInput[]): IEditorInputLabel[] {
|
||||
const labelFormat = this.editorGroupService.getTabOptions().labelFormat;
|
||||
const { verbosity, shortenDuplicates } = this.getLabelConfigFlags(labelFormat);
|
||||
|
||||
// Build labels and descriptions for each editor
|
||||
editors.forEach(editor => {
|
||||
const name = editor.getName();
|
||||
let description = editor.getDescription();
|
||||
if (mapLabelAndDescriptionToDuplicates.has(`${name}${description}`)) {
|
||||
description = editor.getDescription(true); // try verbose description if name+description already exists
|
||||
}
|
||||
const labels = editors.map(editor => ({
|
||||
editor,
|
||||
name: editor.getName(),
|
||||
description: editor.getDescription(verbosity),
|
||||
title: editor.getTitle(Verbosity.LONG)
|
||||
}));
|
||||
|
||||
const item: IEditorInputLabel = {
|
||||
name,
|
||||
description,
|
||||
title: editor.getTitle(Verbosity.LONG)
|
||||
};
|
||||
labels.push(item);
|
||||
|
||||
getOrSet(mapLabelToDuplicates, item.name, []).push(item);
|
||||
|
||||
if (typeof description === 'string') {
|
||||
getOrSet(mapLabelAndDescriptionToDuplicates, `${item.name}${item.description}`, []).push(item);
|
||||
}
|
||||
});
|
||||
|
||||
// Mark duplicates and shorten their descriptions
|
||||
mapLabelToDuplicates.forEach(duplicates => {
|
||||
if (duplicates.length > 1) {
|
||||
duplicates = duplicates.filter(d => {
|
||||
// we could have items with equal label and description. in that case it does not make much
|
||||
// sense to produce a shortened version of the label, so we ignore those kind of items
|
||||
return typeof d.description === 'string' && mapLabelAndDescriptionToDuplicates.get(`${d.name}${d.description}`).length === 1;
|
||||
});
|
||||
|
||||
if (duplicates.length > 1) {
|
||||
const shortenedDescriptions = shorten(duplicates.map(duplicate => duplicate.description));
|
||||
duplicates.forEach((duplicate, i) => {
|
||||
duplicate.description = shortenedDescriptions[i];
|
||||
duplicate.hasAmbiguousName = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// Shorten labels as needed
|
||||
if (shortenDuplicates) {
|
||||
this.shortenTabLabels(labels);
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
private shortenTabLabels(labels: AugmentedLabel[]): void {
|
||||
|
||||
// Gather duplicate titles, while filtering out invalid descriptions
|
||||
const mapTitleToDuplicates = new Map<string, AugmentedLabel[]>();
|
||||
for (const label of labels) {
|
||||
if (typeof label.description === 'string') {
|
||||
getOrSet(mapTitleToDuplicates, label.name, []).push(label);
|
||||
} else {
|
||||
label.description = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Identify duplicate titles and shorten descriptions
|
||||
mapTitleToDuplicates.forEach(duplicateTitles => {
|
||||
|
||||
// Remove description if the title isn't duplicated
|
||||
if (duplicateTitles.length === 1) {
|
||||
duplicateTitles[0].description = '';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Identify duplicate descriptions
|
||||
const mapDescriptionToDuplicates = new Map<string, AugmentedLabel[]>();
|
||||
for (const label of duplicateTitles) {
|
||||
getOrSet(mapDescriptionToDuplicates, label.description, []).push(label);
|
||||
}
|
||||
|
||||
// For editors with duplicate descriptions, check whether any long descriptions differ
|
||||
let useLongDescriptions = false;
|
||||
mapDescriptionToDuplicates.forEach((duplicateDescriptions, name) => {
|
||||
if (!useLongDescriptions && duplicateDescriptions.length > 1) {
|
||||
const [first, ...rest] = duplicateDescriptions.map(({ editor }) => editor.getDescription(Verbosity.LONG));
|
||||
useLongDescriptions = rest.some(description => description !== first);
|
||||
}
|
||||
});
|
||||
|
||||
// If so, replace all descriptions with long descriptions
|
||||
if (useLongDescriptions) {
|
||||
mapDescriptionToDuplicates.clear();
|
||||
duplicateTitles.forEach(label => {
|
||||
label.description = label.editor.getDescription(Verbosity.LONG);
|
||||
getOrSet(mapDescriptionToDuplicates, label.description, []).push(label);
|
||||
});
|
||||
}
|
||||
|
||||
// Obtain final set of descriptions
|
||||
const descriptions: string[] = [];
|
||||
mapDescriptionToDuplicates.forEach((_, description) => descriptions.push(description));
|
||||
|
||||
// Remove description if all descriptions are identical
|
||||
if (descriptions.length === 1) {
|
||||
for (const label of mapDescriptionToDuplicates.get(descriptions[0])) {
|
||||
label.description = '';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Shorten descriptions
|
||||
const shortenedDescriptions = shorten(descriptions);
|
||||
descriptions.forEach((description, i) => {
|
||||
for (const label of mapDescriptionToDuplicates.get(description)) {
|
||||
label.description = shortenedDescriptions[i];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private getLabelConfigFlags(value: string) {
|
||||
switch (value) {
|
||||
case 'short':
|
||||
return { verbosity: Verbosity.SHORT, shortenDuplicates: false };
|
||||
case 'medium':
|
||||
return { verbosity: Verbosity.MEDIUM, shortenDuplicates: false };
|
||||
case 'long':
|
||||
return { verbosity: Verbosity.LONG, shortenDuplicates: false };
|
||||
default:
|
||||
return { verbosity: Verbosity.MEDIUM, shortenDuplicates: true };
|
||||
}
|
||||
}
|
||||
|
||||
protected doRefresh(): void {
|
||||
const group = this.context;
|
||||
const editor = group && group.activeEditor;
|
||||
@@ -451,8 +505,11 @@ export class TabsTitleControl extends TitleControl {
|
||||
tabContainer.setAttribute('role', 'presentation'); // cannot use role "tab" here due to https://github.com/Microsoft/vscode/issues/8659
|
||||
DOM.addClass(tabContainer, 'tab');
|
||||
|
||||
// Gesture Support
|
||||
const gestureSupport = new Gesture(tabContainer);
|
||||
|
||||
// Tab Editor Label
|
||||
const editorLabel = this.instantiationService.createInstance(EditorLabel, tabContainer, void 0);
|
||||
const editorLabel = this.instantiationService.createInstance(ResourceLabel, tabContainer, void 0);
|
||||
this.editorLabels.push(editorLabel);
|
||||
|
||||
// Tab Close
|
||||
@@ -466,7 +523,7 @@ export class TabsTitleControl extends TitleControl {
|
||||
// Eventing
|
||||
const disposable = this.hookTabListeners(tabContainer, index);
|
||||
|
||||
this.tabDisposeables.push(combinedDisposable([disposable, bar, editorLabel]));
|
||||
this.tabDisposeables.push(combinedDisposable([disposable, bar, editorLabel, gestureSupport]));
|
||||
|
||||
return tabContainer;
|
||||
}
|
||||
@@ -516,14 +573,42 @@ export class TabsTitleControl extends TitleControl {
|
||||
private hookTabListeners(tab: HTMLElement, index: number): IDisposable {
|
||||
const disposables: IDisposable[] = [];
|
||||
|
||||
// Open on Click
|
||||
disposables.push(DOM.addDisposableListener(tab, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => {
|
||||
const handleClickOrTouch = (e: MouseEvent | GestureEvent) => {
|
||||
tab.blur();
|
||||
|
||||
if (e instanceof MouseEvent && e.button !== 0) {
|
||||
if (e.button === 1) {
|
||||
return false; // required due to https://github.com/Microsoft/vscode/issues/16690
|
||||
}
|
||||
|
||||
return void 0; // only for left mouse click
|
||||
}
|
||||
|
||||
const { editor, position } = this.toTabContext(index);
|
||||
if (e.button === 0 /* Left Button */ && !this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) {
|
||||
if (!this.isTabActionBar((e.target || e.srcElement) as HTMLElement)) {
|
||||
setTimeout(() => this.editorService.openEditor(editor, null, position).done(null, errors.onUnexpectedError)); // timeout to keep focus in editor after mouse up
|
||||
}
|
||||
|
||||
return void 0;
|
||||
};
|
||||
|
||||
const showContextMenu = (e: Event) => {
|
||||
DOM.EventHelper.stop(e);
|
||||
|
||||
const { group, editor } = this.toTabContext(index);
|
||||
|
||||
this.onContextMenu({ group, editor }, e, tab);
|
||||
};
|
||||
|
||||
// Open on Click
|
||||
disposables.push(DOM.addDisposableListener(tab, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => handleClickOrTouch(e)));
|
||||
|
||||
// Open on Touch
|
||||
disposables.push(DOM.addDisposableListener(tab, TouchEventType.Tap, (e: GestureEvent) => handleClickOrTouch(e)));
|
||||
|
||||
// Touch Scroll Support
|
||||
disposables.push(DOM.addDisposableListener(tab, TouchEventType.Change, (e: GestureEvent) => {
|
||||
this.tabsContainer.scrollLeft -= e.translationX;
|
||||
}));
|
||||
|
||||
// Close on mouse middle click
|
||||
@@ -540,14 +625,15 @@ export class TabsTitleControl extends TitleControl {
|
||||
disposables.push(DOM.addDisposableListener(tab, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.shiftKey && event.keyCode === KeyCode.F10) {
|
||||
DOM.EventHelper.stop(e);
|
||||
|
||||
const { group, editor } = this.toTabContext(index);
|
||||
|
||||
this.onContextMenu({ group, editor }, e, tab);
|
||||
showContextMenu(e);
|
||||
}
|
||||
}));
|
||||
|
||||
// Context menu on touch context menu gesture
|
||||
disposables.push(DOM.addDisposableListener(tab, TouchEventType.Contextmenu, (e: GestureEvent) => {
|
||||
showContextMenu(e);
|
||||
}));
|
||||
|
||||
// Keyboard accessibility
|
||||
disposables.push(DOM.addDisposableListener(tab, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
@@ -617,12 +703,15 @@ export class TabsTitleControl extends TitleControl {
|
||||
e.dataTransfer.effectAllowed = 'copyMove';
|
||||
|
||||
// Insert transfer accordingly
|
||||
const fileResource = toResource(editor, { supportSideBySide: true, filter: 'file' });
|
||||
if (fileResource) {
|
||||
const resource = fileResource.toString();
|
||||
e.dataTransfer.setData('URL', resource); // enables cross window DND of tabs
|
||||
e.dataTransfer.setData('DownloadURL', [MIME_BINARY, editor.getName(), resource].join(':')); // enables support to drag a tab as file to desktop
|
||||
const resource = toResource(editor, { supportSideBySide: true });
|
||||
if (resource) {
|
||||
const resourceStr = resource.toString();
|
||||
e.dataTransfer.setData('URL', resourceStr); // enables cross window DND of tabs
|
||||
e.dataTransfer.setData('text/plain', getPathLabel(resource)); // enables dropping tab resource path into text controls
|
||||
|
||||
if (resource.scheme === 'file') {
|
||||
e.dataTransfer.setData('DownloadURL', [MIME_BINARY, editor.getName(), resourceStr].join(':')); // enables support to drag a tab as file to desktop
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -635,7 +724,21 @@ export class TabsTitleControl extends TitleControl {
|
||||
// Drag over
|
||||
disposables.push(DOM.addDisposableListener(tab, DOM.EventType.DRAG_ENTER, (e: DragEvent) => {
|
||||
counter++;
|
||||
this.updateDropFeedback(tab, true, index);
|
||||
|
||||
// Find out if the currently dragged editor is this tab and in that
|
||||
// case we do not want to show any drop feedback
|
||||
let draggedEditorIsTab = false;
|
||||
const draggedEditor = TabsTitleControl.getDraggedEditor();
|
||||
if (draggedEditor) {
|
||||
const { group, editor } = this.toTabContext(index);
|
||||
if (draggedEditor.editor === editor && draggedEditor.group === group) {
|
||||
draggedEditorIsTab = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!draggedEditorIsTab) {
|
||||
this.updateDropFeedback(tab, true, index);
|
||||
}
|
||||
}));
|
||||
|
||||
// Drag leave
|
||||
|
||||
@@ -22,14 +22,13 @@ import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { DiffNavigator } from 'vs/editor/browser/widget/diffNavigator';
|
||||
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
|
||||
import { TextDiffEditorModel } from 'vs/workbench/common/editor/textDiffEditorModel';
|
||||
import { DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IWorkbenchEditorService, DelegatingWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
@@ -112,16 +111,12 @@ export class TextDiffEditor extends BaseTextEditor {
|
||||
}
|
||||
|
||||
public setInput(input: EditorInput, options?: EditorOptions): TPromise<void> {
|
||||
const oldInput = this.input;
|
||||
super.setInput(input, options);
|
||||
|
||||
// Detect options
|
||||
// Return early for same input unless we force to open
|
||||
const forceOpen = options && options.forceOpen;
|
||||
if (!forceOpen && input.matches(this.input)) {
|
||||
|
||||
// Same Input
|
||||
if (!forceOpen && input.matches(oldInput)) {
|
||||
|
||||
// TextOptions (avoiding instanceof here for a reason, do not change!)
|
||||
// Still apply options if any (avoiding instanceof here for a reason, do not change!)
|
||||
const textOptions = <TextEditorOptions>options;
|
||||
if (textOptions && types.isFunction(textOptions.apply)) {
|
||||
textOptions.apply(<IDiffEditor>this.getControl(), ScrollType.Smooth);
|
||||
@@ -135,49 +130,51 @@ export class TextDiffEditor extends BaseTextEditor {
|
||||
this.diffNavigator.dispose();
|
||||
}
|
||||
|
||||
// Different Input (Reload)
|
||||
return input.resolve(true).then(resolvedModel => {
|
||||
// Set input and resolve
|
||||
return super.setInput(input, options).then(() => {
|
||||
return input.resolve(true).then(resolvedModel => {
|
||||
|
||||
// Assert Model Instance
|
||||
if (!(resolvedModel instanceof TextDiffEditorModel) && this.openAsBinary(input, options)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Assert that the current input is still the one we expect. This prevents a race condition when loading a diff takes long and another input was set meanwhile
|
||||
if (!this.input || this.input !== input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Editor
|
||||
const diffEditor = <IDiffEditor>this.getControl();
|
||||
diffEditor.setModel((<TextDiffEditorModel>resolvedModel).textDiffEditorModel);
|
||||
|
||||
// Handle TextOptions
|
||||
let alwaysRevealFirst = true;
|
||||
if (options && types.isFunction((<TextEditorOptions>options).apply)) {
|
||||
const hadOptions = (<TextEditorOptions>options).apply(<IDiffEditor>diffEditor, ScrollType.Immediate);
|
||||
if (hadOptions) {
|
||||
alwaysRevealFirst = false; // Do not reveal if we are instructed to open specific line/col
|
||||
// Assert Model Instance
|
||||
if (!(resolvedModel instanceof TextDiffEditorModel) && this.openAsBinary(input, options)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Listen on diff updated changes to reveal the first change
|
||||
this.diffNavigator = new DiffNavigator(diffEditor, {
|
||||
alwaysRevealFirst
|
||||
// Assert that the current input is still the one we expect. This prevents a race condition when loading a diff takes long and another input was set meanwhile
|
||||
if (!this.input || this.input !== input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Editor
|
||||
const diffEditor = <IDiffEditor>this.getControl();
|
||||
diffEditor.setModel((<TextDiffEditorModel>resolvedModel).textDiffEditorModel);
|
||||
|
||||
// Handle TextOptions
|
||||
let alwaysRevealFirst = true;
|
||||
if (options && types.isFunction((<TextEditorOptions>options).apply)) {
|
||||
const hadOptions = (<TextEditorOptions>options).apply(<IDiffEditor>diffEditor, ScrollType.Immediate);
|
||||
if (hadOptions) {
|
||||
alwaysRevealFirst = false; // Do not reveal if we are instructed to open specific line/col
|
||||
}
|
||||
}
|
||||
|
||||
// Listen on diff updated changes to reveal the first change
|
||||
this.diffNavigator = new DiffNavigator(diffEditor, {
|
||||
alwaysRevealFirst
|
||||
});
|
||||
this.diffNavigator.addListener(DiffNavigator.Events.UPDATED, () => {
|
||||
this.nextDiffAction.updateEnablement();
|
||||
this.previousDiffAction.updateEnablement();
|
||||
});
|
||||
}, error => {
|
||||
|
||||
// In case we tried to open a file and the response indicates that this is not a text file, fallback to binary diff.
|
||||
if (this.isFileBinaryError(error) && this.openAsBinary(input, options)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Otherwise make sure the error bubbles up
|
||||
return TPromise.wrapError(error);
|
||||
});
|
||||
this.diffNavigator.addListener(DiffNavigator.Events.UPDATED, () => {
|
||||
this.nextDiffAction.updateEnablement();
|
||||
this.previousDiffAction.updateEnablement();
|
||||
});
|
||||
}, error => {
|
||||
|
||||
// In case we tried to open a file and the response indicates that this is not a text file, fallback to binary diff.
|
||||
if (this.isFileBinaryError(error) && this.openAsBinary(input, options)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Otherwise make sure the error bubbles up
|
||||
return TPromise.wrapError(error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import types = require('vs/base/common/types');
|
||||
import errors = require('vs/base/common/errors');
|
||||
import DOM = require('vs/base/browser/dom');
|
||||
import { CodeEditor } from 'vs/editor/browser/codeEditor';
|
||||
import { EditorInput, EditorOptions, toResource } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { IEditorViewState, IEditor, isCommonCodeEditor, isCommonDiffEditor } from 'vs/editor/common/editorCommon';
|
||||
import { Position } from 'vs/platform/editor/common/editor';
|
||||
@@ -66,7 +66,7 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
) {
|
||||
super(id, telemetryService, themeService);
|
||||
|
||||
this.toUnbind.push(this.configurationService.onDidUpdateConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration<IEditorConfiguration>(this.getResource()))));
|
||||
this.toUnbind.push(this.configurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getConfiguration<IEditorConfiguration>(this.getResource()))));
|
||||
}
|
||||
|
||||
protected get instantiationService(): IInstantiationService {
|
||||
@@ -196,6 +196,7 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
// Update editor options after having set the input. We do this because there can be
|
||||
// editor input specific options (e.g. an ARIA label depending on the input showing)
|
||||
this.updateEditorConfiguration();
|
||||
this._editorContainer.getHTMLElement().setAttribute('aria-label', this.computeAriaLabel());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -240,7 +241,7 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
*/
|
||||
protected saveTextEditorViewState(key: string): void {
|
||||
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
|
||||
let textEditorViewStateMemento = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
|
||||
let textEditorViewStateMemento: { [key: string]: { [position: number]: IEditorViewState } } = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
|
||||
if (!textEditorViewStateMemento) {
|
||||
textEditorViewStateMemento = Object.create(null);
|
||||
memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY] = textEditorViewStateMemento;
|
||||
@@ -248,7 +249,7 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
|
||||
const editorViewState = this.getControl().saveViewState();
|
||||
|
||||
let lastKnownViewState: ITextEditorViewState = textEditorViewStateMemento[key];
|
||||
let lastKnownViewState = textEditorViewStateMemento[key];
|
||||
if (!lastKnownViewState) {
|
||||
lastKnownViewState = Object.create(null);
|
||||
textEditorViewStateMemento[key] = lastKnownViewState;
|
||||
@@ -264,7 +265,7 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
*/
|
||||
protected clearTextEditorViewState(keys: string[]): void {
|
||||
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
|
||||
const textEditorViewStateMemento = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
|
||||
const textEditorViewStateMemento: { [key: string]: { [position: number]: IEditorViewState } } = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
|
||||
if (textEditorViewStateMemento) {
|
||||
keys.forEach(key => delete textEditorViewStateMemento[key]);
|
||||
}
|
||||
@@ -275,9 +276,9 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
*/
|
||||
protected loadTextEditorViewState(key: string): IEditorViewState {
|
||||
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
|
||||
const textEditorViewStateMemento = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
|
||||
const textEditorViewStateMemento: { [key: string]: { [position: number]: IEditorViewState } } = memento[TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY];
|
||||
if (textEditorViewStateMemento) {
|
||||
const viewState: ITextEditorViewState = textEditorViewStateMemento[key];
|
||||
const viewState = textEditorViewStateMemento[key];
|
||||
if (viewState) {
|
||||
return viewState[this.position];
|
||||
}
|
||||
@@ -317,7 +318,7 @@ export abstract class BaseTextEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
if (this.input) {
|
||||
return toResource(this.input);
|
||||
return this.input.getResource();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -55,16 +55,12 @@ export class TextResourceEditor extends BaseTextEditor {
|
||||
}
|
||||
|
||||
public setInput(input: EditorInput, options?: EditorOptions): TPromise<void> {
|
||||
const oldInput = this.input;
|
||||
super.setInput(input, options);
|
||||
|
||||
// Detect options
|
||||
// Return early for same input unless we force to open
|
||||
const forceOpen = options && options.forceOpen;
|
||||
if (!forceOpen && input.matches(this.input)) {
|
||||
|
||||
// Same Input
|
||||
if (!forceOpen && input.matches(oldInput)) {
|
||||
|
||||
// TextOptions (avoiding instanceof here for a reason, do not change!)
|
||||
// Still apply options if any (avoiding instanceof here for a reason, do not change!)
|
||||
const textOptions = <TextEditorOptions>options;
|
||||
if (textOptions && types.isFunction(textOptions.apply)) {
|
||||
textOptions.apply(this.getControl(), ScrollType.Smooth);
|
||||
@@ -74,39 +70,41 @@ export class TextResourceEditor extends BaseTextEditor {
|
||||
}
|
||||
|
||||
// Remember view settings if input changes
|
||||
this.saveTextEditorViewStateForInput(oldInput);
|
||||
this.saveTextEditorViewStateForInput(this.input);
|
||||
|
||||
// Different Input (Reload)
|
||||
return input.resolve(true).then((resolvedModel: EditorModel) => {
|
||||
// Set input and resolve
|
||||
return super.setInput(input, options).then(() => {
|
||||
return input.resolve(true).then((resolvedModel: EditorModel) => {
|
||||
|
||||
// Assert Model instance
|
||||
if (!(resolvedModel instanceof BaseTextEditorModel)) {
|
||||
return TPromise.wrapError<void>(new Error('Unable to open file as text'));
|
||||
}
|
||||
// Assert Model instance
|
||||
if (!(resolvedModel instanceof BaseTextEditorModel)) {
|
||||
return TPromise.wrapError<void>(new Error('Unable to open file as text'));
|
||||
}
|
||||
|
||||
// Assert that the current input is still the one we expect. This prevents a race condition when loading takes long and another input was set meanwhile
|
||||
if (!this.input || this.input !== input) {
|
||||
return null;
|
||||
}
|
||||
// Assert that the current input is still the one we expect. This prevents a race condition when loading takes long and another input was set meanwhile
|
||||
if (!this.input || this.input !== input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set Editor Model
|
||||
const textEditor = this.getControl();
|
||||
const textEditorModel = resolvedModel.textEditorModel;
|
||||
textEditor.setModel(textEditorModel);
|
||||
// Set Editor Model
|
||||
const textEditor = this.getControl();
|
||||
const textEditorModel = resolvedModel.textEditorModel;
|
||||
textEditor.setModel(textEditorModel);
|
||||
|
||||
// Apply Options from TextOptions
|
||||
let optionsGotApplied = false;
|
||||
const textOptions = <TextEditorOptions>options;
|
||||
if (textOptions && types.isFunction(textOptions.apply)) {
|
||||
optionsGotApplied = textOptions.apply(textEditor, ScrollType.Immediate);
|
||||
}
|
||||
// Apply Options from TextOptions
|
||||
let optionsGotApplied = false;
|
||||
const textOptions = <TextEditorOptions>options;
|
||||
if (textOptions && types.isFunction(textOptions.apply)) {
|
||||
optionsGotApplied = textOptions.apply(textEditor, ScrollType.Immediate);
|
||||
}
|
||||
|
||||
// Otherwise restore View State
|
||||
if (!optionsGotApplied) {
|
||||
this.restoreViewState(input);
|
||||
}
|
||||
// Otherwise restore View State
|
||||
if (!optionsGotApplied) {
|
||||
this.restoreViewState(input);
|
||||
}
|
||||
|
||||
return void 0;
|
||||
return void 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ export interface ITitleAreaControl {
|
||||
getContainer(): HTMLElement;
|
||||
refresh(instant?: boolean): void;
|
||||
update(instant?: boolean): void;
|
||||
updateEditorActionsToolbar(): void;
|
||||
layout(): void;
|
||||
dispose(): void;
|
||||
}
|
||||
@@ -259,6 +260,12 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl
|
||||
|
||||
// Log in telemetry
|
||||
if (this.telemetryService) {
|
||||
/* __GDPR__
|
||||
"workbenchActionExecuted" : {
|
||||
"id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
|
||||
"from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.telemetryService.publicLog('workbenchActionExecuted', { id: e.action.id, from: 'editorPart' });
|
||||
}
|
||||
}));
|
||||
@@ -334,7 +341,7 @@ export abstract class TitleControl extends Themable implements ITitleAreaControl
|
||||
return { primary, secondary };
|
||||
}
|
||||
|
||||
protected updateEditorActionsToolbar(): void {
|
||||
public updateEditorActionsToolbar(): void {
|
||||
const group = this.context;
|
||||
if (!group) {
|
||||
return;
|
||||
@@ -543,7 +550,7 @@ export function handleWorkspaceExternalDrop(
|
||||
|
||||
// Multiple folders: Create new workspace with folders and open
|
||||
else if (folders.length > 1) {
|
||||
workspacesToOpen = workspacesService.createWorkspace([...folders].map(folder => folder.fsPath)).then(workspace => [workspace.configPath]);
|
||||
workspacesToOpen = workspacesService.createWorkspace(folders.map(folder => ({ uri: folder }))).then(workspace => [workspace.configPath]);
|
||||
}
|
||||
|
||||
// Open
|
||||
|
||||
@@ -40,13 +40,13 @@ export abstract class BaseWebviewEditor extends BaseEditor {
|
||||
|
||||
protected saveViewState(resource: URI | string, editorViewState: HtmlPreviewEditorViewState): void {
|
||||
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
|
||||
let editorViewStateMemento = memento[this.viewStateStorageKey];
|
||||
let editorViewStateMemento: { [key: string]: { [position: number]: HtmlPreviewEditorViewState } } = memento[this.viewStateStorageKey];
|
||||
if (!editorViewStateMemento) {
|
||||
editorViewStateMemento = Object.create(null);
|
||||
memento[this.viewStateStorageKey] = editorViewStateMemento;
|
||||
}
|
||||
|
||||
let fileViewState: HtmlPreviewEditorViewStates = editorViewStateMemento[resource.toString()];
|
||||
let fileViewState = editorViewStateMemento[resource.toString()];
|
||||
if (!fileViewState) {
|
||||
fileViewState = Object.create(null);
|
||||
editorViewStateMemento[resource.toString()] = fileViewState;
|
||||
@@ -59,9 +59,9 @@ export abstract class BaseWebviewEditor extends BaseEditor {
|
||||
|
||||
protected loadViewState(resource: URI | string): HtmlPreviewEditorViewState | null {
|
||||
const memento = this.getMemento(this.storageService, Scope.WORKSPACE);
|
||||
const editorViewStateMemento = memento[this.viewStateStorageKey];
|
||||
const editorViewStateMemento: { [key: string]: { [position: number]: HtmlPreviewEditorViewState } } = memento[this.viewStateStorageKey];
|
||||
if (editorViewStateMemento) {
|
||||
const fileViewState: HtmlPreviewEditorViewStates = editorViewStateMemento[resource.toString()];
|
||||
const fileViewState = editorViewStateMemento[resource.toString()];
|
||||
if (fileViewState) {
|
||||
return fileViewState[this.position];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user