@theia/terminal-manager 1.68.0-next.9 → 1.68.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/terminal-manager-frontend-contribution.d.ts +9 -1
- package/lib/browser/terminal-manager-frontend-contribution.d.ts.map +1 -1
- package/lib/browser/terminal-manager-frontend-contribution.js +45 -5
- package/lib/browser/terminal-manager-frontend-contribution.js.map +1 -1
- package/lib/browser/terminal-manager-frontend-view-contribution.d.ts +6 -1
- package/lib/browser/terminal-manager-frontend-view-contribution.d.ts.map +1 -1
- package/lib/browser/terminal-manager-frontend-view-contribution.js +42 -17
- package/lib/browser/terminal-manager-frontend-view-contribution.js.map +1 -1
- package/lib/browser/terminal-manager-tree-model.d.ts +3 -1
- package/lib/browser/terminal-manager-tree-model.d.ts.map +1 -1
- package/lib/browser/terminal-manager-tree-model.js +45 -34
- package/lib/browser/terminal-manager-tree-model.js.map +1 -1
- package/lib/browser/terminal-manager-tree-widget.d.ts +0 -1
- package/lib/browser/terminal-manager-tree-widget.d.ts.map +1 -1
- package/lib/browser/terminal-manager-tree-widget.js +6 -6
- package/lib/browser/terminal-manager-tree-widget.js.map +1 -1
- package/lib/browser/terminal-manager-types.d.ts +6 -5
- package/lib/browser/terminal-manager-types.d.ts.map +1 -1
- package/lib/browser/terminal-manager-types.js.map +1 -1
- package/lib/browser/terminal-manager-widget.d.ts +13 -1
- package/lib/browser/terminal-manager-widget.d.ts.map +1 -1
- package/lib/browser/terminal-manager-widget.js +107 -71
- package/lib/browser/terminal-manager-widget.js.map +1 -1
- package/package.json +5 -5
- package/src/browser/terminal-manager-frontend-contribution.ts +51 -2
- package/src/browser/terminal-manager-frontend-view-contribution.ts +40 -6
- package/src/browser/terminal-manager-tree-model.ts +35 -31
- package/src/browser/terminal-manager-types.ts +2 -0
- package/src/browser/terminal-manager-widget.ts +90 -44
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { injectable } from '@theia/core/shared/inversify';
|
|
17
|
+
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
18
18
|
import {
|
|
19
19
|
AbstractViewContribution,
|
|
20
20
|
codicon,
|
|
@@ -23,18 +23,24 @@ import {
|
|
|
23
23
|
MAXIMIZED_CLASS,
|
|
24
24
|
Widget,
|
|
25
25
|
} from '@theia/core/lib/browser';
|
|
26
|
-
import { CommandRegistry, Event, MenuModelRegistry, nls } from '@theia/core';
|
|
26
|
+
import { CommandRegistry, Disposable, Event, MenuModelRegistry, nls } from '@theia/core';
|
|
27
27
|
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
28
28
|
import { BOTTOM_AREA_ID } from '@theia/core/lib/browser/shell/theia-dock-panel';
|
|
29
29
|
import { TerminalManagerCommands, TerminalManagerTreeTypes, TERMINAL_MANAGER_TREE_CONTEXT_MENU } from './terminal-manager-types';
|
|
30
30
|
import { TerminalManagerWidget } from './terminal-manager-widget';
|
|
31
31
|
import { TerminalManagerTreeWidget } from './terminal-manager-tree-widget';
|
|
32
32
|
import { ConfirmDialog, Dialog } from '@theia/core/lib/browser/dialogs';
|
|
33
|
+
import { TerminalManagerPreferences } from './terminal-manager-preferences';
|
|
33
34
|
|
|
34
35
|
@injectable()
|
|
35
36
|
export class TerminalManagerFrontendViewContribution extends AbstractViewContribution<TerminalManagerWidget>
|
|
36
37
|
implements TabBarToolbarContribution, KeybindingContribution {
|
|
37
38
|
|
|
39
|
+
@inject(TerminalManagerPreferences)
|
|
40
|
+
protected readonly preferences: TerminalManagerPreferences;
|
|
41
|
+
|
|
42
|
+
protected quickViewDisposable: Disposable | undefined;
|
|
43
|
+
|
|
38
44
|
constructor() {
|
|
39
45
|
super({
|
|
40
46
|
widgetId: TerminalManagerWidget.ID,
|
|
@@ -46,7 +52,17 @@ export class TerminalManagerFrontendViewContribution extends AbstractViewContrib
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
override registerCommands(commands: CommandRegistry): void {
|
|
49
|
-
super.registerCommands(
|
|
55
|
+
// Don't call super.registerCommands() - we manage quick view registration manually
|
|
56
|
+
// based on the terminal.grouping.mode preference
|
|
57
|
+
|
|
58
|
+
this.preferences.ready.then(() => {
|
|
59
|
+
this.updateQuickViewRegistration();
|
|
60
|
+
this.preferences.onPreferenceChanged(change => {
|
|
61
|
+
if (change.preferenceName === 'terminal.grouping.mode') {
|
|
62
|
+
this.updateQuickViewRegistration();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
|
50
66
|
|
|
51
67
|
commands.registerCommand(TerminalManagerCommands.MANAGER_NEW_TERMINAL_GROUP, {
|
|
52
68
|
execute: (
|
|
@@ -152,15 +168,15 @@ export class TerminalManagerFrontendViewContribution extends AbstractViewContrib
|
|
|
152
168
|
primaryButtonText: PRIMARY_BUTTON,
|
|
153
169
|
});
|
|
154
170
|
if (dialogResponse === PRIMARY_BUTTON) {
|
|
155
|
-
|
|
156
|
-
widget.deletePage(id);
|
|
157
|
-
}
|
|
171
|
+
widget.resetView();
|
|
158
172
|
}
|
|
159
173
|
}
|
|
160
174
|
},
|
|
161
175
|
});
|
|
162
176
|
commands.registerCommand(TerminalManagerCommands.MANAGER_OPEN_VIEW, {
|
|
163
177
|
execute: () => this.openView({ activate: true }),
|
|
178
|
+
isEnabled: () => this.isTreeMode(),
|
|
179
|
+
isVisible: () => this.isTreeMode(),
|
|
164
180
|
});
|
|
165
181
|
commands.registerCommand(TerminalManagerCommands.MANAGER_CLOSE_VIEW, {
|
|
166
182
|
isVisible: () => Boolean(this.tryGetWidget()),
|
|
@@ -169,6 +185,24 @@ export class TerminalManagerFrontendViewContribution extends AbstractViewContrib
|
|
|
169
185
|
});
|
|
170
186
|
}
|
|
171
187
|
|
|
188
|
+
protected isTreeMode(): boolean {
|
|
189
|
+
return this.preferences.get('terminal.grouping.mode') === 'tree';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
protected updateQuickViewRegistration(): void {
|
|
193
|
+
if (this.isTreeMode()) {
|
|
194
|
+
if (!this.quickViewDisposable) {
|
|
195
|
+
this.quickViewDisposable = this.quickView?.registerItem({
|
|
196
|
+
label: this.viewLabel,
|
|
197
|
+
open: () => this.openView({ activate: true })
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
this.quickViewDisposable?.dispose();
|
|
202
|
+
this.quickViewDisposable = undefined;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
172
206
|
protected async confirmUserAction(options: { title: string, message: string, primaryButtonText: string }): Promise<string | undefined> {
|
|
173
207
|
const dialog = new ConfirmDialog({
|
|
174
208
|
title: options.title,
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { injectable, postConstruct } from '@theia/core/shared/inversify';
|
|
18
|
-
import { TreeModelImpl, CompositeTreeNode, SelectableTreeNode, DepthFirstTreeIterator } from '@theia/core/lib/browser';
|
|
18
|
+
import { TreeModelImpl, CompositeTreeNode, SelectableTreeNode, DepthFirstTreeIterator, TreeNode } from '@theia/core/lib/browser';
|
|
19
19
|
import { Emitter, nls } from '@theia/core';
|
|
20
20
|
import { TerminalManagerTreeTypes } from './terminal-manager-types';
|
|
21
21
|
|
|
@@ -112,14 +112,10 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
112
112
|
deleteTerminalPage(pageId: TerminalManagerTreeTypes.PageId): void {
|
|
113
113
|
const pageNode = this.getNode(pageId);
|
|
114
114
|
if (TerminalManagerTreeTypes.isPageNode(pageNode) && CompositeTreeNode.is(this.root)) {
|
|
115
|
-
|
|
116
|
-
const groupNode = pageNode.children[pageNode.children.length - 1];
|
|
117
|
-
this.doDeleteTerminalGroup(groupNode, pageNode);
|
|
118
|
-
}
|
|
115
|
+
const isActive = this.activePageNode === pageNode;
|
|
119
116
|
this.onDidDeletePageEmitter.fire(pageNode.id);
|
|
120
117
|
CompositeTreeNode.removeChild(this.root, pageNode);
|
|
121
|
-
|
|
122
|
-
this.refresh();
|
|
118
|
+
this.refreshWithSelection(this.root, undefined, isActive ? pageNode : undefined);
|
|
123
119
|
}
|
|
124
120
|
}
|
|
125
121
|
|
|
@@ -135,10 +131,7 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
135
131
|
this.onDidAddTerminalGroupEmitter.fire({ groupId: groupNode.id, pageId, terminalKey });
|
|
136
132
|
CompositeTreeNode.addChild(groupNode, terminalNode);
|
|
137
133
|
CompositeTreeNode.addChild(pageNode, groupNode);
|
|
138
|
-
this.
|
|
139
|
-
setTimeout(() => {
|
|
140
|
-
this.selectionService.addSelection(terminalNode);
|
|
141
|
-
});
|
|
134
|
+
this.refreshWithSelection(pageNode, terminalNode);
|
|
142
135
|
}
|
|
143
136
|
}
|
|
144
137
|
|
|
@@ -176,17 +169,14 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
176
169
|
if (parentPageNode.children.length === 1) {
|
|
177
170
|
this.deleteTerminalPage(parentPageNode.id);
|
|
178
171
|
} else {
|
|
172
|
+
const isActive = this.activeGroupNode === groupNode;
|
|
179
173
|
this.doDeleteTerminalGroup(groupNode, parentPageNode);
|
|
180
|
-
this.
|
|
174
|
+
this.refreshWithSelection(parentPageNode, undefined, isActive ? groupNode : undefined);
|
|
181
175
|
}
|
|
182
176
|
}
|
|
183
177
|
}
|
|
184
178
|
|
|
185
179
|
protected doDeleteTerminalGroup(group: TerminalManagerTreeTypes.TerminalGroupNode, page: TerminalManagerTreeTypes.PageNode): void {
|
|
186
|
-
while (group.children.length > 0) {
|
|
187
|
-
const terminalNode = group.children[group.children.length - 1];
|
|
188
|
-
this.doDeleteTerminalNode(terminalNode, group);
|
|
189
|
-
}
|
|
190
180
|
this.onDidDeleteTerminalGroupEmitter.fire(group.id);
|
|
191
181
|
CompositeTreeNode.removeChild(page, group);
|
|
192
182
|
}
|
|
@@ -197,12 +187,7 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
197
187
|
const terminalNode = this.createTerminalNode(newTerminalId, groupId);
|
|
198
188
|
CompositeTreeNode.addChild(groupNode, terminalNode);
|
|
199
189
|
this.onDidAddTerminalToGroupEmitter.fire({ terminalId: newTerminalId, groupId });
|
|
200
|
-
this.
|
|
201
|
-
setTimeout(() => {
|
|
202
|
-
if (SelectableTreeNode.is(terminalNode)) {
|
|
203
|
-
this.selectionService.addSelection(terminalNode);
|
|
204
|
-
}
|
|
205
|
-
});
|
|
190
|
+
this.refreshWithSelection(undefined, terminalNode);
|
|
206
191
|
}
|
|
207
192
|
}
|
|
208
193
|
|
|
@@ -229,20 +214,19 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
229
214
|
if (parentGroupNode.children.length === 1) {
|
|
230
215
|
this.deleteTerminalGroup(parentGroupNode.id);
|
|
231
216
|
} else {
|
|
217
|
+
const isActive = this.activeTerminalNode === terminalNode;
|
|
232
218
|
this.doDeleteTerminalNode(terminalNode, parentGroupNode);
|
|
233
|
-
this.
|
|
219
|
+
this.refreshWithSelection(parentGroupNode, undefined, isActive ? terminalNode : undefined);
|
|
234
220
|
}
|
|
235
221
|
}
|
|
236
222
|
}
|
|
237
223
|
|
|
238
224
|
protected doDeleteTerminalNode(node: TerminalManagerTreeTypes.TerminalNode, parent: TerminalManagerTreeTypes.TerminalGroupNode): void {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
CompositeTreeNode.removeChild(parent, node);
|
|
245
|
-
}
|
|
225
|
+
this.onDidDeleteTerminalFromGroupEmitter.fire({
|
|
226
|
+
terminalId: node.id,
|
|
227
|
+
groupId: parent.id,
|
|
228
|
+
});
|
|
229
|
+
CompositeTreeNode.removeChild(parent, node);
|
|
246
230
|
}
|
|
247
231
|
|
|
248
232
|
toggleRenameTerminal(entityId: TerminalManagerTreeTypes.TerminalManagerValidId): void {
|
|
@@ -268,7 +252,6 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
268
252
|
let activeTerminal: TerminalManagerTreeTypes.TerminalNode | undefined = undefined;
|
|
269
253
|
let activeGroup: TerminalManagerTreeTypes.TerminalGroupNode | undefined = undefined;
|
|
270
254
|
let activePage: TerminalManagerTreeTypes.PageNode | undefined = undefined;
|
|
271
|
-
|
|
272
255
|
if (TerminalManagerTreeTypes.isTerminalNode(selectedNode)) {
|
|
273
256
|
activeTerminal = selectedNode;
|
|
274
257
|
const { parent } = activeTerminal;
|
|
@@ -333,4 +316,25 @@ export class TerminalManagerTreeModel extends TreeModelImpl {
|
|
|
333
316
|
this.selectNode(node);
|
|
334
317
|
}
|
|
335
318
|
}
|
|
319
|
+
|
|
320
|
+
protected async refreshWithSelection(refreshTarget?: CompositeTreeNode, selectionTarget?: SelectableTreeNode, selectionReferent?: TreeNode): Promise<void> {
|
|
321
|
+
await this.refresh(refreshTarget);
|
|
322
|
+
if (selectionTarget) {
|
|
323
|
+
return this.selectNode(selectionTarget);
|
|
324
|
+
}
|
|
325
|
+
if (selectionReferent) {
|
|
326
|
+
const { previousSibling, nextSibling } = selectionReferent;
|
|
327
|
+
const toSelect = this.findSelection(previousSibling) ?? this.findSelection(nextSibling);
|
|
328
|
+
if (toSelect) {
|
|
329
|
+
this.selectNode(toSelect);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
protected findSelection(start?: TreeNode): SelectableTreeNode | undefined {
|
|
335
|
+
if (!start) { return undefined; }
|
|
336
|
+
if (TerminalManagerTreeTypes.isTerminalNode(start)) { return start; }
|
|
337
|
+
if (TerminalManagerTreeTypes.isGroupNode(start)) { return start.children.at(0); }
|
|
338
|
+
if (TerminalManagerTreeTypes.isPageNode(start)) { return start.children.at(0)?.children.at(0); }
|
|
339
|
+
}
|
|
336
340
|
}
|
|
@@ -122,6 +122,7 @@ export namespace TerminalManagerTreeTypes {
|
|
|
122
122
|
export const isGroupId = (obj: unknown): obj is GroupId => typeof obj === 'string' && obj.startsWith('group-');
|
|
123
123
|
export interface GroupSplitPanel extends SplitPanel {
|
|
124
124
|
id: GroupId;
|
|
125
|
+
widgets: readonly TerminalWidgetImpl[];
|
|
125
126
|
}
|
|
126
127
|
export interface TerminalGroupNode extends SelectableTreeNode, ExpandableTreeNode {
|
|
127
128
|
terminalGroup: true;
|
|
@@ -137,6 +138,7 @@ export namespace TerminalManagerTreeTypes {
|
|
|
137
138
|
export const isPageId = (obj: unknown): obj is PageId => typeof obj === 'string' && obj.startsWith('page-');
|
|
138
139
|
export interface PageSplitPanel extends SplitPanel {
|
|
139
140
|
id: PageId;
|
|
141
|
+
widgets: readonly GroupSplitPanel[];
|
|
140
142
|
}
|
|
141
143
|
export interface PageNode extends SelectableTreeNode, ExpandableTreeNode {
|
|
142
144
|
page: true;
|
|
@@ -83,13 +83,15 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
83
83
|
static LABEL = nls.localize('theia/terminal-manager/label', 'Terminals');
|
|
84
84
|
|
|
85
85
|
protected panel: SplitPanel;
|
|
86
|
-
|
|
87
86
|
protected pageAndTreeLayout: SplitLayout | undefined;
|
|
88
87
|
protected stateIsSet = false;
|
|
89
88
|
|
|
90
89
|
pagePanels = new Map<TerminalManagerTreeTypes.PageId, TerminalManagerTreeTypes.PageSplitPanel>();
|
|
91
90
|
groupPanels = new Map<TerminalManagerTreeTypes.GroupId, TerminalManagerTreeTypes.GroupSplitPanel>();
|
|
91
|
+
/** By node ID: safer for state restoration. */
|
|
92
92
|
terminalWidgets = new Map<TerminalManagerTreeTypes.TerminalKey, TerminalWidget>();
|
|
93
|
+
/** By terminal ID to work from widget to internal metadata. */
|
|
94
|
+
terminalWidgetIdsToNodeIds = new Map<string, TerminalManagerTreeTypes.TerminalKey>();
|
|
93
95
|
|
|
94
96
|
protected readonly onDidChangeTrackableWidgetsEmitter = new Emitter<Widget[]>();
|
|
95
97
|
readonly onDidChangeTrackableWidgets = this.onDidChangeTrackableWidgetsEmitter.event;
|
|
@@ -133,13 +135,23 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
133
135
|
this.id = TerminalManagerWidget.ID;
|
|
134
136
|
this.title.closable = true;
|
|
135
137
|
this.title.label = TerminalManagerWidget.LABEL;
|
|
138
|
+
this.title.caption = TerminalManagerWidget.LABEL;
|
|
136
139
|
this.node.tabIndex = 0;
|
|
137
140
|
this.registerListeners();
|
|
138
141
|
this.createPageAndTreeLayout();
|
|
139
142
|
}
|
|
140
143
|
|
|
144
|
+
/** Yields all terminal widgets owned by this widget and then closes this widget. */
|
|
145
|
+
*drainWidgets(): IterableIterator<TerminalWidget> {
|
|
146
|
+
for (const [key, widget] of this.terminalWidgets) {
|
|
147
|
+
this.removeTerminalReferenceByNodeId(key);
|
|
148
|
+
yield widget;
|
|
149
|
+
}
|
|
150
|
+
this.close();
|
|
151
|
+
}
|
|
152
|
+
|
|
141
153
|
async populateLayout(force?: boolean): Promise<void> {
|
|
142
|
-
if (!this.stateIsSet || force) {
|
|
154
|
+
if ((!this.stateIsSet && this.terminalWidgets.size === 0) || force) {
|
|
143
155
|
const terminalWidget = await this.createTerminalWidget();
|
|
144
156
|
this.addTerminalPage(terminalWidget);
|
|
145
157
|
this.onDidChangeTrackableWidgetsEmitter.fire(this.getTrackableWidgets());
|
|
@@ -243,7 +255,7 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
243
255
|
}
|
|
244
256
|
|
|
245
257
|
protected override onCloseRequest(msg: Message): void {
|
|
246
|
-
if (this.interceptCloseRequest) {
|
|
258
|
+
if (this.interceptCloseRequest && this.terminalWidgets.size > 0) {
|
|
247
259
|
this.interceptCloseRequest = false;
|
|
248
260
|
this.confirmClose()
|
|
249
261
|
.then(confirmed => {
|
|
@@ -275,19 +287,42 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
275
287
|
}
|
|
276
288
|
|
|
277
289
|
addTerminalPage(widget: Widget): void {
|
|
290
|
+
this.doAddTerminalPage(widget);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
protected doAddTerminalPage(widget: Widget): TerminalManagerTreeTypes.PageSplitPanel | undefined {
|
|
278
294
|
if (widget instanceof TerminalWidgetImpl) {
|
|
279
295
|
const terminalKey = TerminalManagerTreeTypes.generateTerminalKey(widget);
|
|
280
|
-
this.
|
|
281
|
-
this.terminalWidgets.set(terminalKey, widget);
|
|
296
|
+
this.addTerminalReference(widget, terminalKey);
|
|
282
297
|
this.onDidChangeTrackableWidgetsEmitter.fire(this.getTrackableWidgets());
|
|
283
298
|
const groupPanel = this.createTerminalGroupPanel();
|
|
284
299
|
groupPanel.addWidget(widget);
|
|
285
300
|
const pagePanel = this.createPagePanel();
|
|
286
301
|
pagePanel.addWidget(groupPanel);
|
|
287
302
|
this.treeWidget.model.addTerminalPage(terminalKey, groupPanel.id, pagePanel.id);
|
|
303
|
+
return pagePanel;
|
|
288
304
|
}
|
|
289
305
|
}
|
|
290
306
|
|
|
307
|
+
protected addTerminalReference(widget: TerminalWidget, nodeId: TerminalManagerTreeTypes.TerminalKey): void {
|
|
308
|
+
this.terminalWidgets.set(nodeId, widget);
|
|
309
|
+
this.terminalWidgetIdsToNodeIds.set(widget.id, nodeId);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
protected removeTerminalReferenceByWidgetId(widgetId: string): boolean {
|
|
313
|
+
const nodeId = this.terminalWidgetIdsToNodeIds.get(widgetId);
|
|
314
|
+
if (nodeId === undefined) {return false; }
|
|
315
|
+
return this.terminalWidgets.delete(nodeId);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
protected removeTerminalReferenceByNodeId(nodeId: TerminalManagerTreeTypes.TerminalKey): boolean {
|
|
319
|
+
const widget = this.terminalWidgets.get(nodeId);
|
|
320
|
+
if (!widget) {return false; }
|
|
321
|
+
this.terminalWidgets.delete(nodeId);
|
|
322
|
+
this.terminalWidgetIdsToNodeIds.delete(widget.id);
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
|
|
291
326
|
protected createPagePanel(pageId?: TerminalManagerTreeTypes.PageId): TerminalManagerTreeTypes.PageSplitPanel {
|
|
292
327
|
const newPageLayout = new ViewContainerLayout({
|
|
293
328
|
renderer: SplitPanel.defaultRenderer,
|
|
@@ -332,10 +367,25 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
332
367
|
}
|
|
333
368
|
|
|
334
369
|
protected handlePageDeleted(pagePanelId: TerminalManagerTreeTypes.PageId): void {
|
|
335
|
-
this.pagePanels.get(pagePanelId)
|
|
370
|
+
const panel = this.pagePanels.get(pagePanelId);
|
|
371
|
+
if (!panel) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const isLastPanel = this.pagePanels.size === 1;
|
|
375
|
+
if (isLastPanel) {
|
|
376
|
+
this.interceptCloseRequest = false;
|
|
377
|
+
this.close();
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
this.clearGroupReferences(panel);
|
|
381
|
+
panel.dispose();
|
|
336
382
|
this.pagePanels.delete(pagePanelId);
|
|
337
|
-
|
|
338
|
-
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
protected clearGroupReferences(panel: TerminalManagerTreeTypes.PageSplitPanel): void {
|
|
386
|
+
for (const group of panel.widgets) {
|
|
387
|
+
this.clearTerminalReferences(group);
|
|
388
|
+
this.groupPanels.delete(group.id);
|
|
339
389
|
}
|
|
340
390
|
}
|
|
341
391
|
|
|
@@ -345,8 +395,7 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
345
395
|
}
|
|
346
396
|
if (widget instanceof TerminalWidgetImpl) {
|
|
347
397
|
const terminalId = TerminalManagerTreeTypes.generateTerminalKey(widget);
|
|
348
|
-
this.
|
|
349
|
-
this.terminalWidgets.set(terminalId, widget);
|
|
398
|
+
this.addTerminalReference(widget, terminalId);
|
|
350
399
|
this.onDidChangeTrackableWidgetsEmitter.fire(this.getTrackableWidgets());
|
|
351
400
|
const groupPanel = this.createTerminalGroupPanel();
|
|
352
401
|
groupPanel.addWidget(widget);
|
|
@@ -403,22 +452,28 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
403
452
|
|
|
404
453
|
activateWidget(id: string): Widget | undefined {
|
|
405
454
|
const widget = Array.from(this.terminalWidgets.values()).find(terminalWidget => terminalWidget.id === id);
|
|
406
|
-
|
|
407
|
-
widget.activate();
|
|
408
|
-
}
|
|
455
|
+
widget?.activate();
|
|
409
456
|
return widget;
|
|
410
457
|
}
|
|
411
458
|
|
|
412
459
|
protected handleTerminalGroupDeleted(groupPanelId: TerminalManagerTreeTypes.GroupId): void {
|
|
413
|
-
this.groupPanels.get(groupPanelId)
|
|
460
|
+
const panel = this.groupPanels.get(groupPanelId);
|
|
414
461
|
this.groupPanels.delete(groupPanelId);
|
|
462
|
+
if (!panel) { return; }
|
|
463
|
+
this.clearTerminalReferences(panel);
|
|
464
|
+
panel.dispose();
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
protected clearTerminalReferences(panel: TerminalManagerTreeTypes.GroupSplitPanel): void {
|
|
468
|
+
for (const terminal of panel.widgets) {
|
|
469
|
+
this.removeTerminalReferenceByWidgetId(terminal.id);
|
|
470
|
+
}
|
|
415
471
|
}
|
|
416
472
|
|
|
417
473
|
addWidgetToTerminalGroup(widget: Widget, groupId: TerminalManagerTreeTypes.GroupId): void {
|
|
418
474
|
if (widget instanceof TerminalWidgetImpl) {
|
|
419
475
|
const newTerminalId = TerminalManagerTreeTypes.generateTerminalKey(widget);
|
|
420
|
-
this.
|
|
421
|
-
this.terminalWidgets.set(newTerminalId, widget);
|
|
476
|
+
this.addTerminalReference(widget, newTerminalId);
|
|
422
477
|
this.onDidChangeTrackableWidgetsEmitter.fire(this.getTrackableWidgets());
|
|
423
478
|
this.treeWidget.model.addTerminal(newTerminalId, groupId);
|
|
424
479
|
}
|
|
@@ -449,14 +504,10 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
449
504
|
|
|
450
505
|
protected handleTerminalDeleted(terminalId: TerminalManagerTreeTypes.TerminalKey): void {
|
|
451
506
|
const terminalWidget = this.terminalWidgets.get(terminalId);
|
|
452
|
-
|
|
453
|
-
if (!this.terminalsDeletingFromClose.has(terminalId)) {
|
|
507
|
+
if (!terminalWidget?.isDisposed) {
|
|
454
508
|
terminalWidget?.dispose();
|
|
455
509
|
}
|
|
456
|
-
this.
|
|
457
|
-
if (wasActiveWidget) {
|
|
458
|
-
this.activateNextAvailableTerminal(terminalId);
|
|
459
|
-
}
|
|
510
|
+
this.removeTerminalReferenceByNodeId(terminalId);
|
|
460
511
|
}
|
|
461
512
|
|
|
462
513
|
protected handleOnDidChangeActiveWidget(widget: Widget | null): void {
|
|
@@ -535,6 +586,16 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
535
586
|
this.terminalWidgets = new Map();
|
|
536
587
|
}
|
|
537
588
|
|
|
589
|
+
async resetView(): Promise<void> {
|
|
590
|
+
const terminalWidget = await this.createTerminalWidget();
|
|
591
|
+
const page = this.doAddTerminalPage(terminalWidget);
|
|
592
|
+
for (const id of this.pagePanels.keys()) {
|
|
593
|
+
if (id !== page?.id) {
|
|
594
|
+
this.deletePage(id);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
538
599
|
protected iterateAndRestoreLayoutTree(pageLayouts: TerminalManagerWidgetState.PageLayoutData[], treeWidget: TerminalManagerTreeWidget): void {
|
|
539
600
|
for (const pageLayout of pageLayouts) {
|
|
540
601
|
const pageId = pageLayout.id;
|
|
@@ -565,8 +626,7 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
565
626
|
if (!TerminalManagerTreeTypes.isTerminalNode(widgetNode)) {
|
|
566
627
|
throw TerminalManagerWidget.createRestoreError(widgetId);
|
|
567
628
|
}
|
|
568
|
-
this.
|
|
569
|
-
this.registerTerminalCloseListener(widget, widgetId);
|
|
629
|
+
this.addTerminalReference(widget, widgetId);
|
|
570
630
|
this.onDidChangeTrackableWidgetsEmitter.fire(this.getTrackableWidgets());
|
|
571
631
|
groupPanel.addWidget(widget);
|
|
572
632
|
}
|
|
@@ -646,26 +706,6 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
646
706
|
return fullLayoutData;
|
|
647
707
|
}
|
|
648
708
|
|
|
649
|
-
protected registerTerminalCloseListener(widget: TerminalWidget, terminalKey: TerminalManagerTreeTypes.TerminalKey): void {
|
|
650
|
-
const originalOnCloseRequest = widget['onCloseRequest'].bind(widget);
|
|
651
|
-
widget['onCloseRequest'] = (msg: Message) => {
|
|
652
|
-
const wasActiveWidget = this.shell.activeWidget === widget;
|
|
653
|
-
if (wasActiveWidget) {
|
|
654
|
-
this.activateNextAvailableTerminal(terminalKey);
|
|
655
|
-
}
|
|
656
|
-
originalOnCloseRequest(msg);
|
|
657
|
-
};
|
|
658
|
-
const disposable = widget.onTerminalDidClose(() => {
|
|
659
|
-
this.terminalsDeletingFromClose.add(terminalKey);
|
|
660
|
-
try {
|
|
661
|
-
this.treeWidget.model.deleteTerminalNode(terminalKey);
|
|
662
|
-
} finally {
|
|
663
|
-
this.terminalsDeletingFromClose.delete(terminalKey);
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
this.toDispose.push(disposable);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
709
|
protected activateNextAvailableTerminal(excludeTerminalKey: TerminalManagerTreeTypes.TerminalKey): void {
|
|
670
710
|
const remainingTerminals = Array.from(this.terminalWidgets.entries()).filter(([key]) => key !== excludeTerminalKey);
|
|
671
711
|
if (remainingTerminals.length > 0) {
|
|
@@ -683,4 +723,10 @@ export class TerminalManagerWidget extends BaseWidget implements StatefulWidget,
|
|
|
683
723
|
this.shell.activateWidget(this.id);
|
|
684
724
|
}
|
|
685
725
|
}
|
|
726
|
+
|
|
727
|
+
override dispose(): void {
|
|
728
|
+
this.toDispose.dispose();
|
|
729
|
+
super.dispose();
|
|
730
|
+
this.terminalWidgets.clear();
|
|
731
|
+
}
|
|
686
732
|
}
|