提交 701fe8cf 编写于 作者: D Daniel Imms

Merge remote-tracking branch 'origin/master' into tyriar/101_hot_exit

......@@ -61,7 +61,15 @@
{
"fileMatch": "/.vscode/extensions.json",
"url": "vscode://schemas/extensions"
},
{
"fileMatch": "%APP_SETTINGS_HOME%/extensions.json",
"url": "vscode://schemas/extensionsstorage"
},
{
"fileMatch": "%APP_SETTINGS_HOME%/**/extensions.json",
"url": "vscode://schemas/extensionsstorage"
}
]
}
}
}
\ No newline at end of file
......@@ -334,8 +334,8 @@
},
"pty.js": {
"version": "0.3.0",
"from": "https://github.com/Tyriar/pty.js/tarball/fffbf86eb9e8051b5b2be4ba9c7b07faa018ce8d",
"resolved": "https://github.com/Tyriar/pty.js/tarball/fffbf86eb9e8051b5b2be4ba9c7b07faa018ce8d",
"from": "https://github.com/Tyriar/pty.js/tarball/e42781661143541fa08309adc9b0091e7b8674d3",
"resolved": "https://github.com/Tyriar/pty.js/tarball/e42781661143541fa08309adc9b0091e7b8674d3",
"dependencies": {
"extend": {
"version": "1.2.1",
......
......@@ -8,7 +8,7 @@ Packager: Visual Studio Code Team <vscode-linux@microsoft.com>
License: MIT
URL: https://code.visualstudio.com/
Icon: @@NAME@@.xpm
Requires: glibc >= 2.15, libXScrnSaver
Requires: glibc >= 2.15, libXss.so.1
AutoReq: 0
%description
......
......@@ -234,9 +234,4 @@ export interface IExtensionTipsService {
}
export const ExtensionsLabel = nls.localize('extensions', "Extensions");
export const ExtensionsChannelId = 'extensions';
export const ExtensionsStorageFile = 'extensions.json';
export interface IExtensionsStorageData {
disabledExtensions?: string[];
}
\ No newline at end of file
export const ExtensionsChannelId = 'extensions';
\ No newline at end of file
......@@ -93,7 +93,7 @@ export class ExtensionManagementService implements IExtensionManagementService {
private extensionsPath: string;
private obsoletePath: string;
private obsoleteFileLimiter: Limiter<void>;
private disposables: IDisposable[];
private disposables: IDisposable[] = [];
private _onInstallExtension = new Emitter<InstallExtensionEvent>();
onInstallExtension: Event<InstallExtensionEvent> = this._onInstallExtension.event;
......
......@@ -7,6 +7,7 @@
import Severity from 'vs/base/common/severity';
import { TPromise } from 'vs/base/common/winjs.base';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { StorageScope } from 'vs/platform/storage/common/storage';
export interface IExtensionDescription {
id: string;
......@@ -62,3 +63,15 @@ export interface IExtensionService {
*/
getExtensionsStatus(): { [id: string]: IExtensionsStatus };
}
export interface IExtensionsStorageData {
disabled?: string[];
}
export const IExtensionsRuntimeService = createDecorator<IExtensionsRuntimeService>('extensionsRuntimeService');
export interface IExtensionsRuntimeService {
_serviceBrand: any;
getStoragePath(scope: StorageScope): string;
getDisabledExtensions(scope?: StorageScope): string[];
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { distinct } from 'vs/base/common/arrays';
import * as paths from 'vs/base/common/paths';
import { ConfigWatcher } from 'vs/base/node/config';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtensionsRuntimeService, IExtensionsStorageData } from 'vs/platform/extensions/common/extensions';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
export class ExtensionsRuntimeService implements IExtensionsRuntimeService {
_serviceBrand: any;
private workspaceStorage: ExtensionsStorage;
private globalStorage: ExtensionsStorage;
constructor(
@IStorageService private storageService: IStorageService
) {
}
public getStoragePath(scope: StorageScope): string {
return this.getPath(scope);
}
public getDisabledExtensions(scope?: StorageScope): string[] {
if (scope) {
return this.getData(scope).disabled || [];
}
const globalData = this.getData(StorageScope.GLOBAL).disabled || [];
const workspaceData = this.getData(StorageScope.WORKSPACE).disabled || [];
return distinct([...globalData, ...workspaceData]);
}
private getData(scope: StorageScope): IExtensionsStorageData {
const extensionsStorage = this.getStorage(scope);
return extensionsStorage ? extensionsStorage.data : {};
}
private getStorage(scope: StorageScope): ExtensionsStorage {
const path = this.getPath(scope);
if (path) {
if (StorageScope.WORKSPACE === scope) {
return this.getWorkspaceStorage(path);
}
return this.getGlobalStorage(path);
}
return null;
}
private getGlobalStorage(path: string): ExtensionsStorage {
if (!this.globalStorage) {
this.globalStorage = new ExtensionsStorage(path);
}
return this.globalStorage;
}
private getWorkspaceStorage(path: string): ExtensionsStorage {
if (!this.workspaceStorage) {
this.workspaceStorage = new ExtensionsStorage(path);
}
return this.workspaceStorage;
}
private getPath(scope: StorageScope): string {
const path = this.storageService.getStoragePath(scope);
return path ? paths.join(path, 'extensions.json') : void 0;
}
public dispose() {
if (this.workspaceStorage) {
this.workspaceStorage.dispose();
this.workspaceStorage = null;
}
if (this.globalStorage) {
this.globalStorage.dispose();
this.globalStorage = null;
}
}
}
export class ExtensionsStorage extends Disposable {
private _watcher: ConfigWatcher<IExtensionsStorageData>;
constructor(path: string) {
super();
this._watcher = this._register(new ConfigWatcher(path, { changeBufferDelay: 300, defaultConfig: Object.create(null) }));
}
public get data(): IExtensionsStorageData {
return this._watcher.getConfig();
}
}
\ No newline at end of file
......@@ -61,6 +61,17 @@ export interface IStorageService {
* The optional scope argument allows to define the scope of the operation.
*/
getBoolean(key: string, scope?: StorageScope, defaultValue?: boolean): boolean;
/**
* Returns an absolute file path in which private state can be stored as JSON data
* in separate modules.
*
* For workspace scope {StorageScope.WORKSPACE}, a workspace specific directory
* under global scope is returned.
*
* NOTE: This is not the same as the local storage used by the other APIs.
*/
getStoragePath(scope: StorageScope): string;
}
export enum StorageScope {
......@@ -85,4 +96,5 @@ export const NullStorageService: IStorageService = {
get(a, b, defaultValue) { return defaultValue; },
getInteger(a, b, defaultValue) { return defaultValue; },
getBoolean(a, b, defaultValue) { return defaultValue; },
getStoragePath(scope) { return void 0; },
};
......@@ -13,7 +13,7 @@ import { EventEmitter } from 'vs/base/common/eventEmitter';
import * as paths from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import { ITelemetryService, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/common/storage';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/node/storage';
import { EditorInputEvent, IEditorGroup, ConfirmResult } from 'vs/workbench/common/editor';
import Event, { Emitter } from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
......@@ -280,7 +280,7 @@ export class TestStorageService extends EventEmitter implements IStorageService
super();
let context = new TestContextService();
this.storage = new Storage(new InMemoryLocalStorage(), null, context);
this.storage = new Storage(new InMemoryLocalStorage(), null, context, TestEnvironmentService);
}
store(key: string, value: any, scope: StorageScope = StorageScope.GLOBAL): void {
......@@ -306,6 +306,11 @@ export class TestStorageService extends EventEmitter implements IStorageService
getBoolean(key: string, scope: StorageScope = StorageScope.GLOBAL, defaultValue?: boolean): boolean {
return this.storage.getBoolean(key, scope, defaultValue);
}
getStoragePath(scope: StorageScope = StorageScope.GLOBAL): string {
return this.storage.getStoragePath(scope);
}
}
export class TestEditorGroupService implements IEditorGroupService {
......
......@@ -5,10 +5,7 @@
'use strict';
import * as fs from 'fs';
import * as crypto from 'crypto';
import * as nls from 'vs/nls';
import * as json from 'vs/base/common/json';
import pkg from 'vs/platform/package';
import paths = require('vs/base/common/paths');
import { toErrorMessage } from 'vs/base/common/errorMessage';
......@@ -27,11 +24,11 @@ import { ipcRenderer as ipc } from 'electron';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionDescription, IMessage } from 'vs/platform/extensions/common/extensions';
import { IExtensionsStorageData, ExtensionsStorageFile } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionDescription, IMessage, IExtensionsRuntimeService } from 'vs/platform/extensions/common/extensions';
import { ExtensionScanner, MessagesCollector } from 'vs/workbench/node/extensionPoints';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
import Event, { Emitter } from 'vs/base/common/event';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog';
export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach';
......@@ -61,8 +58,6 @@ export class ExtensionHostProcessWorker {
private isExtensionDevelopmentTestFromCli: boolean;
private isExtensionDevelopmentDebugging: boolean;
private workspaceStoragePath: string;
private _onMessage = new Emitter<any>();
public get onMessage(): Event<any> {
return this._onMessage.event;
......@@ -74,7 +69,9 @@ export class ExtensionHostProcessWorker {
@IWindowService private windowService: IWindowService,
@ILifecycleService lifecycleService: ILifecycleService,
@IInstantiationService private instantiationService: IInstantiationService,
@IEnvironmentService private environmentService: IEnvironmentService
@IEnvironmentService private environmentService: IEnvironmentService,
@IStorageService private storageService: IStorageService,
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService
) {
// handle extension host lifecycle a bit special when we know we are developing an extension that runs inside
this.isExtensionDevelopmentHost = !!environmentService.extensionDevelopmentPath;
......@@ -221,7 +218,7 @@ export class ExtensionHostProcessWorker {
contextService: {
workspace: this.contextService.getWorkspace()
},
workspaceStoragePath: this.getOrCreateWorkspaceStoragePath(),
workspaceStoragePath: this.storageService.getStoragePath(StorageScope.WORKSPACE),
extensions: extensionDescriptors
});
this.extensionHostProcessHandle.send(initPayload);
......@@ -271,34 +268,10 @@ export class ExtensionHostProcessWorker {
private getUserExtensions(version: string, collector: MessagesCollector): TPromise<IExtensionDescription[]> {
return ExtensionScanner.scanExtensions(version, collector, this.environmentService.extensionsPath, false)
.then(extensionDescriptions => this.getDisabledExtensions()
.then(disabledExtensions => extensionDescriptions.filter(e => disabledExtensions.indexOf(`${e.publisher}.${e.name}`) === -1)));
}
private getDisabledExtensions(): TPromise<string[]> {
return this.getWorkspaceDisabledExtensions();
}
private getWorkspaceDisabledExtensions(): TPromise<string[]> {
const workspaceStoragePath = this.getOrCreateWorkspaceStoragePath();
if (!workspaceStoragePath) {
return TPromise.wrap([]);
}
return new TPromise<string[]>((c, e) => {
fs.readFile(paths.join(workspaceStoragePath, ExtensionsStorageFile), (error, raw) => {
let result = [];
if (!error) {
try {
const extensionsData: IExtensionsStorageData = json.parse(raw.toString());
result = extensionsData.disabledExtensions || [];
} catch (error) {
// Ignore parsing errors
}
}
return c(result);
.then(extensionDescriptions => {
const disabledExtensions = this.extensionsRuntimeService.getDisabledExtensions();
return disabledExtensions.length ? extensionDescriptions.filter(e => disabledExtensions.indexOf(`${e.publisher}.${e.name}`) === -1) : extensionDescriptions;
});
});
}
private logExtensionHostMessage(logEntry: ILogEntry) {
......@@ -432,57 +405,4 @@ export class ExtensionHostProcessWorker {
}
}
}
private getOrCreateWorkspaceStoragePath(): string {
const workspace = this.contextService.getWorkspace();
if (!workspace) {
return void 0;
}
if (this.workspaceStoragePath) {
return this.workspaceStoragePath;
}
function rmkDir(directory: string): boolean {
try {
fs.mkdirSync(directory);
return true;
} catch (err) {
if (err.code === 'ENOENT') {
if (rmkDir(paths.dirname(directory))) {
fs.mkdirSync(directory);
return true;
}
} else {
return fs.statSync(directory).isDirectory();
}
}
}
if (workspace) {
const hash = crypto.createHash('md5');
hash.update(workspace.resource.fsPath);
if (workspace.uid) {
hash.update(workspace.uid.toString());
}
this.workspaceStoragePath = paths.join(this.environmentService.appSettingsHome, 'workspaceStorage', hash.digest('hex'));
if (!fs.existsSync(this.workspaceStoragePath)) {
try {
if (rmkDir(this.workspaceStoragePath)) {
fs.writeFileSync(paths.join(this.workspaceStoragePath, 'meta.json'), JSON.stringify({
workspacePath: workspace.resource.fsPath,
uid: workspace.uid ? workspace.uid : null
}, null, 4));
} else {
this.workspaceStoragePath = void 0;
}
} catch (err) {
this.workspaceStoragePath = void 0;
}
}
}
return this.workspaceStoragePath;
}
}
\ No newline at end of file
......@@ -23,7 +23,7 @@ import timer = require('vs/base/common/timer');
import { BackupService } from 'vs/workbench/common/backup';
import { IBackupService } from 'vs/platform/backup/common/backup';
import { Workbench } from 'vs/workbench/electron-browser/workbench';
import { Storage, inMemoryLocalStorageInstance } from 'vs/workbench/common/storage';
import { Storage, inMemoryLocalStorageInstance } from 'vs/workbench/node/storage';
import { ITelemetryService, NullTelemetryService, loadExperiments } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryAppenderChannel, TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
......@@ -67,7 +67,8 @@ import { IThreadService } from 'vs/workbench/services/thread/common/threadServic
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CommandService } from 'vs/platform/commands/common/commandService';
import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { IExtensionService, IExtensionsRuntimeService } from 'vs/platform/extensions/common/extensions';
import { ExtensionsRuntimeService } from 'vs/platform/extensions/node/extensions';
import { MainThreadModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
......@@ -297,6 +298,10 @@ export class WorkbenchShell {
this.toUnbind.push(lifecycleService.onShutdown(() => disposables.dispose()));
serviceCollection.set(ILifecycleService, lifecycleService);
const extensionsRuntimeService = instantiationService.createInstance(ExtensionsRuntimeService);
serviceCollection.set(IExtensionsRuntimeService, extensionsRuntimeService);
disposables.add(extensionsRuntimeService);
const extensionHostProcessWorker = this.startExtensionHost(instantiationService);
this.threadService = instantiationService.createInstance(MainThreadService, extensionHostProcessWorker.messagingProtocol);
serviceCollection.set(IThreadService, this.threadService);
......
......@@ -4,11 +4,15 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as fs from 'fs';
import * as crypto from 'crypto';
import * as paths from 'vs/base/common/paths';
import types = require('vs/base/common/types');
import errors = require('vs/base/common/errors');
import strings = require('vs/base/common/strings');
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
// Browser localStorage interface
export interface IStorage {
......@@ -34,11 +38,13 @@ export class Storage implements IStorageService {
private globalStorage: IStorage;
private workspaceKey: string;
private workspaceStoragePath: string;
constructor(
globalStorage: IStorage,
workspaceStorage: IStorage,
@IWorkspaceContextService contextService: IWorkspaceContextService
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IEnvironmentService private environmentService: IEnvironmentService
) {
const workspace = contextService.getWorkspace();
......@@ -190,6 +196,63 @@ export class Storage implements IStorageService {
return value ? true : false;
}
public getStoragePath(scope: StorageScope): string {
if (StorageScope.GLOBAL === scope) {
return this.environmentService.appSettingsHome;
}
const workspace = this.contextService.getWorkspace();
if (!workspace) {
return void 0;
}
if (this.workspaceStoragePath) {
return this.workspaceStoragePath;
}
function rmkDir(directory: string): boolean {
try {
fs.mkdirSync(directory);
return true;
} catch (err) {
if (err.code === 'ENOENT') {
if (rmkDir(paths.dirname(directory))) {
fs.mkdirSync(directory);
return true;
}
} else {
return fs.statSync(directory).isDirectory();
}
}
}
if (workspace) {
const hash = crypto.createHash('md5');
hash.update(workspace.resource.fsPath);
if (workspace.uid) {
hash.update(workspace.uid.toString());
}
this.workspaceStoragePath = paths.join(this.environmentService.appSettingsHome, 'workspaceStorage', hash.digest('hex'));
if (!fs.existsSync(this.workspaceStoragePath)) {
try {
if (rmkDir(this.workspaceStoragePath)) {
fs.writeFileSync(paths.join(this.workspaceStoragePath, 'meta.json'), JSON.stringify({
workspacePath: workspace.resource.fsPath,
uid: workspace.uid ? workspace.uid : null
}, null, 4));
} else {
this.workspaceStoragePath = void 0;
}
} catch (err) {
this.workspaceStoragePath = void 0;
}
}
}
return this.workspaceStoragePath;
}
private toStorageKey(key: string, scope: StorageScope): string {
if (scope === StorageScope.GLOBAL) {
return Storage.GLOBAL_PREFIX + key.toLowerCase();
......
......@@ -154,7 +154,7 @@ const schema: IJSONSchema = {
},
configurations: {
type: 'array',
description: nls.localize('app.launch.json.configurations', "List of configurations. Add new configurations or edit existing ones."),
description: nls.localize('app.launch.json.configurations', "List of configurations. Add new configurations or edit existing ones by using IntelliSense."),
items: {
'type': 'object',
oneOf: []
......
......@@ -20,7 +20,7 @@ import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/co
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { VIEWLET_ID, IExtensionsWorkbenchService } from './extensions';
import { ExtensionsWorkbenchService } from './extensionsWorkbenchService';
import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, UpdateAllAction, OpenExtensionsFolderAction, ConfigureWorkspaceRecommendedExtensionsAction, InstallVSIXAction } from './extensionsActions';
import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, UpdateAllAction, OpenExtensionsFolderAction, ConfigureWorkspaceRecommendedExtensionsAction, OpenWorkspaceExtensionsStorageFile, OpenGlobalExtensionsStorageFile, InstallVSIXAction } from './extensionsActions';
import { ExtensionsInput } from './extensionsInput';
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { ExtensionEditor } from './extensionEditor';
......@@ -28,7 +28,7 @@ import { StatusUpdater } from './extensionsViewlet';
import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import jsonContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry');
import { Schema, SchemaId } from 'vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate';
import { ExtensionsConfigurationSchema, ExtensionsConfigurationSchemaId, ExtensionsStorageSchema, ExtensionsStorageSchemaId } from 'vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate';
// Singletons
registerSingleton(IExtensionGalleryService, ExtensionGalleryService);
......@@ -110,6 +110,9 @@ actionRegistry.registerWorkbenchAction(popularActionDescriptor, 'Extensions: Sho
const installedActionDescriptor = new SyncActionDescriptor(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL);
actionRegistry.registerWorkbenchAction(installedActionDescriptor, 'Extensions: Show Installed Extensions', ExtensionsLabel);
const disabledActionDescriptor = new SyncActionDescriptor(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL);
actionRegistry.registerWorkbenchAction(disabledActionDescriptor, 'Extensions: Show Disabled Extensions', ExtensionsLabel);
const updateAllActionDescriptor = new SyncActionDescriptor(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL);
actionRegistry.registerWorkbenchAction(updateAllActionDescriptor, 'Extensions: Update All Extensions', ExtensionsLabel);
......@@ -119,6 +122,12 @@ actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Ex
const openExtensionsFileActionDescriptor = new SyncActionDescriptor(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL);
actionRegistry.registerWorkbenchAction(openExtensionsFileActionDescriptor, 'Extensions: Open Extensions File', ExtensionsLabel);
const disableExtensionsActionDescriptor = new SyncActionDescriptor(OpenGlobalExtensionsStorageFile, OpenGlobalExtensionsStorageFile.ID, localize('disableGlobalExtensions', "Configure Disabled Extensions"));
actionRegistry.registerWorkbenchAction(disableExtensionsActionDescriptor, 'Extensions: Configure Disabled Extensions', ExtensionsLabel);
const disableWorkspaceExtensionsActionDescriptor = new SyncActionDescriptor(OpenWorkspaceExtensionsStorageFile, OpenWorkspaceExtensionsStorageFile.ID, localize('disableWorkspaceExtensions', "Configure Disabled Extensions (Workspace)"));
actionRegistry.registerWorkbenchAction(disableWorkspaceExtensionsActionDescriptor, 'Extensions: Configure Disabled Extensions (Workspace)', ExtensionsLabel);
const installVSIXActionDescriptor = new SyncActionDescriptor(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL);
actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: Install from VSIX...', ExtensionsLabel);
......@@ -138,4 +147,5 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
});
const jsonRegistry = <jsonContributionRegistry.IJSONContributionRegistry>Registry.as(jsonContributionRegistry.Extensions.JSONContribution);
jsonRegistry.registerSchema(SchemaId, Schema);
\ No newline at end of file
jsonRegistry.registerSchema(ExtensionsConfigurationSchemaId, ExtensionsConfigurationSchema);
jsonRegistry.registerSchema(ExtensionsStorageSchemaId, ExtensionsStorageSchema);
\ No newline at end of file
......@@ -40,6 +40,7 @@ export interface IExtension {
rating: number;
ratingCount: number;
outdated: boolean;
disabled: boolean;
hasDependencies: boolean;
telemetryData: any;
getManifest(): TPromise<IExtensionManifest>;
......
......@@ -14,6 +14,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, ConfigurationKey } from './extensions';
import { LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IExtensionsRuntimeService } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IMessageService, LaterAction } from 'vs/platform/message/common/message';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
......@@ -22,10 +23,11 @@ import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletSer
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { Query } from '../common/extensionQuery';
import { shell, remote } from 'electron';
import { InitialContent } from 'vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate';
import { ExtensionsConfigurationInitialContent, ExtensionStorageInitialContent } from 'vs/workbench/parts/extensions/electron-browser/extensionsFileTemplate';
import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import URI from 'vs/base/common/uri';
import { StorageScope } from 'vs/platform/storage/common/storage';
const dialog = remote.dialog;
......@@ -379,6 +381,30 @@ export class ShowInstalledExtensionsAction extends Action {
}
}
export class ShowDisabledExtensionsAction extends Action {
static ID = 'workbench.extensions.action.showDisabledExtensions';
static LABEL = localize('showDisabledExtensions', "Show Disabled Extensions");
constructor(
id: string,
label: string,
@IViewletService private viewletService: IViewletService,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService
) {
super(id, label, 'null', true);
}
run(): TPromise<void> {
return this.viewletService.openViewlet(VIEWLET_ID, true)
.then(viewlet => viewlet as IExtensionsViewlet)
.then(viewlet => {
viewlet.search('@disabled ');
viewlet.focus();
});
}
}
export class ClearExtensionsInputAction extends ShowInstalledExtensionsAction {
static ID = 'workbench.extensions.action.clearExtensionsInput';
......@@ -496,9 +522,10 @@ export class ShowWorkspaceRecommendedExtensionsAction extends Action {
constructor(
id: string,
label: string,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IViewletService private viewletService: IViewletService
) {
super(id, label, null, true);
super(id, label, null, !!contextService.getWorkspace());
}
run(): TPromise<void> {
......@@ -587,7 +614,7 @@ export class OpenExtensionsFolderAction extends Action {
export class ConfigureWorkspaceRecommendedExtensionsAction extends Action {
static ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions';
static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Workspace Recommended Extensions");
static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)");
constructor(
id: string,
......@@ -598,7 +625,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends Action {
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IMessageService private messageService: IMessageService
) {
super(id, label, null, true);
super(id, label, null, !!contextService.getWorkspace());
}
public run(event: any): TPromise<any> {
......@@ -628,13 +655,87 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends Action {
return this.fileService.resolveContent(extensionsFileResource).then(content => {
return { created: false, extensionsFileResource };
}, err => {
return this.fileService.updateContent(extensionsFileResource, InitialContent).then(() => {
return this.fileService.updateContent(extensionsFileResource, ExtensionsConfigurationInitialContent).then(() => {
return { created: true, extensionsFileResource };
});
});
}
}
export abstract class OpenExtensionsStorageFile extends Action {
constructor(
id: string,
label: string,
enabled: boolean,
private scope: StorageScope,
@IFileService private fileService: IFileService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService
) {
super(id, label, null, enabled);
}
public run(event: any): TPromise<any> {
return this.openExtensionsStorageFile();
}
private openExtensionsStorageFile(): TPromise<any> {
return this.getOrCreateExtensionsFile().then(value => {
return this.editorService.openEditor({
resource: value.extensionsFileResource,
options: {
forceOpen: true,
pinned: value.created
},
});
}, (error) => TPromise.wrapError(new Error(localize('OpenGlobalExtensionsStorageFile.failed', "Unable to create 'extensions.json' file inside the '{0}' folder ({1}).", this.extensionsRuntimeService.getStoragePath(this.scope), error))));
}
private getOrCreateExtensionsFile(): TPromise<{ created: boolean, extensionsFileResource: URI }> {
const extensionsFileResource = URI.file(this.extensionsRuntimeService.getStoragePath(this.scope));
return this.fileService.resolveContent(extensionsFileResource).then(content => {
return { created: false, extensionsFileResource };
}, err => {
return this.fileService.updateContent(extensionsFileResource, ExtensionStorageInitialContent).then(() => {
return { created: true, extensionsFileResource };
});
});
}
}
export class OpenWorkspaceExtensionsStorageFile extends OpenExtensionsStorageFile {
static ID = 'workbench.extensions.action.openWorkspaceExtensionsStorageFile';
constructor(
id: string,
label: string,
@IFileService fileService: IFileService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IExtensionsRuntimeService extensionsRuntimeService: IExtensionsRuntimeService
) {
super(id, label, !!contextService.getWorkspace(), StorageScope.WORKSPACE, fileService, editorService, extensionsRuntimeService);
}
}
export class OpenGlobalExtensionsStorageFile extends OpenExtensionsStorageFile {
static ID = 'workbench.extensions.action.openGlobalExtensionsStorageFile';
constructor(
id: string,
label: string,
@IFileService fileService: IFileService,
@IWorkbenchEditorService editorService: IWorkbenchEditorService,
@IExtensionsRuntimeService extensionsRuntimeService: IExtensionsRuntimeService
) {
super(id, label, true, StorageScope.GLOBAL, fileService, editorService, extensionsRuntimeService);
}
}
export class InstallVSIXAction extends Action {
static ID = 'workbench.extensions.action.installVSIX';
......
......@@ -7,9 +7,9 @@ import { localize } from 'vs/nls';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { EXTENSION_IDENTIFIER_PATTERN } from 'vs/platform/extensionManagement/common/extensionManagement';
export const SchemaId = 'vscode://schemas/extensions';
export const Schema: IJSONSchema = {
id: SchemaId,
export const ExtensionsConfigurationSchemaId = 'vscode://schemas/extensions';
export const ExtensionsConfigurationSchema: IJSONSchema = {
id: ExtensionsConfigurationSchemaId,
type: 'object',
title: localize('app.extensions.json.title', "Extensions"),
properties: {
......@@ -26,7 +26,7 @@ export const Schema: IJSONSchema = {
}
};
export const InitialContent: string = [
export const ExtensionsConfigurationInitialContent: string = [
'{',
'\t// See http://go.microsoft.com/fwlink/?LinkId=827846',
'\t// for the documentation about the extensions.json format',
......@@ -35,4 +35,32 @@ export const InitialContent: string = [
'\t\t',
'\t]',
'}'
].join('\n');
export const ExtensionsStorageSchemaId = 'vscode://schemas/extensionsstorage';
export const ExtensionsStorageSchema: IJSONSchema = {
id: ExtensionsStorageSchemaId,
type: 'object',
title: localize('app.extensionsstorage.json.title', "Extensions Storage"),
properties: {
disabled: {
type: 'array',
description: localize('app.extensionsstorage.json.disabled', "List of disabled extensions. The identifier of an extension is always '${publisher}.${name}'. For example: 'vscode.csharp'."),
items: {
type: 'string',
defaultSnippets: [{ label: 'Example', body: 'vscode.csharp' }],
pattern: EXTENSION_IDENTIFIER_PATTERN,
errorMessage: localize('app.extension.identifier.errorMessage', "Expected format '${publisher}.${name}'. Example: 'vscode.csharp'.")
},
},
}
};
export const ExtensionStorageInitialContent: string = [
'{',
'\t"disabled": [',
'\t\t// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp',
'\t\t',
'\t]',
'}'
].join('\n');
\ No newline at end of file
......@@ -5,7 +5,8 @@
'use strict';
import { append, $, addClass, removeClass } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { append, $, addClass, removeClass, toggleClass } from 'vs/base/browser/dom';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
......@@ -16,6 +17,7 @@ import { once } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension } from './extensions';
import { CombinedInstallAction, UpdateAction, EnableAction, BuiltinStatusLabelAction } from './extensionsActions';
import { ExtensionState } from './extensions';
import { Label, RatingsWidget, InstallWidget } from './extensionsWidgets';
import { EventType } from 'vs/base/common/events';
......@@ -25,6 +27,7 @@ export interface ITemplateData {
name: HTMLElement;
installCount: HTMLElement;
ratings: HTMLElement;
state: HTMLElement;
author: HTMLElement;
description: HTMLElement;
extension: IExtension;
......@@ -57,6 +60,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const version = append(header, $('span.version'));
const installCount = append(header, $('span.install-count'));
const ratings = append(header, $('span.ratings'));
const state = append(header, $('span.state'));
const description = append(details, $('.description.ellipsis'));
const footer = append(details, $('.footer'));
const author = append(footer, $('.author.ellipsis'));
......@@ -77,7 +81,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
const disposables = [versionWidget, installCountWidget, ratingsWidget, installAction, builtinStatusAction, updateAction, restartAction, actionbar];
return {
element, icon, name, installCount, ratings, author, description, disposables,
element, icon, name, state, installCount, ratings, author, description, disposables,
extensionDisposables: [],
set extension(extension: IExtension) {
versionWidget.extension = extension;
......@@ -109,6 +113,8 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
data.extensionDisposables = dispose(data.extensionDisposables);
toggleClass(data.element, 'disabled', extension.disabled);
const onError = once(domEvent(data.icon, 'error'));
onError(() => data.icon.src = extension.iconUrlFallback, null, data.extensionDisposables);
data.icon.src = extension.iconUrl;
......@@ -126,6 +132,10 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
data.installCount.style.display = '';
data.ratings.style.display = '';
data.extension = extension;
const installed = extension.state === ExtensionState.Installed;
toggleClass(data.state, 'installed', installed);
data.state.title = extension.disabled ? localize('disabled', "Disabled") : installed ? localize('active', "Active") : '';
}
disposeTemplate(data: ITemplateData): void {
......
......@@ -30,7 +30,7 @@ import { PagedList } from 'vs/base/browser/ui/list/listPaging';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Delegate, Renderer } from './extensionsList';
import { IExtensionsWorkbenchService, IExtension, IExtensionsViewlet, VIEWLET_ID, ExtensionState } from './extensions';
import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, InstallVSIXAction, ConfigureWorkspaceRecommendedExtensionsAction } from './extensionsActions';
import { ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowDisabledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, InstallVSIXAction, ConfigureWorkspaceRecommendedExtensionsAction } from './extensionsActions';
import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, SortBy, SortOrder, IQueryOptions, LocalExtensionType } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionsInput } from './extensionsInput';
import { Query } from '../common/extensionQuery';
......@@ -163,6 +163,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
new Separator(),
this.instantiationService.createInstance(ShowInstalledExtensionsAction, ShowInstalledExtensionsAction.ID, ShowInstalledExtensionsAction.LABEL),
this.instantiationService.createInstance(ShowOutdatedExtensionsAction, ShowOutdatedExtensionsAction.ID, ShowOutdatedExtensionsAction.LABEL),
this.instantiationService.createInstance(ShowDisabledExtensionsAction, ShowDisabledExtensionsAction.ID, ShowDisabledExtensionsAction.LABEL),
this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, ShowRecommendedExtensionsAction.LABEL),
this.instantiationService.createInstance(ShowWorkspaceRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction.ID, ShowWorkspaceRecommendedExtensionsAction.LABEL),
this.instantiationService.createInstance(ShowPopularExtensionsAction, ShowPopularExtensionsAction.ID, ShowPopularExtensionsAction.LABEL),
......@@ -233,6 +234,12 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet {
.then(result => new PagedModel(result));
}
if (/@disabled/i.test(value)) {
return this.extensionsWorkbenchService.queryLocal()
.then(result => result.filter(e => e.disabled))
.then(result => new PagedModel(result));
}
const query = Query.parse(value);
let options: IQueryOptions = {};
......
......@@ -38,6 +38,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions';
import { IURLService } from 'vs/platform/url/common/url';
import { ExtensionsInput } from './extensionsInput';
import { IExtensionsRuntimeService } from 'vs/platform/extensions/common/extensions';
interface IExtensionStateProvider {
(extension: Extension): ExtensionState;
......@@ -46,6 +47,7 @@ interface IExtensionStateProvider {
class Extension implements IExtension {
public needsRestart = false;
private _disabled = false;
constructor(
private galleryService: IExtensionGalleryService,
......@@ -163,6 +165,14 @@ class Extension implements IExtension {
return this.type === LocalExtensionType.User && semver.gt(this.latestVersion, this.version);
}
get disabled(): boolean {
return this._disabled;
}
set disabled(disabled: boolean) {
this._disabled = disabled;
}
get telemetryData(): any {
const { local, gallery } = this;
......@@ -300,7 +310,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
@IConfigurationService private configurationService: IConfigurationService,
@ITelemetryService private telemetryService: ITelemetryService,
@IMessageService private messageService: IMessageService,
@IURLService urlService: IURLService
@IURLService urlService: IURLService,
@IExtensionsRuntimeService private extensionsRuntimeService: IExtensionsRuntimeService
) {
this.stateProvider = ext => this.getExtensionState(ext);
......@@ -328,12 +339,14 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService {
}
queryLocal(): TPromise<IExtension[]> {
const disabled = this.extensionsRuntimeService.getDisabledExtensions();
return this.extensionService.getInstalled().then(result => {
const installedById = index(this.installed, e => e.local.id);
this.installed = result.map(local => {
const extension = installedById[local.id] || new Extension(this.galleryService, this.stateProvider, local);
extension.local = local;
extension.disabled = local.type === LocalExtensionType.User && disabled.indexOf(`${extension.publisher}.${extension.name}`) !== -1;
return extension;
});
......
......@@ -103,6 +103,20 @@
display: none;
}
.extensions-viewlet > .extensions .extension > .details > .header > .state.installed {
background: #478E4B;
width: 7px;
height: 7px;
border-radius: 50%;
/*display: inline-block;*/
display: none;
margin-left: 5px;
}
.extensions-viewlet > .extensions .extension.disabled > .details > .header > .state.installed {
background: #5f5f5f;
}
.extensions-viewlet > .extensions .extension > .details > .footer {
display: flex;
justify-content: flex-end;
......@@ -134,6 +148,13 @@
text-overflow: ellipsis;
}
.extensions-viewlet > .extensions .extension.disabled > .icon,
.extensions-viewlet > .extensions .extension.disabled > .details > .header,
.extensions-viewlet > .extensions .extension.disabled > .details > .description,
.extensions-viewlet > .extensions .extension.disabled > .details > .footer > .author {
opacity: 0.5;
}
.extensions-badge.progress-badge > .badge-content {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4=");
background-position: center center;
......
......@@ -61,6 +61,14 @@ configurationRegistry.registerConfiguration({
'type': 'string',
'default': TERMINAL_DEFAULT_SHELL_WINDOWS
},
'terminal.integrated.shellArgs.windows': {
'description': nls.localize('terminal.integrated.shellArgs.windows', "The command line arguments to use when on the Windows terminal."),
'type': 'array',
'items': {
'type': 'string'
},
'default': []
},
'terminal.integrated.fontFamily': {
'description': nls.localize('terminal.integrated.fontFamily', "Controls the font family of the terminal, this defaults to editor.fontFamily's value."),
'type': 'string'
......
......@@ -39,7 +39,8 @@ export interface ITerminalConfiguration {
},
shellArgs: {
linux: string[],
osx: string[]
osx: string[],
windows: string[]
},
cursorBlinking: boolean,
fontFamily: string,
......
......@@ -137,9 +137,9 @@ export class TerminalConfigHelper {
if (fontSize <= 0) {
fontSize = DefaultConfig.editor.fontSize;
}
let lineHeight = this.toInteger(terminalConfig.lineHeight, DEFAULT_LINE_HEIGHT);
let lineHeight = terminalConfig.lineHeight <= 0 ? DEFAULT_LINE_HEIGHT : terminalConfig.lineHeight;
return this._measureFont(fontFamily, fontSize, lineHeight <= 0 ? DEFAULT_LINE_HEIGHT : lineHeight);
return this._measureFont(fontFamily, fontSize, lineHeight);
}
public getFontLigaturesEnabled(): boolean {
......@@ -160,6 +160,7 @@ export class TerminalConfigHelper {
};
if (this._platform === Platform.Windows) {
shell.executable = config.terminal.integrated.shell.windows;
shell.args = config.terminal.integrated.shellArgs.windows;
} else if (this._platform === Platform.Mac) {
shell.executable = config.terminal.integrated.shell.osx;
shell.args = config.terminal.integrated.shellArgs.osx;
......
......@@ -12,7 +12,7 @@ import * as Types from 'vs/base/common/types';
import * as TestUtils from 'vs/test/utils/servicesTestUtils';
import { IWorkspaceContextService, WorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/common/storage';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/node/storage';
class MyPart extends Part {
......@@ -105,7 +105,7 @@ suite('Workbench Part', () => {
fixture.id = fixtureId;
document.body.appendChild(fixture);
context = new WorkspaceContextService(TestUtils.TestWorkspace);
storage = new Storage(new InMemoryLocalStorage(), null, context);
storage = new Storage(new InMemoryLocalStorage(), null, context, TestUtils.TestEnvironmentService);
});
teardown(() => {
......
......@@ -10,7 +10,7 @@ import { WorkspaceContextService } from 'vs/platform/workspace/common/workspace'
import { StorageScope } from 'vs/platform/storage/common/storage';
import * as TestUtils from 'vs/test/utils/servicesTestUtils';
import { Memento, Scope } from 'vs/workbench/common/memento';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/common/storage';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/node/storage';
suite('Workbench Memento', () => {
let context;
......@@ -18,7 +18,7 @@ suite('Workbench Memento', () => {
setup(() => {
context = new WorkspaceContextService(TestUtils.TestWorkspace);
storage = new Storage(new InMemoryLocalStorage(), null, context);
storage = new Storage(new InMemoryLocalStorage(), null, context, TestUtils.TestEnvironmentService);
});
test('Loading and Saving Memento with Scopes', () => {
......
......@@ -8,14 +8,14 @@
import * as assert from 'assert';
import { clone } from 'vs/base/common/objects';
import { StorageScope } from 'vs/platform/storage/common/storage';
import { TestContextService, TestWorkspace } from 'vs/test/utils/servicesTestUtils';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/common/storage';
import { TestContextService, TestWorkspace, TestEnvironmentService } from 'vs/test/utils/servicesTestUtils';
import { Storage, InMemoryLocalStorage } from 'vs/workbench/node/storage';
suite('Workbench Storage', () => {
test('Swap Data with undefined default value', () => {
let context = new TestContextService();
let s = new Storage(new InMemoryLocalStorage(), null, context);
let s = new Storage(new InMemoryLocalStorage(), null, context, TestEnvironmentService);
s.swap('Monaco.IDE.Core.Storage.Test.swap', 'foobar', 'barfoo');
assert.strictEqual('foobar', s.get('Monaco.IDE.Core.Storage.Test.swap'));
......@@ -27,7 +27,7 @@ suite('Workbench Storage', () => {
test('Remove Data', () => {
let context = new TestContextService();
let s = new Storage(new InMemoryLocalStorage(), null, context);
let s = new Storage(new InMemoryLocalStorage(), null, context, TestEnvironmentService);
s.store('Monaco.IDE.Core.Storage.Test.remove', 'foobar');
assert.strictEqual('foobar', s.get('Monaco.IDE.Core.Storage.Test.remove'));
......@@ -37,7 +37,7 @@ suite('Workbench Storage', () => {
test('Get Data, Integer, Boolean', () => {
let context = new TestContextService();
let s = new Storage(new InMemoryLocalStorage(), null, context);
let s = new Storage(new InMemoryLocalStorage(), null, context, TestEnvironmentService);
assert.strictEqual(s.get('Monaco.IDE.Core.Storage.Test.get', StorageScope.GLOBAL, 'foobar'), 'foobar');
assert.strictEqual(s.get('Monaco.IDE.Core.Storage.Test.get', StorageScope.GLOBAL, ''), '');
......@@ -72,14 +72,14 @@ suite('Workbench Storage', () => {
test('Storage cleans up when workspace changes', () => {
let storageImpl = new InMemoryLocalStorage();
let context = new TestContextService();
let s = new Storage(storageImpl, null, context);
let s = new Storage(storageImpl, null, context, TestEnvironmentService);
s.store('key1', 'foobar');
s.store('key2', 'something');
s.store('wkey1', 'foo', StorageScope.WORKSPACE);
s.store('wkey2', 'foo2', StorageScope.WORKSPACE);
s = new Storage(storageImpl, null, context);
s = new Storage(storageImpl, null, context, TestEnvironmentService);
assert.strictEqual(s.get('key1', StorageScope.GLOBAL), 'foobar');
assert.strictEqual(s.get('key1', StorageScope.WORKSPACE, null), null);
......@@ -91,7 +91,7 @@ suite('Workbench Storage', () => {
let ws: any = clone(TestWorkspace);
ws.uid = new Date().getTime() + 100;
context = new TestContextService(ws);
s = new Storage(storageImpl, null, context);
s = new Storage(storageImpl, null, context, TestEnvironmentService);
assert.strictEqual(s.get('key1', StorageScope.GLOBAL), 'foobar');
assert.strictEqual(s.get('key1', StorageScope.WORKSPACE, null), null);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册