Skip to content

Commit

Permalink
Close duplicate editors on same tabbar (#12147)
Browse files Browse the repository at this point in the history
  • Loading branch information
colin-grant-work authored Feb 9, 2023
1 parent 52d6e87 commit 62ada24
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 30 deletions.
33 changes: 5 additions & 28 deletions packages/editor-preview/src/browser/editor-preview-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,17 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { Message } from '@theia/core/shared/@phosphor/messaging';
import { DockPanel, TabBar, Widget, PINNED_CLASS } from '@theia/core/lib/browser';
import { TabBar, Widget, PINNED_CLASS } from '@theia/core/lib/browser';
import { EditorWidget, TextEditor } from '@theia/editor/lib/browser';
import { Disposable, DisposableCollection, Emitter, SelectionService, UNTITLED_SCHEME } from '@theia/core/lib/common';
import { find } from '@theia/core/shared/@phosphor/algorithm';

const PREVIEW_TITLE_CLASS = 'theia-editor-preview-title-unpinned';
export class EditorPreviewWidget extends EditorWidget {
protected _isPreview = false;
protected lastTabbar: TabBar<Widget> | undefined;

protected readonly onDidChangePreviewStateEmitter = new Emitter<void>();
readonly onDidChangePreviewState = this.onDidChangePreviewStateEmitter.event;

protected readonly toDisposeOnLocationChange = new DisposableCollection();

get isPreview(): boolean {
return this._isPreview;
}
Expand All @@ -40,7 +35,6 @@ export class EditorPreviewWidget extends EditorWidget {
) {
super(editor, selectionService);
this.toDispose.push(this.onDidChangePreviewStateEmitter);
this.toDispose.push(this.toDisposeOnLocationChange);
}

initializePreview(): void {
Expand All @@ -66,34 +60,17 @@ export class EditorPreviewWidget extends EditorWidget {
convertToNonPreview(): void {
if (this._isPreview) {
this._isPreview = false;
this.toDisposeOnLocationChange.dispose();
this.lastTabbar = undefined;
this.currentTabbar = undefined;
this.title.className = this.title.className.replace(PREVIEW_TITLE_CLASS, '');
this.onDidChangePreviewStateEmitter.fire();
this.onDidChangePreviewStateEmitter.dispose();
}
}

protected override onAfterAttach(msg: Message): void {
super.onAfterAttach(msg);
protected override handleTabBarChange(oldTabBar?: TabBar<Widget> | undefined, newTabBar?: TabBar<Widget> | undefined): void {
super.handleTabBarChange(oldTabBar, newTabBar);
if (this._isPreview) {
this.checkForTabbarChange();
}
}

protected checkForTabbarChange(): void {
const { parent } = this;
if (parent instanceof DockPanel) {
this.toDisposeOnLocationChange.dispose();
const newTabbar = find(parent.tabBars(), tabbar => !!tabbar.titles.find(title => title === this.title));
if (this.lastTabbar && this.lastTabbar !== newTabbar) {
this.convertToNonPreview();
} else {
this.lastTabbar = newTabbar;
const listener = () => this.checkForTabbarChange();
parent.layoutModified.connect(listener);
this.toDisposeOnLocationChange.push(Disposable.create(() => parent.layoutModified.disconnect(listener)));
}
if (oldTabBar && newTabBar) { this.convertToNonPreview(); }
}
}

Expand Down
36 changes: 34 additions & 2 deletions packages/editor/src/browser/editor-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

import { Disposable, SelectionService, Event, UNTITLED_SCHEME } from '@theia/core/lib/common';
import { Widget, BaseWidget, Message, Saveable, SaveableSource, Navigatable, StatefulWidget, lock } from '@theia/core/lib/browser';
import { Disposable, SelectionService, Event, UNTITLED_SCHEME, DisposableCollection } from '@theia/core/lib/common';
import { Widget, BaseWidget, Message, Saveable, SaveableSource, Navigatable, StatefulWidget, lock, TabBar, DockPanel } from '@theia/core/lib/browser';
import URI from '@theia/core/lib/common/uri';
import { find } from '@theia/core/shared/@phosphor/algorithm';
import { TextEditor } from './editor';

export class EditorWidget extends BaseWidget implements SaveableSource, Navigatable, StatefulWidget {

protected toDisposeOnTabbarChange = new DisposableCollection();
protected currentTabbar: TabBar<Widget> | undefined;

constructor(
readonly editor: TextEditor,
protected readonly selectionService: SelectionService
Expand All @@ -31,6 +35,7 @@ export class EditorWidget extends BaseWidget implements SaveableSource, Navigata
lock(this.title);
}
this.toDispose.push(this.editor);
this.toDispose.push(this.toDisposeOnTabbarChange);
this.toDispose.push(this.editor.onSelectionChanged(() => this.setSelection()));
this.toDispose.push(this.editor.onFocusChanged(() => this.setSelection()));
this.toDispose.push(Disposable.create(() => {
Expand Down Expand Up @@ -68,6 +73,33 @@ export class EditorWidget extends BaseWidget implements SaveableSource, Navigata
if (this.isVisible) {
this.editor.refresh();
}
this.checkForTabbarChange();
}

protected checkForTabbarChange(): void {
const { parent } = this;
if (parent instanceof DockPanel) {
const newTabbar = find(parent.tabBars(), tabbar => !!tabbar.titles.find(title => title === this.title));
if (this.currentTabbar !== newTabbar) {
this.toDisposeOnTabbarChange.dispose();
const listener = () => this.checkForTabbarChange();
parent.layoutModified.connect(listener);
this.toDisposeOnTabbarChange.push(Disposable.create(() => parent.layoutModified.disconnect(listener)));
const last = this.currentTabbar;
this.currentTabbar = newTabbar;
this.handleTabBarChange(last, newTabbar);
}
}
}

protected handleTabBarChange(oldTabBar?: TabBar<Widget>, newTabBar?: TabBar<Widget>): void {
const ownSaveable = Saveable.get(this);
const competingEditors = ownSaveable && newTabBar?.titles.filter(title => title !== this.title
&& (title.owner instanceof EditorWidget)
&& title.owner.editor.uri.isEqual(this.editor.uri)
&& Saveable.get(title.owner) === ownSaveable
);
competingEditors?.forEach(title => title.owner.close());
}

protected override onAfterShow(msg: Message): void {
Expand Down

0 comments on commit 62ada24

Please sign in to comment.