diff --git a/lib/vscode/src/vs/platform/environment/common/environmentService.ts b/lib/vscode/src/vs/platform/environment/common/environmentService.ts index 9fc2f174a..3acc61084 100644 --- a/lib/vscode/src/vs/platform/environment/common/environmentService.ts +++ b/lib/vscode/src/vs/platform/environment/common/environmentService.ts @@ -15,6 +15,23 @@ import { URI } from 'vs/base/common/uri'; import { ExtensionKind } from 'vs/platform/extensions/common/extensions'; import { env } from 'vs/base/common/process'; + +function parsePathArg(arg: string | undefined, process: NodeJS.Process): string | undefined { + if (!arg) { + return undefined; + } + + // Determine if the arg is relative or absolute, if relative use the original CWD + // (VSCODE_CWD), not the potentially overridden one (process.cwd()). + const resolved = resolve(arg); + + if (normalize(arg) === resolved) { + return resolved; + } + + return resolve(process.env['VSCODE_CWD'] || process.cwd(), arg); +} + export interface INativeEnvironmentPaths { /** @@ -173,6 +190,19 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron return undefined; } + /** + * NOTE@coder: add extraExtensionPaths and extraBuiltinExtensionPaths + * Code location changed after 1.54 (was earlier directly in NativeEnvironmentService). + */ + @memoize + get extraExtensionPaths(): string[] { + return (this._args['extra-extensions-dir'] || []).map((p) => parsePathArg(p, process)); + } + @memoize + get extraBuiltinExtensionPaths(): string[] { + return (this._args['extra-builtin-extensions-dir'] || []).map((p) => parsePathArg(p, process)); + } + @memoize get extensionDevelopmentKind(): ExtensionKind[] | undefined { return this.args.extensionDevelopmentKind?.map(kind => kind === 'ui' || kind === 'workspace' || kind === 'web' ? kind : 'workspace'); diff --git a/lib/vscode/src/vs/server/node/channel.ts b/lib/vscode/src/vs/server/node/channel.ts index 347bccc42..619f8ccd3 100644 --- a/lib/vscode/src/vs/server/node/channel.ts +++ b/lib/vscode/src/vs/server/node/channel.ts @@ -33,7 +33,7 @@ import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBu import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment'; import { TerminalProcess } from 'vs/platform/terminal/node/terminalProcess'; -import { ISetTerminalLayoutInfoArgs, IGetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess'; +import { ISetTerminalLayoutInfoArgs, IGetTerminalLayoutInfoArgs, IProcessDetails } from 'vs/platform/terminal/common/terminalProcess'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; import { ExtensionScanner, ExtensionScannerInput } from 'vs/workbench/services/extensions/node/extensionPoints'; @@ -415,7 +415,7 @@ class Terminal { private disposeDelay = 48 * 60 * 60 * 1000; private buffering = false; - private readonly _onEvent = new Emitter({ + private readonly _onEvent = new Emitter({ // Don't bind to data until something is listening. onFirstListenerAdd: () => { logger.debug('Terminal bound', field('id', this.id)); @@ -461,7 +461,7 @@ class Terminal { } }); - public get onEvent(): Event { return this._onEvent.event; } + public get onEvent(): Event { return this._onEvent.event; } // Buffer to reduce the number of messages going to the renderer. private readonly bufferer = new TerminalDataBufferer((_, data) => { @@ -624,7 +624,7 @@ class Terminal { /** * Serializable terminal information that can be sent to the client. */ - public async description(id: number): Promise { + public async description(id: number): Promise { const cwd = await this.getCwd(); return { id, @@ -658,23 +658,22 @@ export class TerminalProviderChannel implements IServerChannel { - return this.getTerminal(args.id).onEvent; + private onTerminalProcessEvent(id: number): Event { + return this.getTerminal(id).onEvent; } public call(context: RemoteAgentConnectionContext, command: string, args?: any): Promise { switch (command) { case '$createTerminalProcess': return this.createTerminalProcess(context.remoteAuthority, args); - case '$startTerminalProcess': return this.startTerminalProcess(args); - case '$sendInputToTerminalProcess': return this.sendInputToTerminalProcess(args); - case '$sendCharCountToTerminalProcess': return this.sendCharCountToTerminalProcess(args); - case '$shutdownTerminalProcess': return this.shutdownTerminalProcess(args); - case '$resizeTerminalProcess': return this.resizeTerminalProcess(args); - case '$getTerminalInitialCwd': return this.getTerminalInitialCwd(args); - case '$getTerminalCwd': return this.getTerminalCwd(args); - case '$sendCommandResultToTerminalProcess': return this.sendCommandResultToTerminalProcess(args); - case '$orphanQuestionReply': return this.orphanQuestionReply(args[0]); - case '$listTerminals': return this.listTerminals(args[0]); + case '$startTerminalProcess': return this.startTerminalProcess(...args as [number]); + case '$sendInputToTerminalProcess': return this.sendInputToTerminalProcess(...args as [number, string]); + case '$sendCharCountToTerminalProcess': return this.sendCharCountToTerminalProcess(...args as [number, number]); + case '$shutdownTerminalProcess': return this.shutdownTerminalProcess(...args as [number, boolean]); + case '$resizeTerminalProcess': return this.resizeTerminalProcess(...args as [number, number, number]); + case '$getTerminalInitialCwd': return this.getTerminalInitialCwd(...args as [number]); + case '$getTerminalCwd': return this.getTerminalCwd(...args as [number]); + case '$sendCommandResultToTerminalProcess': return this.sendCommandResultToTerminalProcess(...args as [number, number, boolean, any]); + case '$orphanQuestionReply': return this.orphanQuestionReply(...args as [number]); case '$setTerminalLayoutInfo': return this.setTerminalLayoutInfo(args); case '$getTerminalLayoutInfo': return this.getTerminalLayoutInfo(args); } @@ -729,7 +728,7 @@ export class TerminalProviderChannel implements IServerChannel args.configuration[key], args.isWorkspaceShellAllowed, - await getSystemShell(platform.platform), + await getSystemShell(platform.platform, env), process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'), process.env.windir, resolver, @@ -816,7 +815,7 @@ export class TerminalProviderChannel implements IServerChannel this.terminals.delete(terminalId)); return { - terminalId, + persistentTerminalId: terminalId, resolvedShellLaunchConfig, }; } @@ -829,58 +828,44 @@ export class TerminalProviderChannel implements IServerChannel { - return this.getTerminal(args.id).start(); + private async startTerminalProcess(id: number): Promise { + return this.getTerminal(id).start(); } - private async sendInputToTerminalProcess(args: terminal.ISendInputToTerminalProcessArguments): Promise { - return this.getTerminal(args.id).input(args.data); + private async sendInputToTerminalProcess(id: number, data: string): Promise { + return this.getTerminal(id).input(data); } - private async sendCharCountToTerminalProcess(args: terminal.ISendCharCountToTerminalProcessArguments): Promise { - return this.getTerminal(args.id).acknowledgeDataEvent(args.charCount); + private async sendCharCountToTerminalProcess(id: number, charCount: number): Promise { + return this.getTerminal(id).acknowledgeDataEvent(charCount); } - private async shutdownTerminalProcess(args: terminal.IShutdownTerminalProcessArguments): Promise { - return this.getTerminal(args.id).shutdown(args.immediate); + private async shutdownTerminalProcess(id: number, immediate: boolean): Promise { + return this.getTerminal(id).shutdown(immediate); } - private async resizeTerminalProcess(args: terminal.IResizeTerminalProcessArguments): Promise { - return this.getTerminal(args.id).resize(args.cols, args.rows); + private async resizeTerminalProcess(id: number, cols: number, rows: number): Promise { + return this.getTerminal(id).resize(cols, rows); } - private async getTerminalInitialCwd(args: terminal.IGetTerminalInitialCwdArguments): Promise { - return this.getTerminal(args.id).getInitialCwd(); + private async getTerminalInitialCwd(id: number): Promise { + return this.getTerminal(id).getInitialCwd(); } - private async getTerminalCwd(args: terminal.IGetTerminalCwdArguments): Promise { - return this.getTerminal(args.id).getCwd(); + private async getTerminalCwd(id: number): Promise { + return this.getTerminal(id).getCwd(); } - private async sendCommandResultToTerminalProcess(_: terminal.ISendCommandResultToTerminalProcessArguments): Promise { + private async sendCommandResultToTerminalProcess(id: number, reqId: number, isError: boolean, payload: any): Promise { // NOTE: Not required unless we implement the `execCommand` event, see above. throw new Error('not implemented'); } - private async orphanQuestionReply(_: terminal.IOrphanQuestionReplyArgs): Promise { + private async orphanQuestionReply(id: number): Promise { // NOTE: Not required unless we implement the `orphan?` event, see above. throw new Error('not implemented'); } - private async listTerminals(_: terminal.IListTerminalsArgs): Promise { - // TODO: args.isInitialization. Maybe this is to have slightly different - // behavior when first listing terminals but I don't know what you'd want to - // do differently. Maybe it's to reset the terminal dispose timeouts or - // 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]) => { - return terminal.description(id); - })); - - // Only returned orphaned terminals so we don't end up attaching to - // terminals already attached elsewhere. - return terminals.filter((t) => t.isOrphan); - } - public async setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): Promise { this.layouts.set(args.workspaceId, args); } diff --git a/lib/vscode/src/vs/server/node/nls.ts b/lib/vscode/src/vs/server/node/nls.ts index 3d428a57d..926500c14 100644 --- a/lib/vscode/src/vs/server/node/nls.ts +++ b/lib/vscode/src/vs/server/node/nls.ts @@ -1,13 +1,13 @@ import * as fs from 'fs'; import * as path from 'path'; import * as util from 'util'; -import { getPathFromAmdModule } from 'vs/base/common/amd'; +import { FileAccess } from 'vs/base/common/network'; import * as lp from 'vs/base/node/languagePacks'; import product from 'vs/platform/product/common/product'; import { Translations } from 'vs/workbench/services/extensions/common/extensionPoints'; const configurations = new Map>(); -const metadataPath = path.join(getPathFromAmdModule(require, ''), 'nls.metadata.json'); +const metadataPath = path.join(FileAccess.asFileUri('', require).fsPath, 'nls.metadata.json'); export const isInternalConfiguration = (config: lp.NLSConfiguration): config is lp.InternalNLSConfiguration => { return config && !!(config)._languagePackId; diff --git a/lib/vscode/src/vs/server/node/server.ts b/lib/vscode/src/vs/server/node/server.ts index 3c99d415e..f21532763 100644 --- a/lib/vscode/src/vs/server/node/server.ts +++ b/lib/vscode/src/vs/server/node/server.ts @@ -209,7 +209,7 @@ export class Vscode { // ../../electron-browser/sharedProcess/sharedProcessMain.ts#L148 // ../../../code/electron-main/app.ts private async initializeServices(args: NativeParsedArgs): Promise { - const environmentService = new NativeEnvironmentService(args); + const environmentService = new NativeEnvironmentService(args, this.services.get(IProductService) as IProductService); // https://github.com/cdr/code-server/issues/1693 fs.mkdirSync(environmentService.globalStorageHome.fsPath, { recursive: true }); const logService = new MultiplexLogService([