deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
10
packages/external-terminal/.eslintrc.js
Normal file
10
packages/external-terminal/.eslintrc.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: [
|
||||
'../../configs/build.eslintrc.json'
|
||||
],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: 'tsconfig.json'
|
||||
}
|
||||
};
|
||||
47
packages/external-terminal/README.md
Normal file
47
packages/external-terminal/README.md
Normal file
@@ -0,0 +1,47 @@
|
||||
<div align='center'>
|
||||
|
||||
<br />
|
||||
|
||||
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
|
||||
|
||||
<h2>ECLIPSE THEIA - EXTERNAL-TERMINAL EXTENSION</h2>
|
||||
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
|
||||
## Description
|
||||
|
||||
The `@theia/external-terminal` extension contributes the ability to spawn external terminals for `electron` applications.
|
||||
The extension includes the necessary logic to spawn the appropriate terminal application for each operating system (Windows, Linux, OSX)
|
||||
by identifying certain environment variables. The extension also contributes preferences to control this behavior if necessary.
|
||||
|
||||
**Note:** The extension does not support browser applications.
|
||||
|
||||
## Contributions
|
||||
|
||||
### Commands
|
||||
|
||||
- `OPEN_NATIVE_CONSOLE`: spawns an external terminal (native console) for different use-cases.
|
||||
|
||||
### Preferences
|
||||
|
||||
- `terminal.external.windowsExec`: the application executable for Windows.
|
||||
- `terminal.external.linuxExec`: the application executable for Linux.
|
||||
- `terminal.external.osxExec`: the application executable for OSX.
|
||||
|
||||
## Additional Information
|
||||
|
||||
- [API documentation for `@theia/external-terminal`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_external-terminal.html)
|
||||
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
|
||||
- [Theia - Website](https://theia-ide.org/)
|
||||
|
||||
## License
|
||||
|
||||
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
|
||||
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
|
||||
|
||||
## Trademark
|
||||
|
||||
"Theia" is a trademark of the Eclipse Foundation
|
||||
<https://www.eclipse.org/theia>
|
||||
51
packages/external-terminal/package.json
Normal file
51
packages/external-terminal/package.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "@theia/external-terminal",
|
||||
"version": "1.68.0",
|
||||
"description": "Theia - External Terminal Extension",
|
||||
"dependencies": {
|
||||
"@theia/core": "1.68.0",
|
||||
"@theia/editor": "1.68.0",
|
||||
"@theia/workspace": "1.68.0",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"theiaExtensions": [
|
||||
{
|
||||
"backendElectron": "lib/electron-node/external-terminal-backend-module",
|
||||
"frontendElectron": "lib/electron-browser/external-terminal-frontend-module"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"theia-extension"
|
||||
],
|
||||
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/eclipse-theia/theia.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/eclipse-theia/theia/issues"
|
||||
},
|
||||
"homepage": "https://github.com/eclipse-theia/theia",
|
||||
"files": [
|
||||
"lib",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "theiaext build",
|
||||
"clean": "theiaext clean",
|
||||
"compile": "theiaext compile",
|
||||
"lint": "theiaext lint",
|
||||
"test": "theiaext test",
|
||||
"watch": "theiaext watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@theia/ext-scripts": "1.68.0"
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "../../configs/nyc.json"
|
||||
},
|
||||
"gitHead": "21358137e41342742707f660b8e222f940a27652"
|
||||
}
|
||||
55
packages/external-terminal/src/common/external-terminal.ts
Normal file
55
packages/external-terminal/src/common/external-terminal.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
// *****************************************************************************
|
||||
// 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
|
||||
// *****************************************************************************
|
||||
|
||||
export const ExternalTerminalService = Symbol('ExternalTerminalService');
|
||||
export const externalTerminalServicePath = '/services/external-terminal';
|
||||
|
||||
/**
|
||||
* Represents the external terminal configuration options.
|
||||
*/
|
||||
export interface ExternalTerminalConfiguration {
|
||||
/**
|
||||
* The external terminal executable for Windows.
|
||||
*/
|
||||
'terminal.external.windowsExec': string;
|
||||
/**
|
||||
* The external terminal executable for OSX.
|
||||
*/
|
||||
'terminal.external.osxExec': string;
|
||||
/**
|
||||
* The external terminal executable for Linux.
|
||||
*/
|
||||
'terminal.external.linuxExec': string;
|
||||
}
|
||||
|
||||
export interface ExternalTerminalService {
|
||||
|
||||
/**
|
||||
* Open a native terminal in the designated working directory.
|
||||
*
|
||||
* @param configuration the configuration for opening external terminals.
|
||||
* @param cwd the string URI of the current working directory where the terminal should open from.
|
||||
*/
|
||||
openTerminal(configuration: ExternalTerminalConfiguration, cwd: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Get the default executable.
|
||||
*
|
||||
* @returns the default terminal executable.
|
||||
*/
|
||||
getDefaultExec(): Promise<string>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// *****************************************************************************
|
||||
// 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 { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { Command, CommandContribution, CommandRegistry } from '@theia/core/lib/common';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { KeybindingContribution, KeybindingRegistry, LabelProvider } from '@theia/core/lib/browser';
|
||||
import { EditorManager } from '@theia/editor/lib/browser/editor-manager';
|
||||
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
||||
import { ExternalTerminalService } from '../common/external-terminal';
|
||||
import { ExternalTerminalPreferenceService } from './external-terminal-preference';
|
||||
import { QuickPickService } from '@theia/core/lib/common/quick-pick-service';
|
||||
import { nls } from '@theia/core/lib/common/nls';
|
||||
|
||||
export namespace ExternalTerminalCommands {
|
||||
export const OPEN_NATIVE_CONSOLE = Command.toDefaultLocalizedCommand({
|
||||
id: 'workbench.action.terminal.openNativeConsole',
|
||||
label: 'Open New External Terminal'
|
||||
});
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ExternalTerminalFrontendContribution implements CommandContribution, KeybindingContribution {
|
||||
|
||||
@inject(EditorManager)
|
||||
protected readonly editorManager: EditorManager;
|
||||
|
||||
@inject(EnvVariablesServer)
|
||||
protected readonly envVariablesServer: EnvVariablesServer;
|
||||
|
||||
@inject(LabelProvider)
|
||||
protected readonly labelProvider: LabelProvider;
|
||||
|
||||
@inject(QuickPickService)
|
||||
protected readonly quickPickService: QuickPickService;
|
||||
|
||||
@inject(ExternalTerminalService)
|
||||
protected readonly externalTerminalService: ExternalTerminalService;
|
||||
|
||||
@inject(ExternalTerminalPreferenceService)
|
||||
protected readonly externalTerminalPreferences: ExternalTerminalPreferenceService;
|
||||
|
||||
@inject(WorkspaceService)
|
||||
protected readonly workspaceService: WorkspaceService;
|
||||
|
||||
registerCommands(commands: CommandRegistry): void {
|
||||
commands.registerCommand(ExternalTerminalCommands.OPEN_NATIVE_CONSOLE, {
|
||||
execute: () => this.openExternalTerminal()
|
||||
});
|
||||
}
|
||||
|
||||
registerKeybindings(keybindings: KeybindingRegistry): void {
|
||||
keybindings.registerKeybinding({
|
||||
command: ExternalTerminalCommands.OPEN_NATIVE_CONSOLE.id,
|
||||
keybinding: 'ctrlcmd+shift+c',
|
||||
when: '!terminalFocus'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a native console on the host machine.
|
||||
*
|
||||
* - If multi-root workspace is open, displays a quick pick to let users choose which workspace to spawn the terminal.
|
||||
* - If only one workspace is open, the terminal spawns at the root of the current workspace.
|
||||
* - If no workspace is open and there is an active editor, the terminal spawns at the parent folder of that file.
|
||||
* - If no workspace is open and there are no active editors, the terminal spawns at user home directory.
|
||||
*/
|
||||
protected async openExternalTerminal(): Promise<void> {
|
||||
const configuration = this.externalTerminalPreferences.getExternalTerminalConfiguration();
|
||||
|
||||
if (this.workspaceService.isMultiRootWorkspaceOpened) {
|
||||
const chosenWorkspaceRoot = await this.selectCwd();
|
||||
if (chosenWorkspaceRoot) {
|
||||
await this.externalTerminalService.openTerminal(configuration, chosenWorkspaceRoot);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.workspaceService.opened) {
|
||||
const workspaceRootUri = this.workspaceService.tryGetRoots()[0].resource;
|
||||
await this.externalTerminalService.openTerminal(configuration, workspaceRootUri.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
const fallbackUri = this.editorManager.activeEditor?.editor.uri.parent ?? await this.envVariablesServer.getHomeDirUri();
|
||||
await this.externalTerminalService.openTerminal(configuration, fallbackUri.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a quick pick for user to choose a target workspace in opened workspaces.
|
||||
*/
|
||||
protected async selectCwd(): Promise<string | undefined> {
|
||||
const roots = this.workspaceService.tryGetRoots();
|
||||
const selectedItem = await this.quickPickService.show(roots.map(
|
||||
({ resource }) => ({
|
||||
label: this.labelProvider.getName(resource),
|
||||
description: this.labelProvider.getLongName(resource),
|
||||
value: resource.toString()
|
||||
})
|
||||
), { placeholder: nls.localize('theia/external-terminal/cwd', 'Select current working directory for new external terminal') });
|
||||
return selectedItem?.value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// *****************************************************************************
|
||||
// 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 { ContainerModule, interfaces } from '@theia/core/shared/inversify';
|
||||
import { CommandContribution } from '@theia/core/lib/common';
|
||||
import { KeybindingContribution, WebSocketConnectionProvider } from '@theia/core/lib/browser';
|
||||
import { bindExternalTerminalPreferences } from './external-terminal-preference';
|
||||
import { ExternalTerminalFrontendContribution } from './external-terminal-contribution';
|
||||
import { ExternalTerminalService, externalTerminalServicePath } from '../common/external-terminal';
|
||||
|
||||
export default new ContainerModule((bind: interfaces.Bind) => {
|
||||
bind(ExternalTerminalFrontendContribution).toSelf().inSingletonScope();
|
||||
bindExternalTerminalPreferences(bind);
|
||||
[CommandContribution, KeybindingContribution].forEach(serviceIdentifier =>
|
||||
bind(serviceIdentifier).toService(ExternalTerminalFrontendContribution)
|
||||
);
|
||||
bind(ExternalTerminalService).toDynamicValue(ctx =>
|
||||
WebSocketConnectionProvider.createProxy<ExternalTerminalService>(ctx.container, externalTerminalServicePath)
|
||||
).inSingletonScope();
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
// *****************************************************************************
|
||||
// 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 { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
|
||||
import { isWindows, isOSX } from '@theia/core/lib/common/os';
|
||||
import { ExternalTerminalService, ExternalTerminalConfiguration } from '../common/external-terminal';
|
||||
import { nls } from '@theia/core/lib/common/nls';
|
||||
import { PreferenceProxy, PreferenceSchema, PreferenceProxyFactory, PreferenceSchemaService } from '@theia/core';
|
||||
|
||||
export const ExternalTerminalPreferences = Symbol('ExternalTerminalPreferences');
|
||||
export type ExternalTerminalPreferences = PreferenceProxy<ExternalTerminalConfiguration>;
|
||||
|
||||
export const ExternalTerminalSchemaProvider = Symbol('ExternalTerminalSchemaPromise');
|
||||
export type ExternalTerminalSchemaProvider = () => Promise<PreferenceSchema>;
|
||||
|
||||
export function bindExternalTerminalPreferences(bind: interfaces.Bind): void {
|
||||
bind(ExternalTerminalPreferenceService).toSelf().inSingletonScope();
|
||||
bind(ExternalTerminalSchemaProvider)
|
||||
.toProvider(ctx => {
|
||||
const schema = getExternalTerminalSchema(ctx.container.get(ExternalTerminalService));
|
||||
return () => schema;
|
||||
});
|
||||
bind(ExternalTerminalPreferences)
|
||||
.toDynamicValue(ctx => {
|
||||
const factory = ctx.container.get<PreferenceProxyFactory>(PreferenceProxyFactory);
|
||||
const schemaProvider = ctx.container.get<ExternalTerminalSchemaProvider>(ExternalTerminalSchemaProvider);
|
||||
return factory(schemaProvider());
|
||||
})
|
||||
.inSingletonScope();
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ExternalTerminalPreferenceService {
|
||||
|
||||
@inject(ExternalTerminalPreferences)
|
||||
protected readonly preferences: ExternalTerminalPreferences;
|
||||
|
||||
@inject(PreferenceSchemaService)
|
||||
protected readonly preferenceSchemaProvider: PreferenceSchemaService;
|
||||
|
||||
@inject(ExternalTerminalSchemaProvider)
|
||||
protected readonly promisedSchema: ExternalTerminalSchemaProvider;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.doInit();
|
||||
}
|
||||
|
||||
protected async doInit(): Promise<void> {
|
||||
this.preferenceSchemaProvider.addSchema(await this.promisedSchema());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the external terminal configurations from preferences.
|
||||
*/
|
||||
getExternalTerminalConfiguration(): ExternalTerminalConfiguration {
|
||||
return {
|
||||
'terminal.external.linuxExec': this.preferences['terminal.external.linuxExec'],
|
||||
'terminal.external.osxExec': this.preferences['terminal.external.osxExec'],
|
||||
'terminal.external.windowsExec': this.preferences['terminal.external.windowsExec'],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the backend {@link ExternalTerminalService} to establish the schema for the `ExternalTerminalPreferences`.
|
||||
*
|
||||
* @param externalTerminalService the external terminal backend service.
|
||||
* @returns a preference schema with the OS default exec set by the backend service.
|
||||
*/
|
||||
export async function getExternalTerminalSchema(externalTerminalService: ExternalTerminalService): Promise<PreferenceSchema> {
|
||||
const hostExec = await externalTerminalService.getDefaultExec();
|
||||
return {
|
||||
properties: {
|
||||
'terminal.external.windowsExec': {
|
||||
type: 'string',
|
||||
typeDetails: { isFilepath: true },
|
||||
description: nls.localizeByDefault('Customizes which terminal to run on Windows.'),
|
||||
default: `${isWindows ? hostExec : 'C:\\WINDOWS\\System32\\cmd.exe'}`
|
||||
},
|
||||
'terminal.external.osxExec': {
|
||||
type: 'string',
|
||||
description: nls.localizeByDefault('Customizes which terminal application to run on macOS.'),
|
||||
default: `${isOSX ? hostExec : 'Terminal.app'}`
|
||||
},
|
||||
'terminal.external.linuxExec': {
|
||||
type: 'string',
|
||||
description: nls.localizeByDefault('Customizes which terminal to run on Linux.'),
|
||||
default: `${!(isWindows || isOSX) ? hostExec : 'xterm'}`
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// *****************************************************************************
|
||||
// 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 { ContainerModule, interfaces } from '@theia/core/shared/inversify';
|
||||
import { ConnectionHandler, RpcConnectionHandler } from '@theia/core/lib/common';
|
||||
import { isWindows, isOSX } from '@theia/core/lib/common/os';
|
||||
import { ExternalTerminalService, externalTerminalServicePath } from '../common/external-terminal';
|
||||
import { MacExternalTerminalService } from './mac-external-terminal-service';
|
||||
import { LinuxExternalTerminalService } from './linux-external-terminal-service';
|
||||
import { WindowsExternalTerminalService } from './windows-external-terminal-service';
|
||||
|
||||
export function bindExternalTerminalService(bind: interfaces.Bind): void {
|
||||
const serviceProvider: interfaces.ServiceIdentifier<ExternalTerminalService> =
|
||||
isWindows ? WindowsExternalTerminalService : isOSX ? MacExternalTerminalService : LinuxExternalTerminalService;
|
||||
bind(serviceProvider).toSelf().inSingletonScope();
|
||||
bind(ExternalTerminalService).toService(serviceProvider);
|
||||
|
||||
bind(ConnectionHandler).toDynamicValue(ctx =>
|
||||
new RpcConnectionHandler(externalTerminalServicePath, () =>
|
||||
ctx.container.get(ExternalTerminalService)
|
||||
)
|
||||
).inSingletonScope();
|
||||
}
|
||||
|
||||
export default new ContainerModule(bind => {
|
||||
bindExternalTerminalService(bind);
|
||||
});
|
||||
@@ -0,0 +1,95 @@
|
||||
// *****************************************************************************
|
||||
// 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 * as cp from 'child_process';
|
||||
import * as fs from '@theia/core/shared/fs-extra';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { OS } from '@theia/core/lib/common/os';
|
||||
import { FileUri } from '@theia/core/lib/common/file-uri';
|
||||
import { ExternalTerminalService, ExternalTerminalConfiguration } from '../common/external-terminal';
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// some code copied and modified from https://github.com/microsoft/vscode/blob/1.52.1/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts
|
||||
|
||||
@injectable()
|
||||
export class LinuxExternalTerminalService implements ExternalTerminalService {
|
||||
protected DEFAULT_TERMINAL_LINUX_READY: Promise<string>;
|
||||
|
||||
async openTerminal(configuration: ExternalTerminalConfiguration, cwd: string): Promise<void> {
|
||||
await this.spawnTerminal(configuration, FileUri.fsPath(cwd));
|
||||
}
|
||||
|
||||
async getDefaultExec(): Promise<string> {
|
||||
return this.getDefaultTerminalLinux();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn the external terminal for the given options.
|
||||
* - The method spawns the terminal application based on the preferences, else uses the default value.
|
||||
* @param configuration the preference configuration.
|
||||
* @param cwd the optional current working directory to spawn from.
|
||||
*/
|
||||
protected async spawnTerminal(configuration: ExternalTerminalConfiguration, cwd?: string): Promise<void> {
|
||||
|
||||
// Use the executable value from the preferences if available, else fallback to the default.
|
||||
const terminalConfig = configuration['terminal.external.linuxExec'];
|
||||
const execPromise = terminalConfig ? Promise.resolve(terminalConfig) : this.getDefaultTerminalLinux();
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
execPromise.then(exec => {
|
||||
const env = cwd ? { cwd } : undefined;
|
||||
const child = cp.spawn(exec, [], env);
|
||||
child.on('error', reject);
|
||||
child.on('exit', resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default terminal application on Linux.
|
||||
* - The following method uses environment variables to identify the best default possible for each distro.
|
||||
*
|
||||
* @returns the default application on Linux.
|
||||
*/
|
||||
protected async getDefaultTerminalLinux(): Promise<string> {
|
||||
if (!this.DEFAULT_TERMINAL_LINUX_READY) {
|
||||
this.DEFAULT_TERMINAL_LINUX_READY = new Promise(async resolve => {
|
||||
if (OS.type() === OS.Type.Linux) {
|
||||
const isDebian = await fs.pathExists('/etc/debian_version');
|
||||
if (isDebian) {
|
||||
resolve('x-terminal-emulator');
|
||||
} else if (process.env.DESKTOP_SESSION === 'gnome' || process.env.DESKTOP_SESSION === 'gnome-classic') {
|
||||
resolve('gnome-terminal');
|
||||
} else if (process.env.DESKTOP_SESSION === 'kde-plasma') {
|
||||
resolve('konsole');
|
||||
} else if (process.env.COLORTERM) {
|
||||
resolve(process.env.COLORTERM);
|
||||
} else if (process.env.TERM) {
|
||||
resolve(process.env.TERM);
|
||||
} else {
|
||||
resolve('xterm');
|
||||
}
|
||||
} else {
|
||||
resolve('xterm');
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.DEFAULT_TERMINAL_LINUX_READY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// *****************************************************************************
|
||||
// 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 * as cp from 'child_process';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { FileUri } from '@theia/core/lib/common/file-uri';
|
||||
import { ExternalTerminalService, ExternalTerminalConfiguration } from '../common/external-terminal';
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// some code copied and modified from https://github.com/microsoft/vscode/blob/1.52.1/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts
|
||||
|
||||
@injectable()
|
||||
export class MacExternalTerminalService implements ExternalTerminalService {
|
||||
protected osxOpener = '/usr/bin/open';
|
||||
protected defaultTerminalApp = 'Terminal.app';
|
||||
|
||||
async openTerminal(configuration: ExternalTerminalConfiguration, cwd: string): Promise<void> {
|
||||
await this.spawnTerminal(configuration, FileUri.fsPath(cwd));
|
||||
}
|
||||
|
||||
async getDefaultExec(): Promise<string> {
|
||||
return this.getDefaultTerminalOSX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn the external terminal for the given options.
|
||||
* - The method spawns the terminal application based on the preferences, else uses the default value.
|
||||
* @param configuration the preference configuration.
|
||||
* @param cwd the optional current working directory to spawn from.
|
||||
*/
|
||||
protected async spawnTerminal(configuration: ExternalTerminalConfiguration, cwd?: string): Promise<void> {
|
||||
|
||||
// Use the executable value from the preferences if available, else fallback to the default.
|
||||
const terminalConfig = configuration['terminal.external.osxExec'];
|
||||
const terminalApp = terminalConfig || this.getDefaultTerminalOSX();
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const args = ['-a', terminalApp];
|
||||
if (cwd) {
|
||||
args.push(cwd);
|
||||
}
|
||||
const child = cp.spawn(this.osxOpener, args);
|
||||
child.on('error', reject);
|
||||
child.on('exit', () => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default terminal app on OSX.
|
||||
*/
|
||||
protected getDefaultTerminalOSX(): string {
|
||||
return this.defaultTerminalApp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
// *****************************************************************************
|
||||
// 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 * as cp from 'child_process';
|
||||
import * as path from 'path';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { FileUri } from '@theia/core/lib/common/file-uri';
|
||||
import { ExternalTerminalService, ExternalTerminalConfiguration } from '../common/external-terminal';
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// some code copied and modified from https://github.com/microsoft/vscode/blob/1.52.1/src/vs/workbench/contrib/externalTerminal/node/externalTerminalService.ts
|
||||
|
||||
@injectable()
|
||||
export class WindowsExternalTerminalService implements ExternalTerminalService {
|
||||
protected readonly CMD = 'cmd.exe';
|
||||
protected DEFAULT_TERMINAL_WINDOWS: string;
|
||||
|
||||
async openTerminal(configuration: ExternalTerminalConfiguration, cwd: string): Promise<void> {
|
||||
await this.spawnTerminal(configuration, FileUri.fsPath(cwd));
|
||||
}
|
||||
|
||||
async getDefaultExec(): Promise<string> {
|
||||
return this.getDefaultTerminalWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn the external terminal for the given options.
|
||||
* - The method spawns the terminal application based on the preferences, else uses the default value.
|
||||
* @param configuration the preference configuration.
|
||||
* @param cwd the optional current working directory to spawn from.
|
||||
*/
|
||||
protected async spawnTerminal(configuration: ExternalTerminalConfiguration, cwd?: string): Promise<void> {
|
||||
|
||||
// Use the executable value from the preferences if available, else fallback to the default.
|
||||
const terminalConfig = configuration['terminal.external.windowsExec'];
|
||||
const exec = terminalConfig || this.getDefaultTerminalWindows();
|
||||
|
||||
// Make the drive letter uppercase on Windows (https://github.com/microsoft/vscode/issues/9448).
|
||||
if (cwd && cwd[1] === ':') {
|
||||
cwd = cwd[0].toUpperCase() + cwd.substring(1);
|
||||
}
|
||||
|
||||
// cmder ignores the environment cwd and instead opts to always open in %USERPROFILE%
|
||||
// unless otherwise specified.
|
||||
const basename = path.basename(exec).toLowerCase();
|
||||
if (basename === 'cmder' || basename === 'cmder.exe') {
|
||||
cp.spawn(exec, cwd ? [cwd] : undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const cmdArgs = ['/c', 'start', '/wait'];
|
||||
// The "" argument is the window title. Without this, exec doesn't work when the path contains spaces.
|
||||
if (exec.indexOf(' ') >= 0) {
|
||||
cmdArgs.push('""');
|
||||
}
|
||||
|
||||
cmdArgs.push(exec);
|
||||
|
||||
// Add starting directory parameter for Windows Terminal app.
|
||||
if (basename === 'wt' || basename === 'wt.exe') {
|
||||
cmdArgs.push('-d .');
|
||||
}
|
||||
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
const env = cwd ? { cwd } : undefined;
|
||||
const command = this.getWindowsShell();
|
||||
const child = cp.spawn(command, cmdArgs, env);
|
||||
child.on('error', reject);
|
||||
child.on('exit', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default terminal application on Windows.
|
||||
* - The following method uses environment variables to identify the best default possible value.
|
||||
*
|
||||
* @returns the default application on Windows.
|
||||
*/
|
||||
protected getDefaultTerminalWindows(): string {
|
||||
if (!this.DEFAULT_TERMINAL_WINDOWS) {
|
||||
const isWoW64 = !!process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
||||
this.DEFAULT_TERMINAL_WINDOWS = `${process.env.windir ? process.env.windir : 'C:\\Windows'}\\${isWoW64 ? 'Sysnative' : 'System32'}\\cmd.exe`;
|
||||
}
|
||||
return this.DEFAULT_TERMINAL_WINDOWS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the Windows Shell process to start up (defaults to cmd.exe).
|
||||
*/
|
||||
protected getWindowsShell(): string {
|
||||
// Find the path to cmd.exe if possible (%compsec% environment variable).
|
||||
return process.env.compsec || this.CMD;
|
||||
}
|
||||
}
|
||||
29
packages/external-terminal/src/package.spec.ts
Normal file
29
packages/external-terminal/src/package.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// *****************************************************************************
|
||||
// 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
|
||||
// *****************************************************************************
|
||||
|
||||
/* note: this bogus test file is required so that
|
||||
we are able to run mocha unit tests on this
|
||||
package, without having any actual unit tests in it.
|
||||
This way a coverage report will be generated,
|
||||
showing 0% coverage, instead of no report.
|
||||
This file can be removed once we have real unit
|
||||
tests in place. */
|
||||
|
||||
describe('external-terminal package', () => {
|
||||
|
||||
it('support code coverage statistics', () => true);
|
||||
|
||||
});
|
||||
22
packages/external-terminal/tsconfig.json
Normal file
22
packages/external-terminal/tsconfig.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"extends": "../../configs/base.tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../core"
|
||||
},
|
||||
{
|
||||
"path": "../editor"
|
||||
},
|
||||
{
|
||||
"path": "../workspace"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user