editors - remove delegating editor service
This commit is contained in:
parent
5cfa24eba1
commit
9f59e87b66
4 changed files with 44 additions and 157 deletions
|
@ -5,7 +5,7 @@
|
|||
|
||||
import 'vs/css!./media/explorerviewlet';
|
||||
import { localize } from 'vs/nls';
|
||||
import { VIEWLET_ID, ExplorerViewletVisibleContext, IFilesConfiguration, OpenEditorsVisibleContext, VIEW_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { VIEWLET_ID, ExplorerViewletVisibleContext, OpenEditorsVisibleContext, VIEW_ID, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { ExplorerView } from 'vs/workbench/contrib/files/browser/views/explorerView';
|
||||
|
@ -16,7 +16,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IViewsRegistry, IViewDescriptor, Extensions, ViewContainer, IViewContainersRegistry, ViewContainerLocation, IViewDescriptorService, ViewContentGroups } from 'vs/workbench/common/views';
|
||||
|
@ -24,10 +23,6 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
|||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
|
||||
import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
@ -175,7 +170,6 @@ export class ExplorerViewPaneContainer extends ViewPaneContainer {
|
|||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
|
@ -199,53 +193,54 @@ export class ExplorerViewPaneContainer extends ViewPaneContainer {
|
|||
|
||||
protected override createView(viewDescriptor: IViewDescriptor, options: IViewletViewOptions): ViewPane {
|
||||
if (viewDescriptor.id === VIEW_ID) {
|
||||
// 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(DelegatingEditorService, async (group, delegate): Promise<IEditorPane | undefined> => {
|
||||
let openEditorsView = this.getOpenEditorsView();
|
||||
if (openEditorsView) {
|
||||
let delay = 0;
|
||||
|
||||
const config = this.configurationService.getValue<IFilesConfiguration>();
|
||||
const delayEditorOpeningInOpenedEditors = !!config.workbench?.editor?.enablePreview; // No need to delay if preview is disabled
|
||||
|
||||
const activeGroup = this.editorGroupService.activeGroup;
|
||||
if (delayEditorOpeningInOpenedEditors && group === activeGroup && !activeGroup.previewEditor) {
|
||||
delay = 250; // a new editor entry is likely because there is either no group or no preview in group
|
||||
return this.instantiationService.createInstance(ExplorerView, options, {
|
||||
willOpenElement: e => {
|
||||
if (!(e instanceof MouseEvent)) {
|
||||
return; // only delay when user clicks
|
||||
}
|
||||
|
||||
openEditorsView.setStructuralRefreshDelay(delay);
|
||||
}
|
||||
const openEditorsView = this.getOpenEditorsView();
|
||||
if (openEditorsView) {
|
||||
let delay = 0;
|
||||
|
||||
try {
|
||||
return await delegate();
|
||||
} catch (error) {
|
||||
return undefined; // ignore
|
||||
} finally {
|
||||
const config = this.configurationService.getValue<IFilesConfiguration>();
|
||||
if (!!config.workbench?.editor?.enablePreview) {
|
||||
// delay open editors view when preview is enabled
|
||||
// to accomodate for the user doing a double click
|
||||
// to pin the editor.
|
||||
// without this delay a double click would be not
|
||||
// possible because the next element would move
|
||||
// under the mouse after the first click.
|
||||
delay = 250;
|
||||
}
|
||||
|
||||
openEditorsView.setStructuralRefreshDelay(delay);
|
||||
}
|
||||
},
|
||||
didOpenElement: e => {
|
||||
if (!(e instanceof MouseEvent)) {
|
||||
return; // only delay when user clicks
|
||||
}
|
||||
|
||||
const openEditorsView = this.getOpenEditorsView();
|
||||
if (openEditorsView) {
|
||||
openEditorsView.setStructuralRefreshDelay(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IEditorService, delegatingEditorService]));
|
||||
return explorerInstantiator.createInstance(ExplorerView, options);
|
||||
}
|
||||
return super.createView(viewDescriptor, options);
|
||||
}
|
||||
|
||||
public getExplorerView(): ExplorerView {
|
||||
getExplorerView(): ExplorerView {
|
||||
return <ExplorerView>this.getView(VIEW_ID);
|
||||
}
|
||||
|
||||
public getOpenEditorsView(): OpenEditorsView {
|
||||
getOpenEditorsView(): OpenEditorsView {
|
||||
return <OpenEditorsView>this.getView(OpenEditorsView.ID);
|
||||
}
|
||||
|
||||
public override setVisible(visible: boolean): void {
|
||||
override setVisible(visible: boolean): void {
|
||||
this.viewletVisibleContextKey.set(visible);
|
||||
super.setVisible(visible);
|
||||
}
|
||||
|
|
|
@ -131,6 +131,11 @@ export function getContext(focus: ExplorerItem[], selection: ExplorerItem[], res
|
|||
return [focusedStat];
|
||||
}
|
||||
|
||||
export interface IExplorerViewContainerDelegate {
|
||||
willOpenElement(event?: UIEvent): void;
|
||||
didOpenElement(event?: UIEvent): void;
|
||||
}
|
||||
|
||||
export class ExplorerView extends ViewPane {
|
||||
static readonly TREE_VIEW_STATE_STORAGE_KEY: string = 'workbench.explorer.treeViewState';
|
||||
|
||||
|
@ -164,6 +169,7 @@ export class ExplorerView extends ViewPane {
|
|||
|
||||
constructor(
|
||||
options: IViewPaneOptions,
|
||||
private readonly delegate: IExplorerViewContainerDelegate,
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
|
@ -439,7 +445,12 @@ export class ExplorerView extends ViewPane {
|
|||
return;
|
||||
}
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'explorer' });
|
||||
await this.editorService.openEditor({ resource: element.resource, options: { preserveFocus: e.editorOptions.preserveFocus, pinned: e.editorOptions.pinned } }, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
try {
|
||||
this.delegate.willOpenElement(e.browserEvent);
|
||||
await this.editorService.openEditor({ resource: element.resource, options: { preserveFocus: e.editorOptions.preserveFocus, pinned: e.editorOptions.pinned } }, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
||||
} finally {
|
||||
this.delegate.didOpenElement();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
|
|
@ -1290,88 +1290,4 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
|||
}
|
||||
}
|
||||
|
||||
export interface IEditorOpenHandler {
|
||||
(
|
||||
group: IEditorGroup,
|
||||
delegate: () => Promise<IEditorPane | undefined>,
|
||||
): Promise<IEditorPane | undefined>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The delegating workbench editor service can be used to override the behaviour of the openEditor()
|
||||
* method by providing a IEditorOpenHandler. All calls are being delegated to the existing editor
|
||||
* service otherwise.
|
||||
*/
|
||||
export class DelegatingEditorService implements IEditorService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
private editorOpenHandler: IEditorOpenHandler,
|
||||
@IEditorService private editorService: EditorService
|
||||
) { }
|
||||
|
||||
openEditor(editor: IEditorInput, options?: IEditorOptions, group?: OpenInEditorGroup): Promise<IEditorPane | undefined>;
|
||||
openEditor(editor: IResourceEditorInput | IUntitledTextResourceEditorInput, group?: OpenInEditorGroup): Promise<ITextEditorPane | undefined>;
|
||||
openEditor(editor: IResourceDiffEditorInput, group?: OpenInEditorGroup): Promise<ITextDiffEditorPane | undefined>;
|
||||
async openEditor(editor: IEditorInput | IResourceEditorInputType, optionsOrGroup?: IEditorOptions | OpenInEditorGroup, group?: OpenInEditorGroup): Promise<IEditorPane | undefined> {
|
||||
const result = this.editorService.doResolveEditorOpenRequest(editor, optionsOrGroup, group);
|
||||
if (result) {
|
||||
const [resolvedGroup, resolvedEditor, resolvedOptions] = result;
|
||||
|
||||
return this.editorOpenHandler(resolvedGroup, () => this.editorService.openEditor(resolvedEditor, resolvedOptions, resolvedGroup));
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
//#region Delegate to IEditorService
|
||||
|
||||
get onDidActiveEditorChange(): Event<void> { return this.editorService.onDidActiveEditorChange; }
|
||||
get onDidVisibleEditorsChange(): Event<void> { return this.editorService.onDidVisibleEditorsChange; }
|
||||
get onDidCloseEditor(): Event<IEditorCloseEvent> { return this.editorService.onDidCloseEditor; }
|
||||
|
||||
get activeEditor(): IEditorInput | undefined { return this.editorService.activeEditor; }
|
||||
get activeEditorPane(): IVisibleEditorPane | undefined { return this.editorService.activeEditorPane; }
|
||||
get activeTextEditorControl(): ICodeEditor | IDiffEditor | undefined { return this.editorService.activeTextEditorControl; }
|
||||
get activeTextEditorMode(): string | undefined { return this.editorService.activeTextEditorMode; }
|
||||
get visibleEditors(): readonly IEditorInput[] { return this.editorService.visibleEditors; }
|
||||
get visibleEditorPanes(): readonly IVisibleEditorPane[] { return this.editorService.visibleEditorPanes; }
|
||||
get visibleTextEditorControls(): readonly (ICodeEditor | IDiffEditor)[] { return this.editorService.visibleTextEditorControls; }
|
||||
get editors(): readonly IEditorInput[] { return this.editorService.editors; }
|
||||
get count(): number { return this.editorService.count; }
|
||||
|
||||
getEditors(order: EditorsOrder, options?: { excludeSticky?: boolean }): readonly IEditorIdentifier[] { return this.editorService.getEditors(order, options); }
|
||||
|
||||
openEditors(editors: IEditorInputWithOptions[], group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise<IEditorPane[]>;
|
||||
openEditors(editors: IResourceEditorInputType[], group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise<IEditorPane[]>;
|
||||
openEditors(editors: Array<IEditorInputWithOptions | IResourceEditorInputType>, group?: OpenInEditorGroup, options?: IOpenEditorsOptions): Promise<IEditorPane[]> {
|
||||
return this.editorService.openEditors(editors, group, options);
|
||||
}
|
||||
|
||||
replaceEditors(editors: IResourceEditorReplacement[], group: IEditorGroup | GroupIdentifier): Promise<void>;
|
||||
replaceEditors(editors: IEditorReplacement[], group: IEditorGroup | GroupIdentifier): Promise<void>;
|
||||
replaceEditors(editors: Array<IEditorReplacement | IResourceEditorReplacement>, group: IEditorGroup | GroupIdentifier): Promise<void> {
|
||||
return this.editorService.replaceEditors(editors, group);
|
||||
}
|
||||
|
||||
isOpened(editor: IResourceEditorInputIdentifier): boolean { return this.editorService.isOpened(editor); }
|
||||
|
||||
findEditors(resource: URI): readonly IEditorIdentifier[];
|
||||
findEditors(resource: IResourceEditorInputIdentifier): readonly IEditorIdentifier[];
|
||||
findEditors(resource: URI, group: IEditorGroup | GroupIdentifier): readonly IEditorInput[];
|
||||
findEditors(resource: IResourceEditorInputIdentifier, group: IEditorGroup | GroupIdentifier): IEditorInput | undefined;
|
||||
findEditors(arg1: URI | IResourceEditorInputIdentifier, arg2?: IEditorGroup | GroupIdentifier): readonly IEditorIdentifier[] | readonly IEditorInput[] | IEditorInput | undefined { return this.editorService.findEditors(arg1, arg2); }
|
||||
|
||||
createEditorInput(input: IResourceEditorInputType): EditorInput { return this.editorService.createEditorInput(input); }
|
||||
|
||||
save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise<boolean> { return this.editorService.save(editors, options); }
|
||||
saveAll(options?: ISaveAllEditorsOptions): Promise<boolean> { return this.editorService.saveAll(options); }
|
||||
|
||||
revert(editors: IEditorIdentifier | IEditorIdentifier[], options?: IRevertOptions): Promise<boolean> { return this.editorService.revert(editors, options); }
|
||||
revertAll(options?: IRevertAllEditorsOptions): Promise<boolean> { return this.editorService.revertAll(options); }
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
registerSingleton(IEditorService, EditorService);
|
||||
|
|
|
@ -7,12 +7,10 @@ import * as assert from 'assert';
|
|||
import { EditorActivation, EditorOverride } from 'vs/platform/editor/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { EditorsOrder, IResourceDiffEditorInput, isResourceDiffEditorInput } from 'vs/workbench/common/editor';
|
||||
import { workbenchInstantiationService, TestServiceAccessor, registerTestEditor, TestFileEditorInput, ITestInstantiationService, registerTestResourceEditor, registerTestSideBySideEditor, createEditorPart } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TextResourceEditorInput } from 'vs/workbench/common/editor/textResourceEditorInput';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { EditorService, DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { IEditorGroup, IEditorGroupsService, GroupDirection, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
|
||||
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
@ -27,7 +25,6 @@ import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
|
|||
import { UntitledTextEditorModel } from 'vs/workbench/services/untitled/common/untitledTextEditorModel';
|
||||
import { NullFileSystemProvider } from 'vs/platform/files/test/common/nullFileSystemProvider';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { MockScopableContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
|
||||
import { RegisteredEditorPriority } from 'vs/workbench/services/editor/common/editorOverrideService';
|
||||
|
@ -493,38 +490,6 @@ suite('EditorService', () => {
|
|||
assert.strictEqual(untypedDiffInput.modifiedInput.resource?.toString(), resourceDiffInput.modifiedInput.resource.toString());
|
||||
});
|
||||
|
||||
test('delegate', function (done) {
|
||||
const instantiationService = workbenchInstantiationService();
|
||||
|
||||
class MyEditor extends EditorPane {
|
||||
|
||||
constructor(id: string) {
|
||||
super(id, undefined!, new TestThemeService(), new TestStorageService());
|
||||
}
|
||||
|
||||
override getId(): string {
|
||||
return 'myEditor';
|
||||
}
|
||||
|
||||
layout(): void { }
|
||||
|
||||
createEditor(): void { }
|
||||
}
|
||||
|
||||
const editor = instantiationService.createInstance(MyEditor, 'my.editor');
|
||||
|
||||
const input = instantiationService.createInstance(TextResourceEditorInput, URI.parse('my://resource-delegate'), 'name', 'description', undefined, undefined);
|
||||
const delegate = instantiationService.createInstance(DelegatingEditorService, async (group, delegate) => {
|
||||
assert.ok(group);
|
||||
|
||||
done();
|
||||
|
||||
return editor;
|
||||
});
|
||||
|
||||
delegate.openEditor(input);
|
||||
});
|
||||
|
||||
test('close editor does not dispose when editor opened in other group', async () => {
|
||||
const [part, service] = await createEditorService();
|
||||
|
||||
|
|
Loading…
Reference in a new issue