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

Correctly show descriptions for each scope #182914

Merged
merged 1 commit into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import { deepStrictEqual, doesNotThrow, equal, strictEqual, throws } from 'assert';
import { ConfigurationTarget, Disposable, env, EnvironmentVariableMutator, EnvironmentVariableMutatorType, EventEmitter, ExtensionContext, extensions, ExtensionTerminalOptions, Pseudoterminal, Terminal, TerminalDimensions, TerminalExitReason, TerminalOptions, TerminalState, UIKind, window, workspace } from 'vscode';
import { ConfigurationTarget, Disposable, env, EnvironmentVariableCollection, EnvironmentVariableMutator, EnvironmentVariableMutatorType, EnvironmentVariableScope, EventEmitter, ExtensionContext, extensions, ExtensionTerminalOptions, Pseudoterminal, Terminal, TerminalDimensions, TerminalExitReason, TerminalOptions, TerminalState, UIKind, Uri, window, workspace } from 'vscode';
import { assertNoRpc, poll } from '../utils';

// Disable terminal tests:
Expand Down Expand Up @@ -848,19 +848,45 @@ import { assertNoRpc, poll } from '../utils';
collection.replace('A', '~a2~');
collection.append('B', '~b2~');
collection.prepend('C', '~c2~');

// Verify get
deepStrictEqual(collection.get('A'), { value: '~a2~', type: EnvironmentVariableMutatorType.Replace, scope: undefined, options: {} });
deepStrictEqual(collection.get('B'), { value: '~b2~', type: EnvironmentVariableMutatorType.Append, scope: undefined, options: {} });
deepStrictEqual(collection.get('C'), { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend, scope: undefined, options: {} });

deepStrictEqual(collection.get('A'), { value: '~a2~', type: EnvironmentVariableMutatorType.Replace, options: {} });
deepStrictEqual(collection.get('B'), { value: '~b2~', type: EnvironmentVariableMutatorType.Append, options: {} });
deepStrictEqual(collection.get('C'), { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend, options: {} });
// Verify forEach
const entries: [string, EnvironmentVariableMutator][] = [];
collection.forEach((v, m) => entries.push([v, m]));
deepStrictEqual(entries, [
['A', { value: '~a2~', type: EnvironmentVariableMutatorType.Replace, scope: undefined, options: {} }],
['B', { value: '~b2~', type: EnvironmentVariableMutatorType.Append, scope: undefined, options: {} }],
['C', { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend, scope: undefined, options: {} }]
['A', { value: '~a2~', type: EnvironmentVariableMutatorType.Replace, options: {} }],
['B', { value: '~b2~', type: EnvironmentVariableMutatorType.Append, options: {} }],
['C', { value: '~c2~', type: EnvironmentVariableMutatorType.Prepend, options: {} }]
]);
});

test('get and forEach should work (scope)', () => {
// TODO: Remove cast once `envCollectionWorkspace` API is finalized.
const collection = extensionContext.environmentVariableCollection as (EnvironmentVariableCollection & { getScopedEnvironmentVariableCollection(scope: EnvironmentVariableScope): EnvironmentVariableCollection });
disposables.push({ dispose: () => collection.clear() });
const scope = { workspaceFolder: { uri: Uri.file('workspace1'), name: 'workspace1', index: 0 } };
const scopedCollection = collection.getScopedEnvironmentVariableCollection(scope);
scopedCollection.replace('A', 'scoped~a2~');
scopedCollection.append('B', 'scoped~b2~');
scopedCollection.prepend('C', 'scoped~c2~');
karrtikr marked this conversation as resolved.
Show resolved Hide resolved
collection.replace('A', '~a2~');
collection.append('B', '~b2~');
collection.prepend('C', '~c2~');
// Verify get for scope
const expectedScopedCollection = collection.getScopedEnvironmentVariableCollection(scope);
deepStrictEqual(expectedScopedCollection.get('A'), { value: 'scoped~a2~', type: EnvironmentVariableMutatorType.Replace, options: {} });
deepStrictEqual(expectedScopedCollection.get('B'), { value: 'scoped~b2~', type: EnvironmentVariableMutatorType.Append, options: {} });
deepStrictEqual(expectedScopedCollection.get('C'), { value: 'scoped~c2~', type: EnvironmentVariableMutatorType.Prepend, options: {} });

// Verify forEach
const entries: [string, EnvironmentVariableMutator][] = [];
expectedScopedCollection.forEach((v, m) => entries.push([v, m]));
deepStrictEqual(entries.map(v => v[1]), [
{ value: 'scoped~a2~', type: EnvironmentVariableMutatorType.Replace, options: {} },
{ value: 'scoped~b2~', type: EnvironmentVariableMutatorType.Append, options: {} },
{ value: 'scoped~c2~', type: EnvironmentVariableMutatorType.Prepend, options: {} }
]);
});
});
Expand Down
3 changes: 2 additions & 1 deletion src/vs/platform/terminal/common/environmentVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ export interface IMergedEnvironmentVariableCollection {
getVariableMap(scope: EnvironmentVariableScope | undefined): Map<string, IExtensionOwnedEnvironmentVariableMutator[]>;
/**
* Gets the description map for a given scope.
* @param scope The scope to get the description map for. If undefined, the global scope is used.
* @param scope The scope to get the description map for. If undefined, description map for the
* global scope is returned.
*/
getDescriptionMap(scope: EnvironmentVariableScope | undefined): Map<string, string | undefined>;
/**
Expand Down
15 changes: 13 additions & 2 deletions src/vs/platform/terminal/common/environmentVariableCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVa
getDescriptionMap(scope: EnvironmentVariableScope | undefined): Map<string, string | undefined> {
const result = new Map<string, string | undefined>();
this.descriptionMap.forEach((mutators, _key) => {
const filteredMutators = mutators.filter(m => filterScope(m, scope));
const filteredMutators = mutators.filter(m => filterScope(m, scope, true));
if (filteredMutators.length > 0) {
// There should be exactly one description per extension per scope.
result.set(filteredMutators[0].extensionIdentifier, filteredMutators[0].description);
Expand Down Expand Up @@ -190,11 +190,22 @@ export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVa
}
}

/**
* Returns whether a mutator matches with the scope provided.
* @param mutator Mutator to filter
* @param scope Scope to be used for querying
* @param strictFilter If true, mutators with global scope is not returned when querying for workspace scope.
* i.e whether mutator scope should always exactly match with query scope.
*/
function filterScope(
mutator: IExtensionOwnedEnvironmentVariableMutator | IExtensionOwnedEnvironmentDescriptionMutator,
scope: EnvironmentVariableScope | undefined
scope: EnvironmentVariableScope | undefined,
strictFilter = false
): boolean {
if (!mutator.scope) {
if (strictFilter) {
return scope === mutator.scope;
}
return true;
}
// If a mutator is scoped to a workspace folder, only apply it if the workspace
Expand Down
26 changes: 13 additions & 13 deletions src/vs/workbench/api/common/extHostTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
protected _terminalProcessDisposables: { [id: number]: IDisposable } = {};
protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal | undefined> } = {};
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
protected _environmentVariableCollections: Map<string, UnifiedEnvironmentVariableCollection> = new Map();
private _defaultProfile: ITerminalProfile | undefined;
private _defaultAutomationProfile: ITerminalProfile | undefined;

Expand Down Expand Up @@ -827,13 +827,13 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
public getEnvironmentVariableCollection(extension: IExtensionDescription): IEnvironmentVariableCollection {
let collection = this._environmentVariableCollections.get(extension.identifier.value);
if (!collection) {
collection = new EnvironmentVariableCollection(extension);
collection = new UnifiedEnvironmentVariableCollection(extension);
this._setEnvironmentVariableCollection(extension.identifier.value, collection);
}
return collection.getScopedEnvironmentVariableCollection(undefined);
}

private _syncEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
private _syncEnvironmentVariableCollection(extensionIdentifier: string, collection: UnifiedEnvironmentVariableCollection): void {
const serialized = serializeEnvironmentVariableCollection(collection.map);
const serializedDescription = serializeEnvironmentDescriptionMap(collection.descriptionMap);
this._proxy.$setEnvironmentVariableCollection(extensionIdentifier, collection.persistent, serialized.length === 0 ? undefined : serialized, serializedDescription);
Expand All @@ -842,7 +842,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
collections.forEach(entry => {
const extensionIdentifier = entry[0];
const collection = new EnvironmentVariableCollection(undefined, entry[1]);
const collection = new UnifiedEnvironmentVariableCollection(undefined, entry[1]);
this._setEnvironmentVariableCollection(extensionIdentifier, collection);
});
}
Expand All @@ -856,7 +856,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
}
}

private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: UnifiedEnvironmentVariableCollection): void {
this._environmentVariableCollections.set(extensionIdentifier, collection);
collection.onDidChangeCollection(() => {
// When any collection value changes send this immediately, this is done to ensure
Expand All @@ -868,7 +868,10 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
}
}

class EnvironmentVariableCollection {
/**
* Unified environment variable collection carrying information for all scopes, for a specific extension.
*/
class UnifiedEnvironmentVariableCollection {
readonly map: Map<string, IEnvironmentVariableMutator> = new Map();
private readonly scopedCollections: Map<string, ScopedEnvironmentVariableCollection> = new Map();
readonly descriptionMap: Map<string, IEnvironmentDescriptionMutator> = new Map();
Expand Down Expand Up @@ -930,9 +933,6 @@ class EnvironmentVariableCollection {
if (mutator.options && mutator.options.applyAtProcessCreation === false && !mutator.options.applyAtShellIntegration) {
throw new Error('EnvironmentVariableMutatorOptions must apply at either process creation or shell integration');
}
if (!mutator.scope) {
delete (mutator as any).scope; // Convenient for tests
}
const key = this.getKey(variable, mutator.scope);
const current = this.map.get(key);
if (!current || current.value !== mutator.value || current.type !== mutator.type || current.scope?.workspaceFolder?.index !== mutator.scope?.workspaceFolder?.index) {
Expand Down Expand Up @@ -1032,13 +1032,13 @@ class ScopedEnvironmentVariableCollection implements vscode.EnvironmentVariableC
get onDidChangeCollection(): Event<void> { return this._onDidChangeCollection && this._onDidChangeCollection.event; }

constructor(
private readonly collection: EnvironmentVariableCollection,
private readonly collection: UnifiedEnvironmentVariableCollection,
private readonly scope: vscode.EnvironmentVariableScope | undefined
) {
}

getScopedEnvironmentVariableCollection() {
return this.collection.getScopedEnvironmentVariableCollection(this.scope);
getScopedEnvironmentVariableCollection(scope: vscode.EnvironmentVariableScope | undefined) {
return this.collection.getScopedEnvironmentVariableCollection(scope);
}

replace(variable: string, value: string, options?: vscode.EnvironmentVariableMutatorOptions | undefined): void {
Expand Down Expand Up @@ -1120,7 +1120,7 @@ function asTerminalColor(color?: vscode.ThemeColor): ThemeColor | undefined {

function convertMutator(mutator: IEnvironmentVariableMutator): vscode.EnvironmentVariableMutator {
const newMutator = { ...mutator };
newMutator.scope = newMutator.scope ?? undefined;
delete newMutator.scope;
newMutator.options = newMutator.options ?? undefined;
delete (newMutator as any).variable;
return newMutator as vscode.EnvironmentVariableMutator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,7 @@ export class EnvironmentVariableInfoStale implements IEnvironmentVariableInfo {
addExtensionIdentifiers(extSet, this._diff.changed.values());

let message = localize('extensionEnvironmentContributionInfoStale', "The following extensions want to relaunch the terminal to contribute to its environment:");
message += '\n';
const descriptionMap = this._collection.getDescriptionMap(scope);
for (const ext of extSet) {
message += `\n- \`${getExtensionName(ext, this._extensionService)}\``;
const description = descriptionMap.get(ext);
if (description) {
message += `: ${description}`;
}
}
message += getMergedDescription(this._collection, scope, this._extensionService, extSet);
return message;
}

Expand Down Expand Up @@ -79,15 +71,7 @@ export class EnvironmentVariableInfoChangesActive implements IEnvironmentVariabl
addExtensionIdentifiers(extSet, this._collection.getVariableMap(scope).values());

let message = localize('extensionEnvironmentContributionInfoActive', "The following extensions have contributed to this terminal's environment:");
message += '\n';
const descriptionMap = this._collection.getDescriptionMap(scope);
for (const ext of extSet) {
message += `\n- \`${getExtensionName(ext, this._extensionService)}\``;
const description = descriptionMap.get(ext);
if (description) {
message += `: ${description}`;
}
}
message += getMergedDescription(this._collection, scope, this._extensionService, extSet);
return message;
}

Expand All @@ -109,6 +93,28 @@ export class EnvironmentVariableInfoChangesActive implements IEnvironmentVariabl
}
}

function getMergedDescription(collection: IMergedEnvironmentVariableCollection, scope: EnvironmentVariableScope | undefined, extensionService: IExtensionService, extSet: Set<string>): string {
const message = ['\n'];
const globalDescriptions = collection.getDescriptionMap(undefined);
const workspaceDescriptions = collection.getDescriptionMap(scope);
for (const ext of extSet) {
const globalDescription = globalDescriptions.get(ext);
if (globalDescription) {
message.push(`\n- \`${getExtensionName(ext, extensionService)}\``);
message.push(`: ${globalDescription}`);
}
const workspaceDescription = workspaceDescriptions.get(ext);
if (workspaceDescription) {
message.push(`\n- \`${getExtensionName(ext, extensionService)} (${localize('ScopedEnvironmentContributionInfo', 'workspace')})\``);
message.push(`: ${workspaceDescription}`);
}
if (!globalDescription && !workspaceDescription) {
message.push(`\n- \`${getExtensionName(ext, extensionService)}\``);
}
}
return message.join('');
}

function addExtensionIdentifiers(extSet: Set<string>, diff: IterableIterator<IExtensionOwnedEnvironmentVariableMutator[]>): void {
for (const mutators of diff) {
for (const mutator of mutators) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ suite('EnvironmentVariable - MergedEnvironmentVariableCollection', () => {
]));
deepStrictEqual([...merged.getDescriptionMap(scope1).entries()], [
['ext1', 'ext1 scope1 description'],
]);
deepStrictEqual([...merged.getDescriptionMap(undefined).entries()], [
['ext2', 'ext2 global description'],
]);
});
Expand Down