mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 04:49:35 +00:00
Fix restoring commands not working reliably
This commit is contained in:
parent
9addadc0b0
commit
5738c241b1
|
@ -104,6 +104,7 @@ export interface ICommandDetectionCapability {
|
|||
* Set the command line explicitly.
|
||||
*/
|
||||
setCommandLine(commandLine: string): void;
|
||||
serializeCommands(): ISerializedCommand[];
|
||||
restoreCommands(serialized: ISerializedCommand[]): void;
|
||||
}
|
||||
|
||||
|
|
|
@ -225,8 +225,29 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
|||
this._currentCommand.command = commandLine;
|
||||
}
|
||||
|
||||
serializeCommands(): ISerializedCommand[] {
|
||||
const serialized = this.commands.map(e => {
|
||||
return {
|
||||
startLine: e.marker?.line,
|
||||
endLine: e.endMarker?.line,
|
||||
cwd: e.cwd,
|
||||
exitCode: e.exitCode,
|
||||
timestamp: e.timestamp
|
||||
};
|
||||
});
|
||||
if (this._currentCommand.commandStartMarker) {
|
||||
serialized.push({
|
||||
startLine: this._currentCommand.commandStartMarker.line,
|
||||
endLine: undefined,
|
||||
cwd: undefined,
|
||||
exitCode: undefined,
|
||||
timestamp: 0,
|
||||
});
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
restoreCommands(serialized: ISerializedCommand[]): void {
|
||||
console.log('restoreCommands', serialized);
|
||||
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;
|
||||
|
@ -241,6 +262,7 @@ export class CommandDetectionCapability implements ICommandDetectionCapability {
|
|||
timestamp: e.timestamp,
|
||||
cwd: e.cwd,
|
||||
exitCode: e.exitCode,
|
||||
// TODO: Implement correctly
|
||||
hasOutput: false,
|
||||
getOutput: () => ''
|
||||
// hasOutput: !!(this._currentCommand.commandExecutedMarker && this._currentCommand.commandFinishedMarker && this._currentCommand.commandExecutedMarker?.line < this._currentCommand.commandFinishedMarker!.line),
|
||||
|
|
|
@ -598,6 +598,7 @@ export interface ITerminalChildProcess {
|
|||
onProcessReady: Event<IProcessReadyEvent>;
|
||||
onDidChangeProperty: Event<IProcessProperty<any>>;
|
||||
onProcessExit: Event<number | undefined>;
|
||||
onRestoreCommands?: Event<ISerializedCommand[]>;
|
||||
|
||||
/**
|
||||
* Starts the process.
|
||||
|
|
|
@ -191,6 +191,14 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
|
|||
return false;
|
||||
}
|
||||
|
||||
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');
|
||||
|
|
|
@ -18,7 +18,7 @@ import { escapeNonWindowsPath } from 'vs/platform/terminal/common/terminalEnviro
|
|||
import { Terminal as XtermTerminal } from 'xterm-headless';
|
||||
import type { ISerializeOptions, SerializeAddon as XtermSerializeAddon } from 'xterm-addon-serialize';
|
||||
import type { Unicode11Addon as XtermUnicode11Addon } from 'xterm-addon-unicode11';
|
||||
import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISerializedCommand, ISetTerminalLayoutInfoArgs, ITerminalTabLayoutInfoDto } from 'vs/platform/terminal/common/terminalProcess';
|
||||
import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs, ITerminalTabLayoutInfoDto } from 'vs/platform/terminal/common/terminalProcess';
|
||||
import { getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment';
|
||||
import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess';
|
||||
import { localize } from 'vs/nls';
|
||||
|
@ -26,7 +26,6 @@ import { ignoreProcessNames } from 'vs/platform/terminal/node/childProcessMonito
|
|||
import { TerminalAutoResponder } from 'vs/platform/terminal/common/terminalAutoResponder';
|
||||
import { ErrorNoTelemetry } from 'vs/base/common/errors';
|
||||
import { ShellIntegrationAddon } from 'vs/platform/terminal/common/xterm/shellIntegrationAddon';
|
||||
import { TerminalCapability } from 'vs/platform/terminal/common/capabilities/capabilities';
|
||||
|
||||
type WorkspaceId = string;
|
||||
|
||||
|
@ -772,7 +771,7 @@ class XtermSerializer implements ITerminalSerializer {
|
|||
data: serialized
|
||||
}
|
||||
],
|
||||
commands: this._getSerializedCommands()
|
||||
commands: this._shellIntegrationAddon.serializeCommands()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -803,22 +802,6 @@ class XtermSerializer implements ITerminalSerializer {
|
|||
}
|
||||
return SerializeAddon;
|
||||
}
|
||||
|
||||
private _getSerializedCommands(): ISerializedCommand[] {
|
||||
const commandDetection = this._shellIntegrationAddon.capabilities.get(TerminalCapability.CommandDetection);
|
||||
if (!commandDetection) {
|
||||
return [];
|
||||
}
|
||||
return commandDetection.commands.map(e => {
|
||||
return {
|
||||
cwd: e.cwd,
|
||||
startLine: e.marker?.line,
|
||||
endLine: e.endMarker?.line,
|
||||
exitCode: e.exitCode,
|
||||
timestamp: e.timestamp
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function printTime(ms: number): string {
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ import { TerminalCapabilityStore } from 'vs/platform/terminal/common/capabilitie
|
|||
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) {
|
||||
|
|
|
@ -281,9 +281,6 @@ export class TerminalService implements ITerminalService {
|
|||
}
|
||||
}
|
||||
});
|
||||
backend.onRestoreCommands(e => {
|
||||
this.getInstanceFromId(e.id)?.xterm?.shellIntegration?.restoreCommands(e.commands);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,6 @@ export interface ITerminalBackend {
|
|||
onPtyHostRestart: Event<void>;
|
||||
|
||||
onDidRequestDetach: Event<{ requestId: number; workspaceId: string; instanceId: number }>;
|
||||
onRestoreCommands: Event<{ id: number; commands: ISerializedCommand[] }>;
|
||||
|
||||
attachToProcess(id: number): Promise<ITerminalChildProcess | undefined>;
|
||||
listProcesses(): Promise<IProcessDetails[]>;
|
||||
|
@ -383,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>;
|
||||
|
|
|
@ -141,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 });
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { IProcessPropertyMap, IShellLaunchConfig, ITerminalChildProcess, ITerminalEnvironment, ITerminalProcessOptions, ITerminalsLayoutInfo, ITerminalsLayoutInfoById, ProcessPropertyType, TerminalSettingId, TitleEventSource } from 'vs/platform/terminal/common/terminal';
|
||||
import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISerializedCommand, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';
|
||||
import { IGetTerminalLayoutInfoArgs, IProcessDetails, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';
|
||||
import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
|
@ -47,8 +47,6 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke
|
|||
|
||||
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,
|
||||
|
@ -82,12 +80,7 @@ class LocalTerminalBackend extends BaseTerminalBackend implements ITerminalBacke
|
|||
}
|
||||
});
|
||||
this._localPtyService.onProcessReady(e => this._ptys.get(e.id)?.handleReady(e.event));
|
||||
this._localPtyService.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._localPtyService.onProcessReplay(e => this._ptys.get(e.id)?.handleReplay(e.event));
|
||||
this._localPtyService.onProcessOrphanQuestion(e => this._ptys.get(e.id)?.handleOrphanQuestion());
|
||||
this._localPtyService.onDidRequestDetach(e => this._onDidRequestDetach.fire(e));
|
||||
|
||||
|
|
Loading…
Reference in a new issue