Files
theia-code-os/packages/memory-inspector/src/browser/utils/memory-widget-manager.ts
mawkone 8bb5110148
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled
deploy: current vibn theia state
Made-with: Cursor
2026-02-27 12:01:08 -08:00

180 lines
7.7 KiB
TypeScript

/********************************************************************************
* Copyright (C) 2021 Ericsson and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
********************************************************************************/
import { Disposable, DisposableCollection, Emitter, MessageService } from '@theia/core';
import { ApplicationShell, OpenViewArguments, WidgetManager } from '@theia/core/lib/browser';
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
import { MemoryDiffTableWidget, MemoryDiffWidget } from '../diff-widget/memory-diff-table-widget';
import { MemoryWidget } from '../memory-widget/memory-widget';
import { RegisterWidget } from '../register-widget/register-widget-types';
import { MemoryDiffWidgetData, MemoryWidgetOptions } from './memory-widget-utils';
import { nls } from '@theia/core/lib/common/nls';
import { EditableMemoryWidget } from '../editable-widget/memory-editable-table-widget';
@injectable()
export class MemoryWidgetManager implements Disposable {
protected createdWidgetCount = 0;
protected widgetDisplayId = 0;
protected readonly toDispose = new DisposableCollection();
@inject(WidgetManager) protected readonly widgetManager: WidgetManager;
@inject(ApplicationShell) protected readonly shell: ApplicationShell;
@inject(MessageService) protected readonly messageService: MessageService;
protected readonly onNewWidgetCreated = new Emitter<MemoryWidget>();
readonly onDidCreateNewWidget = this.onNewWidgetCreated.event;
protected readonly onSelectedWidgetChanged = new Emitter<MemoryWidget | undefined>();
readonly onDidChangeSelectedWidget = this.onSelectedWidgetChanged.event;
protected readonly onChangedEmitter = new Emitter<void>();
readonly onChanged = this.onChangedEmitter.event;
protected readonly _availableWidgets = new Map<string, MemoryWidget>();
protected _focusedWidget: MemoryWidget | undefined;
protected _canCompare = false;
get availableWidgets(): MemoryWidget[] {
return Array.from(this._availableWidgets.values());
}
get canCompare(): boolean {
return this._canCompare;
}
@postConstruct()
protected init(): void {
this.toDispose.pushAll([
this.shell.onDidChangeActiveWidget(({ newValue }) => {
if (newValue instanceof MemoryWidget) {
this._focusedWidget = newValue;
}
}),
this.widgetManager.onDidCreateWidget(e => {
const { widget } = e;
if (widget instanceof MemoryWidget) {
this._availableWidgets.set(widget.id, widget);
this.toDispose.push(widget.onDidDispose(() => {
this._availableWidgets.delete(widget.id);
if (widget === this._focusedWidget) {
this.focusedWidget = undefined;
}
this.onChangedEmitter.fire();
}));
}
}),
this.onChanged(() => this.setCanCompare()),
this.onNewWidgetCreated,
this.onChangedEmitter,
this.onSelectedWidgetChanged,
]);
}
get focusedWidget(): MemoryWidget | undefined {
return this._focusedWidget ?? this._availableWidgets.values().next().value;
}
set focusedWidget(title: MemoryWidget | undefined) {
this._focusedWidget = title;
this.onSelectedWidgetChanged.fire(title);
}
protected setCanCompare(): void {
this._canCompare = this.availableWidgets.filter(widget => !RegisterWidget.is(widget) && !MemoryDiffWidget.is(widget)).length > 1;
}
async createNewMemoryWidget<T extends MemoryWidget>(kind: 'register' | 'memory' | 'writable' | string = 'memory'): Promise<T> {
this.widgetDisplayId = this._availableWidgets.size !== 0 ? this.widgetDisplayId + 1 : 1;
const widget = await this.getWidgetOfKind<T>(kind);
this._availableWidgets.set(widget.id, widget);
widget.title.changed.connect(() => this.onChangedEmitter.fire());
widget.activate();
this.fireNewWidget(widget);
return widget;
}
protected getWidgetOfKind<T extends MemoryWidget>(kind: string): Promise<T> {
const widgetId = this.getWidgetIdForKind(kind);
const options = this.getWidgetOptionsForId(widgetId);
return this.widgetManager.getOrCreateWidget<T>(widgetId, options);
}
protected getWidgetIdForKind(kind: string): string {
switch (kind) {
case 'register':
case RegisterWidget.ID:
return RegisterWidget.ID;
case 'writable':
case EditableMemoryWidget.ID:
return EditableMemoryWidget.ID;
default:
return MemoryWidget.ID;
}
}
protected getWidgetOptionsForId(widgetId: string): MemoryWidgetOptions {
return { identifier: this.createdWidgetCount += 1, displayId: this.widgetDisplayId };
}
dispose(): void {
this.toDispose.dispose();
}
protected fireNewWidget(widget: MemoryWidget): void {
this.onNewWidgetCreated.fire(widget);
this.onChangedEmitter.fire();
}
async doDiff(options: Omit<MemoryDiffWidgetData, 'dynamic' | 'identifier'>): Promise<MemoryDiffWidget | undefined> {
if (options.beforeBytes.length === 0) {
// eslint-disable-next-line max-len
const beforeBytesMessage = nls.localize('theia/memory-inspector/utils/bytesMessage', 'You must load memory in both widgets you would like to compare. {0} has no memory loaded.', options.titles[0]);
this.messageService.warn(beforeBytesMessage);
return undefined;
} else if (options.afterBytes.length === 0) {
// eslint-disable-next-line max-len
const afterBytesMessage = nls.localize('theia/memory-inspector/utils/afterBytes', 'You must load memory in both widgets you would like to compare. {0} has no memory loaded.', options.titles[1]);
this.messageService.warn(afterBytesMessage);
return undefined;
}
const fullOptions: MemoryDiffWidgetData = { ...options, dynamic: false, identifier: options.titles.join('-') };
const existingWidget = this._availableWidgets.get(MemoryWidget.getIdentifier(fullOptions.identifier.toString())) as MemoryDiffWidget;
if (existingWidget && existingWidget.tableWidget instanceof MemoryDiffTableWidget) {
existingWidget.tableWidget.updateDiffData(options);
}
const widget = existingWidget ?? await this.widgetManager
.getOrCreateWidget<MemoryDiffWidget>(
MemoryDiffWidget.ID,
{ ...options, dynamic: false, identifier: options.titles.join('-') },
);
const tabBar = this.shell.getTabBarFor(widget);
if (!tabBar) {
// The widget is not attached yet, so add it to the shell
const widgetArgs: OpenViewArguments = {
area: 'main',
};
await this.shell.addWidget(widget, widgetArgs);
}
await this.shell.activateWidget(widget.id);
return widget;
}
}