Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose shell's environment - pwsh #237415

Merged
merged 54 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
714bb39
start terminal shell env proposed
anthonykim1 Sep 17, 2024
3c412ff
fix typo
anthonykim1 Sep 17, 2024
f214756
progress on shellEnvDetectionCapability, mainThreadTerminalSI
anthonykim1 Sep 19, 2024
3923373
update IShellEnvDetectionCapability interface
anthonykim1 Sep 19, 2024
0465588
touch up on $shellEnvChange
anthonykim1 Sep 19, 2024
e1d611a
adjust IShellEnvDetectionCapability
anthonykim1 Sep 19, 2024
98131e7
properly listen to envChangeEvent
anthonykim1 Sep 19, 2024
e37f119
Serialize env map, expose on exthost
anthonykim1 Nov 4, 2024
a0602bc
Merge remote-tracking branch 'upstream/main' into shellEnvAPI
anthonykim1 Nov 4, 2024
94c6574
start adding to zsh script
anthonykim1 Nov 4, 2024
e4ab9e8
receive environment variable in extension host, properly escape "
anthonykim1 Nov 19, 2024
e2b4ca1
clean up
anthonykim1 Nov 19, 2024
1cf51a5
Add TODO: properly escape double quotes, figure out why JSON parse fa…
anthonykim1 Nov 21, 2024
f0b1578
Fix nonce check, ignore PS1 for now in bash
Tyriar Dec 2, 2024
1b2eb1f
Add some simple PS1 string tests to deserializeMessage
Tyriar Dec 2, 2024
0956b86
New approach of sending env entries separately
Tyriar Dec 2, 2024
bb735f8
be able to get EnvSingleVar
anthonykim1 Dec 3, 2024
a1503da
few comments
anthonykim1 Jan 4, 2025
61653d5
add function signature for start, set, end environment var
anthonykim1 Jan 5, 2025
db981ae
implement EnvStart, EnvEntry, EnvEnd for single env entry
anthonykim1 Jan 6, 2025
a25a9a9
deserialize env value for EnvEntry
anthonykim1 Jan 6, 2025
7fe7c26
Remove unncessary comments
anthonykim1 Jan 6, 2025
338514c
only leave pwsh in this PR and exclude other shells
anthonykim1 Jan 7, 2025
9b97e1b
keep exlcuding other shell env - only pwsh should remain
anthonykim1 Jan 7, 2025
fc9f3f5
Update src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
anthonykim1 Jan 8, 2025
bb93fdd
Update src/vscode-dts/vscode.proposed.terminalShellEnv.d.ts
anthonykim1 Jan 8, 2025
0ca8a75
Update src/vs/workbench/contrib/terminal/common/scripts/shellIntegrat…
anthonykim1 Jan 8, 2025
935f14a
Update src/vs/workbench/contrib/terminal/common/scripts/shellIntegrat…
anthonykim1 Jan 8, 2025
2f7b969
Update src/vs/workbench/contrib/terminal/common/scripts/shellIntegrat…
anthonykim1 Jan 8, 2025
cb997d5
Update src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
anthonykim1 Jan 8, 2025
b6b673f
Update src/vs/platform/terminal/common/capabilities/shellEnvDetection…
anthonykim1 Jan 8, 2025
0ab7322
Update src/vs/workbench/api/common/extHost.protocol.ts
anthonykim1 Jan 8, 2025
fe93145
Update src/vs/workbench/api/browser/mainThreadTerminalShellIntegratio…
anthonykim1 Jan 8, 2025
badfb37
Update src/vs/platform/terminal/common/capabilities/shellEnvDetection…
anthonykim1 Jan 8, 2025
3f156f9
Update src/vs/platform/terminal/common/capabilities/shellEnvDetection…
anthonykim1 Jan 8, 2025
4e8c2cb
Update src/vs/platform/terminal/common/capabilities/shellEnvDetection…
anthonykim1 Jan 8, 2025
333c8d5
Update src/vs/platform/terminal/common/capabilities/capabilities.ts
anthonykim1 Jan 8, 2025
c68c58a
Update src/vs/workbench/api/browser/mainThreadTerminalShellIntegratio…
anthonykim1 Jan 8, 2025
944ce9a
Update src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts
anthonykim1 Jan 8, 2025
b2afe32
Update src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts
anthonykim1 Jan 8, 2025
dbbe2df
Update src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts
anthonykim1 Jan 8, 2025
0b248e2
add comment for ShellEnvDetection
anthonykim1 Jan 8, 2025
d246ba7
change envs in shellEnvDetectionCapability to env
anthonykim1 Jan 8, 2025
6b081da
Mention escaping character for EnvJSON similar to commandLine
anthonykim1 Jan 8, 2025
d555813
Do not fire env event if env has not changed
anthonykim1 Jan 8, 2025
3591fa4
add link to CommandLine
anthonykim1 Jan 9, 2025
143a4cc
follow main branch format so I avoid merge conflict
anthonykim1 Jan 9, 2025
6509fa1
Merge branch 'main' into shellEnvPwshOnly
anthonykim1 Jan 9, 2025
03fe326
remove resolved TODO
anthonykim1 Jan 9, 2025
d501cee
Update src/vs/workbench/api/browser/mainThreadTerminalShellIntegratio…
anthonykim1 Jan 9, 2025
e94cf4d
Update src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts
anthonykim1 Jan 9, 2025
0b831a5
use vscode object equals
anthonykim1 Jan 9, 2025
5f9f2db
Merge branch 'main' into shellEnvPwshOnly
Tyriar Jan 9, 2025
949fbec
Merge branch 'main' into shellEnvPwshOnly
Tyriar Jan 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/vs/platform/extensions/common/extensionsApiProposals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@ const _allApiProposals = {
terminalSelection: {
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalSelection.d.ts',
},
terminalShellEnv: {
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalShellEnv.d.ts',
},
testObserver: {
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testObserver.d.ts',
},
Expand Down
15 changes: 14 additions & 1 deletion src/vs/platform/terminal/common/capabilities/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ export const enum TerminalCapability {
* the request (task, debug, etc) provides an ID, optional marker, hoverMessage, and hidden property. When
* hidden is not provided, a generic decoration is added to the buffer and overview ruler.
*/
BufferMarkDetection
BufferMarkDetection,

// TODO: Shell Environment --> listen to from
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
ShellEnvDetection,

anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -133,6 +137,7 @@ export interface ITerminalCapabilityImplMap {
[TerminalCapability.NaiveCwdDetection]: INaiveCwdDetectionCapability;
[TerminalCapability.PartialCommandDetection]: IPartialCommandDetectionCapability;
[TerminalCapability.BufferMarkDetection]: IBufferMarkCapability;
[TerminalCapability.ShellEnvDetection]: IShellEnvDetectionCapability;
}

export interface ICwdDetectionCapability {
Expand All @@ -143,6 +148,14 @@ export interface ICwdDetectionCapability {
updateCwd(cwd: string): void;
}

export interface IShellEnvDetectionCapability {
readonly type: TerminalCapability.ShellEnvDetection;
readonly onDidChangeEnv: Event<Map<string, string>>;
get envs(): Map<string, string>;
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
setEnvironment(envs: { [key: string]: string | undefined } | undefined, isTrusted: boolean): void;
applyEnvironmentDiff(envs: { [key: string]: string | undefined } | undefined): void;
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
}

export const enum CommandInvalidationReason {
Windows = 'windows',
NoProblemsReported = 'noProblemsReported'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Disposable } from '../../../../base/common/lifecycle.js';
import { IShellEnvDetectionCapability, TerminalCapability } from './capabilities.js';
import { Emitter } from '../../../../base/common/event.js';

export class ShellEnvDetectionCapability extends Disposable implements IShellEnvDetectionCapability {
readonly type = TerminalCapability.ShellEnvDetection;
private readonly _env: Map<string, string> = new Map();
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
get envs(): Map<string, string> { return this._env; }

private readonly _onDidChangeEnv = this._register(new Emitter<Map<string, string>>());
readonly onDidChangeEnv = this._onDidChangeEnv.event;

constructor() {
super();
}

setEnvironment(env: { [key: string]: string | undefined }, isTrusted: boolean): void {
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
if (!isTrusted) {
return;
}

this._env.clear();
for (const [key, value] of Object.entries(env)) {
if (value !== undefined) {
this._env.set(key, value);
}
}

// Convert to event and fire event
this._onDidChangeEnv.fire(this._env);
}

applyEnvironmentDiff(env: { [key: string]: string | undefined }): void {
// TODO: Implement
throw new Error('Method not implemented.');
//look at every key, fire event after applying everything.
}
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
}

// bash, pwsh => capability (env change =>) main thread (env change =>)
// extension host [(new or changed) .cwd, .env, .shellIntegration SI Change event => ] Extension
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
44 changes: 43 additions & 1 deletion src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Disposable, dispose, IDisposable, toDisposable } from '../../../../base
import { TerminalCapabilityStore } from '../capabilities/terminalCapabilityStore.js';
import { CommandDetectionCapability } from '../capabilities/commandDetectionCapability.js';
import { CwdDetectionCapability } from '../capabilities/cwdDetectionCapability.js';
import { IBufferMarkCapability, ICommandDetectionCapability, ICwdDetectionCapability, ISerializedCommandDetectionCapability, TerminalCapability } from '../capabilities/capabilities.js';
import { IBufferMarkCapability, ICommandDetectionCapability, ICwdDetectionCapability, ISerializedCommandDetectionCapability, IShellEnvDetectionCapability, TerminalCapability } from '../capabilities/capabilities.js';
import { PartialCommandDetectionCapability } from '../capabilities/partialCommandDetectionCapability.js';
import { ILogService } from '../../../log/common/log.js';
import { ITelemetryService } from '../../../telemetry/common/telemetry.js';
Expand All @@ -18,6 +18,7 @@ import type { ITerminalAddon, Terminal } from '@xterm/headless';
import { URI } from '../../../../base/common/uri.js';
import { sanitizeCwd } from '../terminalEnvironment.js';
import { removeAnsiEscapeCodesFromPrompt } from '../../../../base/common/strings.js';
import { ShellEnvDetectionCapability } from '../capabilities/shellEnvDetectionCapability.js';


/**
Expand Down Expand Up @@ -224,6 +225,21 @@ const enum VSCodeOscPt {
* WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.
*/
SetMark = 'SetMark',

/**
* Sends the shell's environment.
*
* Format: `OSC 633 ; Env ; <Environment> ; <Nonce>`
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
*
* `Environment` - A JSON string containing the shell's environment variables.
* TODO: Encoding information for commandline sequence.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mention encoding information like in CommandLine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tyriar Do you think 6b081da is enough?

Since we are using the same escaping function as commandLine, I included a short single line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but let's add a link that will work in hovers via {@link CommandLine}

* `Nonce` - An optional nonce can be provided which is may be required by the terminal in order enable
* some features. This helps ensure no malicious command injection has occurred.
*
* WARNING: This sequence is unfinalized, DO NOT use this in your shell integration script.
*/
Env = 'Env',

}

/**
Expand Down Expand Up @@ -418,6 +434,23 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
this._createOrGetCommandDetection(this._terminal).handleContinuationEnd();
return true;
}
// TODO: Name EnvJson
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
case VSCodeOscPt.Env: {
const arg0 = args[0];
const arg1 = args[1];
if (arg0 !== undefined) {
try {
const env = JSON.parse(deserializeMessage(arg0));
console.log('In zsh I want to see if arg1 is nonce ---> arg1', arg1);
console.log('In zsh I want to see if nonce matches ---> nonce', this._nonce);
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
this._createOrGetShellEnvDetection().setEnvironment(env, arg1 === this._nonce);
} catch (e) {
console.log('JSON.parse throw', { e, arg0 });
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
this._logService.warn('Failed to parse environment from shell integration sequence', arg0);
} // TODO: issue with double quotes. Dont worry about encoding variable name. Just escape the value
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
}
return true;
}
case VSCodeOscPt.RightPromptStart: {
this._createOrGetCommandDetection(this._terminal).handleRightPromptStart();
return true;
Expand Down Expand Up @@ -614,6 +647,15 @@ export class ShellIntegrationAddon extends Disposable implements IShellIntegrati
}
return bufferMarkDetection;
}

protected _createOrGetShellEnvDetection(): IShellEnvDetectionCapability {
let shellEnvDetection = this.capabilities.get(TerminalCapability.ShellEnvDetection);
if (!shellEnvDetection) {
shellEnvDetection = this._register(new ShellEnvDetectionCapability());
this.capabilities.add(TerminalCapability.ShellEnvDetection, shellEnvDetection);
}
return shellEnvDetection;
}
}

export function deserializeMessage(message: string): string {
Expand Down
14 changes: 14 additions & 0 deletions src/vs/workbench/api/browser/mainThreadTerminalShellIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ export class MainThreadTerminalShellIntegration extends Disposable implements Ma
})).event;
this._store.add(onDidAddCommandDetection(e => this._proxy.$shellIntegrationChange(e.instanceId)));


// TODO: Listen to environment changes on our new capability, send to extension host via a $... method
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
// onDidChangeTerminalShellIntegrationEnvironment
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
const envChangeEvent = this._store.add(this._terminalService.createOnInstanceCapabilityEvent(TerminalCapability.ShellEnvDetection, e => e.onDidChangeEnv));
this._store.add(envChangeEvent.event(e => {
console.log('True');

// convert map into keys and values
const keysArr = Array.from(e.data.keys());
const valuesArr = Array.from(e.data.values());
this._proxy.$shellEnvChange(e.instance.instanceId, keysArr, valuesArr); // sending to ext host via $ method
}));

anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved

// onDidStartTerminalShellExecution
const commandDetectionStartEvent = this._store.add(this._terminalService.createOnInstanceCapabilityEvent(TerminalCapability.CommandDetection, e => e.onCommandExecuted));
let currentCommand: ITerminalCommand | undefined;
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2408,7 +2408,8 @@ export interface ExtHostTerminalShellIntegrationShape {
$shellExecutionStart(instanceId: number, commandLineValue: string, commandLineConfidence: TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, cwd: UriComponents | undefined): void;
$shellExecutionEnd(instanceId: number, commandLineValue: string, commandLineConfidence: TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, exitCode: number | undefined): void;
$shellExecutionData(instanceId: number, data: string): void;
$cwdChange(instanceId: number, cwd: UriComponents | undefined): void;
$shellEnvChange(instanceId: number, shellEnvKeys: string[], shellEnvValues: string[]): void;
$cwdChange(instanceId: number, cwd: UriComponents | undefined): void; // Question: MainThread vs. extHost
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
$closeTerminal(instanceId: number): void;
}

Expand Down
71 changes: 46 additions & 25 deletions src/vs/workbench/api/common/extHostTerminalShellIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,30 +55,30 @@ export class ExtHostTerminalShellIntegration extends Disposable implements IExtH
}));

// Convenient test code:
// this.onDidChangeTerminalShellIntegration(e => {
// console.log('*** onDidChangeTerminalShellIntegration', e);
// });
// this.onDidStartTerminalShellExecution(async e => {
// console.log('*** onDidStartTerminalShellExecution', e);
// // new Promise<void>(r => {
// // (async () => {
// // for await (const d of e.execution.read()) {
// // console.log('data2', d);
// // }
// // })();
// // });
// for await (const d of e.execution.read()) {
// console.log('data', d);
// }
// });
// this.onDidEndTerminalShellExecution(e => {
// console.log('*** onDidEndTerminalShellExecution', e);
// });
// setTimeout(() => {
// console.log('before executeCommand(\"echo hello\")');
// Array.from(this._activeShellIntegrations.values())[0].value.executeCommand('echo hello');
// console.log('after executeCommand(\"echo hello\")');
// }, 4000);
this.onDidChangeTerminalShellIntegration(e => {
console.log('*** onDidChangeTerminalShellIntegration env', e.shellIntegration.env);
});
this.onDidStartTerminalShellExecution(async e => {
console.log('*** onDidStartTerminalShellExecution', e);
// new Promise<void>(r => {
// (async () => {
// for await (const d of e.execution.read()) {
// console.log('data2', d);
// }
// })();
// });
for await (const d of e.execution.read()) {
console.log('data', d);
}
});
this.onDidEndTerminalShellExecution(e => {
console.log('*** onDidEndTerminalShellExecution', e);
});
setTimeout(() => {
console.log('before executeCommand(\"echo hello\")');
Array.from(this._activeShellIntegrations.values())[0].value.executeCommand('echo hello');
console.log('after executeCommand(\"echo hello\")');
}, 4000);
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
}

public $shellIntegrationChange(instanceId: number): void {
Expand Down Expand Up @@ -131,6 +131,10 @@ export class ExtHostTerminalShellIntegration extends Disposable implements IExtH
this._activeShellIntegrations.get(instanceId)?.emitData(data);
}

public $shellEnvChange(instanceId: number, shellEnvKeys: string[], shellEnvValues: string[]): void {
this._activeShellIntegrations.get(instanceId)?.setEnv(shellEnvKeys, shellEnvValues);
}

public $cwdChange(instanceId: number, cwd: UriComponents | undefined): void {
this._activeShellIntegrations.get(instanceId)?.setCwd(URI.revive(cwd));
}
Expand All @@ -147,6 +151,7 @@ class InternalTerminalShellIntegration extends Disposable {
get currentExecution(): InternalTerminalShellExecution | undefined { return this._currentExecution; }

private _ignoreNextExecution: boolean = false;
private _env: { [key: string]: string | undefined } | undefined;
private _cwd: URI | undefined;

readonly store: DisposableStore = this._register(new DisposableStore());
Expand All @@ -171,6 +176,9 @@ class InternalTerminalShellIntegration extends Disposable {
get cwd(): URI | undefined {
return that._cwd;
},
get env(): { [key: string]: string | undefined } | undefined {
return that._env;
},
// executeCommand(commandLine: string): vscode.TerminalShellExecution;
// executeCommand(executable: string, args: string[]): vscode.TerminalShellExecution;
executeCommand(commandLineOrExecutable: string, args?: string[]): vscode.TerminalShellExecution {
Expand Down Expand Up @@ -232,6 +240,16 @@ class InternalTerminalShellIntegration extends Disposable {
}
}

setEnv(keys: string[], values: string[]): void {
const env: { [key: string]: string | undefined } = {};
for (let i = 0; i < keys.length; i++) {
env[keys[i]] = values[i];
}
this._env = env;
// TODO: Make sure env changed. If env doesnt change, dont fire event.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do this, can we stop it at the capability time, rather than here or on the exthost?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added them here: d555813
at shellEnvDetectionCapability!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

this._fireChangeEvent();
}

setCwd(cwd: URI | undefined): void {
let wasChanged = false;
if (URI.isUri(this._cwd)) {
Expand All @@ -241,9 +259,12 @@ class InternalTerminalShellIntegration extends Disposable {
}
if (wasChanged) {
this._cwd = cwd;
this._onDidRequestChangeShellIntegration.fire({ terminal: this._terminal, shellIntegration: this.value });
this._fireChangeEvent();
}
}
private _fireChangeEvent() {
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
this._onDidRequestChangeShellIntegration.fire({ terminal: this._terminal, shellIntegration: this.value });
}
}

class InternalTerminalShellExecution {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ __vsc_command_complete() {
fi
__vsc_update_cwd
}

if [[ -o NOUNSET ]]; then
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
if [ -z "${RPROMPT-}" ]; then
RPROMPT=""
Expand Down Expand Up @@ -173,6 +172,7 @@ __vsc_precmd() {
# non null
__vsc_update_prompt
fi

}
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved

__vsc_preexec() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function Global:__VSCode-Escape-Value([string]$value) {
})
}


anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
function Global:Prompt() {
$FakeCode = [int]!$global:?
# NOTE: We disable strict mode for the scope of this function because it unhelpfully throws an
Expand All @@ -88,6 +89,16 @@ function Global:Prompt() {
# Current working directory
# OSC 633 ; <Property>=<Value> ST
$Result += if ($pwd.Provider.Name -eq 'FileSystem') { "$([char]0x1b)]633;P;Cwd=$(__VSCode-Escape-Value $pwd.ProviderPath)`a" }

# Send current environment variables as JSON
# OSC 633 ; Env ; <Environment> ; <Nonce>
if ($isStable -eq "0") {
$envMap = @{}
Get-ChildItem Env: | ForEach-Object { $envMap[$_.Name] = $_.Value }
$envJson = $envMap | ConvertTo-Json -Compress
$Result += "$([char]0x1b)]633;Env;$(__VSCode-Escape-Value $envJson);$Nonce`a"
}

# Before running the original prompt, put $? back to what it was:
if ($FakeCode -ne 0) {
Write-Error "failure" -ea ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ suite('ShellIntegrationAddon', () => {
['escaped newline (upper hex)', `${Backslash}x0A`, Newline],
['escaped backslash followed by literal "x0a" is not a newline', `${Backslash}${Backslash}x0a`, `${Backslash}x0a`],
['non-initial escaped backslash followed by literal "x0a" is not a newline', `foo${Backslash}${Backslash}x0a`, `foo${Backslash}x0a`],
['PS1 simple', '[\\u@\\h \\W]\\$', '[\\u@\\h \\W]\\$'],
['PS1 VSC SI', `${Backslash}x1b]633;A${Backslash}x07\\[${Backslash}x1b]0;\\u@\\h:\\w\\a\\]${Backslash}x1b]633;B${Backslash}x07`, '\x1b]633;A\x07\\[\x1b]0;\\u@\\h:\\w\\a\\]\x1b]633;B\x07']
];

cases.forEach(([title, input, expected]) => {
Expand Down
22 changes: 22 additions & 0 deletions src/vscode-dts/vscode.proposed.terminalShellEnv.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {
// @anthonykim1 @tyriar https://github.com/microsoft/vscode/issues/227467

// Expose the terminal's actual shell environment to extensions
export interface TerminalShellIntegration {
// The shell environment
// undefined means we don't know anything about the env
// NOTE: This is similar to command line in that it's verified with a nonce, however we just ignore when there's no nonce, so we don't need the trust flag like `TerminalShellExecutionCommandLine.isTrusted`
readonly env: { [key: string]: string | undefined } | undefined;
}

export namespace window {
// Fires when TerminalShellIntegration.env changes
// TODO: Should this just use `onDidChangeTerminalShellIntegration` like `TerminalShellIntegration.cwd` does?
export const onDidChangeTerminalShellIntegrationEnvironment: Event<TerminalShellIntegration>;
}
}
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
Loading