@theia/terminal-manager 1.67.0-next.86
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/README.md +31 -0
- package/lib/browser/terminal-manager-frontend-contribution.d.ts +25 -0
- package/lib/browser/terminal-manager-frontend-contribution.d.ts.map +1 -0
- package/lib/browser/terminal-manager-frontend-contribution.js +173 -0
- package/lib/browser/terminal-manager-frontend-contribution.js.map +1 -0
- package/lib/browser/terminal-manager-frontend-module.d.ts +5 -0
- package/lib/browser/terminal-manager-frontend-module.d.ts.map +1 -0
- package/lib/browser/terminal-manager-frontend-module.js +55 -0
- package/lib/browser/terminal-manager-frontend-module.js.map +1 -0
- package/lib/browser/terminal-manager-frontend-view-contribution.d.ts +27 -0
- package/lib/browser/terminal-manager-frontend-view-contribution.d.ts.map +1 -0
- package/lib/browser/terminal-manager-frontend-view-contribution.js +278 -0
- package/lib/browser/terminal-manager-frontend-view-contribution.js.map +1 -0
- package/lib/browser/terminal-manager-preferences.d.ts +12 -0
- package/lib/browser/terminal-manager-preferences.d.ts.map +1 -0
- package/lib/browser/terminal-manager-preferences.js +42 -0
- package/lib/browser/terminal-manager-preferences.js.map +1 -0
- package/lib/browser/terminal-manager-tree-model.d.ts +71 -0
- package/lib/browser/terminal-manager-tree-model.d.ts.map +1 -0
- package/lib/browser/terminal-manager-tree-model.js +299 -0
- package/lib/browser/terminal-manager-tree-model.js.map +1 -0
- package/lib/browser/terminal-manager-tree-widget.d.ts +40 -0
- package/lib/browser/terminal-manager-tree-widget.d.ts.map +1 -0
- package/lib/browser/terminal-manager-tree-widget.js +276 -0
- package/lib/browser/terminal-manager-tree-widget.js.map +1 -0
- package/lib/browser/terminal-manager-types.d.ts +77 -0
- package/lib/browser/terminal-manager-types.d.ts.map +1 -0
- package/lib/browser/terminal-manager-types.js +117 -0
- package/lib/browser/terminal-manager-types.js.map +1 -0
- package/lib/browser/terminal-manager-widget.d.ts +108 -0
- package/lib/browser/terminal-manager-widget.d.ts.map +1 -0
- package/lib/browser/terminal-manager-widget.js +616 -0
- package/lib/browser/terminal-manager-widget.js.map +1 -0
- package/lib/package.spec.d.ts +1 -0
- package/lib/package.spec.d.ts.map +1 -0
- package/lib/package.spec.js +26 -0
- package/lib/package.spec.js.map +1 -0
- package/package.json +40 -0
- package/src/browser/terminal-manager-frontend-contribution.ts +164 -0
- package/src/browser/terminal-manager-frontend-module.ts +64 -0
- package/src/browser/terminal-manager-frontend-view-contribution.ts +309 -0
- package/src/browser/terminal-manager-preferences.ts +52 -0
- package/src/browser/terminal-manager-tree-model.ts +336 -0
- package/src/browser/terminal-manager-tree-widget.tsx +305 -0
- package/src/browser/terminal-manager-types.ts +173 -0
- package/src/browser/terminal-manager-widget.ts +686 -0
- package/src/browser/terminal-manager.css +51 -0
- package/src/package.spec.ts +27 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2017 Ericsson and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
/* note: this bogus test file is required so that
|
|
17
|
+
we are able to run mocha unit tests on this
|
|
18
|
+
package, without having any actual unit tests in it.
|
|
19
|
+
This way a coverage report will be generated,
|
|
20
|
+
showing 0% coverage, instead of no report.
|
|
21
|
+
This file can be removed once we have real unit
|
|
22
|
+
tests in place. */
|
|
23
|
+
describe('terminal package', () => {
|
|
24
|
+
it('support code coverage statistics', () => true);
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=package.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.spec.js","sourceRoot":"","sources":["../src/package.spec.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0CAA0C;AAC1C,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAEhF;;;;;;qBAMqB;AAErB,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theia/terminal-manager",
|
|
3
|
+
"version": "1.67.0-next.86+03f92ff1d97",
|
|
4
|
+
"description": "Theia - Terminal Manager Extension",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"theia-extension"
|
|
7
|
+
],
|
|
8
|
+
"homepage": "https://github.com/eclipse-theia/theia",
|
|
9
|
+
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/eclipse-theia/theia.git"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"lib",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "theiaext build",
|
|
20
|
+
"clean": "theiaext clean",
|
|
21
|
+
"compile": "theiaext compile",
|
|
22
|
+
"lint": "theiaext lint",
|
|
23
|
+
"test": "theiaext test",
|
|
24
|
+
"watch": "theiaext watch"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@theia/core": "1.67.0-next.86+03f92ff1d97",
|
|
28
|
+
"@theia/preferences": "1.67.0-next.86+03f92ff1d97",
|
|
29
|
+
"@theia/terminal": "1.67.0-next.86+03f92ff1d97"
|
|
30
|
+
},
|
|
31
|
+
"theiaExtensions": [
|
|
32
|
+
{
|
|
33
|
+
"frontend": "lib/browser/terminal-manager-frontend-module"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"gitHead": "03f92ff1d97dcb199de39b48e60a53535de22808"
|
|
40
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2025 EclipseSource and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
9
|
+
// *****************************************************************************
|
|
10
|
+
|
|
11
|
+
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
12
|
+
import { CommandRegistry, PreferenceService, DisposableCollection } from '@theia/core/lib/common';
|
|
13
|
+
import { TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
|
|
14
|
+
import { TerminalFrontendContribution, TerminalCommands } from '@theia/terminal/lib/browser/terminal-frontend-contribution';
|
|
15
|
+
import { ApplicationShell, WidgetManager, FrontendApplicationContribution, FrontendApplication } from '@theia/core/lib/browser';
|
|
16
|
+
import { TerminalManagerWidget } from './terminal-manager-widget';
|
|
17
|
+
import { TerminalManagerFrontendViewContribution } from './terminal-manager-frontend-view-contribution';
|
|
18
|
+
import { TerminalManagerPreferences } from './terminal-manager-preferences';
|
|
19
|
+
/**
|
|
20
|
+
* Re-registers terminal commands (e.g. new terminal) to execute them via the terminal manager
|
|
21
|
+
* instead of creating new, separate terminals.
|
|
22
|
+
*/
|
|
23
|
+
@injectable()
|
|
24
|
+
export class TerminalManagerFrontendContribution implements FrontendApplicationContribution {
|
|
25
|
+
@inject(TerminalFrontendContribution)
|
|
26
|
+
protected readonly terminalFrontendContribution: TerminalFrontendContribution;
|
|
27
|
+
|
|
28
|
+
@inject(TerminalManagerFrontendViewContribution)
|
|
29
|
+
protected readonly terminalManagerViewContribution: TerminalManagerFrontendViewContribution;
|
|
30
|
+
|
|
31
|
+
@inject(WidgetManager)
|
|
32
|
+
protected readonly widgetManager: WidgetManager;
|
|
33
|
+
|
|
34
|
+
@inject(ApplicationShell)
|
|
35
|
+
protected readonly shell: ApplicationShell;
|
|
36
|
+
|
|
37
|
+
@inject(PreferenceService)
|
|
38
|
+
protected readonly preferenceService: PreferenceService;
|
|
39
|
+
|
|
40
|
+
@inject(TerminalManagerPreferences)
|
|
41
|
+
protected readonly preferences: TerminalManagerPreferences;
|
|
42
|
+
|
|
43
|
+
@inject(CommandRegistry)
|
|
44
|
+
protected readonly commandRegistry: CommandRegistry;
|
|
45
|
+
|
|
46
|
+
protected commandHandlerDisposables = new DisposableCollection();
|
|
47
|
+
|
|
48
|
+
onStart(app: FrontendApplication): void {
|
|
49
|
+
this.preferenceService.ready.then(() => {
|
|
50
|
+
this.preferenceService.onPreferenceChanged(change => {
|
|
51
|
+
if (change.preferenceName === 'terminal.grouping.mode') {
|
|
52
|
+
this.handleTabsDisplayChange(change.newValue as string);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
if (this.preferences.get('terminal.grouping.mode') !== 'tree') {
|
|
56
|
+
console.debug('Terminal tab style is not tree. Use separate terminal views.');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
console.debug('Terminal tab style is tree. Override command handlers accordingly.');
|
|
60
|
+
this.registerHandlers();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected handleTabsDisplayChange(newValue: string): void {
|
|
65
|
+
if (newValue === 'tree') {
|
|
66
|
+
this.registerHandlers();
|
|
67
|
+
} else {
|
|
68
|
+
this.unregisterHandlers();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected unregisterHandlers(): void {
|
|
73
|
+
this.commandHandlerDisposables.dispose();
|
|
74
|
+
this.commandHandlerDisposables = new DisposableCollection();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected registerHandlers(): void {
|
|
78
|
+
this.unregisterHandlers();
|
|
79
|
+
this.registerCommands();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
protected registerCommands(): void {
|
|
83
|
+
this.commandHandlerDisposables.push(this.commandRegistry.registerHandler(TerminalCommands.NEW.id, {
|
|
84
|
+
execute: async () => {
|
|
85
|
+
// Only create a new terminal if the view was existing as opening it automatically create a terminal
|
|
86
|
+
const existing = this.terminalManagerViewContribution.tryGetWidget();
|
|
87
|
+
const managerWidget = await this.terminalManagerViewContribution.openView({ reveal: true });
|
|
88
|
+
if (managerWidget instanceof TerminalManagerWidget && existing) {
|
|
89
|
+
const terminalWidget = await managerWidget.createTerminalWidget();
|
|
90
|
+
managerWidget.addTerminalPage(terminalWidget);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
this.commandHandlerDisposables.push(this.commandRegistry.registerHandler(TerminalCommands.NEW_ACTIVE_WORKSPACE.id, {
|
|
96
|
+
execute: async () => {
|
|
97
|
+
// Only create a new terminal if the view was existing as opening it automatically create a terminal
|
|
98
|
+
const existing = this.terminalManagerViewContribution.tryGetWidget();
|
|
99
|
+
const managerWidget = await this.terminalManagerViewContribution.openView({ reveal: true });
|
|
100
|
+
if (managerWidget instanceof TerminalManagerWidget && existing) {
|
|
101
|
+
const terminalWidget = await managerWidget.createTerminalWidget();
|
|
102
|
+
managerWidget.addTerminalPage(terminalWidget);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}));
|
|
106
|
+
|
|
107
|
+
this.commandHandlerDisposables.push(this.commandRegistry.registerHandler(TerminalCommands.SPLIT.id, {
|
|
108
|
+
execute: async () => {
|
|
109
|
+
const managerWidget = await this.terminalManagerViewContribution.openView({ reveal: true });
|
|
110
|
+
if (managerWidget instanceof TerminalManagerWidget) {
|
|
111
|
+
const terminalWidget = await managerWidget.createTerminalWidget();
|
|
112
|
+
const { model } = managerWidget.treeWidget;
|
|
113
|
+
const activeGroupId = model.activeGroupNode?.id;
|
|
114
|
+
const activePageId = model.activePageNode?.id;
|
|
115
|
+
|
|
116
|
+
if (activeGroupId) {
|
|
117
|
+
managerWidget.addWidgetToTerminalGroup(terminalWidget, activeGroupId);
|
|
118
|
+
} else if (activePageId) {
|
|
119
|
+
managerWidget.addTerminalGroupToPage(terminalWidget, activePageId);
|
|
120
|
+
} else {
|
|
121
|
+
managerWidget.addTerminalPage(terminalWidget);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
isEnabled: w => w instanceof TerminalWidget || w instanceof TerminalManagerWidget,
|
|
126
|
+
isVisible: w => w instanceof TerminalWidget || w instanceof TerminalManagerWidget,
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
this.commandHandlerDisposables.push(this.commandRegistry.registerHandler(TerminalCommands.TOGGLE_TERMINAL.id, {
|
|
130
|
+
execute: async () => {
|
|
131
|
+
const existing = this.terminalManagerViewContribution.tryGetWidget();
|
|
132
|
+
if (!existing || !(existing instanceof TerminalManagerWidget)) {
|
|
133
|
+
const managerWidget = await this.terminalManagerViewContribution.openView({ activate: true });
|
|
134
|
+
if (managerWidget instanceof TerminalManagerWidget && !this.shell.isExpanded('bottom')) {
|
|
135
|
+
this.shell.expandPanel('bottom');
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!existing.isAttached) {
|
|
141
|
+
await this.terminalManagerViewContribution.openView({ activate: true });
|
|
142
|
+
if (!this.shell.isExpanded('bottom')) {
|
|
143
|
+
this.shell.expandPanel('bottom');
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!this.shell.isExpanded('bottom')) {
|
|
149
|
+
this.shell.expandPanel('bottom');
|
|
150
|
+
this.shell.bottomPanel.activateWidget(existing);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const active = this.shell.activeWidget;
|
|
155
|
+
const isManagerOrChildActive = active === existing || Array.from(existing.terminalWidgets.values()).some(widget => widget === active);
|
|
156
|
+
if (isManagerOrChildActive) {
|
|
157
|
+
this.shell.collapsePanel('bottom');
|
|
158
|
+
} else {
|
|
159
|
+
this.shell.bottomPanel.activateWidget(existing);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2023 Ericsson and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
|
|
18
|
+
import {
|
|
19
|
+
bindViewContribution,
|
|
20
|
+
WidgetFactory,
|
|
21
|
+
WidgetManager,
|
|
22
|
+
FrontendApplicationContribution,
|
|
23
|
+
} from '@theia/core/lib/browser';
|
|
24
|
+
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
25
|
+
import { TerminalManagerWidget } from './terminal-manager-widget';
|
|
26
|
+
import { TerminalManagerFrontendViewContribution } from './terminal-manager-frontend-view-contribution';
|
|
27
|
+
import { TerminalManagerFrontendContribution } from './terminal-manager-frontend-contribution';
|
|
28
|
+
import { TerminalManagerPreferenceContribution, TerminalManagerPreferences, TerminalManagerPreferenceSchema } from './terminal-manager-preferences';
|
|
29
|
+
import { TerminalManagerTreeWidget } from './terminal-manager-tree-widget';
|
|
30
|
+
import '../../src/browser/terminal-manager.css';
|
|
31
|
+
import { PreferenceContribution, PreferenceProxyFactory } from '@theia/core';
|
|
32
|
+
|
|
33
|
+
export default new ContainerModule((bind: interfaces.Bind) => {
|
|
34
|
+
bindViewContribution(bind, TerminalManagerFrontendViewContribution);
|
|
35
|
+
bind(TabBarToolbarContribution).toService(TerminalManagerFrontendViewContribution);
|
|
36
|
+
|
|
37
|
+
// Bind the contribution for overridden terminal commands
|
|
38
|
+
bind(TerminalManagerFrontendContribution).toSelf().inSingletonScope();
|
|
39
|
+
bind(FrontendApplicationContribution).toService(TerminalManagerFrontendContribution);
|
|
40
|
+
|
|
41
|
+
bind(WidgetFactory).toDynamicValue(({ container }) => ({
|
|
42
|
+
id: TerminalManagerTreeWidget.ID,
|
|
43
|
+
createWidget: () => TerminalManagerTreeWidget.createWidget(container),
|
|
44
|
+
})).inSingletonScope();
|
|
45
|
+
|
|
46
|
+
bind(WidgetFactory).toDynamicValue(({ container }) => ({
|
|
47
|
+
id: TerminalManagerWidget.ID,
|
|
48
|
+
createWidget: async () => {
|
|
49
|
+
const child = container.createChild();
|
|
50
|
+
const widgetManager = container.get(WidgetManager);
|
|
51
|
+
const terminalManagerTreeWidget = await widgetManager.getOrCreateWidget<TerminalManagerTreeWidget>(TerminalManagerTreeWidget.ID);
|
|
52
|
+
child.bind(TerminalManagerTreeWidget).toConstantValue(terminalManagerTreeWidget);
|
|
53
|
+
return TerminalManagerWidget.createWidget(child);
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
bind(TerminalManagerPreferences).toDynamicValue(ctx => {
|
|
58
|
+
const factory = ctx.container.get<PreferenceProxyFactory>(PreferenceProxyFactory);
|
|
59
|
+
return factory(TerminalManagerPreferenceSchema);
|
|
60
|
+
}).inSingletonScope();
|
|
61
|
+
bind(TerminalManagerPreferenceContribution).toConstantValue({ schema: TerminalManagerPreferenceSchema });
|
|
62
|
+
bind(PreferenceContribution).toService(TerminalManagerPreferenceContribution);
|
|
63
|
+
});
|
|
64
|
+
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2023 Ericsson and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { injectable } from '@theia/core/shared/inversify';
|
|
18
|
+
import {
|
|
19
|
+
AbstractViewContribution,
|
|
20
|
+
codicon,
|
|
21
|
+
KeybindingContribution,
|
|
22
|
+
KeybindingRegistry,
|
|
23
|
+
MAXIMIZED_CLASS,
|
|
24
|
+
Widget,
|
|
25
|
+
} from '@theia/core/lib/browser';
|
|
26
|
+
import { CommandRegistry, Event, MenuModelRegistry } from '@theia/core';
|
|
27
|
+
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
28
|
+
import { BOTTOM_AREA_ID } from '@theia/core/lib/browser/shell/theia-dock-panel';
|
|
29
|
+
import { TerminalManagerCommands, TerminalManagerTreeTypes, TERMINAL_MANAGER_TREE_CONTEXT_MENU } from './terminal-manager-types';
|
|
30
|
+
import { TerminalManagerWidget } from './terminal-manager-widget';
|
|
31
|
+
import { TerminalManagerTreeWidget } from './terminal-manager-tree-widget';
|
|
32
|
+
import { ConfirmDialog, Dialog } from '@theia/core/lib/browser/dialogs';
|
|
33
|
+
|
|
34
|
+
@injectable()
|
|
35
|
+
export class TerminalManagerFrontendViewContribution extends AbstractViewContribution<TerminalManagerWidget>
|
|
36
|
+
implements TabBarToolbarContribution, KeybindingContribution {
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
super({
|
|
40
|
+
widgetId: TerminalManagerWidget.ID,
|
|
41
|
+
widgetName: 'Terminal Manager',
|
|
42
|
+
defaultWidgetOptions: {
|
|
43
|
+
area: 'bottom',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override registerCommands(commands: CommandRegistry): void {
|
|
49
|
+
super.registerCommands(commands);
|
|
50
|
+
|
|
51
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_NEW_TERMINAL_GROUP, {
|
|
52
|
+
execute: (
|
|
53
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
54
|
+
) => {
|
|
55
|
+
const nodeId = args[1];
|
|
56
|
+
if (TerminalManagerTreeTypes.isPageId(nodeId)) {
|
|
57
|
+
this.createNewTerminalGroup(nodeId);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
isVisible: (
|
|
61
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
62
|
+
) => args[0] instanceof TerminalManagerTreeWidget && TerminalManagerTreeTypes.isPageId(args[1]),
|
|
63
|
+
});
|
|
64
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_SHOW_TREE_TOOLBAR, {
|
|
65
|
+
execute: () => this.handleToggleTree(),
|
|
66
|
+
isVisible: widget => widget instanceof TerminalManagerWidget,
|
|
67
|
+
});
|
|
68
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_NEW_PAGE_BOTTOM_TOOLBAR, {
|
|
69
|
+
execute: () => this.createNewTerminalPage(),
|
|
70
|
+
isVisible: (
|
|
71
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
72
|
+
) => args[0] instanceof TerminalManagerWidget,
|
|
73
|
+
});
|
|
74
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_DELETE_TERMINAL, {
|
|
75
|
+
execute: (
|
|
76
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
77
|
+
) => TerminalManagerTreeTypes.isTerminalKey(args[1]) && this.deleteTerminalFromManager(args[1]),
|
|
78
|
+
isVisible: (...args: TerminalManagerTreeTypes.ContextMenuArgs) => {
|
|
79
|
+
const treeWidget = args[0];
|
|
80
|
+
const nodeId = args[1];
|
|
81
|
+
if (treeWidget instanceof TerminalManagerTreeWidget && TerminalManagerTreeTypes.isTerminalKey(nodeId)) {
|
|
82
|
+
const { model } = treeWidget;
|
|
83
|
+
const terminalNode = model.getNode(nodeId);
|
|
84
|
+
return TerminalManagerTreeTypes.isTerminalNode(terminalNode);
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_DELETE_PAGE, {
|
|
90
|
+
execute: (
|
|
91
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
92
|
+
) => TerminalManagerTreeTypes.isPageId(args[1]) && this.deletePageFromManager(args[1]),
|
|
93
|
+
isVisible: (...args: TerminalManagerTreeTypes.ContextMenuArgs) => {
|
|
94
|
+
const widget = args[0];
|
|
95
|
+
return widget instanceof TerminalManagerTreeWidget && TerminalManagerTreeTypes.isPageId(args[1]) && widget.model.pages.size >= 1;
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_RENAME_TERMINAL, {
|
|
99
|
+
execute: (...args: TerminalManagerTreeTypes.ContextMenuArgs) => this.toggleRenameTerminalFromManager(args[1]),
|
|
100
|
+
isVisible: (...args: TerminalManagerTreeTypes.ContextMenuArgs) => args[0] instanceof TerminalManagerTreeWidget,
|
|
101
|
+
});
|
|
102
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_ADD_TERMINAL_TO_GROUP, {
|
|
103
|
+
execute: (
|
|
104
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
105
|
+
) => {
|
|
106
|
+
const nodeId = args[1];
|
|
107
|
+
if (TerminalManagerTreeTypes.isGroupId(nodeId)) {
|
|
108
|
+
this.addTerminalToGroup(nodeId);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
isVisible: (
|
|
112
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
113
|
+
) => args[0] instanceof TerminalManagerTreeWidget && TerminalManagerTreeTypes.isGroupId(args[1]),
|
|
114
|
+
});
|
|
115
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_DELETE_GROUP, {
|
|
116
|
+
execute: (
|
|
117
|
+
...args: TerminalManagerTreeTypes.ContextMenuArgs
|
|
118
|
+
) => TerminalManagerTreeTypes.isGroupId(args[1]) && this.deleteGroupFromManager(args[1]),
|
|
119
|
+
isVisible: (...args: TerminalManagerTreeTypes.ContextMenuArgs) => {
|
|
120
|
+
const treeWidget = args[0];
|
|
121
|
+
const groupId = args[1];
|
|
122
|
+
if (treeWidget instanceof TerminalManagerTreeWidget && TerminalManagerTreeTypes.isGroupId(groupId)) {
|
|
123
|
+
const { model } = treeWidget;
|
|
124
|
+
const groupNode = model.getNode(groupId);
|
|
125
|
+
return TerminalManagerTreeTypes.isGroupNode(groupNode);
|
|
126
|
+
}
|
|
127
|
+
return false;
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_MAXIMIZE_BOTTOM_PANEL_TOOLBAR, {
|
|
131
|
+
execute: () => this.maximizeBottomPanel(),
|
|
132
|
+
isVisible: widget => widget instanceof Widget
|
|
133
|
+
&& widget.parent?.id === BOTTOM_AREA_ID
|
|
134
|
+
&& !this.shell.bottomPanel.hasClass(MAXIMIZED_CLASS),
|
|
135
|
+
});
|
|
136
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_MINIMIZE_BOTTOM_PANEL_TOOLBAR, {
|
|
137
|
+
execute: () => this.maximizeBottomPanel(),
|
|
138
|
+
isVisible: widget => widget instanceof Widget
|
|
139
|
+
&& widget.parent?.id === BOTTOM_AREA_ID
|
|
140
|
+
&& this.shell.bottomPanel.hasClass(MAXIMIZED_CLASS),
|
|
141
|
+
});
|
|
142
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_CLEAR_ALL, {
|
|
143
|
+
isVisible: widget => widget instanceof TerminalManagerWidget,
|
|
144
|
+
execute: async widget => {
|
|
145
|
+
if (widget instanceof TerminalManagerWidget) {
|
|
146
|
+
const PRIMARY_BUTTON = 'Reset Layout';
|
|
147
|
+
const dialogResponse = await this.confirmUserAction({
|
|
148
|
+
title: 'Do you want to reset the terminal manager layout?',
|
|
149
|
+
message: 'Once the layout is reset, it cannot be restored. Are you sure you would like to clear the layout?',
|
|
150
|
+
primaryButtonText: PRIMARY_BUTTON,
|
|
151
|
+
});
|
|
152
|
+
if (dialogResponse === PRIMARY_BUTTON) {
|
|
153
|
+
for (const id of widget.pagePanels.keys()) {
|
|
154
|
+
widget.deletePage(id);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_OPEN_VIEW, {
|
|
161
|
+
execute: () => this.openView({ activate: true }),
|
|
162
|
+
});
|
|
163
|
+
commands.registerCommand(TerminalManagerCommands.MANAGER_CLOSE_VIEW, {
|
|
164
|
+
isVisible: () => Boolean(this.tryGetWidget()),
|
|
165
|
+
isEnabled: () => Boolean(this.tryGetWidget()),
|
|
166
|
+
execute: () => this.closeView(),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
protected async confirmUserAction(options: { title: string, message: string, primaryButtonText: string }): Promise<string | undefined> {
|
|
171
|
+
const dialog = new ConfirmDialog({
|
|
172
|
+
title: options.title,
|
|
173
|
+
msg: options.message,
|
|
174
|
+
ok: options.primaryButtonText,
|
|
175
|
+
cancel: Dialog.CANCEL,
|
|
176
|
+
});
|
|
177
|
+
const confirmed = await dialog.open();
|
|
178
|
+
return confirmed ? options.primaryButtonText : undefined;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
protected maximizeBottomPanel(): void {
|
|
182
|
+
this.shell.bottomPanel.toggleMaximized();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
protected async createNewTerminalPage(): Promise<void> {
|
|
186
|
+
const terminalManagerWidget = await this.widget;
|
|
187
|
+
const terminalWidget = await terminalManagerWidget.createTerminalWidget();
|
|
188
|
+
terminalManagerWidget.addTerminalPage(terminalWidget);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
protected async createNewTerminalGroup(pageId: TerminalManagerTreeTypes.PageId): Promise<void> {
|
|
192
|
+
const terminalManagerWidget = await this.widget;
|
|
193
|
+
const terminalWidget = await terminalManagerWidget.createTerminalWidget();
|
|
194
|
+
terminalManagerWidget.addTerminalGroupToPage(terminalWidget, pageId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
protected async addTerminalToGroup(groupId: TerminalManagerTreeTypes.GroupId): Promise<void> {
|
|
198
|
+
const terminalManagerWidget = await this.widget;
|
|
199
|
+
const terminalWidget = await terminalManagerWidget.createTerminalWidget();
|
|
200
|
+
terminalManagerWidget.addWidgetToTerminalGroup(terminalWidget, groupId);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
protected async handleToggleTree(): Promise<void> {
|
|
204
|
+
const terminalManagerWidget = await this.widget;
|
|
205
|
+
terminalManagerWidget.toggleTreeVisibility();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
protected async deleteTerminalFromManager(terminalId: TerminalManagerTreeTypes.TerminalKey): Promise<void> {
|
|
209
|
+
const terminalManagerWidget = await this.widget;
|
|
210
|
+
terminalManagerWidget?.deleteTerminal(terminalId);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
protected async deleteGroupFromManager(groupId: TerminalManagerTreeTypes.GroupId): Promise<void> {
|
|
214
|
+
const widget = await this.widget;
|
|
215
|
+
widget.deleteGroup(groupId);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
protected async deletePageFromManager(pageId: TerminalManagerTreeTypes.PageId): Promise<void> {
|
|
219
|
+
const widget = await this.widget;
|
|
220
|
+
widget.deletePage(pageId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
protected async toggleRenameTerminalFromManager(entityId: TerminalManagerTreeTypes.TerminalManagerValidId): Promise<void> {
|
|
224
|
+
const widget = await this.widget;
|
|
225
|
+
widget.toggleRenameTerminal(entityId);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
override registerMenus(menus: MenuModelRegistry): void {
|
|
229
|
+
super.registerMenus(menus);
|
|
230
|
+
menus.registerMenuAction(TERMINAL_MANAGER_TREE_CONTEXT_MENU, {
|
|
231
|
+
commandId: TerminalManagerCommands.MANAGER_ADD_TERMINAL_TO_GROUP.id,
|
|
232
|
+
order: 'a',
|
|
233
|
+
});
|
|
234
|
+
menus.registerMenuAction(TERMINAL_MANAGER_TREE_CONTEXT_MENU, {
|
|
235
|
+
commandId: TerminalManagerCommands.MANAGER_RENAME_TERMINAL.id,
|
|
236
|
+
order: 'b',
|
|
237
|
+
});
|
|
238
|
+
menus.registerMenuAction(TERMINAL_MANAGER_TREE_CONTEXT_MENU, {
|
|
239
|
+
commandId: TerminalManagerCommands.MANAGER_DELETE_TERMINAL.id,
|
|
240
|
+
order: 'c',
|
|
241
|
+
});
|
|
242
|
+
menus.registerMenuAction(TERMINAL_MANAGER_TREE_CONTEXT_MENU, {
|
|
243
|
+
commandId: TerminalManagerCommands.MANAGER_DELETE_PAGE.id,
|
|
244
|
+
order: 'c',
|
|
245
|
+
});
|
|
246
|
+
menus.registerMenuAction(TERMINAL_MANAGER_TREE_CONTEXT_MENU, {
|
|
247
|
+
commandId: TerminalManagerCommands.MANAGER_DELETE_GROUP.id,
|
|
248
|
+
order: 'c',
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
menus.registerMenuAction(TerminalManagerTreeTypes.PAGE_NODE_MENU, {
|
|
252
|
+
commandId: TerminalManagerCommands.MANAGER_NEW_TERMINAL_GROUP.id,
|
|
253
|
+
order: 'a',
|
|
254
|
+
});
|
|
255
|
+
menus.registerMenuAction(TerminalManagerTreeTypes.PAGE_NODE_MENU, {
|
|
256
|
+
commandId: TerminalManagerCommands.MANAGER_DELETE_PAGE.id,
|
|
257
|
+
order: 'b',
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
menus.registerMenuAction(TerminalManagerTreeTypes.TERMINAL_NODE_MENU, {
|
|
261
|
+
commandId: TerminalManagerCommands.MANAGER_DELETE_TERMINAL.id,
|
|
262
|
+
order: 'c',
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
menus.registerMenuAction(TerminalManagerTreeTypes.GROUP_NODE_MENU, {
|
|
266
|
+
commandId: TerminalManagerCommands.MANAGER_ADD_TERMINAL_TO_GROUP.id,
|
|
267
|
+
order: 'a',
|
|
268
|
+
});
|
|
269
|
+
menus.registerMenuAction(TerminalManagerTreeTypes.GROUP_NODE_MENU, {
|
|
270
|
+
commandId: TerminalManagerCommands.MANAGER_DELETE_GROUP.id,
|
|
271
|
+
order: 'c',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
registerToolbarItems(toolbar: TabBarToolbarRegistry): void {
|
|
276
|
+
toolbar.registerItem({
|
|
277
|
+
id: TerminalManagerCommands.MANAGER_NEW_PAGE_BOTTOM_TOOLBAR.id,
|
|
278
|
+
command: TerminalManagerCommands.MANAGER_NEW_PAGE_BOTTOM_TOOLBAR.id,
|
|
279
|
+
});
|
|
280
|
+
toolbar.registerItem({
|
|
281
|
+
id: TerminalManagerCommands.MANAGER_SHOW_TREE_TOOLBAR.id,
|
|
282
|
+
command: TerminalManagerCommands.MANAGER_SHOW_TREE_TOOLBAR.id,
|
|
283
|
+
});
|
|
284
|
+
toolbar.registerItem({
|
|
285
|
+
id: TerminalManagerCommands.MANAGER_CLEAR_ALL.id,
|
|
286
|
+
command: TerminalManagerCommands.MANAGER_CLEAR_ALL.id,
|
|
287
|
+
});
|
|
288
|
+
const bottomPanelMaximizationChanged = Event.map(Event.filter(this.shell.onDidToggleMaximized, widget => widget === this.shell.bottomPanel), () => undefined);
|
|
289
|
+
toolbar.registerItem({
|
|
290
|
+
id: TerminalManagerCommands.MANAGER_MAXIMIZE_BOTTOM_PANEL_TOOLBAR.id,
|
|
291
|
+
command: TerminalManagerCommands.MANAGER_MAXIMIZE_BOTTOM_PANEL_TOOLBAR.id,
|
|
292
|
+
icon: codicon('chevron-up'),
|
|
293
|
+
onDidChange: bottomPanelMaximizationChanged,
|
|
294
|
+
});
|
|
295
|
+
toolbar.registerItem({
|
|
296
|
+
id: TerminalManagerCommands.MANAGER_MINIMIZE_BOTTOM_PANEL_TOOLBAR.id,
|
|
297
|
+
command: TerminalManagerCommands.MANAGER_MINIMIZE_BOTTOM_PANEL_TOOLBAR.id,
|
|
298
|
+
icon: codicon('chevron-down'),
|
|
299
|
+
onDidChange: bottomPanelMaximizationChanged,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
override registerKeybindings(registry: KeybindingRegistry): void {
|
|
304
|
+
registry.registerKeybinding({
|
|
305
|
+
command: TerminalManagerCommands.MANAGER_MINIMIZE_BOTTOM_PANEL_TOOLBAR.id,
|
|
306
|
+
keybinding: 'alt+q',
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2023 Ericsson and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { nls, PreferenceProxy, PreferenceSchema, PreferenceScope } from '@theia/core';
|
|
18
|
+
|
|
19
|
+
export const TerminalManagerPreferenceSchema: PreferenceSchema = {
|
|
20
|
+
properties: {
|
|
21
|
+
'terminal.grouping.treeViewLocation': {
|
|
22
|
+
'type': 'string',
|
|
23
|
+
'enum': ['left', 'right'],
|
|
24
|
+
'description': nls.localize('theia/terminalManager/treeViewLocation', 'The location of the terminal manager\'s tree view.'
|
|
25
|
+
+ ' Only applies when \'terminal.grouping.mode\' is set to \'tree\'.'),
|
|
26
|
+
'default': 'left',
|
|
27
|
+
'scope': PreferenceScope.Workspace,
|
|
28
|
+
},
|
|
29
|
+
'terminal.grouping.mode': {
|
|
30
|
+
'type': 'string',
|
|
31
|
+
'enum': ['tabbed', 'tree'],
|
|
32
|
+
'description': nls.localize('theia/terminalManager/tabsDisplay',
|
|
33
|
+
'Controls how terminals are displayed. \'tree\' shows multiple terminals in a single view with a tree view for management,'
|
|
34
|
+
+ '\'tabbed\' shows each terminal in its own view in a separate tab.'),
|
|
35
|
+
'default': 'tabbed',
|
|
36
|
+
'scope': PreferenceScope.Workspace,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type TerminalManagerTreeViewLocation = 'left' | 'right';
|
|
42
|
+
export type TerminalGroupingMode = 'tabbed' | 'tree';
|
|
43
|
+
|
|
44
|
+
export interface TerminalManagerConfiguration {
|
|
45
|
+
'terminal.grouping.treeViewLocation': TerminalManagerTreeViewLocation;
|
|
46
|
+
'terminal.grouping.mode': TerminalGroupingMode;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const TerminalManagerPreferences = Symbol('TerminalManagerPreferences');
|
|
50
|
+
export const TerminalManagerPreferenceContribution = Symbol('TerminalManagerPreferenceContribution');
|
|
51
|
+
export type TerminalManagerPreferences = PreferenceProxy<TerminalManagerConfiguration>;
|
|
52
|
+
|