microsoft/vscode

Allow EnvironmentVariableCollection to unset variables

mkhl opened this issue · 2 comments

mkhl commented

EnvironmentVariableCollection currently support modifying a variable, or deleting a modification in that collection, but not unsetting an environment variable.

Sometimes we want to unset variables in the direnv extension but there is no API for it (and if we force null or undefined through the current API they get automatically stringified to "null" and "undefined").
The closest we can do is set them to the empty string (what POSIX calls null), but then some programs insist on distinguishing empty from undefined variables.
(N.B. Shells make this intentionally hard, for example the bash man page omits the expansion modifiers that distinguish null and unset variables.)

This could be done either by allowing null and/or undefined as the replacement value for replace, or with a new method on the API.

Related issue: direnv/direnv-vscode#527, and previously NixOS/nix#6409

Related commits: direnv/direnv-vscode@9905fe7, and previously direnv/direnv-vscode@79a4841

This feature request is now a candidate for our backlog. The community has 60 days to upvote the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our documentation.

Happy Coding!

Tyriar commented

Here's a natural proposal:

export interface EnvironmentVariableMutator {
	readonly value: string | undefined;
}

export interface EnvironmentVariableCollection extends Iterable<[variable: string, mutator: EnvironmentVariableMutator]> {
	/**
	* @param value The value to replace the variable with, undefined will unset the variable.
	*/
	replace(variable: string, value: string | undefined): void;
}

But this would be a breaking API change and so would a separate EnvironmentVariableCollection.delete API as it would have to change the Iterable part. So this ask is a bit trickier than it looks.

Here's something that would work but it's a little more clunky:

export interface EnvironmentVariableCollection extends Iterable<[variable: string, mutator: EnvironmentVariableMutator]> {
	/**
	 * Whether to unset instead of set when mutators replace a variable with the empty string.
	 */
	unsetEmpty: boolean;
}