Skip to content

Commit

Permalink
Serialize buffer progress
Browse files Browse the repository at this point in the history
Part of #131634
  • Loading branch information
Tyriar committed Sep 9, 2021
1 parent 850ebc8 commit 6e6f175
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/vs/platform/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ export interface IPtyService {
reduceConnectionGraceTime(): Promise<void>;
requestDetachInstance(workspaceId: string, instanceId: number): Promise<IProcessDetails | undefined>;
acceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise<void>;
persistTerminalState(): Promise<void>;
}

export interface IRequestResolveVariablesEvent {
Expand Down
8 changes: 5 additions & 3 deletions src/vs/platform/terminal/node/ptyHostService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ export class PtyHostService extends Disposable implements IPtyService {
return this._proxy.acceptDetachInstanceReply(requestId, persistentProcessId);
}

async persistTerminalState(): Promise<void> {
return this._proxy.persistTerminalState();
}

async restartPtyHost(): Promise<void> {
/* __GDPR__
"ptyHost/restart" : {}
Expand All @@ -277,9 +281,7 @@ export class PtyHostService extends Disposable implements IPtyService {
}

private _disposePtyHost(): void {
if (this._proxy.shutdownAll) {
this._proxy.shutdownAll();
}
this._proxy.shutdownAll?.();
this._client.dispose();
}

Expand Down
17 changes: 17 additions & 0 deletions src/vs/platform/terminal/node/ptyService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { IGetTerminalLayoutInfoArgs, IProcessDetails, IPtyHostProcessReplayEvent
import { ITerminalSerializer, TerminalRecorder } from 'vs/platform/terminal/common/terminalRecorder';
import { getWindowsBuildNumber } from 'vs/platform/terminal/node/terminalEnvironment';
import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess';
import { Promises as pfs } from 'vs/base/node/pfs';
import { join } from 'path';

type WorkspaceId = string;

Expand Down Expand Up @@ -97,6 +99,21 @@ export class PtyService extends Disposable implements IPtyService {
this._detachInstanceRequestStore.acceptReply(requestId, processDetails);
}

async persistTerminalState(): Promise<void> {
let processes: any[] = [];
for (const [persistentProcessId, persistentProcess] of this._ptys.entries()) {
processes.push({
id: persistentProcessId,
// TODO: Serialize in parallel
buffer: await (persistentProcess as any)._serializer.generateReplayEvent()
});
}
const state = {
processes
};
pfs.writeFile(join(process.env.HOME!, 'testbuffer2'), JSON.stringify(state));
}

async shutdownAll(): Promise<void> {
this.dispose();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ export class RemoteTerminalService extends Disposable implements IRemoteTerminal
return this._remoteTerminalChannel.acceptDetachInstanceReply(requestId, persistentProcessId);
}

async persistTerminalState(): Promise<void> {
throw new Error('NYI'); // TODO: Implement
}

async createProcess(shellLaunchConfig: IShellLaunchConfig, configuration: ICompleteTerminalConfiguration, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, unicodeVersion: '6' | '11', shouldPersist: boolean): Promise<ITerminalChildProcess> {
if (!this._remoteTerminalChannel) {
throw new Error(`Cannot create remote terminal when there is no remote!`);
Expand Down
25 changes: 19 additions & 6 deletions src/vs/workbench/contrib/terminal/browser/terminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,20 +529,29 @@ export class TerminalService implements ITerminalService {
return this._defaultProfileName;
}

private _onBeforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
private async _onBeforeShutdown(reason: ShutdownReason): Promise<boolean> {
if (this.instances.length === 0) {
// No terminal instances, don't veto
return false;
}

// TODO: Fine tune which reasons are supported - what is LOAD?
console.log('persist buffer, reason: ' + reason);
if (reason === ShutdownReason.CLOSE) {
// TODO: persist buffer to disk
// TODO: This is called once per workspace?
// TODO: Either do this or confirm dialog?
await this._localTerminalService?.persistTerminalState();
}

const shouldPersistTerminals = this._configHelper.config.enablePersistentSessions && reason === ShutdownReason.RELOAD;
if (!shouldPersistTerminals) {
const hasDirtyInstances = (
(this.configHelper.config.confirmOnExit === 'always' && this.instances.length > 0) ||
(this.configHelper.config.confirmOnExit === 'hasChildProcesses' && this.instances.some(e => e.hasChildProcesses))
);
if (hasDirtyInstances) {
return this._onBeforeShutdownAsync();
return this._onBeforeShutdownAsync(reason);
}
}

Expand All @@ -551,26 +560,30 @@ export class TerminalService implements ITerminalService {
return false;
}

private async _onBeforeShutdownAsync(): Promise<boolean> {
private async _onBeforeShutdownAsync(reason: ShutdownReason): Promise<boolean> {
// veto if configured to show confirmation and the user chose not to exit
const veto = await this._showTerminalCloseConfirmation();
if (!veto) {
this._isShuttingDown = true;
}

return veto;
}

private _onWillShutdown(e: WillShutdownEvent): void {
// Don't touch processes if the shutdown was a result of reload as they will be reattached
const shouldPersistTerminals = this._configHelper.config.enablePersistentSessions && e.reason === ShutdownReason.RELOAD;
if (shouldPersistTerminals) {
this.instances.forEach(instance => instance.detachFromProcess());
for (const instance of this.instances) {
instance.detachFromProcess();
}
return;
}

// Force dispose of all terminal instances
this.instances.forEach(instance => instance.dispose(true));

for (const instance of this.instances) {
instance.dispose();
}
this._localTerminalService?.setTerminalLayoutInfo(undefined);
}

Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/contrib/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ export interface IOffProcessTerminalService {
reduceConnectionGraceTime(): Promise<void>;
requestDetachInstance(workspaceId: string, instanceId: number): Promise<IProcessDetails | undefined>;
acceptDetachInstanceReply(requestId: number, persistentProcessId?: number): Promise<void>;
/**
* Persists a terminal state to disk, this will a
*/
persistTerminalState(): Promise<void>;
}

export const ILocalTerminalService = createDecorator<ILocalTerminalService>('localTerminalService');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ export class LocalTerminalService extends Disposable implements ILocalTerminalSe
return this._localPtyService.acceptDetachInstanceReply(requestId, persistentProcessId);
}

async persistTerminalState(): Promise<void> {
return this._localPtyService.persistTerminalState();
}

async updateTitle(id: number, title: string, titleSource: TitleEventSource): Promise<void> {
await this._localPtyService.updateTitle(id, title, titleSource);
}
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/test/browser/workbenchTestServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,7 @@ export class TestLocalTerminalService implements ILocalTerminalService {
updateIcon(id: number, icon: URI | { light: URI; dark: URI } | { id: string, color?: { id: string } }, color?: string): Promise<void> { throw new Error('Method not implemented.'); }
requestDetachInstance(workspaceId: string, instanceId: number): Promise<IProcessDetails | undefined> { throw new Error('Method not implemented.'); }
acceptDetachInstanceReply(requestId: number, persistentProcessId: number): Promise<void> { throw new Error('Method not implemented.'); }
persistTerminalState(): Promise<void> { throw new Error('Method not implemented.'); }
}

class TestTerminalChildProcess implements ITerminalChildProcess {
Expand Down

0 comments on commit 6e6f175

Please sign in to comment.