From d5cbad347f41b369789162c1fa52efce7574c156 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 14 Jun 2016 09:02:53 +0200 Subject: [PATCH] add setting to control where editors open (for #6787) --- .../parts/editor/editor.contribution.ts | 6 +++ .../browser/parts/editor/editorPart.ts | 13 ++++- src/vs/workbench/common/editor.ts | 8 +++ .../common/editor/editorStacksModel.ts | 43 +++++++++++----- .../parts/files/browser/explorerViewlet.ts | 6 ++- src/vs/workbench/parts/files/common/files.ts | 4 +- .../common/editor/editorStacksModel.test.ts | 50 +++++++++++++++---- .../test/common/servicesTestUtils.ts | 6 ++- 8 files changed, 110 insertions(+), 26 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index b53ab324e20..459f647425c 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -418,6 +418,12 @@ configurationRegistry.registerConfiguration({ 'type': 'boolean', 'description': nls.localize('quickOpenPreviews', "Controls if editors opened from quick open show as preview. Set to false to always open editors from quick open pinned."), 'default': true + }, + 'workbench.editorOpenPositioning': { + 'type': 'string', + 'enum': ['left', 'right', 'beginning', 'end'], + 'default': 'right', + 'description': nls.localize('editorOpenPositioning', "Controls where editors open. Select 'left' or 'right' to open editors to the left or right of the current active one. Select 'beginning' or 'end' to open editors independently from the currently active one.") } } }); \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index cc2ef63b06f..e3dff5b30ac 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -138,7 +138,18 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService } private onConfigurationUpdated(configuration: IWorkbenchEditorConfiguration): void { - this.previewEditors = configuration.workbench.previewEditors; + const newPreviewEditors = configuration.workbench.previewEditors; + + // Pin all preview editors of the user chose to disable preview + if (this.previewEditors !== newPreviewEditors && !newPreviewEditors) { + this.stacks.groups.forEach(group => { + if (group.previewEditor) { + this.pinEditor(this.stacks.positionOfGroup(group), group.previewEditor); + } + }); + } + + this.previewEditors = newPreviewEditors; } private onEditorDirty(identifier: EditorIdentifier): void { diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index afba732b665..4bdc8e40017 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -663,10 +663,18 @@ export interface IEditorContext extends IEditorIdentifier { export type GroupIdentifier = number; +export const EditorOpenPositioning = { + LEFT: 'left', + RIGHT: 'right', + BEGINNING: 'beginning', + END: 'end' +}; + export interface IWorkbenchEditorConfiguration { workbench: { showEditorTabs: boolean; previewEditors: boolean; quickOpenPreviews: boolean; + editorOpenPositioning: string; }; } \ No newline at end of file diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index 0632788f77f..93d8b49f892 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -6,10 +6,11 @@ 'use strict'; import Event, {Emitter} from 'vs/base/common/event'; -import {EditorInput, getUntitledOrFileResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, GroupIdentifier, IStacksModelChangeEvent} from 'vs/workbench/common/editor'; +import {EditorInput, getUntitledOrFileResource, IEditorStacksModel, IEditorGroup, IEditorIdentifier, GroupIdentifier, IStacksModelChangeEvent, IWorkbenchEditorConfiguration, EditorOpenPositioning} from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; import {dispose, IDisposable} from 'vs/base/common/lifecycle'; @@ -37,11 +38,6 @@ export interface IEditorOpenOptions { index?: number; } -let CONFIG_OPEN_EDITOR_DIRECTION = Direction.RIGHT; // open new editors to the right of existing ones -export function setOpenEditorDirection(dir: Direction): void { - CONFIG_OPEN_EDITOR_DIRECTION = dir; -} - export interface ISerializedEditorInput { id: string; value: string; @@ -69,6 +65,7 @@ export class EditorGroup implements IEditorGroup { private active: EditorInput; // editor in active state private toDispose: IDisposable[]; + private editorOpenPositioning: string; private _onEditorActivated: Emitter; private _onEditorOpened: Emitter; @@ -83,7 +80,8 @@ export class EditorGroup implements IEditorGroup { constructor( arg1: string | ISerializedEditorGroup, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @IConfigurationService private configurationService: IConfigurationService ) { this._id = EditorGroup.IDS++; @@ -91,6 +89,7 @@ export class EditorGroup implements IEditorGroup { this.mru = []; this.toDispose = []; this.mapResourceToEditor = Object.create(null); + this.editorOpenPositioning = configurationService.getConfiguration().workbench.editorOpenPositioning; this._onEditorActivated = new Emitter(); this._onEditorOpened = new Emitter(); @@ -110,6 +109,16 @@ export class EditorGroup implements IEditorGroup { } else { this._label = arg1; } + + this.registerListeners(); + } + + private registerListeners(): void { + this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationUpdated(e.config))); + } + + private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { + this.editorOpenPositioning = config.workbench.editorOpenPositioning; } public get id(): GroupIdentifier { @@ -208,20 +217,30 @@ export class EditorGroup implements IEditorGroup { targetIndex = options.index; } - // Insert to the RIGHT of active editor - else if (CONFIG_OPEN_EDITOR_DIRECTION === Direction.RIGHT) { - targetIndex = indexOfActive + 1; + // Insert to the BEGINNING + else if (this.editorOpenPositioning === EditorOpenPositioning.BEGINNING) { + targetIndex = 0; + } + + // Insert to the END + else if (this.editorOpenPositioning === EditorOpenPositioning.END) { + targetIndex = this.editors.length; } // Insert to the LEFT of active editor - else { + else if (this.editorOpenPositioning === EditorOpenPositioning.LEFT) { if (indexOfActive === 0 || !this.editors.length) { targetIndex = 0; // to the left becoming first editor in list } else { - targetIndex = indexOfActive - 1; // to the left of active editor + targetIndex = indexOfActive; // to the left of active editor } } + // Insert to the RIGHT of active editor + else { + targetIndex = indexOfActive + 1; + } + // Insert into our list of editors if pinned or we have no preview editor if (makePinned || !this.preview) { this.splice(targetIndex, false, editor); diff --git a/src/vs/workbench/parts/files/browser/explorerViewlet.ts b/src/vs/workbench/parts/files/browser/explorerViewlet.ts index f8c00f2cb96..3211cd13212 100644 --- a/src/vs/workbench/parts/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/parts/files/browser/explorerViewlet.ts @@ -42,6 +42,7 @@ export class ExplorerViewlet extends Viewlet { private openEditorsVisible: boolean; private lastFocusedView: ExplorerView | OpenEditorsView | EmptyView; private focusListener: IDisposable; + private delayEditorOpeningInOpenedEditors: boolean; private viewletSettings: any; private viewletState: FileViewletState; @@ -85,6 +86,9 @@ export class ExplorerViewlet extends Viewlet { private onConfigurationUpdated(config: IFilesConfiguration): TPromise { + // No need to delay if preview is disabled + this.delayEditorOpeningInOpenedEditors = !!config.workbench.previewEditors; + // Open editors view should always be visible in no folder workspace. let openEditorsVisible = !this.contextService.getWorkspace() || config.explorer.openEditors.visible !== 0; @@ -146,7 +150,7 @@ export class ExplorerViewlet extends Viewlet { const delegatingEditorService = this.instantiationService.createInstance(DelegatingWorkbenchEditorService, (input: EditorInput, options?: EditorOptions, arg3?: any) => { if (this.openEditorsView) { let delay = 0; - if (arg3 === false /* not side by side */ || typeof arg3 !== 'number' /* no explicit position */) { + if (this.delayEditorOpeningInOpenedEditors && (arg3 === false /* not side by side */ || typeof arg3 !== 'number' /* no explicit position */)) { const activeGroup = this.editorGroupService.getStacksModel().activeGroup; if (!activeGroup || !activeGroup.previewEditor) { delay = 250; // a new editor entry is likely because there is either no group or no preview in group diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 2a6ba0716e9..281397a3205 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -10,7 +10,7 @@ import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; import {IModel, IEditorOptions} from 'vs/editor/common/editorCommon'; import {IDisposable} from 'vs/base/common/lifecycle'; -import {EncodingMode, EditorInput, IFileEditorInput, ConfirmResult} from 'vs/workbench/common/editor'; +import {EncodingMode, EditorInput, IFileEditorInput, ConfirmResult, IWorkbenchEditorConfiguration} from 'vs/workbench/common/editor'; import {IFileStat, IFilesConfiguration} from 'vs/platform/files/common/files'; import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; @@ -57,7 +57,7 @@ export abstract class FileEditorInput extends EditorInput implements IFileEditor public abstract getEncoding(): string; } -export interface IFilesConfiguration extends IFilesConfiguration { +export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEditorConfiguration { explorer: { openEditors: { visible: number; diff --git a/src/vs/workbench/test/common/editor/editorStacksModel.test.ts b/src/vs/workbench/test/common/editor/editorStacksModel.test.ts index 35b1b88a196..1929c1467f7 100644 --- a/src/vs/workbench/test/common/editor/editorStacksModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorStacksModel.test.ts @@ -6,11 +6,12 @@ 'use strict'; import * as assert from 'assert'; -import {EditorStacksModel, EditorGroup, setOpenEditorDirection} from 'vs/workbench/common/editor/editorStacksModel'; +import {EditorStacksModel, EditorGroup} from 'vs/workbench/common/editor/editorStacksModel'; import {EditorInput, IFileEditorInput, IEditorIdentifier, IEditorGroup, IStacksModelChangeEvent} from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; -import {TestStorageService, TestLifecycleService, TestContextService, TestWorkspace, TestConfiguration} from 'vs/workbench/test/common/servicesTestUtils'; +import {TestStorageService, TestConfigurationService, TestLifecycleService, TestContextService, TestWorkspace, TestConfiguration} from 'vs/workbench/test/common/servicesTestUtils'; import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; import {IStorageService} from 'vs/platform/storage/common/storage'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; @@ -27,6 +28,10 @@ function create(): EditorStacksModel { services.set(ILifecycleService, new TestLifecycleService()); services.set(IWorkspaceContextService, new TestContextService()); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); + let inst = new InstantiationService(services); return inst.createInstance(EditorStacksModel); @@ -197,7 +202,6 @@ suite('Editor Stacks Model', () => { teardown(() => { index = 1; - setOpenEditorDirection(Direction.RIGHT); }); test('Groups - Basic', function () { @@ -594,6 +598,9 @@ suite('Editor Stacks Model', () => { services.set(IWorkspaceContextService, new TestContextService()); const lifecycle = new TestLifecycleService(); services.set(ILifecycleService, lifecycle); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); let inst = new InstantiationService(services); @@ -636,9 +643,19 @@ suite('Editor Stacks Model', () => { }); test('Stack - Multiple Editors - Pinned and Active (DEFAULT_OPEN_EDITOR_DIRECTION = Direction.LEFT)', function () { - setOpenEditorDirection(Direction.LEFT); + let services = new ServiceCollection(); + services.set(IStorageService, new TestStorageService()); + services.set(ILifecycleService, new TestLifecycleService()); + services.set(IWorkspaceContextService, new TestContextService()); + + const config = new TestConfigurationService(); + services.set(IConfigurationService, config); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'left' }); + + let inst = new InstantiationService(services); + + const model = inst.createInstance(EditorStacksModel); - const model = create(); const group = model.openGroup('group'); const events = groupListener(group); @@ -1165,6 +1182,9 @@ suite('Editor Stacks Model', () => { services.set(IWorkspaceContextService, new TestContextService()); const lifecycle = new TestLifecycleService(); services.set(ILifecycleService, lifecycle); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); let inst = new InstantiationService(services); @@ -1206,6 +1226,9 @@ suite('Editor Stacks Model', () => { services.set(IWorkspaceContextService, new TestContextService()); const lifecycle = new TestLifecycleService(); services.set(ILifecycleService, lifecycle); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); let inst = new InstantiationService(services); @@ -1285,6 +1308,9 @@ suite('Editor Stacks Model', () => { services.set(IWorkspaceContextService, new TestContextService()); const lifecycle = new TestLifecycleService(); services.set(ILifecycleService, lifecycle); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); let inst = new InstantiationService(services); @@ -1332,6 +1358,9 @@ suite('Editor Stacks Model', () => { services.set(IWorkspaceContextService, new TestContextService()); const lifecycle = new TestLifecycleService(); services.set(ILifecycleService, lifecycle); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); let inst = new InstantiationService(services); @@ -1371,6 +1400,9 @@ suite('Editor Stacks Model', () => { services.set(IWorkspaceContextService, new TestContextService(TestWorkspace, TestConfiguration, { filesToCreate: [true] })); const lifecycle = new TestLifecycleService(); services.set(ILifecycleService, lifecycle); + const config = new TestConfigurationService(); + config.setUserConfiguration('workbench', { editorOpenPositioning: 'right' }); + services.set(IConfigurationService, config); let inst = new InstantiationService(services); @@ -1501,7 +1533,7 @@ suite('Editor Stacks Model', () => { assert.ok(model.isOpen(input2Resource)); assert.ok(!model.isOpen(input1Resource)); - group1.openEditor(input3, {pinned: true}); + group1.openEditor(input3, { pinned: true }); assert.ok(model.isOpen(input2Resource)); assert.ok(model.isOpen(input3Resource)); @@ -1606,7 +1638,7 @@ suite('Editor Stacks Model', () => { const diffInput = new DiffEditorInput('name', 'description', input1, input2); - group1.openEditor(diffInput, { pinned: true, active: true}); + group1.openEditor(diffInput, { pinned: true, active: true }); group1.openEditor(input1, { pinned: true, active: true }); group1.closeEditor(diffInput); @@ -1625,11 +1657,11 @@ suite('Editor Stacks Model', () => { const input1 = input(); const input2 = input(); - group1.openEditor(input1, { pinned: true, active: true}); + group1.openEditor(input1, { pinned: true, active: true }); group2.openEditor(input2, { pinned: true, active: true }); let dirtyCounter = 0; - model.onEditorDirty(() => { + model.onEditorDirty(() => { dirtyCounter++; }); diff --git a/src/vs/workbench/test/common/servicesTestUtils.ts b/src/vs/workbench/test/common/servicesTestUtils.ts index 6d7fc4a1a3b..43bbce4f3c2 100644 --- a/src/vs/workbench/test/common/servicesTestUtils.ts +++ b/src/vs/workbench/test/common/servicesTestUtils.ts @@ -541,12 +541,14 @@ export const TestFileService = { export class TestConfigurationService extends EventEmitter.EventEmitter implements IConfigurationService { public serviceId = IConfigurationService; + private configuration = Object.create(null); + public loadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } public getConfiguration(): any { - return {}; + return this.configuration; } public hasWorkspaceConfiguration(): boolean { @@ -558,6 +560,8 @@ export class TestConfigurationService extends EventEmitter.EventEmitter implemen } public setUserConfiguration(key: any, value: any): Thenable { + this.configuration[key] = value; + return TPromise.as(null); } } -- GitLab