提交 e9711141 编写于 作者: B Benjamin Pasero

scope the delay in opened editors to explorer view only

上级 7c483ab8
......@@ -572,7 +572,7 @@ export class RunOnceScheduler {
*/
schedule(delay = this.timeout): void {
this.cancel();
this.timeoutToken = platform.setTimeout(this.timeoutHandler, this.timeout);
this.timeoutToken = platform.setTimeout(this.timeoutHandler, delay);
}
/**
......
......@@ -15,7 +15,6 @@ import types = require('vs/base/common/types');
import {Position} from 'vs/platform/editor/common/editor';
import {IDiffEditor} from 'vs/editor/browser/editorBrowser';
import {IDiffEditorOptions, IEditorOptions} from 'vs/editor/common/editorCommon';
import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor';
import {TextEditorOptions, TextDiffEditorOptions, EditorModel, EditorInput, EditorOptions} from 'vs/workbench/common/editor';
import {StringEditorInput} from 'vs/workbench/common/editor/stringEditorInput';
......@@ -85,16 +84,16 @@ export class TextDiffEditor extends BaseTextEditor {
this.previousDiffAction = new NavigateAction(this, false);
// Support navigation within the diff editor by overriding the editor service within
let delegatingEditorService = this.instantiationService.createInstance(DelegatingWorkbenchEditorService, this, (editor: BaseEditor, input: EditorInput, options?: EditorOptions, arg4?: any) => {
let delegatingEditorService = this.instantiationService.createInstance(DelegatingWorkbenchEditorService, (input: EditorInput, options?: EditorOptions, arg3?: any) => {
// Check if arg4 is a position argument that differs from this editors position
if (types.isUndefinedOrNull(arg4) || arg4 === false || arg4 === this.position) {
if (types.isUndefinedOrNull(arg3) || arg3 === false || arg3 === this.position) {
let activeDiffInput = <DiffEditorInput>this.getInput();
if (input && options && activeDiffInput) {
// Input matches modified side of the diff editor: perform the action on modified side
if (input.matches(activeDiffInput.modifiedInput)) {
return this.setInput(this.getInput(), options).then(() => true);
return this.setInput(this.getInput(), options).then(() => this);
}
// Input matches original side of the diff editor: perform the action on original side
......@@ -103,13 +102,13 @@ export class TextDiffEditor extends BaseTextEditor {
if (options instanceof TextEditorOptions) {
(<TextEditorOptions>options).apply(originalEditor);
return TPromise.as<boolean>(true);
return TPromise.as(this);
}
}
}
}
return TPromise.as<boolean>(false);
return TPromise.as(null);
});
// Create a special child of instantiator that will delegate all calls to openEditor() to the same diff editor if the input matches with the modified one
......
......@@ -24,6 +24,12 @@ import {IStorageService} from 'vs/platform/storage/common/storage';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {DelegatingWorkbenchEditorService} from 'vs/workbench/services/editor/browser/editorService';
import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection';
import {EditorInput, EditorOptions} from 'vs/workbench/common/editor';
import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService';
export class ExplorerViewlet extends Viewlet {
private viewletContainer: Builder;
......@@ -44,6 +50,8 @@ export class ExplorerViewlet extends Viewlet {
@ITelemetryService telemetryService: ITelemetryService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IStorageService private storageService: IStorageService,
@IEditorGroupService private editorGroupService: IEditorGroupService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IConfigurationService private configurationService: IConfigurationService,
@IInstantiationService private instantiationService: IInstantiationService
) {
......@@ -71,6 +79,7 @@ export class ExplorerViewlet extends Viewlet {
}
private onConfigurationUpdated(config: IFilesConfiguration): TPromise<void> {
// Open editors view should always be visible in no folder workspace.
let openEditorsVisible = !this.contextService.getWorkspace() || config.explorer.openEditors.visible !== 0;
......@@ -104,8 +113,7 @@ export class ExplorerViewlet extends Viewlet {
// Update title area since the title actions have changed.
this.updateTitleArea();
// Focus the viewlet since that triggers a rerender.
return this.setVisible(this.isVisible()).then(() => this.focus());
return this.setVisible(this.isVisible()).then(() => this.focus()); // Focus the viewlet since that triggers a rerender.
});
}
......@@ -124,9 +132,40 @@ export class ExplorerViewlet extends Viewlet {
// With a Workspace
if (this.contextService.getWorkspace()) {
// If open editors are not visible set header size explicitly to 0, otherwise let it be computed by super class.
const headerSize = this.openEditorsVisible ? undefined : 0;
this.explorerView = explorerView = this.instantiationService.createInstance(ExplorerView, this.viewletState, this.getActionRunner(), this.viewletSettings, headerSize);
// Create a delegating editor service for the explorer to be able to delay the refresh in the opened
// editors view above. This is a workaround for being able to double click on a file to make it pinned
// without causing the animation in the opened editors view to kick in and change scroll position.
// We try to be smart and only use the delay if we recognize that the user action is likely to cause
// a new entry in the opened editors view.
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 */) {
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
}
}
this.openEditorsView.setStructuralRefreshDelay(delay);
}
const onSuccessOrError = (editor?: BaseEditor) => {
if (this.openEditorsView) {
this.openEditorsView.setStructuralRefreshDelay(0);
}
return editor;
};
return this.editorService.openEditor(input, options, arg3).then(onSuccessOrError, onSuccessOrError);
});
const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IWorkbenchEditorService, delegatingEditorService]));
const headerSize = this.openEditorsVisible ? undefined : 0; // If open editors are not visible set header size explicitly to 0, otherwise let it be computed by super class.
this.explorerView = explorerView = explorerInstantiator.createInstance(ExplorerView, this.viewletState, this.getActionRunner(), this.viewletSettings, headerSize);
}
// No workspace
......
......@@ -15,7 +15,7 @@ import async = require('vs/base/common/async');
import paths = require('vs/base/common/paths');
import errors = require('vs/base/common/errors');
import {isString} from 'vs/base/common/types';
import Actions = require('vs/base/common/actions');
import {IAction, ActionRunner as BaseActionRunner, IActionRunner} from 'vs/base/common/actions';
import comparers = require('vs/base/common/comparers');
import {InputBox} from 'vs/base/browser/ui/inputbox/inputBox';
import {$} from 'vs/base/browser/builder';
......@@ -143,7 +143,7 @@ export class FileActionProvider extends ContributableActionProvider {
return super.hasActions(tree, stat);
}
public getActions(tree: ITree, stat: FileStat): TPromise<Actions.IAction[]> {
public getActions(tree: ITree, stat: FileStat): TPromise<IAction[]> {
if (stat instanceof NewStatPlaceholder) {
return TPromise.as([]);
}
......@@ -159,7 +159,7 @@ export class FileActionProvider extends ContributableActionProvider {
return super.hasSecondaryActions(tree, stat);
}
public getSecondaryActions(tree: ITree, stat: FileStat): TPromise<Actions.IAction[]> {
public getSecondaryActions(tree: ITree, stat: FileStat): TPromise<IAction[]> {
if (stat instanceof NewStatPlaceholder) {
return TPromise.as([]);
}
......@@ -167,7 +167,7 @@ export class FileActionProvider extends ContributableActionProvider {
return super.getSecondaryActions(tree, stat);
}
public runAction(tree: ITree, stat: FileStat, action: Actions.IAction, context?: any): TPromise<any>;
public runAction(tree: ITree, stat: FileStat, action: IAction, context?: any): TPromise<any>;
public runAction(tree: ITree, stat: FileStat, actionID: string, context?: any): TPromise<any>;
public runAction(tree: ITree, stat: FileStat, arg: any, context: any = {}): TPromise<any> {
context = objects.mixin({
......@@ -176,7 +176,7 @@ export class FileActionProvider extends ContributableActionProvider {
}, context);
if (!isString(arg)) {
let action = <Actions.IAction>arg;
let action = <IAction>arg;
if (action.enabled) {
return action.run(context);
}
......@@ -187,7 +187,7 @@ export class FileActionProvider extends ContributableActionProvider {
let id = <string>arg;
let promise = this.hasActions(tree, stat) ? this.getActions(tree, stat) : TPromise.as([]);
return promise.then((actions: Actions.IAction[]) => {
return promise.then((actions: IAction[]) => {
for (let i = 0, len = actions.length; i < len; i++) {
if (actions[i].id === id && actions[i].enabled) {
return actions[i].run(context);
......@@ -196,7 +196,7 @@ export class FileActionProvider extends ContributableActionProvider {
promise = this.hasSecondaryActions(tree, stat) ? this.getSecondaryActions(tree, stat) : TPromise.as([]);
return promise.then((actions: Actions.IAction[]) => {
return promise.then((actions: IAction[]) => {
for (let i = 0, len = actions.length; i < len; i++) {
if (actions[i].id === id && actions[i].enabled) {
return actions[i].run(context);
......@@ -237,7 +237,7 @@ export class FileViewletState implements IFileViewletState {
}
}
export class ActionRunner extends Actions.ActionRunner implements Actions.IActionRunner {
export class ActionRunner extends BaseActionRunner implements IActionRunner {
private viewletState: FileViewletState;
constructor(state: FileViewletState) {
......@@ -246,7 +246,7 @@ export class ActionRunner extends Actions.ActionRunner implements Actions.IActio
this.viewletState = state;
}
public run(action: Actions.IAction, context?: any): TPromise<any> {
public run(action: IAction, context?: any): TPromise<any> {
return super.run(action, { viewletState: this.viewletState });
}
}
......@@ -257,7 +257,7 @@ export class FileRenderer extends ActionsRenderer implements IRenderer {
constructor(
state: FileViewletState,
actionRunner: Actions.IActionRunner,
actionRunner: IActionRunner,
@IContextViewService private contextViewService: IContextViewService
) {
super({
......
......@@ -35,7 +35,6 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
private static MEMENTO_COLLAPSED = 'openEditors.memento.collapsed';
private static DEFAULT_VISIBLE_OPEN_EDITORS = 9;
private static DEFAULT_DYNAMIC_HEIGHT = true;
private static STRUCTURAL_TREE_REFRESH_DELAY = 250;
private settings: any;
private visibleOpenEditors: number;
......@@ -44,6 +43,7 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
private model: IEditorStacksModel;
private dirtyCountElement: HTMLElement;
private structuralTreeRefreshScheduler: RunOnceScheduler;
private structuralRefreshDelay: number;
private groupToRefresh: IEditorGroup;
private fullRefreshNeeded: boolean;
......@@ -64,7 +64,8 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
this.settings = settings;
this.model = editorGroupService.getStacksModel();
this.structuralTreeRefreshScheduler = new RunOnceScheduler(() => this.structuralTreeUpdate(), OpenEditorsView.STRUCTURAL_TREE_REFRESH_DELAY);
this.structuralRefreshDelay = 0;
this.structuralTreeRefreshScheduler = new RunOnceScheduler(() => this.structuralTreeUpdate(), this.structuralRefreshDelay);
}
public renderHeader(container: HTMLElement): void {
......@@ -155,7 +156,7 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
} else {
this.fullRefreshNeeded = true;
}
this.structuralTreeRefreshScheduler.schedule();
this.structuralTreeRefreshScheduler.schedule(this.structuralRefreshDelay);
} else {
const toRefresh = e.editor ? new OpenEditor(e.editor, e.group) : e.group;
this.tree.refresh(toRefresh, false).done(null, errors.onUnexpectedError);
......@@ -248,6 +249,10 @@ export class OpenEditorsView extends AdaptiveCollapsibleViewletView {
return itemsToShow * Renderer.ITEM_HEIGHT;
}
public setStructuralRefreshDelay(delay: number): void {
this.structuralRefreshDelay = delay;
}
public getOptimalWidth():number {
let parentNode = this.tree.getHTMLElement();
let childNodes = [].slice.call(parentNode.querySelectorAll('.monaco-file-label > .file-name'));
......
......@@ -284,25 +284,23 @@ export class WorkbenchEditorService implements IWorkbenchEditorService {
}
}
export interface IDelegatingWorkbenchEditorHandler {
(editor: BaseEditor, input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<boolean>;
(editor: BaseEditor, input: EditorInput, options?: EditorOptions, position?: Position): TPromise<boolean>;
export interface IDelegatingWorkbenchEditorServiceHandler {
(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<BaseEditor>;
(input: EditorInput, options?: EditorOptions, position?: Position): TPromise<BaseEditor>;
}
/**
* Subclass of workbench editor service that delegates all calls to the provided editor service. Subclasses can choose to override the behavior
* of openEditor() by providing a handler. The handler returns a promise that resolves to true or false to indicate if an action has been taken.
* If false is returned, the service will delegate to editor service for handling the call to openEditor().
* of openEditor() by providing a handler. The handler returns a promise that resolves to an editor to indicate if an action has been taken.
* If falsify is returned, the service will delegate to editor service for handling the call to openEditor().
*
* This gives clients a chance to override the behavior of openEditor() to match their context.
*/
export class DelegatingWorkbenchEditorService extends WorkbenchEditorService {
private editor: BaseEditor;
private handler: IDelegatingWorkbenchEditorHandler;
private handler: IDelegatingWorkbenchEditorServiceHandler;
constructor(
editor: BaseEditor,
handler: IDelegatingWorkbenchEditorHandler,
handler: IDelegatingWorkbenchEditorServiceHandler,
@IUntitledEditorService untitledEditorService: IUntitledEditorService,
@IInstantiationService instantiationService: IInstantiationService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService
......@@ -313,16 +311,15 @@ export class DelegatingWorkbenchEditorService extends WorkbenchEditorService {
instantiationService
);
this.editor = editor;
this.handler = handler;
}
protected doOpenEditor(input: EditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<IEditor>;
protected doOpenEditor(input: EditorInput, options?: EditorOptions, position?: Position): TPromise<IEditor>;
protected doOpenEditor(input: EditorInput, options?: EditorOptions, arg3?: any): TPromise<IEditor> {
return this.handler(this.editor, input, options, arg3).then((result) => {
if (result) {
return TPromise.as<BaseEditor>(this.editor);
return this.handler(input, options, arg3).then(editor => {
if (editor) {
return TPromise.as<BaseEditor>(editor);
}
return super.doOpenEditor(input, options, arg3);
......
......@@ -377,11 +377,10 @@ suite('Workbench UI Services', () => {
let ed = inst.createInstance(MyEditor, 'my.editor');
let inp = inst.createInstance(StringEditorInput, 'name', 'description', 'hello world', 'text/plain', false);
let delegate: any = inst.createInstance(<any>DelegatingWorkbenchEditorService, ed, (editor: BaseEditor, input: EditorInput, options?: EditorOptions) => {
let delegate: any = inst.createInstance(<any>DelegatingWorkbenchEditorService, (input: EditorInput, options?: EditorOptions, arg3?: any) => {
assert.strictEqual(input, inp);
assert.strictEqual(editor, ed);
return TPromise.as(true);
return TPromise.as(ed);
});
delegate.openEditor(inp);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册