mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-30 06:10:42 +01:00
Load in persisted collections from past sessions on ext host
This commit is contained in:
@@ -14,7 +14,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
||||
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
import { deserializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
||||
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
|
||||
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
|
||||
@@ -74,6 +74,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
if (activeInstance) {
|
||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||
}
|
||||
if (this._environmentVariableService.collections.size > 0) {
|
||||
const collectionAsArray = [...this._environmentVariableService.collections.entries()];
|
||||
const serializedCollections: [string, ISerializableEnvironmentVariableCollection][] = collectionAsArray.map(e => {
|
||||
return [e[0], serializeEnvironmentVariableCollection(e[1])];
|
||||
});
|
||||
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
|
||||
}
|
||||
|
||||
this._terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
}
|
||||
|
||||
@@ -1388,6 +1388,7 @@ export interface ExtHostTerminalServiceShape {
|
||||
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
$handleLink(id: number, link: string): Promise<boolean>;
|
||||
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
|
||||
}
|
||||
|
||||
export interface ExtHostSCMShape {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/termi
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
|
||||
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
|
||||
|
||||
@@ -336,6 +337,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
public abstract getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
|
||||
public abstract $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
|
||||
|
||||
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options, options.name);
|
||||
@@ -640,39 +642,36 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
}
|
||||
}
|
||||
|
||||
export class EnvironmentVariableMutator implements vscode.EnvironmentVariableMutator {
|
||||
constructor(
|
||||
public value: string,
|
||||
public type: vscode.EnvironmentVariableMutatorType
|
||||
) { }
|
||||
}
|
||||
|
||||
export class EnvironmentVariableCollection implements vscode.EnvironmentVariableCollection {
|
||||
public map: Map<string, EnvironmentVariableMutator> = new Map();
|
||||
public readonly map: Map<string, vscode.EnvironmentVariableMutator> = new Map();
|
||||
|
||||
protected readonly _onDidChangeCollection: Emitter<void> = new Emitter<void>();
|
||||
get onDidChangeCollection(): Event<void> { return this._onDidChangeCollection && this._onDidChangeCollection.event; }
|
||||
|
||||
constructor(serialized?: ISerializableEnvironmentVariableCollection) {
|
||||
this.map = new Map(serialized);
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.map.size;
|
||||
}
|
||||
|
||||
replace(variable: string, value: string): void {
|
||||
this.map.set(variable, new EnvironmentVariableMutator(value, EnvironmentVariableMutatorType.Replace));
|
||||
this.map.set(variable, { value, type: EnvironmentVariableMutatorType.Replace });
|
||||
this._onDidChangeCollection.fire();
|
||||
}
|
||||
|
||||
append(variable: string, value: string): void {
|
||||
this.map.set(variable, new EnvironmentVariableMutator(value, EnvironmentVariableMutatorType.Append));
|
||||
this.map.set(variable, { value, type: EnvironmentVariableMutatorType.Append });
|
||||
this._onDidChangeCollection.fire();
|
||||
}
|
||||
|
||||
prepend(variable: string, value: string): void {
|
||||
this.map.set(variable, new EnvironmentVariableMutator(value, EnvironmentVariableMutatorType.Prepend));
|
||||
this.map.set(variable, { value, type: EnvironmentVariableMutatorType.Prepend });
|
||||
this._onDidChangeCollection.fire();
|
||||
}
|
||||
|
||||
get(variable: string): EnvironmentVariableMutator | undefined {
|
||||
get(variable: string): vscode.EnvironmentVariableMutator | undefined {
|
||||
return this.map.get(variable);
|
||||
}
|
||||
|
||||
@@ -733,4 +732,8 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
// This is not implemented so worker ext host extensions cannot influence terminal envs
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
|
||||
// No-op for web worker ext host as collections aren't used
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,14 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
|
||||
export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
|
||||
private _variableResolver: ExtHostVariableResolverService | undefined;
|
||||
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
|
||||
|
||||
private _environmentVariableCollection: Map<string, vscode.EnvironmentVariableCollection> = new Map();
|
||||
private _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
|
||||
|
||||
// TODO: Pull this from main side
|
||||
private _isWorkspaceShellAllowed: boolean = false;
|
||||
@@ -48,13 +49,14 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
this._updateVariableResolver();
|
||||
this._registerListeners();
|
||||
|
||||
const c = this.getEnvironmentVariableCollection({ identifier: { value: 'test' } } as any, true);
|
||||
setTimeout(() => {
|
||||
const c = this.getEnvironmentVariableCollection({ identifier: { value: 'test' } } as any, true);
|
||||
c.prepend('a', 'b');
|
||||
c.replace('c', 'd');
|
||||
c.append('e', 'f');
|
||||
}, 2000);
|
||||
setTimeout(() => {
|
||||
const c = this.getEnvironmentVariableCollection({ identifier: { value: 'test' } } as any, true);
|
||||
c.prepend('a', 'late addition');
|
||||
}, 4000);
|
||||
}
|
||||
@@ -232,24 +234,19 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
}
|
||||
|
||||
public getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection {
|
||||
dispose(this._environmentVariableCollection.get(extension.identifier.value));
|
||||
|
||||
let collection: EnvironmentVariableCollection;
|
||||
let collection: EnvironmentVariableCollection | undefined;
|
||||
if (persistent) {
|
||||
// TODO: Persist when persistent is set
|
||||
// TODO: Load collection for this extension when persistent is set
|
||||
collection = new EnvironmentVariableCollection();
|
||||
} else {
|
||||
collection = new EnvironmentVariableCollection();
|
||||
// If persistent is specified, return the current collection if it exists
|
||||
collection = this._environmentVariableCollections.get(extension.identifier.value);
|
||||
}
|
||||
collection.onDidChangeCollection(() => {
|
||||
// When any collection value changes send this immediately, this is done to ensure
|
||||
// following calls to createTerminal will be created with the new environment. It will
|
||||
// result in more noise by sending multiple updates when called but collections are
|
||||
// expected to be small.
|
||||
this._syncEnvironmentVariableCollection(extension.identifier.value, collection);
|
||||
});
|
||||
this._environmentVariableCollection.set(extension.identifier.value, collection);
|
||||
|
||||
if (!collection) {
|
||||
// If not persistent, clear out the current collection and create a new one
|
||||
dispose(this._environmentVariableCollections.get(extension.identifier.value));
|
||||
collection = new EnvironmentVariableCollection();
|
||||
this._setEnvironmentVariableCollection(extension.identifier.value, collection);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
@@ -257,4 +254,23 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
const serialized = serializeEnvironmentVariableCollection(collection.map);
|
||||
this._proxy.$setEnvironmentVariableCollection(extensionIdentifier, serialized.length === 0 ? undefined : serialized);
|
||||
}
|
||||
|
||||
public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
|
||||
collections.forEach(entry => {
|
||||
const extensionIdentifier = entry[0];
|
||||
const collection = new EnvironmentVariableCollection(entry[1]);
|
||||
this._setEnvironmentVariableCollection(extensionIdentifier, collection);
|
||||
});
|
||||
}
|
||||
|
||||
private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
|
||||
this._environmentVariableCollections.set(extensionIdentifier, collection);
|
||||
collection.onDidChangeCollection(() => {
|
||||
// When any collection value changes send this immediately, this is done to ensure
|
||||
// following calls to createTerminal will be created with the new environment. It will
|
||||
// result in more noise by sending multiple updates when called but collections are
|
||||
// expected to be small.
|
||||
this._syncEnvironmentVariableCollection(extensionIdentifier, collection!);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,12 @@ export interface IMergedEnvironmentVariableCollection {
|
||||
export interface IEnvironmentVariableService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Gets a single collection constructed by merging all environment variable collections into
|
||||
* one.
|
||||
*/
|
||||
readonly collections: ReadonlyMap<string, IEnvironmentVariableCollection>;
|
||||
|
||||
/**
|
||||
* Gets a single collection constructed by merging all environment variable collections into
|
||||
* one.
|
||||
|
||||
@@ -24,8 +24,8 @@ interface ISerializableExtensionEnvironmentVariableCollection {
|
||||
export class EnvironmentVariableService implements IEnvironmentVariableService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private _collections: Map<string, IEnvironmentVariableCollection> = new Map();
|
||||
private _mergedCollection: IMergedEnvironmentVariableCollection;
|
||||
collections: Map<string, IEnvironmentVariableCollection> = new Map();
|
||||
mergedCollection: IMergedEnvironmentVariableCollection;
|
||||
|
||||
private readonly _onDidChangeCollections = new Emitter<IMergedEnvironmentVariableCollection>();
|
||||
get onDidChangeCollections(): Event<IMergedEnvironmentVariableCollection> { return this._onDidChangeCollections.event; }
|
||||
@@ -37,36 +37,32 @@ export class EnvironmentVariableService implements IEnvironmentVariableService {
|
||||
const serializedPersistedCollections = this._storageService.get(ENVIRONMENT_VARIABLE_COLLECTIONS_KEY, StorageScope.WORKSPACE);
|
||||
if (serializedPersistedCollections) {
|
||||
const collectionsJson: ISerializableExtensionEnvironmentVariableCollection[] = JSON.parse(serializedPersistedCollections);
|
||||
collectionsJson.forEach(c => this._collections.set(c.extensionIdentifier, deserializeEnvironmentVariableCollection(c.collection)));
|
||||
collectionsJson.forEach(c => this.collections.set(c.extensionIdentifier, deserializeEnvironmentVariableCollection(c.collection)));
|
||||
|
||||
// Asynchronously invalidate collections where extensions have been uninstalled, this is
|
||||
// async to avoid making all functions on the service synchronous and because extensions
|
||||
// being uninstalled is rare.
|
||||
this._invalidateExtensionCollections();
|
||||
}
|
||||
this._mergedCollection = this._resolveMergedCollection();
|
||||
this.mergedCollection = this._resolveMergedCollection();
|
||||
|
||||
// Listen for uninstalled/disabled extensions
|
||||
this._extensionService.onDidChangeExtensions(() => this._invalidateExtensionCollections());
|
||||
}
|
||||
|
||||
get mergedCollection(): IMergedEnvironmentVariableCollection {
|
||||
return this._mergedCollection;
|
||||
}
|
||||
|
||||
set(extensionIdentifier: string, collection: IEnvironmentVariableCollection): void {
|
||||
this._collections.set(extensionIdentifier, collection);
|
||||
this.collections.set(extensionIdentifier, collection);
|
||||
this._updateCollections();
|
||||
}
|
||||
|
||||
delete(extensionIdentifier: string): void {
|
||||
this._collections.delete(extensionIdentifier);
|
||||
this.collections.delete(extensionIdentifier);
|
||||
this._updateCollections();
|
||||
}
|
||||
|
||||
private _updateCollections(): void {
|
||||
this._persistCollectionsEventually();
|
||||
this._mergedCollection = this._resolveMergedCollection();
|
||||
this.mergedCollection = this._resolveMergedCollection();
|
||||
this._notifyCollectionUpdatesEventually();
|
||||
}
|
||||
|
||||
@@ -76,11 +72,11 @@ export class EnvironmentVariableService implements IEnvironmentVariableService {
|
||||
}
|
||||
|
||||
protected _persistCollections(): void {
|
||||
const keys = [...this._collections.keys()];
|
||||
const keys = [...this.collections.keys()];
|
||||
const collectionsJson: ISerializableExtensionEnvironmentVariableCollection[] = keys.map(extensionIdentifier => {
|
||||
return {
|
||||
extensionIdentifier,
|
||||
collection: serializeEnvironmentVariableCollection(this._collections.get(extensionIdentifier)!)
|
||||
collection: serializeEnvironmentVariableCollection(this.collections.get(extensionIdentifier)!)
|
||||
};
|
||||
});
|
||||
const stringifiedJson = JSON.stringify(collectionsJson);
|
||||
@@ -93,24 +89,11 @@ export class EnvironmentVariableService implements IEnvironmentVariableService {
|
||||
}
|
||||
|
||||
protected _notifyCollectionUpdates(): void {
|
||||
this._onDidChangeCollections.fire(this._mergedCollection);
|
||||
this._onDidChangeCollections.fire(this.mergedCollection);
|
||||
}
|
||||
|
||||
private _resolveMergedCollection(): IMergedEnvironmentVariableCollection {
|
||||
return new MergedEnvironmentVariableCollection(this._collections);
|
||||
// const result = new EnvironmentVariableCollection();
|
||||
// this._collections.forEach(collection => {
|
||||
// const it = collection.entries();
|
||||
// let next = it.next();
|
||||
// while (!next.done) {
|
||||
// const variable = next.value[0];
|
||||
// if (!result.entries.has(variable)) {
|
||||
// result.entries.set(variable, next.value[1]);
|
||||
// }
|
||||
// next = it.next();
|
||||
// }
|
||||
// });
|
||||
// return result;
|
||||
return new MergedEnvironmentVariableCollection(this.collections);
|
||||
}
|
||||
|
||||
private async _invalidateExtensionCollections(): Promise<void> {
|
||||
@@ -118,10 +101,10 @@ export class EnvironmentVariableService implements IEnvironmentVariableService {
|
||||
|
||||
const registeredExtensions = await this._extensionService.getExtensions();
|
||||
let changes = false;
|
||||
this._collections.forEach((_, extensionIdentifier) => {
|
||||
this.collections.forEach((_, extensionIdentifier) => {
|
||||
const isExtensionRegistered = registeredExtensions.some(r => r.identifier.value === extensionIdentifier);
|
||||
if (!isExtensionRegistered) {
|
||||
this._collections.delete(extensionIdentifier);
|
||||
this.collections.delete(extensionIdentifier);
|
||||
changes = true;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user