Skip to content

Commit

Permalink
feat: implement Tab APIs (#3413)
Browse files Browse the repository at this point in the history
  • Loading branch information
MMhunter authored Apr 10, 2024
1 parent 3f4b343 commit 0c8a216
Show file tree
Hide file tree
Showing 18 changed files with 2,134 additions and 753 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { LabelService, MaybePromise, URI, WithEventBus } from '@opensumi/ide-cor
import { MergeEditorService } from '@opensumi/ide-monaco/lib/browser/contrib/merge-editor/merge-editor.service';

import { IResource, IResourceProvider } from '../../common';

@Injectable()
export class MergeEditorResourceProvider extends WithEventBus implements IResourceProvider {
scheme = 'mergeEditor';
Expand Down
5 changes: 5 additions & 0 deletions packages/editor/src/browser/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export interface IEditorComponent<MetaData = any> {

// 渲染模式 默认为 ONE_PER_GROUP
renderMode?: EditorComponentRenderMode;

/**
* 有关该 component 的额外信息
*/
metadata?: Record<string, any>;
}

export type EditorSide = 'bottom' | 'top';
Expand Down
97 changes: 89 additions & 8 deletions packages/editor/src/browser/workbench-editor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,10 @@ export class WorkbenchEditorServiceImpl extends WithEventBus implements Workbenc
return this.editorGroups.reduce((pre, cur) => pre + cur.calcDirtyCount(countedUris), 0);
}

private editorGroupIdGen = 0;

createEditorGroup(): EditorGroup {
const editorGroup = this.injector.get(EditorGroup, [this.generateRandomEditorGroupName()]);
const editorGroup = this.injector.get(EditorGroup, [this.generateRandomEditorGroupName(), this.editorGroupIdGen++]);
this.editorGroups.push(editorGroup);
const currentWatchDisposer = new Disposable(
editorGroup.onDidEditorGroupBodyChanged(() => {
Expand Down Expand Up @@ -661,6 +663,12 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
_onDidEditorGroupTabChanged = new EventEmitter<void>();
onDidEditorGroupTabChanged: Event<void> = this._onDidEditorGroupTabChanged.event;

/**
* 当编辑器的tab部分发生变更
*/
_onDidEditorGroupTabOperation = new EventEmitter<IResourceTabOperation>();
onDidEditorGroupTabOperation: Event<IResourceTabOperation> = this._onDidEditorGroupTabOperation.event;

/**
* 当编辑器的主体部分发生变更
*/
Expand Down Expand Up @@ -758,7 +766,7 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {

private _currentOrPreviousFocusedEditor: IEditor | null;

constructor(public readonly name: string) {
constructor(public readonly name: string, public readonly groupId: number) {
super();
this.eventBus.on(ResizeEvent, (e: ResizeEvent) => {
if (e.payload.slotLocation === getSlotLocation('@opensumi/ide-editor', this.config.layoutConfig)) {
Expand Down Expand Up @@ -1351,6 +1359,7 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
} else {
const oldOpenType = this._currentOpenType;
const oldResource = this._currentResource;
let tabOperationToFire: IResourceTabOperation | null = null;
let resource: IResource | null | undefined = this.resources.find((r) => r.uri.toString() === uri.toString());
if (!resource) {
// open new resource
Expand All @@ -1372,13 +1381,28 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
if (options && options.index !== undefined && options.index < this.resources.length) {
replaceResource = this.resources[options.index];
this.resources.splice(options.index, 0, resource);
tabOperationToFire = {
type: 'open',
resource,
index: options.index,
};
} else {
if (this.currentResource) {
const currentIndex = this.resources.indexOf(this.currentResource);
this.resources.splice(currentIndex + 1, 0, resource);
tabOperationToFire = {
type: 'open',
resource,
index: currentIndex + 1,
};
replaceResource = this.currentResource;
} else {
this.resources.push(resource);
tabOperationToFire = {
type: 'open',
resource,
index: this.resources.length - 1,
};
}
}
if (previewMode) {
Expand Down Expand Up @@ -1418,7 +1442,13 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
}, 60);
this.notifyTabChanged();
this.notifyBodyChanged();
await this.displayResourceComponent(resource, options);
try {
await this.displayResourceComponent(resource, options);
} finally {
if (tabOperationToFire) {
this._onDidEditorGroupTabOperation.fire(tabOperationToFire);
}
}
this._currentOrPreviousFocusedEditor = this.currentEditor;

clearTimeout(delayTimer);
Expand Down Expand Up @@ -1765,6 +1795,10 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
}
}

public getLastOpenType(resource: IResource) {
return this.cachedResourcesActiveOpenTypes.get(resource.uri.toString());
}

private async resolveOpenType(
resource: IResource,
options: IResourceOpenOptions,
Expand Down Expand Up @@ -1793,16 +1827,21 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
treatAsNotCurrent?: boolean;
force?: boolean;
} = {},
) {
): Promise<boolean> {
const index = this.resources.findIndex((r) => r.uri.toString() === uri.toString());
if (index !== -1) {
const resource = this.resources[index];
if (!force) {
if (!(await this.shouldClose(resource))) {
return;
return false;
}
}
this.resources.splice(index, 1);
this._onDidEditorGroupTabOperation.fire({
type: 'close',
resource,
index,
});
this.eventBus.fire(
new EditorGroupCloseEvent({
group: this,
Expand Down Expand Up @@ -1853,6 +1892,7 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
}
this.availableOpenTypes = [];
}
return true;
}

private removeResouceFromActiveComponents(resource: IResource) {
Expand Down Expand Up @@ -1914,22 +1954,29 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
/**
* 关闭全部
*/
async closeAll() {
async closeAll(): Promise<boolean> {
for (const resource of this.resources) {
if (!(await this.shouldClose(resource))) {
return;
return false;
}
}
const closed = this.resources.splice(0, this.resources.length);
closed.forEach((resource) => {
// reverse, 发送事件需要从后往前
closed.reverse().forEach((resource, index) => {
this.clearResourceOnClose(resource);
this._onDidEditorGroupTabOperation.fire({
type: 'close',
resource,
index,
});
});
this.activeComponents.clear();
if (this.workbenchEditorService.editorGroups.length > 1) {
this.dispose();
}
this.previewURI = null;
this.backToEmpty();
return true;
}

/**
Expand Down Expand Up @@ -1966,6 +2013,13 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
}
}
this.resources.splice(index + 1);
resourcesToClose.reverse().forEach((resource, i) => {
this._onDidEditorGroupTabOperation.fire({
type: 'close',
resource,
index: index + 1 + (resourcesToClose.length - 1 - i),
});
});
for (const resource of resourcesToClose) {
this.clearResourceOnClose(resource);
}
Expand All @@ -1992,7 +2046,15 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
return;
}
}
const oldResources = this.resources;
this.resources = [this.resources[index]];
resourcesToClose.reverse().forEach((resource) => {
this._onDidEditorGroupTabOperation.fire({
type: 'close',
resource,
index: oldResources.indexOf(resource),
});
});
for (const resource of resourcesToClose) {
this.clearResourceOnClose(resource);
}
Expand Down Expand Up @@ -2063,10 +2125,22 @@ export class EditorGroup extends WithEventBus implements IGridEditorGroup {
if (sourceIndex > targetIndex) {
this.resources.splice(sourceIndex, 1);
this.resources.splice(targetIndex, 0, sourceResource);
this._onDidEditorGroupTabOperation.fire({
type: 'move',
resource: sourceResource,
oldIndex: sourceIndex,
index: targetIndex,
});
await this.open(uri, { preview: false });
} else if (sourceIndex < targetIndex) {
this.resources.splice(targetIndex + 1, 0, sourceResource);
this.resources.splice(sourceIndex, 1);
this._onDidEditorGroupTabOperation.fire({
type: 'move',
resource: sourceResource,
oldIndex: sourceIndex,
index: targetIndex,
});
await this.open(uri, { preview: false });
}
}
Expand Down Expand Up @@ -2318,3 +2392,10 @@ function findSuitableOpenType(
function openTypeSimilar(a: IEditorOpenType, b: IEditorOpenType) {
return a.type === b.type && (a.type !== EditorOpenType.component || a.componentId === b.componentId);
}

export interface IResourceTabOperation {
type: 'open' | 'close' | 'move';
resource: IResource;
oldIndex?: number;
index: number;
}
9 changes: 7 additions & 2 deletions packages/editor/src/common/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,16 +386,21 @@ export interface IEditorGroup {
/**
* 关闭指定的 uri 的 tab, 如果存在的话
* @param uri
* @return 是否成功关闭,不存在的话返回 true
*/
close(uri: URI): Promise<void>;
close(uri: URI): Promise<boolean>;

getState(): IEditorGroupState;

restoreState(IEditorGroupState): Promise<void>;

saveAll(): Promise<void>;

closeAll(): Promise<void>;
/**
* 关闭指定所有的 tab
* @return 是否成功关闭
*/
closeAll(): Promise<boolean>;

/**
* 保存当前的 tab 的文件 (如果它能被保存的话)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ export class MainThreadWebview extends Disposable implements IMainThreadWebview
longLive: webviewOptions.retainContextWhenHidden,
},
id,
{
extWebview: viewType,
},
);
const viewColumn = editorWebview.group ? editorWebview.group.index + 1 : persistedWebviewPanelMeta.viewColumn;
await this.doCreateWebviewPanel(id, viewType, title, { viewColumn }, webviewOptions, extensionInfo, state);
Expand Down Expand Up @@ -346,6 +349,9 @@ export class MainThreadWebview extends Disposable implements IMainThreadWebview
longLive: options.retainContextWhenHidden,
},
id,
{
extWebview: viewType,
},
);
const webviewPanel = new WebviewPanel(
id,
Expand Down
Loading

0 comments on commit 0c8a216

Please sign in to comment.