mirror of https://git.tuxpa.in/a/code-server.git
Implement terminal layouts
It doesn't mean much until we persist terminals though, I think.
This commit is contained in:
parent
058e781b3f
commit
ba4448e72d
|
@ -10,6 +10,7 @@ import * as resources from 'vs/base/common/resources';
|
||||||
import { ReadableStreamEventPayload } from 'vs/base/common/stream';
|
import { ReadableStreamEventPayload } from 'vs/base/common/stream';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { transformOutgoingURIs } from 'vs/base/common/uriIpc';
|
import { transformOutgoingURIs } from 'vs/base/common/uriIpc';
|
||||||
|
import { getSystemShell } from 'vs/base/node/shell';
|
||||||
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
import { IServerChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
import { IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
import { IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnostics';
|
||||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
@ -27,10 +28,9 @@ import { IEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/co
|
||||||
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
|
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
|
||||||
import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
||||||
import * as terminal from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
|
import * as terminal from 'vs/workbench/contrib/terminal/common/remoteTerminalChannel';
|
||||||
import { IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
import { IShellLaunchConfig, ITerminalEnvironment, ITerminalLaunchError, ITerminalsLayoutInfo } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||||
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
||||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||||
import { getSystemShell } from 'vs/base/node/shell';
|
|
||||||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||||
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
|
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
|
||||||
|
@ -611,6 +611,22 @@ class Terminal {
|
||||||
this.rows = rows;
|
this.rows = rows;
|
||||||
return this.process.resize(cols, rows);
|
return this.process.resize(cols, rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializable terminal information that can be sent to the client.
|
||||||
|
*/
|
||||||
|
public async description(id: number): Promise<terminal.IRemoteTerminalDescriptionDto> {
|
||||||
|
const cwd = await this.getCwd();
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
pid: this.pid,
|
||||||
|
title: this.title,
|
||||||
|
cwd,
|
||||||
|
workspaceId: this.workspaceId,
|
||||||
|
workspaceName: this.workspaceName,
|
||||||
|
isOrphan: this.isOrphan,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// References: - ../../workbench/api/node/extHostTerminalService.ts
|
// References: - ../../workbench/api/node/extHostTerminalService.ts
|
||||||
|
@ -619,6 +635,8 @@ export class TerminalProviderChannel implements IServerChannel<RemoteAgentConnec
|
||||||
private readonly terminals = new Map<number, Terminal>();
|
private readonly terminals = new Map<number, Terminal>();
|
||||||
private id = 0;
|
private id = 0;
|
||||||
|
|
||||||
|
private readonly layouts = new Map<string, terminal.ISetTerminalLayoutInfoArgs>();
|
||||||
|
|
||||||
public constructor (private readonly logService: ILogService) {
|
public constructor (private readonly logService: ILogService) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -647,6 +665,8 @@ export class TerminalProviderChannel implements IServerChannel<RemoteAgentConnec
|
||||||
case '$sendCommandResultToTerminalProcess': return this.sendCommandResultToTerminalProcess(args);
|
case '$sendCommandResultToTerminalProcess': return this.sendCommandResultToTerminalProcess(args);
|
||||||
case '$orphanQuestionReply': return this.orphanQuestionReply(args[0]);
|
case '$orphanQuestionReply': return this.orphanQuestionReply(args[0]);
|
||||||
case '$listTerminals': return this.listTerminals(args[0]);
|
case '$listTerminals': return this.listTerminals(args[0]);
|
||||||
|
case '$setTerminalLayoutInfo': return this.setTerminalLayoutInfo(args);
|
||||||
|
case '$getTerminalLayoutInfo': return this.getTerminalLayoutInfo(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Invalid call '${command}'`);
|
throw new Error(`Invalid call '${command}'`);
|
||||||
|
@ -839,24 +859,53 @@ export class TerminalProviderChannel implements IServerChannel<RemoteAgentConnec
|
||||||
// do differently. Maybe it's to reset the terminal dispose timeouts or
|
// do differently. Maybe it's to reset the terminal dispose timeouts or
|
||||||
// something like that, but why not do it each time you list?
|
// something like that, but why not do it each time you list?
|
||||||
const terminals = await Promise.all(Array.from(this.terminals).map(async ([id, terminal]) => {
|
const terminals = await Promise.all(Array.from(this.terminals).map(async ([id, terminal]) => {
|
||||||
const cwd = await terminal.getCwd();
|
return terminal.description(id);
|
||||||
return {
|
|
||||||
id,
|
|
||||||
pid: terminal.pid,
|
|
||||||
title: terminal.title,
|
|
||||||
cwd,
|
|
||||||
workspaceId: terminal.workspaceId,
|
|
||||||
workspaceName: terminal.workspaceName,
|
|
||||||
isOrphan: terminal.isOrphan,
|
|
||||||
};
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Only returned orphaned terminals so we don't end up attaching to
|
// Only returned orphaned terminals so we don't end up attaching to
|
||||||
// terminals already attached elsewhere.
|
// terminals already attached elsewhere.
|
||||||
return terminals.filter((t) => t.isOrphan);
|
return terminals.filter((t) => t.isOrphan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setTerminalLayoutInfo(args: terminal.ISetTerminalLayoutInfoArgs): Promise<void> {
|
||||||
|
this.layouts.set(args.workspaceId, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getTerminalLayoutInfo(args: terminal.IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined> {
|
||||||
|
const layout = this.layouts.get(args.workspaceId);
|
||||||
|
if (!layout) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs = await Promise.all(layout.tabs.map(async (tab) => {
|
||||||
|
// The terminals are stored by ID so look them up.
|
||||||
|
const terminals = await Promise.all(tab.terminals.map(async (t) => {
|
||||||
|
const terminal = this.terminals.get(t.terminal);
|
||||||
|
if (!terminal) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...t,
|
||||||
|
terminal: await terminal.description(t.terminal),
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...tab,
|
||||||
|
// Filter out terminals that have been killed.
|
||||||
|
terminals: terminals.filter(isDefined),
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
return { tabs };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformIncoming(remoteAuthority: string, uri: UriComponents | undefined): URI | undefined {
|
function transformIncoming(remoteAuthority: string, uri: UriComponents | undefined): URI | undefined {
|
||||||
const transformer = getUriTransformer(remoteAuthority);
|
const transformer = getUriTransformer(remoteAuthority);
|
||||||
return uri ? URI.revive(transformer.transformIncoming(uri)) : uri;
|
return uri ? URI.revive(transformer.transformIncoming(uri)) : uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDefined<T>(t: T | undefined): t is T {
|
||||||
|
return typeof t !== "undefined";
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue