Merge pull request #144925 from microsoft/tyriar/142669

Run shell integration on pty host and restore on reconnect
This commit is contained in:
Daniel Imms 2022-03-14 14:37:58 -07:00 committed by GitHub
commit 473ca6818d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 281 additions and 120 deletions

View file

@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { CwdDetectionCapability } from 'vs/workbench/contrib/terminal/common/capabilities/cwdDetectionCapability';
import { NaiveCwdDetectionCapability } from 'vs/workbench/contrib/terminal/common/capabilities/naiveCwdDetectionCapability';
import { ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
/**
* Primarily driven by the shell integration feature, a terminal capability is the mechanism for
@ -69,12 +68,20 @@ export interface ITerminalCapabilityStore {
* implementations.
*/
export interface ITerminalCapabilityImplMap {
[TerminalCapability.CwdDetection]: InstanceType<typeof CwdDetectionCapability>;
[TerminalCapability.CwdDetection]: ICwdDetectionCapability;
[TerminalCapability.CommandDetection]: ICommandDetectionCapability;
[TerminalCapability.NaiveCwdDetection]: InstanceType<typeof NaiveCwdDetectionCapability>;
[TerminalCapability.NaiveCwdDetection]: INaiveCwdDetectionCapability;
[TerminalCapability.PartialCommandDetection]: IPartialCommandDetectionCapability;
}
export interface ICwdDetectionCapability {
readonly type: TerminalCapability.CwdDetection;
readonly onDidChangeCwd: Event<string>;
readonly cwds: string[];
getCwd(): string;
updateCwd(cwd: string): void;
}
export interface ICommandDetectionCapability {
readonly type: TerminalCapability.CommandDetection;
readonly commands: readonly ITerminalCommand[];
@ -97,6 +104,14 @@ export interface ICommandDetectionCapability {
* Set the command line explicitly.
*/
setCommandLine(commandLine: string): void;
serializeCommands(): ISerializedCommand[];
restoreCommands(serialized: ISerializedCommand[]): void;
}
export interface INaiveCwdDetectionCapability {
readonly type: TerminalCapability.NaiveCwdDetection;
readonly onDidChangeCwd: Event<string>;
getCwd(): Promise<string>;
}
export interface IPartialCommandDetectionCapability {
@ -112,6 +127,7 @@ export interface ITerminalCommand {
exitCode?: number;
marker?: IXtermMarker;
endMarker?: IXtermMarker;
executedMarker?: IXtermMarker;
getOutput(): string | undefined;
hasOutput: boolean;
}

View file

@ -6,8 +6,11 @@
import { timeout } from 'vs/base/common/async';
import { Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { ICommandDetectionCapability, TerminalCapability, ITerminalCommand } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { IBuffer, IDisposable, IMarker, Terminal } from 'xterm';
import { ICommandDetectionCapability, TerminalCapability, ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
import { ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
// Importing types is safe in any layer
// eslint-disable-next-line code-import-patterns
import type { IBuffer, IDisposable, IMarker, Terminal } from 'xterm-headless';
export interface ICurrentPartialCommand {
previousCommandMarker?: IMarker;
@ -140,7 +143,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
}
// Sanity check optional props
if (!this._currentCommand.commandStartMarker || !this._currentCommand.commandExecutedMarker || !this._currentCommand.commandStartX) {
if (!this._currentCommand.commandStartMarker || !this._currentCommand.commandExecutedMarker || this._currentCommand.commandStartX === undefined) {
return;
}
@ -197,17 +200,19 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
if (command !== undefined && !command.startsWith('\\')) {
const buffer = this._terminal.buffer.active;
const clonedPartialCommand = { ...this._currentCommand };
const timestamp = Date.now();
const newCommand = {
const executedMarker = this._currentCommand.commandExecutedMarker;
const endMarker = this._currentCommand.commandFinishedMarker;
const newCommand: ITerminalCommand = {
command,
marker: this._currentCommand.commandStartMarker,
endMarker: this._currentCommand.commandFinishedMarker,
endMarker,
executedMarker,
timestamp,
cwd: this._cwd,
exitCode: this._exitCode,
hasOutput: !!(this._currentCommand.commandExecutedMarker && this._currentCommand.commandFinishedMarker && this._currentCommand.commandExecutedMarker?.line < this._currentCommand.commandFinishedMarker!.line),
getOutput: () => getOutputForCommand(clonedPartialCommand, buffer)
hasOutput: !!(executedMarker && endMarker && executedMarker?.line < endMarker!.line),
getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer)
};
this._commands.push(newCommand);
this._logService.debug('CommandDetectionCapability#onCommandFinished', newCommand);
@ -221,11 +226,78 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
this._logService.debug('CommandDetectionCapability#setCommandLine', commandLine);
this._currentCommand.command = commandLine;
}
serializeCommands(): ISerializedCommand[] {
const serialized: ISerializedCommand[] = this.commands.map(e => {
return {
startLine: e.marker?.line,
startX: undefined,
endLine: e.endMarker?.line,
executedLine: e.executedMarker?.line,
command: e.command,
cwd: e.cwd,
exitCode: e.exitCode,
timestamp: e.timestamp
};
});
if (this._currentCommand.commandStartMarker) {
serialized.push({
startLine: this._currentCommand.commandStartMarker.line,
startX: this._currentCommand.commandStartX,
endLine: undefined,
executedLine: undefined,
command: '',
cwd: this._cwd,
exitCode: undefined,
timestamp: 0,
});
}
return serialized;
}
restoreCommands(serialized: ISerializedCommand[]): void {
const buffer = this._terminal.buffer.normal;
for (const e of serialized) {
const marker = e.startLine !== undefined ? this._terminal.registerMarker(e.startLine - (buffer.baseY + buffer.cursorY)) : undefined;
// Check for invalid command
if (!marker) {
continue;
}
// Partial command
if (!e.endLine) {
this._currentCommand.commandStartMarker = marker;
this._currentCommand.commandStartX = e.startX;
this._cwd = e.cwd;
this._onCommandStarted.fire({ marker } as ITerminalCommand);
continue;
}
// Full command
const endMarker = e.endLine !== undefined ? this._terminal.registerMarker(e.endLine - (buffer.baseY + buffer.cursorY)) : undefined;
const executedMarker = e.executedLine !== undefined ? this._terminal.registerMarker(e.executedLine - (buffer.baseY + buffer.cursorY)) : undefined;
const newCommand = {
command: e.command,
marker,
endMarker,
executedMarker,
timestamp: e.timestamp,
cwd: e.cwd,
exitCode: e.exitCode,
hasOutput: !!(executedMarker && endMarker && executedMarker.line < endMarker.line),
getOutput: () => getOutputForCommand(executedMarker, endMarker, buffer)
};
this._commands.push(newCommand);
this._logService.debug('CommandDetectionCapability#onCommandFinished', newCommand);
this._onCommandFinished.fire(newCommand);
}
}
}
function getOutputForCommand(command: ICurrentPartialCommand, buffer: IBuffer): string | undefined {
const startLine = command.commandExecutedMarker!.line;
const endLine = command.commandFinishedMarker!.line;
function getOutputForCommand(executedMarker: IMarker | undefined, endMarker: IMarker | undefined, buffer: IBuffer): string | undefined {
if (!executedMarker || !endMarker) {
return undefined;
}
const startLine = executedMarker.line;
const endLine = endMarker.line;
if (startLine === endLine) {
return undefined;

View file

@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ICwdDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
export class CwdDetectionCapability {
export class CwdDetectionCapability implements ICwdDetectionCapability {
readonly type = TerminalCapability.CwdDetection;
private _cwd = '';
private _cwds = new Map</*cwd*/string, /*frequency*/number>();

View file

@ -5,9 +5,9 @@
import { Emitter } from 'vs/base/common/event';
import { ITerminalChildProcess } from 'vs/platform/terminal/common/terminal';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapability, INaiveCwdDetectionCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
export class NaiveCwdDetectionCapability {
export class NaiveCwdDetectionCapability implements INaiveCwdDetectionCapability {
constructor(private readonly _process: ITerminalChildProcess) { }
readonly type = TerminalCapability.NaiveCwdDetection;
private _cwd = '';

View file

@ -4,8 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { IPartialCommandDetectionCapability, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { IMarker, Terminal } from 'xterm';
import { IPartialCommandDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
// Importing types is safe in any layer
// eslint-disable-next-line code-import-patterns
import { IMarker, Terminal } from 'xterm-headless';
const enum Constants {
/**
@ -31,11 +33,11 @@ export class PartialCommandDetectionCapability implements IPartialCommandDetecti
constructor(
private readonly _terminal: Terminal,
) {
this._terminal.onKey(e => this._onKey(e.key));
this._terminal.onData(e => this._onData(e));
}
private _onKey(key: string): void {
if (key === '\x0d') {
private _onData(data: string): void {
if (data === '\x0d') {
this._onEnter();
}
}

View file

@ -5,7 +5,7 @@
import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { ITerminalCapabilityImplMap, ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityImplMap, ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
export class TerminalCapabilityStore extends Disposable implements ITerminalCapabilityStore {
private _map: Map<TerminalCapability, { type: TerminalCapability }> = new Map();

View file

@ -7,7 +7,8 @@ import { Event } from 'vs/base/common/event';
import { IProcessEnvironment, OperatingSystem } from 'vs/base/common/platform';
import { URI, UriComponents } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';
import { ITerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISerializedCommand, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
export const enum TerminalSettingPrefix {
@ -597,6 +598,7 @@ export interface ITerminalChildProcess {
onProcessReady: Event<IProcessReadyEvent>;
onDidChangeProperty: Event<IProcessProperty<any>>;
onProcessExit: Event<number | undefined>;
onRestoreCommands?: Event<ISerializedCommand[]>;
/**
* Starts the process.
@ -768,3 +770,8 @@ export interface IExtensionTerminalProfile extends ITerminalProfileContribution
export type ITerminalProfileObject = ITerminalExecutable | ITerminalProfileSource | IExtensionTerminalProfile | null;
export type ITerminalProfileType = ITerminalProfile | IExtensionTerminalProfile;
export interface IShellIntegration {
capabilities: ITerminalCapabilityStore;
restoreCommands(serialized: ISerializedCommand[]): void;
}

View file

@ -63,7 +63,22 @@ export interface IProcessDetails {
export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo<IProcessDetails>;
export interface ReplayEntry { cols: number; rows: number; data: string }
export interface ReplayEntry {
cols: number;
rows: number;
data: string;
}
export interface ISerializedCommand {
command: string;
cwd: string | undefined;
startLine: number | undefined;
startX: number | undefined;
endLine: number | undefined;
executedLine: number | undefined;
exitCode: number | undefined;
timestamp: number;
}
export interface IPtyHostProcessReplayEvent {
events: ReplayEntry[];
commands: ISerializedCommand[];
}

View file

@ -84,7 +84,9 @@ export class TerminalRecorder {
}
});
return {
events: this._entries.map(entry => ({ cols: entry.cols, rows: entry.rows, data: entry.data[0] ?? '' }))
events: this._entries.map(entry => ({ cols: entry.cols, rows: entry.rows, data: entry.data[0] ?? '' })),
// No command restoration is needed when relaunching terminals
commands: []
};
}

View file

@ -3,15 +3,18 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITerminalAddon, Terminal } from 'xterm';
import { IShellIntegration } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellIntegration } from 'vs/platform/terminal/common/terminal';
import { Disposable } from 'vs/base/common/lifecycle';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { CommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/commandDetectionCapability';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CwdDetectionCapability } from 'vs/workbench/contrib/terminal/common/capabilities/cwdDetectionCapability';
import { ICommandDetectionCapability, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { PartialCommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/partialCommandDetectionCapability';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
import { CwdDetectionCapability } from 'vs/platform/terminal/common/capabilities/cwdDetectionCapability';
import { ICommandDetectionCapability, ICwdDetectionCapability, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { PartialCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/partialCommandDetectionCapability';
import { ILogService } from 'vs/platform/log/common/log';
// Importing types is safe in any layer
// eslint-disable-next-line code-import-patterns
import type { ITerminalAddon, Terminal } from 'xterm-headless';
import { ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
/**
* Shell integration is a feature that enhances the terminal's understanding of what's happening
@ -112,7 +115,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
readonly capabilities = new TerminalCapabilityStore();
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService
@ILogService private readonly _logService: ILogService
) {
super();
}
@ -188,7 +191,22 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
return false;
}
protected _createOrGetCwdDetection(): CwdDetectionCapability {
serializeCommands(): ISerializedCommand[] {
if (!this._terminal || !this.capabilities.has(TerminalCapability.CommandDetection)) {
return [];
}
const result = this._createOrGetCommandDetection(this._terminal).serializeCommands();
return result;
}
restoreCommands(serialized: ISerializedCommand[]): void {
if (!this._terminal) {
throw new Error('Cannot restore commands before addon is activated');
}
this._createOrGetCommandDetection(this._terminal).restoreCommands(serialized);
}
protected _createOrGetCwdDetection(): ICwdDetectionCapability {
let cwdDetection = this.capabilities.get(TerminalCapability.CwdDetection);
if (!cwdDetection) {
cwdDetection = new CwdDetectionCapability();
@ -200,7 +218,7 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
protected _createOrGetCommandDetection(terminal: Terminal): ICommandDetectionCapability {
let commandDetection = this.capabilities.get(TerminalCapability.CommandDetection);
if (!commandDetection) {
commandDetection = this._instantiationService.createInstance(CommandDetectionCapability, terminal);
commandDetection = new CommandDetectionCapability(terminal, this._logService);
this.capabilities.add(TerminalCapability.CommandDetection, commandDetection);
}
return commandDetection;

View file

@ -25,6 +25,7 @@ import { localize } from 'vs/nls';
import { ignoreProcessNames } from 'vs/platform/terminal/node/childProcessMonitor';
import { TerminalAutoResponder } from 'vs/platform/terminal/common/terminalAutoResponder';
import { ErrorNoTelemetry } from 'vs/base/common/errors';
import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon';
type WorkspaceId = string;
@ -500,7 +501,8 @@ export class PersistentTerminalProcess extends Disposable {
rows,
reconnectConstants.scrollback,
unicodeVersion,
reviveBuffer
reviveBuffer,
this._logService
);
this._fixedDimensions = fixedDimensions;
this._orphanQuestionBarrier = null;
@ -723,35 +725,25 @@ export class PersistentTerminalProcess extends Disposable {
}
class XtermSerializer implements ITerminalSerializer {
private _xterm: XtermTerminal;
private readonly _xterm: XtermTerminal;
private readonly _shellIntegrationAddon: ShellIntegrationAddon;
private _unicodeAddon?: XtermUnicode11Addon;
private _shellIntegrationEnabled: boolean = false;
constructor(
cols: number,
rows: number,
scrollback: number,
unicodeVersion: '6' | '11',
reviveBuffer: string | undefined
reviveBuffer: string | undefined,
logService: ILogService
) {
this._xterm = new XtermTerminal({ cols, rows, scrollback });
if (reviveBuffer) {
this._xterm.writeln(reviveBuffer);
if (this._shellIntegrationEnabled) {
this._xterm.write('\x1b033]133;E\x1b007');
}
}
this._xterm.parser.registerOscHandler(133, (data => this._handleShellIntegration(data)));
this.setUnicodeVersion(unicodeVersion);
}
private _handleShellIntegration(data: string): boolean {
const [command,] = data.split(';');
if (command === 'E') {
this._shellIntegrationEnabled = true;
return true;
}
return false;
this._shellIntegrationAddon = new ShellIntegrationAddon(logService);
this._xterm.loadAddon(this._shellIntegrationAddon);
}
handleData(data: string): void {
@ -778,7 +770,8 @@ class XtermSerializer implements ITerminalSerializer {
rows: this._xterm.getOption('rows'),
data: serialized
}
]
],
commands: this._shellIntegrationAddon.serializeCommands()
};
}

View file

@ -7,7 +7,7 @@ import type { IViewportRange, IBufferRange, IBufferLine, IBuffer, IBufferCellPos
import { IRange } from 'vs/editor/common/core/range';
import { OperatingSystem } from 'vs/base/common/platform';
import { IPath, posix, win32 } from 'vs/base/common/path';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
/**
* Converts a possibly wrapped link's range (comprised of string indices) into a buffer range that plays nicely with xterm.js

View file

@ -29,7 +29,7 @@ import { ITerminalExternalLinkProvider, TerminalLinkQuickPickEvent } from 'vs/wo
import { ILinkHoverTargetOptions, TerminalHover } from 'vs/workbench/contrib/terminal/browser/widgets/terminalHoverWidget';
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager';
import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { ITerminalConfiguration, ITerminalProcessManager, TERMINAL_CONFIG_SECTION } from 'vs/workbench/contrib/terminal/common/terminal';
import { IHoverAction } from 'vs/workbench/services/hover/browser/hover';
import type { ILink, ILinkProvider, IViewportRange, Terminal } from 'xterm';

View file

@ -17,7 +17,7 @@ import { ITerminalLinkOpener, ITerminalSimpleLink } from 'vs/workbench/contrib/t
import { osPathModule, updateLinkWithRelativeCwd } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkHelpers';
import { ILineColumnInfo } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { getLocalLinkRegex, lineAndColumnClause, lineAndColumnClauseGroupCount, unixLineAndColumnMatchIndex, winLineAndColumnMatchIndex } from 'vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IHostService } from 'vs/workbench/services/host/browser/host';

View file

@ -9,7 +9,7 @@ import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ITerminalLinkDetector, ITerminalSimpleLink, ResolvedLink, TerminalBuiltinLinkType } from 'vs/workbench/contrib/terminal/browser/links/links';
import { convertLinkRangeToBuffer, getXtermLineContent, osPathModule, updateLinkWithRelativeCwd } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkHelpers';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IBufferLine, Terminal } from 'xterm';
const enum Constants {

View file

@ -9,7 +9,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { IProcessDataEvent, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal';
import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/terminalProcess';
import { IPtyHostProcessReplayEvent, ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
import { RemoteTerminalChannelClient } from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
@ -22,6 +22,8 @@ export class RemotePty extends Disposable implements ITerminalChildProcess {
readonly onDidChangeProperty = this._onDidChangeProperty.event;
private readonly _onProcessExit = this._register(new Emitter<number | undefined>());
readonly onProcessExit = this._onProcessExit.event;
private readonly _onRestoreCommands = this._register(new Emitter<ISerializedCommand[]>());
readonly onRestoreCommands = this._onRestoreCommands.event;
private _startBarrier: Barrier;
@ -178,6 +180,10 @@ export class RemotePty extends Disposable implements ITerminalChildProcess {
this._inReplay = false;
}
if (e.commands.length > 0) {
this._onRestoreCommands.fire(e.commands);
}
// remove size override
this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: undefined });
}

View file

@ -15,7 +15,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalEnvironment, ITerminalProcessOptions, ITerminalProfile, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, ProcessPropertyType, TerminalIcon, TerminalSettingId, TitleEventSource } from 'vs/platform/terminal/common/terminal';
import { IProcessDetails } from 'vs/platform/terminal/common/terminalProcess';
import { IProcessDetails, ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { BaseTerminalBackend } from 'vs/workbench/contrib/terminal/browser/baseTerminalBackend';
@ -52,6 +52,8 @@ class RemoteTerminalBackend extends BaseTerminalBackend implements ITerminalBack
private readonly _onDidRequestDetach = this._register(new Emitter<{ requestId: number; workspaceId: string; instanceId: number }>());
readonly onDidRequestDetach = this._onDidRequestDetach.event;
private readonly _onRestoreCommands = this._register(new Emitter<{ id: number; commands: ISerializedCommand[] }>());
readonly onRestoreCommands = this._onRestoreCommands.event;
constructor(
readonly remoteAuthority: string | undefined,
@ -70,7 +72,12 @@ class RemoteTerminalBackend extends BaseTerminalBackend implements ITerminalBack
super(_remoteTerminalChannel, logService, notificationService, _historyService, configurationResolverService, workspaceContextService);
this._remoteTerminalChannel.onProcessData(e => this._ptys.get(e.id)?.handleData(e.event));
this._remoteTerminalChannel.onProcessReplay(e => this._ptys.get(e.id)?.handleReplay(e.event));
this._remoteTerminalChannel.onProcessReplay(e => {
this._ptys.get(e.id)?.handleReplay(e.event);
if (e.event.commands.length > 0) {
this._onRestoreCommands.fire({ id: e.id, commands: e.event.commands });
}
});
this._remoteTerminalChannel.onProcessOrphanQuestion(e => this._ptys.get(e.id)?.handleOrphanQuestion());
this._remoteTerminalChannel.onDidRequestDetach(e => this._onDidRequestDetach.fire(e));
this._remoteTerminalChannel.onProcessReady(e => this._ptys.get(e.id)?.handleReady(e.event));

View file

@ -8,14 +8,14 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { FindReplaceState } from 'vs/editor/contrib/find/browser/findState';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource, TerminalShellType, IExtensionTerminalProfile, TerminalLocation, ProcessPropertyType, IProcessPropertyMap } from 'vs/platform/terminal/common/terminal';
import { INavigationMode, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalFont, ITerminalBackend, ITerminalProcessExtHostProxy, IRegisterContributedProfileArgs, IShellIntegration } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellLaunchConfig, ITerminalDimensions, ITerminalLaunchError, ITerminalProfile, ITerminalTabLayoutInfoById, TerminalIcon, TitleEventSource, TerminalShellType, IExtensionTerminalProfile, TerminalLocation, ProcessPropertyType, IProcessPropertyMap, IShellIntegration } from 'vs/platform/terminal/common/terminal';
import { INavigationMode, IRemoteTerminalAttachTarget, IStartExtensionTerminalRequest, ITerminalConfigHelper, ITerminalFont, ITerminalBackend, ITerminalProcessExtHostProxy, IRegisterContributedProfileArgs } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList';
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
import { IEditableData } from 'vs/workbench/common/views';
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { ITerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';

View file

@ -66,8 +66,8 @@ import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/wid
import { LineDataEventAddon } from 'vs/workbench/contrib/terminal/browser/xterm/lineDataEventAddon';
import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/xterm/navigationModeAddon';
import { XtermTerminal } from 'vs/workbench/contrib/terminal/browser/xterm/xtermTerminal';
import { ITerminalCommand, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStoreMultiplexer } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { ITerminalCommand, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStoreMultiplexer } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { getCommandHistory, getDirectoryHistory } from 'vs/workbench/contrib/terminal/common/history';
import { DEFAULT_COMMANDS_TO_SKIP_SHELL, INavigationMode, ITerminalBackend, ITerminalProcessManager, ITerminalProfileResolverService, ProcessState, ShellIntegrationExitCode, TerminalCommandId, TERMINAL_CREATION_COMMANDS, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
@ -708,6 +708,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
this._areLinksReady = true;
this._onLinksReady.fire(this);
});
this._processManager.onRestoreCommands(e => this.xterm?.shellIntegration.restoreCommands(e));
this._loadTypeAheadAddon(xterm);

View file

@ -28,10 +28,11 @@ import { formatMessageForTerminal } from 'vs/workbench/contrib/terminal/common/t
import { IProcessEnvironment, isMacintosh, isWindows, OperatingSystem, OS } from 'vs/base/common/platform';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { NaiveCwdDetectionCapability } from 'vs/workbench/contrib/terminal/common/capabilities/naiveCwdDetectionCapability';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { NaiveCwdDetectionCapability } from 'vs/platform/terminal/common/capabilities/naiveCwdDetectionCapability';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { URI } from 'vs/base/common/uri';
import { ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
/** The amount of time to consider terminal errors to be related to the launch */
const LAUNCHING_DURATION = 500;
@ -105,6 +106,8 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
readonly onEnvironmentVariableInfoChanged = this._onEnvironmentVariableInfoChange.event;
private readonly _onProcessExit = this._register(new Emitter<number | undefined>());
readonly onProcessExit = this._onProcessExit.event;
private readonly _onRestoreCommands = this._register(new Emitter<ISerializedCommand[]>());
readonly onRestoreCommands = this._onRestoreCommands.event;
get persistentProcessId(): number | undefined { return this._process?.id; }
get shouldPersist(): boolean { return this._process ? this._process.shouldPersist : false; }
@ -334,6 +337,11 @@ export class TerminalProcessManager extends Disposable implements ITerminalProce
this._onDidChangeProperty.fire({ type, value });
})
];
if (newProcess.onRestoreCommands) {
this._processListeners.push(newProcess.onRestoreCommands(e => {
this._onRestoreCommands.fire(e);
}));
}
setTimeout(() => {
if (this.processState === ProcessState.Launching) {

View file

@ -5,7 +5,7 @@
import { localize } from 'vs/nls';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
function getCapabilityName(capability: TerminalCapability): string | undefined {
switch (capability) {

View file

@ -13,6 +13,7 @@ export interface IXtermCore {
viewport?: {
_innerRefresh(): void;
};
_onData: IEventEmitter<string>;
_onKey: IEventEmitter<{ key: string }>;
_charSizeService: {

View file

@ -6,7 +6,7 @@
import { coalesce } from 'vs/base/common/arrays';
import { Disposable } from 'vs/base/common/lifecycle';
import { ICommandTracker } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ICommandDetectionCapability, IPartialCommandDetectionCapability, ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ICommandDetectionCapability, IPartialCommandDetectionCapability, ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import type { Terminal, IMarker, ITerminalAddon } from 'xterm';
enum Boundary {

View file

@ -8,7 +8,7 @@ import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal'
import { IDecoration, ITerminalAddon, Terminal } from 'xterm';
import * as dom from 'vs/base/browser/dom';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
@ -131,6 +131,12 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
if (!capability) {
return;
}
if (capability.commands.length > 0) {
const lastCommand = capability.commands[capability.commands.length - 1];
if (lastCommand.marker && !lastCommand.endMarker) {
this.registerCommandDecoration(lastCommand, true);
}
}
this._commandStartedListener = capability.onCommandStarted(command => this.registerCommandDecoration(command, true));
}
@ -143,6 +149,9 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
if (!capability) {
return;
}
for (const command of capability.commands) {
this.registerCommandDecoration(command);
}
this._commandFinishedListener = capability.onCommandFinished(command => {
if (command.command.trim().toLowerCase() === 'clear' || command.command.trim().toLowerCase() === 'cls') {
this.clearDecorations();
@ -174,12 +183,13 @@ export class DecorationAddon extends Disposable implements ITerminalAddon {
this._placeholderDecoration = decoration;
this._placeholderDecoration.onDispose(() => this._placeholderDecoration = undefined);
} else {
this._decorations.set(decoration.marker.id,
{
if (!this._decorations.has(decoration.marker.id)) {
this._decorations.set(decoration.marker.id, {
decoration,
disposables: command.exitCode === undefined ? [] : [this._createContextMenu(element, command), ...this._createHover(element, command)],
exitCode: command.exitCode
});
}
}
if (!element.classList.contains(DecorationSelector.Codicon) || command.marker?.line === 0) {
// first render or buffer was cleared

View file

@ -13,8 +13,8 @@ import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configur
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { TerminalLocation, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { IShellIntegration, ITerminalFont, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { IShellIntegration, TerminalLocation, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { ITerminalFont, TERMINAL_VIEW_ID } from 'vs/workbench/contrib/terminal/common/terminal';
import { isSafari } from 'vs/base/browser/browser';
import { ICommandTracker, IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ILogService } from 'vs/platform/log/common/log';
@ -29,10 +29,10 @@ import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
import { PANEL_BACKGROUND, SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { TERMINAL_FOREGROUND_COLOR, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, ansiColorIdentifiers, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { Color } from 'vs/base/common/color';
import { ShellIntegrationAddon } from 'vs/workbench/contrib/terminal/browser/xterm/shellIntegrationAddon';
import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { DecorationAddon } from 'vs/workbench/contrib/terminal/browser/xterm/decorationAddon';
import { ITerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/capabilities';
import { Emitter } from 'vs/base/common/event';
// How long in milliseconds should an average frame take to render for a notification to appear

View file

@ -12,9 +12,9 @@ import { IProcessDataEvent, IProcessReadyEvent, IShellLaunchConfig, ITerminalChi
import { IEnvironmentVariableInfo } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { IProcessDetails } from 'vs/platform/terminal/common/terminalProcess';
import { IProcessDetails, ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
import { Registry } from 'vs/platform/registry/common/platform';
import { ITerminalCapabilityStore, IXtermMarker } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityStore, IXtermMarker } from 'vs/platform/terminal/common/capabilities/capabilities';
export const TERMINAL_VIEW_ID = 'terminal';
@ -328,10 +328,6 @@ export interface IRemoteTerminalAttachTarget {
fixedDimensions: IFixedTerminalDimensions | undefined;
}
export interface IShellIntegration {
capabilities: ITerminalCapabilityStore;
}
export interface ITerminalCommand {
command: string;
timestamp: number;
@ -386,6 +382,7 @@ export interface ITerminalProcessManager extends IDisposable {
readonly onEnvironmentVariableInfoChanged: Event<IEnvironmentVariableInfo>;
readonly onDidChangeProperty: Event<IProcessProperty<any>>;
readonly onProcessExit: Event<number | undefined>;
readonly onRestoreCommands: Event<ISerializedCommand[]>;
dispose(immediate?: boolean): void;
detachFromProcess(): Promise<void>;

View file

@ -7,7 +7,7 @@ import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal';
import { IProcessDataEvent, ITerminalChildProcess, ITerminalLaunchError, IProcessProperty, IProcessPropertyMap, ProcessPropertyType, IProcessReadyEvent } from 'vs/platform/terminal/common/terminal';
import { IPtyHostProcessReplayEvent } from 'vs/platform/terminal/common/terminalProcess';
import { IPtyHostProcessReplayEvent, ISerializedCommand } from 'vs/platform/terminal/common/terminalProcess';
import { URI } from 'vs/base/common/uri';
/**
@ -36,6 +36,8 @@ export class LocalPty extends Disposable implements ITerminalChildProcess {
readonly onDidChangeProperty = this._onDidChangeProperty.event;
private readonly _onProcessExit = this._register(new Emitter<number | undefined>());
readonly onProcessExit = this._onProcessExit.event;
private readonly _onRestoreCommands = this._register(new Emitter<ISerializedCommand[]>());
readonly onRestoreCommands = this._onRestoreCommands.event;
constructor(
readonly id: number,
@ -139,6 +141,10 @@ export class LocalPty extends Disposable implements ITerminalChildProcess {
this._inReplay = false;
}
if (e.commands.length > 0) {
this._onRestoreCommands.fire(e.commands);
}
// remove size override
this._onDidChangeProperty.fire({ type: ProcessPropertyType.OverrideDimensions, value: undefined });
}

View file

@ -6,9 +6,9 @@
import { deepStrictEqual, ok } from 'assert';
import { timeout } from 'vs/base/common/async';
import { Terminal } from 'xterm';
import { CommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/commandDetectionCapability';
import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
import { NullLogService } from 'vs/platform/log/common/log';
import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCommand } from 'vs/platform/terminal/common/capabilities/capabilities';
async function writeP(terminal: Terminal, data: string): Promise<void> {
return new Promise<void>((resolve, reject) => {

View file

@ -5,7 +5,7 @@
import { deepStrictEqual } from 'assert';
import { timeout } from 'vs/base/common/async';
import { PartialCommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/partialCommandDetectionCapability';
import { PartialCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/partialCommandDetectionCapability';
import { IMarker, Terminal } from 'xterm';
import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
@ -43,11 +43,11 @@ suite('PartialCommandDetectionCapability', () => {
test('should not add commands when the cursor position is too close to the left side', async () => {
assertCommands([]);
xterm._core._onKey.fire({ key: '\x0d' });
xterm._core._onData.fire('\x0d');
await writeP(xterm, '\r\n');
assertCommands([]);
await writeP(xterm, 'a');
xterm._core._onKey.fire({ key: '\x0d' });
xterm._core._onData.fire('\x0d');
await writeP(xterm, '\r\n');
assertCommands([]);
});
@ -55,11 +55,11 @@ suite('PartialCommandDetectionCapability', () => {
test('should add commands when the cursor position is not too close to the left side', async () => {
assertCommands([]);
await writeP(xterm, 'ab');
xterm._core._onKey.fire({ key: '\x0d' });
xterm._core._onData.fire('\x0d');
await writeP(xterm, '\r\n\r\n');
assertCommands([0]);
await writeP(xterm, 'cd');
xterm._core._onKey.fire({ key: '\x0d' });
xterm._core._onData.fire('\x0d');
await writeP(xterm, '\r\n');
assertCommands([0, 2]);
});

View file

@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { deepStrictEqual } from 'assert';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore, TerminalCapabilityStoreMultiplexer } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore, TerminalCapabilityStoreMultiplexer } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
suite('TerminalCapabilityStore', () => {
let store: TerminalCapabilityStore;

View file

@ -17,7 +17,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { ITerminalCapabilityImplMap, ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ITerminalCapabilityImplMap, ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { ITerminalConfiguration, ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal';
import { TestViewDescriptorService } from 'vs/workbench/contrib/terminal/test/browser/xterm/xtermTerminal.test';
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';

View file

@ -14,11 +14,11 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { CommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/commandDetectionCapability';
import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
import { TerminalBuiltinLinkType } from 'vs/workbench/contrib/terminal/browser/links/links';
import { TerminalLocalFileLinkOpener, TerminalLocalFolderInWorkspaceLinkOpener, TerminalSearchLinkOpener } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkOpeners';
import { TerminalCapability, ITerminalCommand, IXtermMarker } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapability, ITerminalCommand, IXtermMarker } from 'vs/platform/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';

View file

@ -10,7 +10,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ITerminalSimpleLink, TerminalBuiltinLinkType } from 'vs/workbench/contrib/terminal/browser/links/links';
import { TerminalLocalLinkDetector } from 'vs/workbench/contrib/terminal/browser/links/terminalLocalLinkDetector';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { assertLinkHelper, resolveLinkForTest } from 'vs/workbench/contrib/terminal/test/browser/links/linkTestUtils';
import { Terminal } from 'xterm';

View file

@ -9,9 +9,9 @@ import { CommandTrackerAddon } from 'vs/workbench/contrib/terminal/browser/xterm
import { isWindows } from 'vs/base/common/platform';
import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
import { timeout } from 'vs/base/common/async';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { PartialCommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/partialCommandDetectionCapability';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { PartialCommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/partialCommandDetectionCapability';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
interface TestTerminal extends Terminal {
_core: IXtermCore;
@ -62,13 +62,13 @@ suite('Workbench - TerminalCommandTracker', function () {
test('should track commands when the prompt is of sufficient size', async () => {
assert.strictEqual(xterm.markers.length, 0);
await writeP(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' });
xterm._core._onData.fire('\x0d');
assert.strictEqual(xterm.markers.length, 1);
});
test('should not track commands when the prompt is too small', async () => {
assert.strictEqual(xterm.markers.length, 0);
await writeP(xterm, '\x1b[2G'); // Move cursor to column 2
xterm._core._onKey.fire({ key: '\x0d' });
xterm._core._onData.fire('\x0d');
assert.strictEqual(xterm.markers.length, 0);
});
});
@ -85,7 +85,7 @@ suite('Workbench - TerminalCommandTracker', function () {
});
test('should scroll to the next and previous commands', async () => {
await writeP(xterm, '\x1b[3G'); // Move cursor to column 3
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line #10
xterm._core._onData.fire('\x0d'); // Mark line #10
assert.strictEqual(xterm.markers[0].line, 9);
await writeP(xterm, `\r\n`.repeat(20));
@ -114,13 +114,13 @@ suite('Workbench - TerminalCommandTracker', function () {
'\n\r1' +
'\x1b[3G' // Move cursor to column 3
);
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
xterm._core._onData.fire('\x0d'); // Mark line
assert.strictEqual(xterm.markers[0].line, 10);
await writeP(xterm,
'\n\r2' +
'\x1b[3G' // Move cursor to column 3
);
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
xterm._core._onData.fire('\x0d'); // Mark line
assert.strictEqual(xterm.markers[1].line, 11);
await writeP(xterm, '\n\r3');
@ -143,13 +143,13 @@ suite('Workbench - TerminalCommandTracker', function () {
'\n\r1' +
'\x1b[3G' // Move cursor to column 3
);
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
xterm._core._onData.fire('\x0d'); // Mark line
assert.strictEqual(xterm.markers[0].line, 10);
await writeP(xterm,
'\n\r2' +
'\x1b[3G' // Move cursor to column 3
);
xterm._core._onKey.fire({ key: '\x0d' }); // Mark line
xterm._core._onData.fire('\x0d'); // Mark line
assert.strictEqual(xterm.markers[1].line, 11);
await writeP(xterm, '\n\r3');

View file

@ -17,8 +17,8 @@ import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/termina
import { ProcessState } from 'vs/workbench/contrib/terminal/common/terminal';
import { basename } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { Schemas } from 'vs/base/common/network';
function createInstance(partial?: Partial<ITerminalInstance>): Pick<ITerminalInstance, 'shellLaunchConfig' | 'userHome' | 'cwd' | 'initialCwd' | 'processName' | 'sequence' | 'workspaceFolder' | 'staticTitle' | 'capabilities' | 'title' | 'description'> {

View file

@ -8,12 +8,12 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
import { DecorationAddon } from 'vs/workbench/contrib/terminal/browser/xterm/decorationAddon';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { ITerminalCommand } from 'vs/workbench/contrib/terminal/common/terminal';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IDecoration, IDecorationOptions, Terminal } from 'xterm';
import { TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { CommandDetectionCapability } from 'vs/workbench/contrib/terminal/browser/capabilities/commandDetectionCapability';
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { CommandDetectionCapability } from 'vs/platform/terminal/common/capabilities/commandDetectionCapability';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';

View file

@ -7,8 +7,8 @@ import { Terminal } from 'xterm';
import { strictEqual } from 'assert';
import { timeout } from 'vs/base/common/async';
import * as sinon from 'sinon';
import { ShellIntegrationAddon } from 'vs/workbench/contrib/terminal/browser/xterm/shellIntegrationAddon';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/workbench/contrib/terminal/common/capabilities/capabilities';
import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon';
import { ITerminalCapabilityStore, TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';

View file

@ -24,7 +24,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
import { isSafari } from 'vs/base/browser/browser';
import { TerminalLocation } from 'vs/platform/terminal/common/terminal';
import { TerminalCapabilityStore } from 'vs/workbench/contrib/terminal/common/capabilities/terminalCapabilityStore';
import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilities/terminalCapabilityStore';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService';