mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from vscode e74405d11443c5361c31e2bc341866d146eee206 (#8740)
This commit is contained in:
@@ -44,16 +44,16 @@ suite('BackupMainService', () => {
|
||||
this.workspacesJsonPath = backupWorkspacesPath;
|
||||
}
|
||||
|
||||
public toBackupPath(arg: URI | string): string {
|
||||
toBackupPath(arg: URI | string): string {
|
||||
const id = arg instanceof URI ? super.getFolderHash(arg) : arg;
|
||||
return path.join(this.backupHome, id);
|
||||
}
|
||||
|
||||
public getFolderHash(folderUri: URI): string {
|
||||
getFolderHash(folderUri: URI): string {
|
||||
return super.getFolderHash(folderUri);
|
||||
}
|
||||
|
||||
public toLegacyBackupPath(folderPath: string): string {
|
||||
toLegacyBackupPath(folderPath: string): string {
|
||||
return path.join(this.backupHome, super.getLegacyFolderHash(folderPath));
|
||||
}
|
||||
}
|
||||
@@ -119,17 +119,16 @@ suite('BackupMainService', () => {
|
||||
let service: TestBackupMainService;
|
||||
let configService: TestConfigurationService;
|
||||
|
||||
setup(() => {
|
||||
setup(async () => {
|
||||
|
||||
// Delete any existing backups completely and then re-create it.
|
||||
return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE).then(() => {
|
||||
return pfs.mkdirp(backupHome);
|
||||
}).then(() => {
|
||||
configService = new TestConfigurationService();
|
||||
service = new TestBackupMainService(backupHome, backupWorkspacesPath, configService);
|
||||
await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
|
||||
await pfs.mkdirp(backupHome);
|
||||
|
||||
return service.initialize();
|
||||
});
|
||||
configService = new TestConfigurationService();
|
||||
service = new TestBackupMainService(backupHome, backupWorkspacesPath, configService);
|
||||
|
||||
return service.initialize();
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
@@ -591,71 +590,71 @@ suite('BackupMainService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (folder workspace)', () => {
|
||||
test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (folder workspace)', async () => {
|
||||
service.registerFolderBackupSync(URI.file(fooFile.fsPath.toUpperCase()));
|
||||
assertEqualUris(service.getFolderBackupPaths(), [URI.file(fooFile.fsPath.toUpperCase())]);
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
|
||||
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
|
||||
assert.deepEqual(json.folderURIWorkspaces, [URI.file(fooFile.fsPath.toUpperCase()).toString()]);
|
||||
});
|
||||
|
||||
const buffer = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
|
||||
assert.deepEqual(json.folderURIWorkspaces, [URI.file(fooFile.fsPath.toUpperCase()).toString()]);
|
||||
});
|
||||
|
||||
test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (root workspace)', () => {
|
||||
test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (root workspace)', async () => {
|
||||
const upperFooPath = fooFile.fsPath.toUpperCase();
|
||||
service.registerWorkspaceBackupSync(toWorkspaceBackupInfo(upperFooPath));
|
||||
assertEqualUris(service.getWorkspaceBackups().map(b => b.workspace.configPath), [URI.file(upperFooPath)]);
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
|
||||
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
|
||||
assert.deepEqual(json.rootURIWorkspaces.map(b => b.configURIPath), [URI.file(upperFooPath).toString()]);
|
||||
});
|
||||
|
||||
const buffer = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json = (<IBackupWorkspacesFormat>JSON.parse(buffer));
|
||||
assert.deepEqual(json.rootURIWorkspaces.map(b => b.configURIPath), [URI.file(upperFooPath).toString()]);
|
||||
});
|
||||
|
||||
suite('removeBackupPathSync', () => {
|
||||
test('should remove folder workspaces from workspaces.json (folder workspace)', () => {
|
||||
test('should remove folder workspaces from workspaces.json (folder workspace)', async () => {
|
||||
service.registerFolderBackupSync(fooFile);
|
||||
service.registerFolderBackupSync(barFile);
|
||||
service.unregisterFolderBackupSync(fooFile);
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
|
||||
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
|
||||
assert.deepEqual(json.folderURIWorkspaces, [barFile.toString()]);
|
||||
service.unregisterFolderBackupSync(barFile);
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
|
||||
const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
|
||||
assert.deepEqual(json2.folderURIWorkspaces, []);
|
||||
});
|
||||
});
|
||||
|
||||
const buffer = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json = (<IBackupWorkspacesFormat>JSON.parse(buffer));
|
||||
assert.deepEqual(json.folderURIWorkspaces, [barFile.toString()]);
|
||||
service.unregisterFolderBackupSync(barFile);
|
||||
|
||||
const content = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json2 = (<IBackupWorkspacesFormat>JSON.parse(content));
|
||||
assert.deepEqual(json2.folderURIWorkspaces, []);
|
||||
});
|
||||
|
||||
test('should remove folder workspaces from workspaces.json (root workspace)', () => {
|
||||
test('should remove folder workspaces from workspaces.json (root workspace)', async () => {
|
||||
const ws1 = toWorkspaceBackupInfo(fooFile.fsPath);
|
||||
service.registerWorkspaceBackupSync(ws1);
|
||||
const ws2 = toWorkspaceBackupInfo(barFile.fsPath);
|
||||
service.registerWorkspaceBackupSync(ws2);
|
||||
service.unregisterWorkspaceBackupSync(ws1.workspace);
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
|
||||
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
|
||||
assert.deepEqual(json.rootURIWorkspaces.map(r => r.configURIPath), [barFile.toString()]);
|
||||
service.unregisterWorkspaceBackupSync(ws2.workspace);
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
|
||||
const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
|
||||
assert.deepEqual(json2.rootURIWorkspaces, []);
|
||||
});
|
||||
});
|
||||
|
||||
const buffer = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json = (<IBackupWorkspacesFormat>JSON.parse(buffer));
|
||||
assert.deepEqual(json.rootURIWorkspaces.map(r => r.configURIPath), [barFile.toString()]);
|
||||
service.unregisterWorkspaceBackupSync(ws2.workspace);
|
||||
|
||||
const content = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json2 = (<IBackupWorkspacesFormat>JSON.parse(content));
|
||||
assert.deepEqual(json2.rootURIWorkspaces, []);
|
||||
});
|
||||
|
||||
test('should remove empty workspaces from workspaces.json', () => {
|
||||
test('should remove empty workspaces from workspaces.json', async () => {
|
||||
service.registerEmptyWindowBackupSync('foo');
|
||||
service.registerEmptyWindowBackupSync('bar');
|
||||
service.unregisterEmptyWindowBackupSync('foo');
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
|
||||
const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
|
||||
assert.deepEqual(json.emptyWorkspaces, ['bar']);
|
||||
service.unregisterEmptyWindowBackupSync('bar');
|
||||
return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
|
||||
const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
|
||||
assert.deepEqual(json2.emptyWorkspaces, []);
|
||||
});
|
||||
});
|
||||
|
||||
const buffer = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json = (<IBackupWorkspacesFormat>JSON.parse(buffer));
|
||||
assert.deepEqual(json.emptyWorkspaces, ['bar']);
|
||||
service.unregisterEmptyWindowBackupSync('bar');
|
||||
|
||||
const content = await pfs.readFile(backupWorkspacesPath, 'utf-8');
|
||||
const json2 = (<IBackupWorkspacesFormat>JSON.parse(content));
|
||||
assert.deepEqual(json2.emptyWorkspaces, []);
|
||||
});
|
||||
|
||||
test('should fail gracefully when removing a path that doesn\'t exist', async () => {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, IDisposable, toDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError } from 'vs/platform/files/common/files';
|
||||
import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED, hasFileReadStreamCapability, IFileSystemProviderWithFileReadStreamCapability, ensureFileSystemProviderError, IFileSystemProviderCapabilitiesChangeEvent } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isAbsolutePath, dirname, basename, joinPath, isEqual, isEqualOrParent } from 'vs/base/common/resources';
|
||||
@@ -33,11 +33,14 @@ export class FileService extends Disposable implements IFileService {
|
||||
|
||||
//#region File System Provider
|
||||
|
||||
private _onDidChangeFileSystemProviderRegistrations: Emitter<IFileSystemProviderRegistrationEvent> = this._register(new Emitter<IFileSystemProviderRegistrationEvent>());
|
||||
readonly onDidChangeFileSystemProviderRegistrations: Event<IFileSystemProviderRegistrationEvent> = this._onDidChangeFileSystemProviderRegistrations.event;
|
||||
private _onDidChangeFileSystemProviderRegistrations = this._register(new Emitter<IFileSystemProviderRegistrationEvent>());
|
||||
readonly onDidChangeFileSystemProviderRegistrations = this._onDidChangeFileSystemProviderRegistrations.event;
|
||||
|
||||
private _onWillActivateFileSystemProvider: Emitter<IFileSystemProviderActivationEvent> = this._register(new Emitter<IFileSystemProviderActivationEvent>());
|
||||
readonly onWillActivateFileSystemProvider: Event<IFileSystemProviderActivationEvent> = this._onWillActivateFileSystemProvider.event;
|
||||
private _onWillActivateFileSystemProvider = this._register(new Emitter<IFileSystemProviderActivationEvent>());
|
||||
readonly onWillActivateFileSystemProvider = this._onWillActivateFileSystemProvider.event;
|
||||
|
||||
private _onDidChangeFileSystemProviderCapabilities = this._register(new Emitter<IFileSystemProviderCapabilitiesChangeEvent>());
|
||||
readonly onDidChangeFileSystemProviderCapabilities = this._onDidChangeFileSystemProviderCapabilities.event;
|
||||
|
||||
private readonly provider = new Map<string, IFileSystemProvider>();
|
||||
|
||||
@@ -53,6 +56,7 @@ export class FileService extends Disposable implements IFileService {
|
||||
// Forward events from provider
|
||||
const providerDisposables = new DisposableStore();
|
||||
providerDisposables.add(provider.onDidChangeFile(changes => this._onFileChanges.fire(new FileChangesEvent(changes))));
|
||||
providerDisposables.add(provider.onDidChangeCapabilities(() => this._onDidChangeFileSystemProviderCapabilities.fire({ provider, scheme })));
|
||||
if (typeof provider.onDidErrorOccur === 'function') {
|
||||
providerDisposables.add(provider.onDidErrorOccur(error => this._onError.fire(new Error(error))));
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ export interface IFileService {
|
||||
*/
|
||||
readonly onDidChangeFileSystemProviderRegistrations: Event<IFileSystemProviderRegistrationEvent>;
|
||||
|
||||
/**
|
||||
* An even that is fired when a registered file system provider changes it's capabilities.
|
||||
*/
|
||||
readonly onDidChangeFileSystemProviderCapabilities: Event<IFileSystemProviderCapabilitiesChangeEvent>;
|
||||
|
||||
/**
|
||||
* An event that is fired when a file system provider is about to be activated. Listeners
|
||||
* can join this event with a long running promise to help in the activation process.
|
||||
@@ -409,6 +414,11 @@ export interface IFileSystemProviderRegistrationEvent {
|
||||
provider?: IFileSystemProvider;
|
||||
}
|
||||
|
||||
export interface IFileSystemProviderCapabilitiesChangeEvent {
|
||||
provider: IFileSystemProvider;
|
||||
scheme: string;
|
||||
}
|
||||
|
||||
export interface IFileSystemProviderActivationEvent {
|
||||
scheme: string;
|
||||
join(promise: Promise<void>): void;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import * as assert from 'assert';
|
||||
import { FileService } from 'vs/platform/files/common/fileService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileSystemProviderRegistrationEvent, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
import { IFileSystemProviderRegistrationEvent, FileSystemProviderCapabilities, IFileSystemProviderCapabilitiesChangeEvent } from 'vs/platform/files/common/files';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
@@ -17,6 +17,7 @@ suite('File Service', () => {
|
||||
test('provider registration', async () => {
|
||||
const service = new FileService(new NullLogService());
|
||||
const resource = URI.parse('test://foo/bar');
|
||||
const provider = new NullFileSystemProvider();
|
||||
|
||||
assert.equal(service.canHandleResource(resource), false);
|
||||
|
||||
@@ -25,6 +26,11 @@ suite('File Service', () => {
|
||||
registrations.push(e);
|
||||
});
|
||||
|
||||
const capabilityChanges: IFileSystemProviderCapabilitiesChangeEvent[] = [];
|
||||
service.onDidChangeFileSystemProviderCapabilities(e => {
|
||||
capabilityChanges.push(e);
|
||||
});
|
||||
|
||||
let registrationDisposable: IDisposable | undefined = undefined;
|
||||
let callCount = 0;
|
||||
service.onWillActivateFileSystemProvider(e => {
|
||||
@@ -32,7 +38,7 @@ suite('File Service', () => {
|
||||
|
||||
if (e.scheme === 'test' && callCount === 1) {
|
||||
e.join(new Promise(resolve => {
|
||||
registrationDisposable = service.registerProvider('test', new NullFileSystemProvider());
|
||||
registrationDisposable = service.registerProvider('test', provider);
|
||||
|
||||
resolve();
|
||||
}));
|
||||
@@ -48,6 +54,13 @@ suite('File Service', () => {
|
||||
assert.equal(registrations[0].added, true);
|
||||
assert.ok(registrationDisposable);
|
||||
|
||||
assert.equal(capabilityChanges.length, 0);
|
||||
|
||||
provider.setCapabilities(FileSystemProviderCapabilities.FileFolderCopy);
|
||||
assert.equal(capabilityChanges.length, 1);
|
||||
provider.setCapabilities(FileSystemProviderCapabilities.Readonly);
|
||||
assert.equal(capabilityChanges.length, 2);
|
||||
|
||||
await service.activateProvider('test');
|
||||
assert.equal(callCount, 2); // activation is called again
|
||||
|
||||
|
||||
@@ -6,14 +6,22 @@
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FileSystemProviderCapabilities, IFileSystemProvider, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, IFileChange } from 'vs/platform/files/common/files';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
export class NullFileSystemProvider implements IFileSystemProvider {
|
||||
|
||||
capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly;
|
||||
|
||||
onDidChangeCapabilities: Event<void> = Event.None;
|
||||
onDidChangeFile: Event<readonly IFileChange[]> = Event.None;
|
||||
private readonly _onDidChangeCapabilities = new Emitter<void>();
|
||||
readonly onDidChangeCapabilities: Event<void> = this._onDidChangeCapabilities.event;
|
||||
|
||||
setCapabilities(capabilities: FileSystemProviderCapabilities): void {
|
||||
this.capabilities = capabilities;
|
||||
|
||||
this._onDidChangeCapabilities.fire();
|
||||
}
|
||||
|
||||
readonly onDidChangeFile: Event<readonly IFileChange[]> = Event.None;
|
||||
|
||||
constructor(private disposableFactory: () => IDisposable = () => Disposable.None) { }
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export interface ResolvedOptions {
|
||||
}
|
||||
|
||||
export interface TunnelInformation {
|
||||
detectedTunnels?: { remote: { port: number, host: string }, localAddress: string }[];
|
||||
environmentTunnels?: { remoteAddress: { port: number, host: string }, localAddress: string }[];
|
||||
}
|
||||
|
||||
export interface ResolverResult {
|
||||
|
||||
@@ -19,9 +19,9 @@ export interface RemoteTunnel {
|
||||
}
|
||||
|
||||
export interface TunnelOptions {
|
||||
remote: { port: number, host: string };
|
||||
remoteAddress: { port: number, host: string };
|
||||
localPort?: number;
|
||||
name?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export interface ITunnelProvider {
|
||||
@@ -33,10 +33,10 @@ export interface ITunnelService {
|
||||
|
||||
readonly tunnels: Promise<readonly RemoteTunnel[]>;
|
||||
readonly onTunnelOpened: Event<RemoteTunnel>;
|
||||
readonly onTunnelClosed: Event<number>;
|
||||
readonly onTunnelClosed: Event<{ host: string, port: number }>;
|
||||
|
||||
openTunnel(remotePort: number, localPort?: number): Promise<RemoteTunnel> | undefined;
|
||||
closeTunnel(remotePort: number): Promise<void>;
|
||||
openTunnel(remoteHost: string | undefined, remotePort: number, localPort?: number): Promise<RemoteTunnel> | undefined;
|
||||
closeTunnel(remoteHost: string, remotePort: number): Promise<void>;
|
||||
setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ export class NoOpTunnelService implements ITunnelService {
|
||||
public readonly tunnels: Promise<readonly RemoteTunnel[]> = Promise.resolve([]);
|
||||
private _onTunnelOpened: Emitter<RemoteTunnel> = new Emitter();
|
||||
public onTunnelOpened: Event<RemoteTunnel> = this._onTunnelOpened.event;
|
||||
private _onTunnelClosed: Emitter<number> = new Emitter();
|
||||
public onTunnelClosed: Event<number> = this._onTunnelClosed.event;
|
||||
openTunnel(_remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
private _onTunnelClosed: Emitter<{ host: string, port: number }> = new Emitter();
|
||||
public onTunnelClosed: Event<{ host: string, port: number }> = this._onTunnelClosed.event;
|
||||
openTunnel(_remoteHost: string, _remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||
return undefined;
|
||||
}
|
||||
async closeTunnel(_remotePort: number): Promise<void> {
|
||||
async closeTunnel(_remoteHost: string, _remotePort: number): Promise<void> {
|
||||
}
|
||||
setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable {
|
||||
throw new Error('Method not implemented.');
|
||||
|
||||
@@ -89,11 +89,11 @@ export class StorageMainService extends Disposable implements IStorageMainServic
|
||||
|
||||
private static readonly STORAGE_NAME = 'state.vscdb';
|
||||
|
||||
private readonly _onDidChangeStorage: Emitter<IStorageChangeEvent> = this._register(new Emitter<IStorageChangeEvent>());
|
||||
readonly onDidChangeStorage: Event<IStorageChangeEvent> = this._onDidChangeStorage.event;
|
||||
private readonly _onDidChangeStorage = this._register(new Emitter<IStorageChangeEvent>());
|
||||
readonly onDidChangeStorage = this._onDidChangeStorage.event;
|
||||
|
||||
private readonly _onWillSaveState: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onWillSaveState: Event<void> = this._onWillSaveState.event;
|
||||
private readonly _onWillSaveState = this._register(new Emitter<void>());
|
||||
readonly onWillSaveState = this._onWillSaveState.event;
|
||||
|
||||
get items(): Map<string, string> { return this.storage.items; }
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@ suite('StorageService', () => {
|
||||
function removeData(scope: StorageScope): void {
|
||||
const storage = new InMemoryStorageService();
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.remove', 'foobar', scope);
|
||||
strictEqual('foobar', storage.get('Monaco.IDE.Core.Storage.Test.remove', scope, (undefined)!));
|
||||
storage.store('test.remove', 'foobar', scope);
|
||||
strictEqual('foobar', storage.get('test.remove', scope, (undefined)!));
|
||||
|
||||
storage.remove('Monaco.IDE.Core.Storage.Test.remove', scope);
|
||||
ok(!storage.get('Monaco.IDE.Core.Storage.Test.remove', scope, (undefined)!));
|
||||
storage.remove('test.remove', scope);
|
||||
ok(!storage.get('test.remove', scope, (undefined)!));
|
||||
}
|
||||
|
||||
test('Get Data, Integer, Boolean (global, in-memory)', () => {
|
||||
@@ -46,34 +46,34 @@ suite('StorageService', () => {
|
||||
function storeData(scope: StorageScope): void {
|
||||
const storage = new InMemoryStorageService();
|
||||
|
||||
strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.get', scope, 'foobar'), 'foobar');
|
||||
strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.get', scope, ''), '');
|
||||
strictEqual(storage.getNumber('Monaco.IDE.Core.Storage.Test.getNumber', scope, 5), 5);
|
||||
strictEqual(storage.getNumber('Monaco.IDE.Core.Storage.Test.getNumber', scope, 0), 0);
|
||||
strictEqual(storage.getBoolean('Monaco.IDE.Core.Storage.Test.getBoolean', scope, true), true);
|
||||
strictEqual(storage.getBoolean('Monaco.IDE.Core.Storage.Test.getBoolean', scope, false), false);
|
||||
strictEqual(storage.get('test.get', scope, 'foobar'), 'foobar');
|
||||
strictEqual(storage.get('test.get', scope, ''), '');
|
||||
strictEqual(storage.getNumber('test.getNumber', scope, 5), 5);
|
||||
strictEqual(storage.getNumber('test.getNumber', scope, 0), 0);
|
||||
strictEqual(storage.getBoolean('test.getBoolean', scope, true), true);
|
||||
strictEqual(storage.getBoolean('test.getBoolean', scope, false), false);
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.get', 'foobar', scope);
|
||||
strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.get', scope, (undefined)!), 'foobar');
|
||||
storage.store('test.get', 'foobar', scope);
|
||||
strictEqual(storage.get('test.get', scope, (undefined)!), 'foobar');
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.get', '', scope);
|
||||
strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.get', scope, (undefined)!), '');
|
||||
storage.store('test.get', '', scope);
|
||||
strictEqual(storage.get('test.get', scope, (undefined)!), '');
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.getNumber', 5, scope);
|
||||
strictEqual(storage.getNumber('Monaco.IDE.Core.Storage.Test.getNumber', scope, (undefined)!), 5);
|
||||
storage.store('test.getNumber', 5, scope);
|
||||
strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 5);
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.getNumber', 0, scope);
|
||||
strictEqual(storage.getNumber('Monaco.IDE.Core.Storage.Test.getNumber', scope, (undefined)!), 0);
|
||||
storage.store('test.getNumber', 0, scope);
|
||||
strictEqual(storage.getNumber('test.getNumber', scope, (undefined)!), 0);
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.getBoolean', true, scope);
|
||||
strictEqual(storage.getBoolean('Monaco.IDE.Core.Storage.Test.getBoolean', scope, (undefined)!), true);
|
||||
storage.store('test.getBoolean', true, scope);
|
||||
strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), true);
|
||||
|
||||
storage.store('Monaco.IDE.Core.Storage.Test.getBoolean', false, scope);
|
||||
strictEqual(storage.getBoolean('Monaco.IDE.Core.Storage.Test.getBoolean', scope, (undefined)!), false);
|
||||
storage.store('test.getBoolean', false, scope);
|
||||
strictEqual(storage.getBoolean('test.getBoolean', scope, (undefined)!), false);
|
||||
|
||||
strictEqual(storage.get('Monaco.IDE.Core.Storage.Test.getDefault', scope, 'getDefault'), 'getDefault');
|
||||
strictEqual(storage.getNumber('Monaco.IDE.Core.Storage.Test.getNumberDefault', scope, 5), 5);
|
||||
strictEqual(storage.getBoolean('Monaco.IDE.Core.Storage.Test.getBooleanDefault', scope, true), true);
|
||||
strictEqual(storage.get('test.getDefault', scope, 'getDefault'), 'getDefault');
|
||||
strictEqual(storage.getNumber('test.getNumberDefault', scope, 5), 5);
|
||||
strictEqual(storage.getBoolean('test.getBooleanDefault', scope, true), true);
|
||||
}
|
||||
|
||||
function uniqueStorageDir(): string {
|
||||
|
||||
@@ -381,12 +381,13 @@ function registerDefaultClassifications(): void {
|
||||
registerTokenType('parameterType', nls.localize('parameterType', "Style for parameter types."), undefined, 'type');
|
||||
|
||||
registerTokenType('function', nls.localize('function', "Style for functions"), [['entity.name.function'], ['support.function']]);
|
||||
registerTokenType('member', nls.localize('member', "Style for member"), [['entity.name.function'], ['support.function']]);
|
||||
registerTokenType('macro', nls.localize('macro', "Style for macros."), undefined, 'function');
|
||||
|
||||
registerTokenType('variable', nls.localize('variable', "Style for variables."), [['variable'], ['entity.name.variable']]);
|
||||
registerTokenType('constant', nls.localize('constant', "Style for constants."), undefined, 'variable');
|
||||
registerTokenType('parameter', nls.localize('parameter', "Style for parameters."), undefined, 'variable');
|
||||
registerTokenType('property', nls.localize('propertie', "Style for properties."), undefined, 'variable');
|
||||
registerTokenType('property', nls.localize('property', "Style for properties."), undefined, 'variable');
|
||||
|
||||
registerTokenType('label', nls.localize('labels', "Style for labels. "), undefined);
|
||||
|
||||
@@ -394,7 +395,7 @@ function registerDefaultClassifications(): void {
|
||||
|
||||
tokenClassificationRegistry.registerTokenModifier('declaration', nls.localize('declaration', "Style for all symbol declarations."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('documentation', nls.localize('documentation', "Style to use for references in documentation."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('member', nls.localize('member', "Style to use for member functions, variables (fields) and types."), undefined);
|
||||
//tokenClassificationRegistry.registerTokenModifier('member', nls.localize('member', "Style to use for member functions, variables (fields) and types."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('static', nls.localize('static', "Style to use for symbols that are static."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('abstract', nls.localize('abstract', "Style to use for symbols that are abstract."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('deprecated', nls.localize('deprecated', "Style to use for symbols that are deprecated."), undefined);
|
||||
|
||||
@@ -13,14 +13,14 @@ import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
|
||||
import { ipcMain as ipc, screen, BrowserWindow, systemPreferences, MessageBoxOptions, Display } from 'electron';
|
||||
import { ipcMain as ipc, screen, BrowserWindow, systemPreferences, MessageBoxOptions, Display, app } from 'electron';
|
||||
import { parseLineAndColumnAware } from 'vs/code/node/paths';
|
||||
import { ILifecycleMainService, UnloadReason, LifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, IPathsToWaitFor, isFileToOpen, isWorkspaceToOpen, isFolderToOpen, IWindowOpenable, IOpenEmptyWindowOptions, IAddFoldersRequest } from 'vs/platform/windows/common/windows';
|
||||
import { getLastActiveWindow, findBestWindowOrFolderForFile, findWindowOnWorkspace, findWindowOnExtensionDevelopmentPath, findWindowOnWorkspaceOrFolderUri } from 'vs/platform/windows/node/window';
|
||||
import { Event as CommonEvent, Emitter } from 'vs/base/common/event';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IWindowsMainService, IOpenConfiguration, IWindowsCountChangedEvent, ICodeWindow, IWindowState as ISingleWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows';
|
||||
import { IWorkspacesHistoryMainService } from 'vs/platform/workspaces/electron-main/workspacesHistoryMainService';
|
||||
@@ -160,14 +160,16 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
private readonly windowsState: IWindowsState;
|
||||
private lastClosedWindowState?: IWindowState;
|
||||
|
||||
private shuttingDown = false;
|
||||
|
||||
private readonly _onWindowReady = this._register(new Emitter<ICodeWindow>());
|
||||
readonly onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
|
||||
readonly onWindowReady = this._onWindowReady.event;
|
||||
|
||||
private readonly _onWindowClose = this._register(new Emitter<number>());
|
||||
readonly onWindowClose: CommonEvent<number> = this._onWindowClose.event;
|
||||
readonly onWindowClose = this._onWindowClose.event;
|
||||
|
||||
private readonly _onWindowsCountChanged = this._register(new Emitter<IWindowsCountChangedEvent>());
|
||||
readonly onWindowsCountChanged: CommonEvent<IWindowsCountChangedEvent> = this._onWindowsCountChanged.event;
|
||||
readonly onWindowsCountChanged = this._onWindowsCountChanged.event;
|
||||
|
||||
constructor(
|
||||
private readonly machineId: string,
|
||||
@@ -236,6 +238,15 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
systemPreferences.on('high-contrast-color-scheme-changed', () => onHighContrastChange());
|
||||
}
|
||||
|
||||
// When a window looses focus, save all windows state. This allows to
|
||||
// prevent loss of window-state data when OS is restarted without properly
|
||||
// shutting down the application (https://github.com/microsoft/vscode/issues/87171)
|
||||
app.on('browser-window-blur', () => {
|
||||
if (!this.shuttingDown) {
|
||||
this.saveWindowsState();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle various lifecycle events around windows
|
||||
this.lifecycleMainService.onBeforeWindowClose(window => this.onBeforeWindowClose(window));
|
||||
this.lifecycleMainService.onBeforeShutdown(() => this.onBeforeShutdown());
|
||||
@@ -292,6 +303,12 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
// - closeAll(2): onBeforeWindowClose(2, false), onBeforeWindowClose(2, false), onBeforeShutdown(0)
|
||||
//
|
||||
private onBeforeShutdown(): void {
|
||||
this.shuttingDown = true;
|
||||
|
||||
this.saveWindowsState();
|
||||
}
|
||||
|
||||
private saveWindowsState(): void {
|
||||
const currentWindowsState: IWindowsState = {
|
||||
openedWindows: [],
|
||||
lastPluginDevelopmentHostWindow: this.windowsState.lastPluginDevelopmentHostWindow,
|
||||
@@ -327,8 +344,11 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
|
||||
// Persist
|
||||
const state = getWindowsStateStoreData(currentWindowsState);
|
||||
this.logService.trace('onBeforeShutdown', state);
|
||||
this.stateService.setItem(WindowsMainService.windowsStateStorageKey, state);
|
||||
|
||||
if (this.shuttingDown) {
|
||||
this.logService.trace('onBeforeShutdown', state);
|
||||
}
|
||||
}
|
||||
|
||||
// See note on #onBeforeShutdown() for details how these events are flowing
|
||||
|
||||
Reference in New Issue
Block a user