mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-08 15:55:15 +01:00
Merge branch 'master' of https://github.com/microsoft/vscode
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.51.0",
|
||||
"distro": "2efd579dedb12e7e9ed9ebd112120fa8b3b0922e",
|
||||
"distro": "5a2a07b357e780fb7130743e24cf814126485ef9",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
||||
@@ -63,7 +63,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._toDispose.add(_terminalService.onInstanceRequestSpawnExtHostProcess(request => this._onRequestSpawnExtHostProcess(request)));
|
||||
this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e)));
|
||||
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
|
||||
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
|
||||
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => instance && this._onTitleChanged(instance.id, instance.title)));
|
||||
this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
|
||||
this._toDispose.add(_terminalService.onRequestAvailableShells(e => this._onRequestAvailableShells(e)));
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShap
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITerminalChildProcess, ITerminalDimensions, EXT_HOST_CREATION_DELAY, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalChildProcess, EXT_HOST_CREATION_DELAY, ITerminalLaunchError, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
||||
@@ -245,8 +245,8 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = new Emitter<string>();
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensionsOverride | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensionsOverride | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
|
||||
constructor(private readonly _pty: vscode.Pseudoterminal) { }
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ export class TreeViewPane extends ViewPane {
|
||||
if (options.title !== this.treeView.title) {
|
||||
this.updateTitle(this.treeView.title);
|
||||
}
|
||||
if (options.titleDescription !== this.treeView.description) {
|
||||
this.updateTitleDescription(this.treeView.description);
|
||||
}
|
||||
this.updateTreeVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,24 +8,21 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { revive } from 'vs/base/common/marshalling';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IRemoteTerminalService, ITerminalInstanceService, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteTerminalService, ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteTerminalProcessExecCommandEvent, IShellLaunchConfigDto, RemoteTerminalChannelClient, REMOTE_TERMINAL_CHANNEL_NAME } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
|
||||
import { IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IProcessDataEvent, IRemoteTerminalAttachTarget, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper, ITerminalDimensionsOverride, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
|
||||
export class RemoteTerminalService extends Disposable implements IRemoteTerminalService {
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
private readonly _remoteTerminalChannel: RemoteTerminalChannelClient | null;
|
||||
private _hasConnectedToRemote = false;
|
||||
|
||||
constructor(
|
||||
@ITerminalService _terminalService: ITerminalService,
|
||||
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
@@ -46,34 +43,42 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal
|
||||
throw new Error(`Cannot create remote terminal when there is no remote!`);
|
||||
}
|
||||
|
||||
let isPreconnectionTerminal = false;
|
||||
if (!this._hasConnectedToRemote) {
|
||||
isPreconnectionTerminal = true;
|
||||
this._remoteAgentService.getEnvironment().then(() => {
|
||||
this._hasConnectedToRemote = true;
|
||||
});
|
||||
}
|
||||
return new RemoteTerminalProcess(terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper, this._remoteTerminalChannel, this._remoteAgentService, this._logService, this._commandService);
|
||||
}
|
||||
|
||||
return new RemoteTerminalProcess(terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper, isPreconnectionTerminal, this._remoteTerminalChannel, this._remoteAgentService, this._logService, this._commandService);
|
||||
public async listTerminals(): Promise<IRemoteTerminalAttachTarget[]> {
|
||||
const terms = this._remoteTerminalChannel ? await this._remoteTerminalChannel.listTerminals() : [];
|
||||
return terms.map(termDto => {
|
||||
return <IRemoteTerminalAttachTarget>{
|
||||
id: termDto.id,
|
||||
pid: termDto.pid,
|
||||
title: termDto.title,
|
||||
cwd: termDto.cwd
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoteTerminalProcess extends Disposable implements ITerminalChildProcess {
|
||||
|
||||
public readonly _onProcessData = this._register(new Emitter<string>());
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
public readonly _onProcessData = this._register(new Emitter<IProcessDataEvent>());
|
||||
public readonly onProcessData: Event<IProcessDataEvent> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = this._register(new Emitter<number | undefined>());
|
||||
public readonly onProcessExit: Event<number | undefined> = this._onProcessExit.event;
|
||||
public readonly _onProcessReady = this._register(new Emitter<{ pid: number, cwd: string }>());
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = this._register(new Emitter<string>());
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = this._register(new Emitter<ITerminalDimensionsOverride | undefined>());
|
||||
public readonly onProcessOverrideDimensions: Event<ITerminalDimensionsOverride | undefined> = this._onProcessOverrideDimensions.event;
|
||||
private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter<IShellLaunchConfig>());
|
||||
public get onProcessResolvedShellLaunchConfig(): Event<IShellLaunchConfig> { return this._onProcessResolvedShellLaunchConfig.event; }
|
||||
|
||||
private _startBarrier: Barrier;
|
||||
private _remoteTerminalId: number;
|
||||
|
||||
private _inReplay = false;
|
||||
|
||||
constructor(
|
||||
private readonly _terminalId: number,
|
||||
private readonly _shellLaunchConfig: IShellLaunchConfig,
|
||||
@@ -81,7 +86,6 @@ export class RemoteTerminalProcess extends Disposable implements ITerminalChildP
|
||||
private readonly _cols: number,
|
||||
private readonly _rows: number,
|
||||
private readonly _configHelper: ITerminalConfigHelper,
|
||||
private readonly _isPreconnectionTerminal: boolean,
|
||||
private readonly _remoteTerminalChannel: RemoteTerminalChannelClient,
|
||||
private readonly _remoteAgentService: IRemoteAgentService,
|
||||
private readonly _logService: ILogService,
|
||||
@@ -94,11 +98,6 @@ export class RemoteTerminalProcess extends Disposable implements ITerminalChildP
|
||||
|
||||
public async start(): Promise<ITerminalLaunchError | undefined> {
|
||||
|
||||
// Add a loading title only if this terminal is instantiated before a connection is up and running
|
||||
if (this._isPreconnectionTerminal) {
|
||||
setTimeout(() => this._onProcessTitleChanged.fire(nls.localize('terminal.integrated.starting', "Starting...")), 0);
|
||||
}
|
||||
|
||||
// Fetch the environment to check shell permissions
|
||||
const env = await this._remoteAgentService.getEnvironment();
|
||||
if (!env) {
|
||||
@@ -106,49 +105,45 @@ export class RemoteTerminalProcess extends Disposable implements ITerminalChildP
|
||||
throw new Error('Could not fetch remote environment');
|
||||
}
|
||||
|
||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions(env.os);
|
||||
if (!this._shellLaunchConfig.remoteAttach) {
|
||||
const isWorkspaceShellAllowed = this._configHelper.checkWorkspaceShellPermissions(env.os);
|
||||
|
||||
const shellLaunchConfigDto: IShellLaunchConfigDto = {
|
||||
name: this._shellLaunchConfig.name,
|
||||
executable: this._shellLaunchConfig.executable,
|
||||
args: this._shellLaunchConfig.args,
|
||||
cwd: this._shellLaunchConfig.cwd,
|
||||
env: this._shellLaunchConfig.env
|
||||
};
|
||||
const shellLaunchConfigDto: IShellLaunchConfigDto = {
|
||||
name: this._shellLaunchConfig.name,
|
||||
executable: this._shellLaunchConfig.executable,
|
||||
args: this._shellLaunchConfig.args,
|
||||
cwd: this._shellLaunchConfig.cwd,
|
||||
env: this._shellLaunchConfig.env
|
||||
};
|
||||
|
||||
this._logService.trace('Spawning remote agent process', { terminalId: this._terminalId, shellLaunchConfigDto });
|
||||
this._logService.trace('Spawning remote agent process', { terminalId: this._terminalId, shellLaunchConfigDto });
|
||||
|
||||
const result = await this._remoteTerminalChannel.createTerminalProcess(
|
||||
shellLaunchConfigDto,
|
||||
this._activeWorkspaceRootUri,
|
||||
this._cols,
|
||||
this._rows,
|
||||
isWorkspaceShellAllowed,
|
||||
);
|
||||
const result = await this._remoteTerminalChannel.createTerminalProcess(
|
||||
shellLaunchConfigDto,
|
||||
this._activeWorkspaceRootUri,
|
||||
this._cols,
|
||||
this._rows,
|
||||
isWorkspaceShellAllowed,
|
||||
);
|
||||
|
||||
this._remoteTerminalId = result.terminalId;
|
||||
this._register(this._remoteTerminalChannel.onTerminalProcessEvent(this._remoteTerminalId)(event => {
|
||||
switch (event.type) {
|
||||
case 'ready':
|
||||
return this._onProcessReady.fire({ pid: event.pid, cwd: event.cwd });
|
||||
case 'titleChanged':
|
||||
return this._onProcessTitleChanged.fire(event.title);
|
||||
case 'data':
|
||||
return this._onProcessData.fire(event.data);
|
||||
case 'exit':
|
||||
return this._onProcessExit.fire(event.exitCode);
|
||||
case 'execCommand':
|
||||
return this._execCommand(event);
|
||||
this._remoteTerminalId = result.terminalId;
|
||||
this.setupTerminalEventListener();
|
||||
this._onProcessResolvedShellLaunchConfig.fire(reviveIShellLaunchConfig(result.resolvedShellLaunchConfig));
|
||||
|
||||
const startResult = await this._remoteTerminalChannel.startTerminalProcess(this._remoteTerminalId);
|
||||
|
||||
if (typeof startResult !== 'undefined') {
|
||||
// An error occurred
|
||||
return startResult;
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
this._remoteTerminalId = this._shellLaunchConfig.remoteAttach.id;
|
||||
this._onProcessReady.fire({ pid: this._shellLaunchConfig.remoteAttach.pid, cwd: this._shellLaunchConfig.remoteAttach.cwd });
|
||||
this.setupTerminalEventListener();
|
||||
|
||||
this._onProcessResolvedShellLaunchConfig.fire(reviveIShellLaunchConfig(result.resolvedShellLaunchConfig));
|
||||
|
||||
const startResult = await this._remoteTerminalChannel.startTerminalProcess(this._remoteTerminalId);
|
||||
|
||||
if (typeof startResult !== 'undefined') {
|
||||
// An error occurred
|
||||
return startResult;
|
||||
setTimeout(() => {
|
||||
this._onProcessTitleChanged.fire(this._shellLaunchConfig.remoteAttach!.title);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
this._startBarrier.open();
|
||||
@@ -162,13 +157,62 @@ export class RemoteTerminalProcess extends Disposable implements ITerminalChildP
|
||||
}
|
||||
|
||||
public input(data: string): void {
|
||||
if (this._inReplay) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._startBarrier.wait().then(_ => {
|
||||
this._remoteTerminalChannel.sendInputToTerminalProcess(this._remoteTerminalId, data);
|
||||
});
|
||||
}
|
||||
|
||||
private setupTerminalEventListener(): void {
|
||||
this._register(this._remoteTerminalChannel.onTerminalProcessEvent(this._remoteTerminalId)(event => {
|
||||
switch (event.type) {
|
||||
case 'ready':
|
||||
return this._onProcessReady.fire({ pid: event.pid, cwd: event.cwd });
|
||||
case 'titleChanged':
|
||||
return this._onProcessTitleChanged.fire(event.title);
|
||||
case 'data':
|
||||
return this._onProcessData.fire({ data: event.data, sync: false });
|
||||
case 'replay': {
|
||||
try {
|
||||
this._inReplay = true;
|
||||
|
||||
for (const e of event.events) {
|
||||
if (e.cols !== 0 || e.rows !== 0) {
|
||||
// never override with 0x0 as that is a marker for an unknown initial size
|
||||
this._onProcessOverrideDimensions.fire({ cols: e.cols, rows: e.rows, forceExactSize: true });
|
||||
}
|
||||
this._onProcessData.fire({ data: e.data, sync: true });
|
||||
}
|
||||
} finally {
|
||||
this._inReplay = false;
|
||||
}
|
||||
|
||||
// remove size override
|
||||
this._onProcessOverrideDimensions.fire(undefined);
|
||||
|
||||
return;
|
||||
}
|
||||
case 'exit':
|
||||
return this._onProcessExit.fire(event.exitCode);
|
||||
case 'execCommand':
|
||||
return this._execCommand(event);
|
||||
case 'orphan?': {
|
||||
this._remoteTerminalChannel.orphanQuestionReply(this._remoteTerminalId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public resize(cols: number, rows: number): void {
|
||||
if (this._inReplay) {
|
||||
return;
|
||||
}
|
||||
this._startBarrier.wait().then(_ => {
|
||||
|
||||
this._remoteTerminalChannel.resizeTerminalProcess(this._remoteTerminalId, cols, rows);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { Terminal as XTermTerminal } from 'xterm';
|
||||
import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||
import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11';
|
||||
import type { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl';
|
||||
import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig, IDefaultShellAndArgsRequest, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, ITerminalProcessExtHostProxy, ICommandTracker, INavigationMode, TitleEventSource, ITerminalDimensions, ITerminalLaunchError, ITerminalNativeWindowsDelegate, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig, IDefaultShellAndArgsRequest, ISpawnExtHostProcessRequest, IStartExtensionTerminalRequest, IAvailableShellsRequest, ITerminalProcessExtHostProxy, ICommandTracker, INavigationMode, TitleEventSource, ITerminalDimensions, ITerminalLaunchError, ITerminalNativeWindowsDelegate, LinuxDistro, IRemoteTerminalAttachTarget } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProcessEnvironment, Platform } from 'vs/base/common/platform';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -79,6 +79,7 @@ export interface ITerminalService {
|
||||
terminalTabs: ITerminalTab[];
|
||||
isProcessSupportRegistered: boolean;
|
||||
|
||||
initializeTerminals(): Promise<void>;
|
||||
onActiveTabChanged: Event<void>;
|
||||
onTabDisposed: Event<ITerminalTab>;
|
||||
onInstanceCreated: Event<ITerminalInstance>;
|
||||
@@ -89,7 +90,7 @@ export interface ITerminalService {
|
||||
onInstanceRequestSpawnExtHostProcess: Event<ISpawnExtHostProcessRequest>;
|
||||
onInstanceRequestStartExtensionTerminal: Event<IStartExtensionTerminalRequest>;
|
||||
onInstancesChanged: Event<void>;
|
||||
onInstanceTitleChanged: Event<ITerminalInstance>;
|
||||
onInstanceTitleChanged: Event<ITerminalInstance | undefined>;
|
||||
onActiveInstanceChanged: Event<ITerminalInstance | undefined>;
|
||||
onRequestAvailableShells: Event<IAvailableShellsRequest>;
|
||||
onDidRegisterProcessSupport: Event<void>;
|
||||
@@ -180,6 +181,7 @@ export interface IRemoteTerminalService {
|
||||
|
||||
dispose(): void;
|
||||
|
||||
listTerminals(): Promise<IRemoteTerminalAttachTarget[]>;
|
||||
createRemoteTerminalProcess(terminalId: number, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, configHelper: ITerminalConfigHelper,): Promise<ITerminalChildProcess>;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,23 +79,9 @@ export class ToggleTerminalAction extends ToggleViewAction {
|
||||
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label, TERMINAL_VIEW_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
|
||||
}
|
||||
|
||||
async run() {
|
||||
if (this.terminalService.isProcessSupportRegistered && this.terminalService.terminalInstances.length === 0) {
|
||||
// If there is not yet an instance attempt to create it here so that we can suggest a
|
||||
// new shell on Windows (and not do so when the panel is restored on reload).
|
||||
const newTerminalInstance = this.terminalService.createTerminal(undefined);
|
||||
const toDispose = newTerminalInstance.onProcessIdReady(() => {
|
||||
newTerminalInstance.focus();
|
||||
toDispose.dispose();
|
||||
});
|
||||
}
|
||||
return super.run();
|
||||
}
|
||||
}
|
||||
|
||||
export class KillTerminalAction extends Action {
|
||||
|
||||
@@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB
|
||||
import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager';
|
||||
import { IShellLaunchConfig, ITerminalDimensions, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_VIEW_ID, IWindowsShellHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, DEFAULT_COMMANDS_TO_SKIP_SHELL, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IShellLaunchConfig, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_VIEW_ID, IWindowsShellHelper, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode, TitleEventSource, DEFAULT_COMMANDS_TO_SKIP_SHELL, ITerminalLaunchError, IProcessDataEvent, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
import { TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
|
||||
@@ -94,7 +94,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
private _terminalA11yTreeFocusContextKey: IContextKey<boolean>;
|
||||
private _cols: number = 0;
|
||||
private _rows: number = 0;
|
||||
private _dimensionsOverride: ITerminalDimensions | undefined;
|
||||
private _dimensionsOverride: ITerminalDimensionsOverride | undefined;
|
||||
private _windowsShellHelper: IWindowsShellHelper | undefined;
|
||||
private _xtermReadyPromise: Promise<XTermTerminal>;
|
||||
private _titleReadyPromise: Promise<string>;
|
||||
@@ -117,12 +117,18 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
public get id(): number { return this._id; }
|
||||
public get cols(): number {
|
||||
if (this._dimensionsOverride && this._dimensionsOverride.cols) {
|
||||
if (this._dimensionsOverride.forceExactSize) {
|
||||
return this._dimensionsOverride.cols;
|
||||
}
|
||||
return Math.min(Math.max(this._dimensionsOverride.cols, 2), this._cols);
|
||||
}
|
||||
return this._cols;
|
||||
}
|
||||
public get rows(): number {
|
||||
if (this._dimensionsOverride && this._dimensionsOverride.rows) {
|
||||
if (this._dimensionsOverride.forceExactSize) {
|
||||
return this._dimensionsOverride.rows;
|
||||
}
|
||||
return Math.min(Math.max(this._dimensionsOverride.rows, 2), this._rows);
|
||||
}
|
||||
return this._rows;
|
||||
@@ -415,7 +421,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
this._xterm.onKey(e => this._onKey(e.key, e.domEvent));
|
||||
this._xterm.onSelectionChange(async () => this._onSelectionChange());
|
||||
|
||||
this._processManager.onProcessData(data => this._onProcessData(data));
|
||||
this._processManager.onProcessData(e => this._onProcessData(e));
|
||||
this._xterm.onData(data => this._processManager.write(data));
|
||||
this.processReady.then(async () => {
|
||||
if (this._linkManager) {
|
||||
@@ -882,11 +888,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
this._processManager = this._instantiationService.createInstance(TerminalProcessManager, this._id, this._configHelper);
|
||||
this._processManager.onProcessReady(() => this._onProcessIdReady.fire(this));
|
||||
this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode));
|
||||
this._processManager.onProcessData(data => {
|
||||
this._initialDataEvents?.push(data);
|
||||
this._onData.fire(data);
|
||||
this._processManager.onProcessData(ev => {
|
||||
this._initialDataEvents?.push(ev.data);
|
||||
this._onData.fire(ev.data);
|
||||
});
|
||||
this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e));
|
||||
this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e, true));
|
||||
this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e));
|
||||
this._processManager.onEnvironmentVariableInfoChanged(e => this._onEnvironmentVariableInfoChanged(e));
|
||||
|
||||
@@ -959,9 +965,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
}
|
||||
}
|
||||
|
||||
private _onProcessData(data: string): void {
|
||||
const messageId = ++this._latestXtermWriteData;
|
||||
this._xterm?.write(data, () => this._latestXtermParseData = messageId);
|
||||
private _onProcessData(ev: IProcessDataEvent): void {
|
||||
if (ev.sync) {
|
||||
this._xtermCore?.writeSync(ev.data);
|
||||
} else {
|
||||
const messageId = ++this._latestXtermWriteData;
|
||||
this._xterm?.write(ev.data, () => this._latestXtermParseData = messageId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1349,6 +1359,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
|
||||
@debounce(50)
|
||||
private async _resize(): Promise<void> {
|
||||
this._resizeNow(false);
|
||||
}
|
||||
|
||||
private async _resizeNow(immediate: boolean): Promise<void> {
|
||||
let cols = this.cols;
|
||||
let rows = this.rows;
|
||||
|
||||
@@ -1398,8 +1412,13 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
}
|
||||
}
|
||||
|
||||
await this._processManager.ptyProcessReady;
|
||||
this._processManager.setDimensions(cols, rows);
|
||||
if (immediate) {
|
||||
// do not await, call setDimensions synchronously
|
||||
this._processManager.setDimensions(cols, rows);
|
||||
} else {
|
||||
await this._processManager.ptyProcessReady;
|
||||
this._processManager.setDimensions(cols, rows);
|
||||
}
|
||||
}
|
||||
|
||||
public setShellType(shellType: TerminalShellType) {
|
||||
@@ -1442,9 +1461,18 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
|
||||
return this._titleReadyPromise;
|
||||
}
|
||||
|
||||
public setDimensions(dimensions: ITerminalDimensions | undefined): void {
|
||||
public setDimensions(dimensions: ITerminalDimensionsOverride | undefined, immediate: boolean = false): void {
|
||||
if (this._dimensionsOverride && this._dimensionsOverride.forceExactSize && !dimensions && this._rows === 0 && this._cols === 0) {
|
||||
// this terminal never had a real size => keep the last dimensions override exact size
|
||||
this._cols = this._dimensionsOverride.cols;
|
||||
this._rows = this._dimensionsOverride.rows;
|
||||
}
|
||||
this._dimensionsOverride = dimensions;
|
||||
this._resize();
|
||||
if (immediate) {
|
||||
this._resizeNow(true);
|
||||
} else {
|
||||
this._resize();
|
||||
}
|
||||
}
|
||||
|
||||
private _setResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper, ITerminalDimensions, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper, ITerminalDimensions, ITerminalLaunchError, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
@@ -23,8 +23,8 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal
|
||||
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
|
||||
private readonly _onProcessTitleChanged = this._register(new Emitter<string>());
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = this._register(new Emitter<ITerminalDimensions | undefined>());
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessOverrideDimensions = this._register(new Emitter<ITerminalDimensionsOverride | undefined>());
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensionsOverride | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessResolvedShellLaunchConfig = this._register(new Emitter<IShellLaunchConfig>());
|
||||
public get onProcessResolvedShellLaunchConfig(): Event<IShellLaunchConfig> { return this._onProcessResolvedShellLaunchConfig.event; }
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { env as processEnv } from 'vs/base/common/process';
|
||||
import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess, IBeforeProcessDataEvent, ITerminalEnvironment, ITerminalDimensions, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess, IBeforeProcessDataEvent, ITerminalEnvironment, ITerminalLaunchError, IProcessDataEvent, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
@@ -69,14 +69,14 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
||||
public get onProcessReady(): Event<void> { return this._onProcessReady.event; }
|
||||
private readonly _onBeforeProcessData = this._register(new Emitter<IBeforeProcessDataEvent>());
|
||||
public get onBeforeProcessData(): Event<IBeforeProcessDataEvent> { return this._onBeforeProcessData.event; }
|
||||
private readonly _onProcessData = this._register(new Emitter<string>());
|
||||
public get onProcessData(): Event<string> { return this._onProcessData.event; }
|
||||
private readonly _onProcessData = this._register(new Emitter<IProcessDataEvent>());
|
||||
public get onProcessData(): Event<IProcessDataEvent> { return this._onProcessData.event; }
|
||||
private readonly _onProcessTitle = this._register(new Emitter<string>());
|
||||
public get onProcessTitle(): Event<string> { return this._onProcessTitle.event; }
|
||||
private readonly _onProcessExit = this._register(new Emitter<number | undefined>());
|
||||
public get onProcessExit(): Event<number | undefined> { return this._onProcessExit.event; }
|
||||
private readonly _onProcessOverrideDimensions = this._register(new Emitter<ITerminalDimensions | undefined>());
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessOverrideDimensions = this._register(new Emitter<ITerminalDimensionsOverride | undefined>());
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensionsOverride | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessOverrideShellLaunchConfig = this._register(new Emitter<IShellLaunchConfig>());
|
||||
public get onProcessResolvedShellLaunchConfig(): Event<IShellLaunchConfig> { return this._onProcessOverrideShellLaunchConfig.event; }
|
||||
private readonly _onEnvironmentVariableInfoChange = this._register(new Emitter<IEnvironmentVariableInfo>());
|
||||
@@ -158,8 +158,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
||||
}
|
||||
|
||||
const activeWorkspaceRootUri = this._historyService.getLastActiveWorkspaceRoot();
|
||||
const enableRemoteAgentTerminals = this._workspaceConfigurationService.getValue('terminal.integrated.serverSpawn');
|
||||
if (enableRemoteAgentTerminals) {
|
||||
const enableRemoteAgentTerminals = this._workspaceConfigurationService.getValue<boolean | undefined>('terminal.integrated.serverSpawn');
|
||||
if (enableRemoteAgentTerminals !== false) {
|
||||
this._process = await this._remoteTerminalService.createRemoteTerminalProcess(this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
|
||||
} else {
|
||||
this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, this._configHelper);
|
||||
@@ -171,11 +171,13 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
|
||||
|
||||
this.processState = ProcessState.LAUNCHING;
|
||||
|
||||
this._process.onProcessData(data => {
|
||||
this._process.onProcessData(ev => {
|
||||
const data = (typeof ev === 'string' ? ev : ev.data);
|
||||
const sync = (typeof ev === 'string' ? false : ev.sync);
|
||||
const beforeProcessDataEvent: IBeforeProcessDataEvent = { data };
|
||||
this._onBeforeProcessData.fire(beforeProcessDataEvent);
|
||||
if (beforeProcessDataEvent.data && beforeProcessDataEvent.data.length > 0) {
|
||||
this._onProcessData.fire(beforeProcessDataEvent.data);
|
||||
this._onProcessData.fire({ data: beforeProcessDataEvent.data, sync });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminalInstance';
|
||||
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType, ITerminalExternalLinkProvider } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { ITerminalService, ITerminalInstance, ITerminalTab, TerminalShellType, WindowsShellType, ITerminalExternalLinkProvider, IRemoteTerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
|
||||
@@ -85,8 +85,8 @@ export class TerminalService implements ITerminalService {
|
||||
public get onInstanceMaximumDimensionsChanged(): Event<ITerminalInstance> { return this._onInstanceMaximumDimensionsChanged.event; }
|
||||
private readonly _onInstancesChanged = new Emitter<void>();
|
||||
public get onInstancesChanged(): Event<void> { return this._onInstancesChanged.event; }
|
||||
private readonly _onInstanceTitleChanged = new Emitter<ITerminalInstance>();
|
||||
public get onInstanceTitleChanged(): Event<ITerminalInstance> { return this._onInstanceTitleChanged.event; }
|
||||
private readonly _onInstanceTitleChanged = new Emitter<ITerminalInstance | undefined>();
|
||||
public get onInstanceTitleChanged(): Event<ITerminalInstance | undefined> { return this._onInstanceTitleChanged.event; }
|
||||
private readonly _onActiveInstanceChanged = new Emitter<ITerminalInstance | undefined>();
|
||||
public get onActiveInstanceChanged(): Event<ITerminalInstance | undefined> { return this._onActiveInstanceChanged.event; }
|
||||
private readonly _onTabDisposed = new Emitter<ITerminalTab>();
|
||||
@@ -108,7 +108,9 @@ export class TerminalService implements ITerminalService {
|
||||
@IConfigurationService private _configurationService: IConfigurationService,
|
||||
@IViewsService private _viewsService: IViewsService,
|
||||
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
|
||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
|
||||
@IConfigurationService private readonly _workspaceConfigurationService: IConfigurationService,
|
||||
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
|
||||
@IRemoteTerminalService private readonly _remoteTerminalService: IRemoteTerminalService
|
||||
) {
|
||||
this._activeTabIndex = 0;
|
||||
this._isShuttingDown = false;
|
||||
@@ -221,7 +223,7 @@ export class TerminalService implements ITerminalService {
|
||||
}
|
||||
|
||||
public getTabLabels(): string[] {
|
||||
return this._terminalTabs.filter(tab => tab.terminalInstances.length > 0).map((tab, index) => `${index + 1}: ${tab.title ? tab.title : ''}`);
|
||||
return this._terminalTabs.map((tab, index) => `${index + 1}: ${tab.title ? tab.title : ''}`);
|
||||
}
|
||||
|
||||
public getFindState(): FindReplaceState {
|
||||
@@ -339,6 +341,31 @@ export class TerminalService implements ITerminalService {
|
||||
}
|
||||
}
|
||||
|
||||
public async initializeTerminals(): Promise<void> {
|
||||
const enableRemoteAgentTerminals = this._workspaceConfigurationService.getValue<boolean | undefined>('terminal.integrated.serverSpawn');
|
||||
if (!!this._environmentService.remoteAuthority && enableRemoteAgentTerminals !== false) {
|
||||
const emptyTab = this._instantiationService.createInstance(TerminalTab, this._terminalContainer, undefined);
|
||||
this._terminalTabs.push(emptyTab);
|
||||
this._onInstanceTitleChanged.fire(undefined);
|
||||
const remoteTerms = await this._remoteTerminalService.listTerminals();
|
||||
if (remoteTerms.length > 0) {
|
||||
// Reattach to all remote terms
|
||||
this.createTerminal({ remoteAttach: remoteTerms[0] }, emptyTab);
|
||||
for (let term of remoteTerms.slice(1)) {
|
||||
this.createTerminal({ remoteAttach: term });
|
||||
}
|
||||
} else {
|
||||
// Remote, no terminals to attach to
|
||||
this.createTerminal(undefined, emptyTab);
|
||||
}
|
||||
} else {
|
||||
if (this.terminalInstances.length === 0) {
|
||||
// Local, just create a terminal
|
||||
this.createTerminal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _getInstanceFromGlobalInstanceIndex(index: number): { tab: ITerminalTab, tabIndex: number, instance: ITerminalInstance, localInstanceIndex: number } | null {
|
||||
let currentTabIndex = 0;
|
||||
while (index >= 0 && currentTabIndex < this._terminalTabs.length) {
|
||||
@@ -610,7 +637,7 @@ export class TerminalService implements ITerminalService {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance {
|
||||
public createTerminal(shell: IShellLaunchConfig = {}, terminalTab?: TerminalTab): ITerminalInstance {
|
||||
if (!this.isProcessSupportRegistered) {
|
||||
throw new Error('Could not create terminal when process support is not registered');
|
||||
}
|
||||
@@ -620,8 +647,14 @@ export class TerminalService implements ITerminalService {
|
||||
this._initInstanceListeners(instance);
|
||||
return instance;
|
||||
}
|
||||
const terminalTab = this._instantiationService.createInstance(TerminalTab, this._terminalContainer, shell);
|
||||
this._terminalTabs.push(terminalTab);
|
||||
|
||||
if (terminalTab) {
|
||||
terminalTab.addInstance(shell);
|
||||
} else {
|
||||
terminalTab = this._instantiationService.createInstance(TerminalTab, this._terminalContainer, shell);
|
||||
this._terminalTabs.push(terminalTab);
|
||||
}
|
||||
|
||||
const instance = terminalTab.terminalInstances[0];
|
||||
terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed));
|
||||
terminalTab.addDisposable(terminalTab.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IShellLaunchConfig, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { SplitView, Orientation, IView, Sizing } from 'vs/base/browser/ui/splitview/splitview';
|
||||
@@ -228,7 +229,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
|
||||
constructor(
|
||||
private _container: HTMLElement | undefined,
|
||||
shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance,
|
||||
shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance | undefined,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService,
|
||||
@IViewDescriptorService private readonly _viewDescriptorService: IViewDescriptorService,
|
||||
@@ -236,6 +237,18 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
) {
|
||||
super();
|
||||
|
||||
if (shellLaunchConfigOrInstance) {
|
||||
this.addInstance(shellLaunchConfigOrInstance);
|
||||
}
|
||||
|
||||
this._activeInstanceIndex = 0;
|
||||
|
||||
if (this._container) {
|
||||
this.attachToElement(this._container);
|
||||
}
|
||||
}
|
||||
|
||||
public addInstance(shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance): void {
|
||||
let instance: ITerminalInstance;
|
||||
if ('id' in shellLaunchConfigOrInstance) {
|
||||
instance = shellLaunchConfigOrInstance;
|
||||
@@ -244,11 +257,12 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
}
|
||||
this._terminalInstances.push(instance);
|
||||
this._initInstanceListeners(instance);
|
||||
this._activeInstanceIndex = 0;
|
||||
|
||||
if (this._container) {
|
||||
this.attachToElement(this._container);
|
||||
if (this._splitPaneContainer) {
|
||||
this._splitPaneContainer!.split(instance);
|
||||
}
|
||||
|
||||
this._onInstancesChanged.fire();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -358,6 +372,10 @@ export class TerminalTab extends Disposable implements ITerminalTab {
|
||||
}
|
||||
|
||||
public get title(): string {
|
||||
if (!this.terminalInstances.length) {
|
||||
return nls.localize('terminal.integrated.starting', "Starting...");
|
||||
}
|
||||
|
||||
let title = this.terminalInstances[0].title;
|
||||
for (let i = 1; i < this.terminalInstances.length; i++) {
|
||||
if (this.terminalInstances[i].title) {
|
||||
|
||||
@@ -41,6 +41,7 @@ export class TerminalViewPane extends ViewPane {
|
||||
private _terminalContainer: HTMLElement | undefined;
|
||||
private _findWidget: TerminalFindWidget | undefined;
|
||||
private _splitTerminalAction: IAction | undefined;
|
||||
private _terminalsInitialized = false;
|
||||
private _bodyDimensions: { width: number, height: number } = { width: 0, height: 0 };
|
||||
|
||||
constructor(
|
||||
@@ -109,14 +110,21 @@ export class TerminalViewPane extends ViewPane {
|
||||
|
||||
this._register(this.onDidChangeBodyVisibility(visible => {
|
||||
if (visible) {
|
||||
const hadTerminals = this._terminalService.terminalInstances.length > 0;
|
||||
if (!hadTerminals) {
|
||||
this._terminalService.createTerminal();
|
||||
const hadTerminals = !!this._terminalService.terminalTabs.length;
|
||||
if (this._terminalsInitialized) {
|
||||
if (!hadTerminals) {
|
||||
this._terminalService.createTerminal();
|
||||
}
|
||||
} else {
|
||||
this._terminalsInitialized = true;
|
||||
this._terminalService.initializeTerminals();
|
||||
}
|
||||
|
||||
this._updateTheme();
|
||||
if (hadTerminals) {
|
||||
this._terminalService.getActiveTab()?.setVisible(visible);
|
||||
} else {
|
||||
// TODO@Tyriar - this call seems unnecessary
|
||||
this.layoutBody(this._bodyDimensions.height, this._bodyDimensions.width);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -26,6 +26,8 @@ export interface XTermCore {
|
||||
};
|
||||
_onIntersectionChange: any;
|
||||
};
|
||||
|
||||
writeSync(data: string | Uint8Array): void;
|
||||
}
|
||||
|
||||
export interface IEventEmitter<T> {
|
||||
|
||||
@@ -116,6 +116,21 @@ export interface ISendCommandResultToTerminalProcessArguments {
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export interface IOrphanQuestionReplyArgs {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface IRemoteTerminalDescriptionDto {
|
||||
id: number;
|
||||
pid: number;
|
||||
title: string;
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
export interface ITriggerTerminalDataReplayArguments {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface IRemoteTerminalProcessReadyEvent {
|
||||
type: 'ready';
|
||||
pid: number;
|
||||
@@ -126,11 +141,16 @@ export interface IRemoteTerminalProcessTitleChangedEvent {
|
||||
title: string;
|
||||
}
|
||||
export interface IRemoteTerminalProcessDataEvent {
|
||||
type: 'data'
|
||||
type: 'data';
|
||||
data: string;
|
||||
}
|
||||
export interface ReplayEntry { cols: number; rows: number; data: string; }
|
||||
export interface IRemoteTerminalProcessReplayEvent {
|
||||
type: 'replay';
|
||||
events: ReplayEntry[];
|
||||
}
|
||||
export interface IRemoteTerminalProcessExitEvent {
|
||||
type: 'exit'
|
||||
type: 'exit';
|
||||
exitCode: number | undefined;
|
||||
}
|
||||
export interface IRemoteTerminalProcessExecCommandEvent {
|
||||
@@ -139,12 +159,17 @@ export interface IRemoteTerminalProcessExecCommandEvent {
|
||||
commandId: string;
|
||||
commandArgs: any[];
|
||||
}
|
||||
export interface IRemoteTerminalProcessOrphanQuestionEvent {
|
||||
type: 'orphan?';
|
||||
}
|
||||
export type IRemoteTerminalProcessEvent = (
|
||||
IRemoteTerminalProcessReadyEvent
|
||||
| IRemoteTerminalProcessTitleChangedEvent
|
||||
| IRemoteTerminalProcessDataEvent
|
||||
| IRemoteTerminalProcessReplayEvent
|
||||
| IRemoteTerminalProcessExitEvent
|
||||
| IRemoteTerminalProcessExecCommandEvent
|
||||
| IRemoteTerminalProcessOrphanQuestionEvent
|
||||
);
|
||||
|
||||
export interface IOnTerminalProcessEventArguments {
|
||||
@@ -166,7 +191,7 @@ export class RemoteTerminalChannelClient {
|
||||
) {
|
||||
}
|
||||
|
||||
private _readSingleTemrinalConfiguration<T>(key: string): ISingleTerminalConfiguration<T> {
|
||||
private _readSingleTerminalConfiguration<T>(key: string): ISingleTerminalConfiguration<T> {
|
||||
const result = this._configurationService.inspect<T>(key);
|
||||
return {
|
||||
userValue: result.userValue,
|
||||
@@ -178,18 +203,18 @@ export class RemoteTerminalChannelClient {
|
||||
public async createTerminalProcess(shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ICreateTerminalProcessResult> {
|
||||
const terminalConfig = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION);
|
||||
const configuration: ICompleteTerminalConfiguration = {
|
||||
'terminal.integrated.automationShell.windows': this._readSingleTemrinalConfiguration('terminal.integrated.automationShell.windows'),
|
||||
'terminal.integrated.automationShell.osx': this._readSingleTemrinalConfiguration('terminal.integrated.automationShell.osx'),
|
||||
'terminal.integrated.automationShell.linux': this._readSingleTemrinalConfiguration('terminal.integrated.automationShell.linux'),
|
||||
'terminal.integrated.shell.windows': this._readSingleTemrinalConfiguration('terminal.integrated.shell.windows'),
|
||||
'terminal.integrated.shell.osx': this._readSingleTemrinalConfiguration('terminal.integrated.shell.osx'),
|
||||
'terminal.integrated.shell.linux': this._readSingleTemrinalConfiguration('terminal.integrated.shell.linux'),
|
||||
'terminal.integrated.shellArgs.windows': this._readSingleTemrinalConfiguration('terminal.integrated.shellArgs.windows'),
|
||||
'terminal.integrated.shellArgs.osx': this._readSingleTemrinalConfiguration('terminal.integrated.shellArgs.osx'),
|
||||
'terminal.integrated.shellArgs.linux': this._readSingleTemrinalConfiguration('terminal.integrated.shellArgs.linux'),
|
||||
'terminal.integrated.env.windows': this._readSingleTemrinalConfiguration('terminal.integrated.env.windows'),
|
||||
'terminal.integrated.env.osx': this._readSingleTemrinalConfiguration('terminal.integrated.env.osx'),
|
||||
'terminal.integrated.env.linux': this._readSingleTemrinalConfiguration('terminal.integrated.env.linux'),
|
||||
'terminal.integrated.automationShell.windows': this._readSingleTerminalConfiguration('terminal.integrated.automationShell.windows'),
|
||||
'terminal.integrated.automationShell.osx': this._readSingleTerminalConfiguration('terminal.integrated.automationShell.osx'),
|
||||
'terminal.integrated.automationShell.linux': this._readSingleTerminalConfiguration('terminal.integrated.automationShell.linux'),
|
||||
'terminal.integrated.shell.windows': this._readSingleTerminalConfiguration('terminal.integrated.shell.windows'),
|
||||
'terminal.integrated.shell.osx': this._readSingleTerminalConfiguration('terminal.integrated.shell.osx'),
|
||||
'terminal.integrated.shell.linux': this._readSingleTerminalConfiguration('terminal.integrated.shell.linux'),
|
||||
'terminal.integrated.shellArgs.windows': this._readSingleTerminalConfiguration('terminal.integrated.shellArgs.windows'),
|
||||
'terminal.integrated.shellArgs.osx': this._readSingleTerminalConfiguration('terminal.integrated.shellArgs.osx'),
|
||||
'terminal.integrated.shellArgs.linux': this._readSingleTerminalConfiguration('terminal.integrated.shellArgs.linux'),
|
||||
'terminal.integrated.env.windows': this._readSingleTerminalConfiguration('terminal.integrated.env.windows'),
|
||||
'terminal.integrated.env.osx': this._readSingleTerminalConfiguration('terminal.integrated.env.osx'),
|
||||
'terminal.integrated.env.linux': this._readSingleTerminalConfiguration('terminal.integrated.env.linux'),
|
||||
'terminal.integrated.inheritEnv': terminalConfig.inheritEnv,
|
||||
'terminal.integrated.cwd': terminalConfig.cwd,
|
||||
'terminal.integrated.detectLocale': terminalConfig.detectLocale,
|
||||
@@ -306,4 +331,15 @@ export class RemoteTerminalChannelClient {
|
||||
};
|
||||
return this._channel.call<void>('$sendCommandResultToTerminalProcess', args);
|
||||
}
|
||||
|
||||
public orphanQuestionReply(id: number): Promise<void> {
|
||||
const args: IOrphanQuestionReplyArgs = {
|
||||
id
|
||||
};
|
||||
return this._channel.call<void>('$orphanQuestionReply', args);
|
||||
}
|
||||
|
||||
public listTerminals(): Promise<IRemoteTerminalDescriptionDto[]> {
|
||||
return this._channel.call<IRemoteTerminalDescriptionDto[]>('$listTerminals');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +165,13 @@ export interface ITerminalEnvironment {
|
||||
[key: string]: string | null;
|
||||
}
|
||||
|
||||
export interface IRemoteTerminalAttachTarget {
|
||||
id: number;
|
||||
pid: number;
|
||||
title: string;
|
||||
cwd: string;
|
||||
}
|
||||
|
||||
export interface IShellLaunchConfig {
|
||||
/**
|
||||
* The name of the terminal, if this is not set the name of the process will be used.
|
||||
@@ -217,6 +224,11 @@ export interface IShellLaunchConfig {
|
||||
*/
|
||||
isExtensionTerminal?: boolean;
|
||||
|
||||
/**
|
||||
* This is a terminal that attaches to an already running remote terminal.
|
||||
*/
|
||||
remoteAttach?: { id: number; pid: number; title: string; cwd: string; };
|
||||
|
||||
/**
|
||||
* Whether the terminal process environment should be exactly as provided in
|
||||
* `TerminalOptions.env`. When this is false (default), the environment will be based on the
|
||||
@@ -268,6 +280,13 @@ export interface ITerminalDimensions {
|
||||
readonly rows: number;
|
||||
}
|
||||
|
||||
export interface ITerminalDimensionsOverride extends ITerminalDimensions {
|
||||
/**
|
||||
* indicate that xterm must receive these exact dimensions, even if they overflow the ui!
|
||||
*/
|
||||
forceExactSize?: boolean;
|
||||
}
|
||||
|
||||
export interface ICommandTracker {
|
||||
scrollToPreviousCommand(): void;
|
||||
scrollToNextCommand(): void;
|
||||
@@ -291,6 +310,11 @@ export interface IBeforeProcessDataEvent {
|
||||
data: string;
|
||||
}
|
||||
|
||||
export interface IProcessDataEvent {
|
||||
data: string;
|
||||
sync: boolean;
|
||||
}
|
||||
|
||||
export interface ITerminalProcessManager extends IDisposable {
|
||||
readonly processState: ProcessState;
|
||||
readonly ptyProcessReady: Promise<void>;
|
||||
@@ -302,10 +326,10 @@ export interface ITerminalProcessManager extends IDisposable {
|
||||
|
||||
readonly onProcessReady: Event<void>;
|
||||
readonly onBeforeProcessData: Event<IBeforeProcessDataEvent>;
|
||||
readonly onProcessData: Event<string>;
|
||||
readonly onProcessData: Event<IProcessDataEvent>;
|
||||
readonly onProcessTitle: Event<string>;
|
||||
readonly onProcessExit: Event<number | undefined>;
|
||||
readonly onProcessOverrideDimensions: Event<ITerminalDimensions | undefined>;
|
||||
readonly onProcessOverrideDimensions: Event<ITerminalDimensionsOverride | undefined>;
|
||||
readonly onProcessResolvedShellLaunchConfig: Event<IShellLaunchConfig>;
|
||||
readonly onEnvironmentVariableInfoChanged: Event<IEnvironmentVariableInfo>;
|
||||
|
||||
@@ -416,11 +440,11 @@ export interface ITerminalLaunchError {
|
||||
* child_process.ChildProcess node.js interface.
|
||||
*/
|
||||
export interface ITerminalChildProcess {
|
||||
onProcessData: Event<string>;
|
||||
onProcessData: Event<IProcessDataEvent | string>;
|
||||
onProcessExit: Event<number | undefined>;
|
||||
onProcessReady: Event<{ pid: number, cwd: string }>;
|
||||
onProcessTitleChanged: Event<string>;
|
||||
onProcessOverrideDimensions?: Event<ITerminalDimensions | undefined>;
|
||||
onProcessOverrideDimensions?: Event<ITerminalDimensionsOverride | undefined>;
|
||||
onProcessResolvedShellLaunchConfig?: Event<IShellLaunchConfig>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IProcessDataEvent } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
|
||||
interface TerminalDataBuffer extends IDisposable {
|
||||
data: string[];
|
||||
@@ -23,19 +24,20 @@ export class TerminalDataBufferer implements IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
startBuffering(id: number, event: Event<string>, throttleBy: number = 5): IDisposable {
|
||||
startBuffering(id: number, event: Event<string | IProcessDataEvent>, throttleBy: number = 5): IDisposable {
|
||||
let disposable: IDisposable;
|
||||
disposable = event((e: string) => {
|
||||
disposable = event((e: string | IProcessDataEvent) => {
|
||||
const data = (typeof e === 'string' ? e : e.data);
|
||||
let buffer = this._terminalBufferMap.get(id);
|
||||
if (buffer) {
|
||||
buffer.data.push(e);
|
||||
buffer.data.push(data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const timeoutId = setTimeout(() => this._flushBuffer(id), throttleBy);
|
||||
buffer = {
|
||||
data: [e],
|
||||
data: [data],
|
||||
timeoutId: timeoutId,
|
||||
dispose: () => {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
Reference in New Issue
Block a user