提交 c2306300 编写于 作者: J Joao Moreno

Merge branch 'master' into yarn

......@@ -3,29 +3,29 @@
"version": "1.0.0",
"dependencies": {
"vscode-css-languageservice": {
"version": "3.0.0",
"from": "vscode-css-languageservice@3.0.0",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-3.0.0.tgz"
"version": "3.0.1",
"from": "vscode-css-languageservice@next",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-3.0.1.tgz"
},
"vscode-jsonrpc": {
"version": "3.5.0-next.2",
"from": "vscode-jsonrpc@3.5.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz"
"version": "3.5.0",
"from": "vscode-jsonrpc@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz"
},
"vscode-languageserver": {
"version": "3.5.0-next.6",
"from": "vscode-languageserver@3.5.0-next.6",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz"
"version": "3.5.0",
"from": "vscode-languageserver@next",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0.tgz"
},
"vscode-languageserver-protocol": {
"version": "3.5.0-next.5",
"from": "vscode-languageserver-protocol@3.5.0-next.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz"
"version": "3.5.0",
"from": "vscode-languageserver-protocol@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz"
},
"vscode-languageserver-types": {
"version": "3.5.0-next.2",
"from": "vscode-languageserver-types@3.5.0-next.2d",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz"
"version": "3.5.0",
"from": "vscode-languageserver-types@3.5.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz"
},
"vscode-nls": {
"version": "2.0.2",
......
......@@ -8,8 +8,8 @@
"node": "*"
},
"dependencies": {
"vscode-css-languageservice": "3.0.0",
"vscode-languageserver": "3.5.0-next.6"
"vscode-css-languageservice": "^3.0.1",
"vscode-languageserver": "^3.5.0"
},
"devDependencies": {
"@types/node": "7.0.43"
......
......@@ -3,43 +3,43 @@
"version": "1.0.0",
"dependencies": {
"vscode-css-languageservice": {
"version": "3.0.0",
"from": "vscode-css-languageservice@3.0.0",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-3.0.0.tgz"
"version": "3.0.1",
"from": "vscode-css-languageservice@>=3.0.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-css-languageservice/-/vscode-css-languageservice-3.0.1.tgz"
},
"vscode-html-languageservice": {
"version": "2.0.10",
"from": "vscode-html-languageservice@2.0.10",
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.10.tgz"
"version": "2.0.11",
"from": "vscode-html-languageservice@>=2.0.11 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-2.0.11.tgz"
},
"vscode-jsonrpc": {
"version": "3.5.0-next.2",
"from": "vscode-jsonrpc@3.5.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz"
"version": "3.5.0",
"from": "vscode-jsonrpc@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz"
},
"vscode-languageserver": {
"version": "3.5.0-next.6",
"from": "vscode-languageserver@3.5.0-next.6",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz"
"version": "3.5.0",
"from": "vscode-languageserver@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0.tgz"
},
"vscode-languageserver-protocol": {
"version": "3.5.0-next.5",
"from": "vscode-languageserver-protocol@3.5.0-next.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz"
"version": "3.5.0",
"from": "vscode-languageserver-protocol@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz"
},
"vscode-languageserver-types": {
"version": "3.5.0-next.2",
"from": "vscode-languageserver-types@3.5.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz"
"version": "3.5.0",
"from": "vscode-languageserver-types@3.5.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz"
},
"vscode-nls": {
"version": "2.0.2",
"from": "vscode-nls@>=2.0.1 <3.0.0",
"from": "vscode-nls@>=2.0.2 <3.0.0",
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-2.0.2.tgz"
},
"vscode-uri": {
"version": "1.0.1",
"from": "vscode-uri@latest",
"from": "vscode-uri@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.1.tgz"
}
}
......
......@@ -8,9 +8,9 @@
"node": "*"
},
"dependencies": {
"vscode-css-languageservice": "3.0.0",
"vscode-html-languageservice": "2.0.10",
"vscode-languageserver": "3.5.0-next.6",
"vscode-css-languageservice": "^3.0.1",
"vscode-html-languageservice": "^2.0.11",
"vscode-languageserver": "^3.5.0",
"vscode-nls": "^2.0.2",
"vscode-uri": "^1.0.1"
},
......
......@@ -8,9 +8,9 @@
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-1.0.2.tgz"
},
"debug": {
"version": "2.6.6",
"version": "2.6.9",
"from": "debug@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.6.tgz"
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
},
"extend": {
"version": "3.0.1",
......@@ -33,39 +33,39 @@
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-1.0.0.tgz"
},
"ms": {
"version": "0.7.3",
"from": "ms@0.7.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz"
"version": "2.0.0",
"from": "ms@2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
},
"request-light": {
"version": "0.2.1",
"from": "request-light@0.2.1",
"from": "request-light@>=0.2.1 <0.3.0",
"resolved": "https://registry.npmjs.org/request-light/-/request-light-0.2.1.tgz"
},
"vscode-json-languageservice": {
"version": "3.0.0",
"from": "vscode-json-languageservice@next",
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-3.0.0.tgz"
"version": "3.0.1",
"from": "vscode-json-languageservice@>=3.0.1 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-3.0.1.tgz"
},
"vscode-jsonrpc": {
"version": "3.5.0-next.2",
"from": "vscode-jsonrpc@3.5.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0-next.2.tgz"
"version": "3.5.0",
"from": "vscode-jsonrpc@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz"
},
"vscode-languageserver": {
"version": "3.5.0-next.6",
"from": "vscode-languageserver@3.5.0-next.6",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0-next.6.tgz"
"version": "3.5.0",
"from": "vscode-languageserver@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-3.5.0.tgz"
},
"vscode-languageserver-protocol": {
"version": "3.5.0-next.5",
"from": "vscode-languageserver-protocol@3.5.0-next.5",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0-next.5.tgz"
"version": "3.5.0",
"from": "vscode-languageserver-protocol@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz"
},
"vscode-languageserver-types": {
"version": "3.5.0-next.2",
"from": "vscode-languageserver-types@3.5.0-next.2",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0-next.2.tgz"
"version": "3.5.0",
"from": "vscode-languageserver-types@>=3.5.0 <4.0.0",
"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz"
},
"vscode-nls": {
"version": "2.0.2",
......@@ -74,7 +74,7 @@
},
"vscode-uri": {
"version": "1.0.1",
"from": "vscode-uri@>=1.0.0 <2.0.0",
"from": "vscode-uri@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.1.tgz"
}
}
......
......@@ -10,8 +10,8 @@
"dependencies": {
"jsonc-parser": "^1.0.0",
"request-light": "^0.2.1",
"vscode-json-languageservice": "3.0.0",
"vscode-languageserver": "3.5.0-next.6",
"vscode-json-languageservice": "^3.0.1",
"vscode-languageserver": "^3.5.0",
"vscode-nls": "^2.0.2",
"vscode-uri": "^1.0.1"
},
......
......@@ -482,7 +482,7 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG
return parsedExpression(<IExpression>arg1, options);
}
function isRelativePattern(obj: any): obj is IRelativePattern {
export function isRelativePattern(obj: any): obj is IRelativePattern {
const rp = obj as IRelativePattern;
return typeof rp.base === 'string' && typeof rp.pattern === 'string';
......
......@@ -370,7 +370,7 @@ export class TernarySearchTree<E> {
this._root = undefined;
}
set(key: string, element: E): void {
set(key: string, element: E): E {
let iter = this._iter.reset(key);
let node: TernarySearchTreeNode<E>;
......@@ -410,7 +410,9 @@ export class TernarySearchTree<E> {
break;
}
}
const oldElement = node.element;
node.element = element;
return oldElement;
}
get(key: string): E {
......
......@@ -78,7 +78,7 @@ export interface IConfigurationService {
reloadConfiguration(): TPromise<void>;
reloadConfiguration(folder: IWorkspaceFolder): TPromise<void>;
inspect<T>(key: string): {
inspect<T>(key: string, overrides?: IConfigurationOverrides): {
default: T,
user: T,
workspace: T,
......
......@@ -338,12 +338,12 @@ export class Configuration {
const folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace);
const memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration;
return {
default: getConfigurationValue<C>(overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).contents : this._defaultConfiguration.freeze().contents, key),
user: getConfigurationValue<C>(overrides.overrideIdentifier ? this._userConfiguration.freeze().override(overrides.overrideIdentifier).contents : this._userConfiguration.freeze().contents, key),
workspace: workspace ? getConfigurationValue<C>(overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().override(overrides.overrideIdentifier).contents : this._workspaceConfiguration.freeze().contents, key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null
workspaceFolder: folderConfigurationModel ? getConfigurationValue<C>(overrides.overrideIdentifier ? folderConfigurationModel.freeze().override(overrides.overrideIdentifier).contents : folderConfigurationModel.freeze().contents, key) : void 0,
memory: getConfigurationValue<C>(overrides.overrideIdentifier ? memoryConfigurationModel.freeze().override(overrides.overrideIdentifier).contents : memoryConfigurationModel.freeze().contents, key),
value: getConfigurationValue<C>(consolidateConfigurationModel.contents, key)
default: overrides.overrideIdentifier ? this._defaultConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._defaultConfiguration.freeze().getValue(key),
user: overrides.overrideIdentifier ? this._userConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._userConfiguration.freeze().getValue(key),
workspace: workspace ? overrides.overrideIdentifier ? this._workspaceConfiguration.freeze().override(overrides.overrideIdentifier).getValue(key) : this._workspaceConfiguration.freeze().getValue(key) : void 0, //Check on workspace exists or not because _workspaceConfiguration is never null
workspaceFolder: folderConfigurationModel ? overrides.overrideIdentifier ? folderConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : folderConfigurationModel.freeze().getValue(key) : void 0,
memory: overrides.overrideIdentifier ? memoryConfigurationModel.freeze().override(overrides.overrideIdentifier).getValue(key) : memoryConfigurationModel.freeze().getValue(key),
value: consolidateConfigurationModel.getValue(key)
};
}
......@@ -354,12 +354,12 @@ export class Configuration {
workspaceFolder: string[];
} {
const folderConfigurationModel = this.getFolderConfigurationModelForResource(null, workspace);
return objects.deepClone({
return {
default: this._defaultConfiguration.freeze().keys,
user: this._userConfiguration.freeze().keys,
workspace: this._workspaceConfiguration.freeze().keys,
workspaceFolder: folderConfigurationModel ? folderConfigurationModel.freeze().keys : []
});
};
}
updateDefaultConfiguration(defaultConfiguration: ConfigurationModel): void {
......@@ -446,8 +446,14 @@ export class Configuration {
private getFolderConsolidatedConfiguration(folder: URI): ConfigurationModel {
let folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);
if (!folderConsolidatedConfiguration) {
folderConsolidatedConfiguration = this.getWorkspaceConsolidatedConfiguration().merge(this._folderConfigurations.get(folder)).freeze();
this._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);
const workspaceConsolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();
const folderConfiguration = this._folderConfigurations.get(folder);
if (folderConfiguration) {
folderConsolidatedConfiguration = workspaceConsolidateConfiguration.merge(folderConfiguration).freeze();
this._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);
} else {
folderConsolidatedConfiguration = workspaceConsolidateConfiguration;
}
}
return folderConsolidatedConfiguration;
}
......
......@@ -449,6 +449,14 @@ export interface IContent extends IBaseStat {
encoding: string;
}
// this should eventually replace IContent such
// that we have a clear separation between content
// and metadata (TODO@Joh, TODO@Ben)
export interface IContentData {
encoding: string;
stream: IStringStream;
}
/**
* A Stream emitting strings.
*/
......
......@@ -8,6 +8,7 @@
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// --- other interested parties
import { JSONValidationExtensionPoint } from 'vs/platform/jsonschemas/common/jsonValidationExtensionPoint';
......@@ -64,6 +65,4 @@ export class ExtensionPoints implements IWorkbenchContribution {
}
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
ExtensionPoints
);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ExtensionPoints, LifecyclePhase.Starting);
......@@ -14,7 +14,7 @@ import { MainThreadWorkspaceShape, ExtHostWorkspaceShape, ExtHostContext, MainCo
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IRelativePattern } from 'vs/base/common/glob';
import { IRelativePattern, isRelativePattern } from 'vs/base/common/glob';
@extHostNamedCustomer(MainContext.MainThreadWorkspace)
export class MainThreadWorkspace implements MainThreadWorkspaceShape {
......@@ -61,10 +61,14 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
let folderQueries: IFolderQuery[];
if (typeof include === 'string' || !include) {
folderQueries = workspace.folders.map(folder => ({ folder: folder.uri })); // absolute pattern: search across all folders
} else {
} else if (isRelativePattern(include)) {
folderQueries = [{ folder: URI.file(include.base) }]; // relative pattern: search only in base folder
}
if (!folderQueries) {
return undefined; // invalid query parameters
}
const useRipgrep = folderQueries.every(folderQuery => {
const folderConfig = this._configurationService.getValue<ISearchConfiguration>({ resource: folderQuery.folder });
return folderConfig.search.useRipgrep;
......
......@@ -408,9 +408,11 @@ class NavigateTypeAdapter {
return asWinJsPromise(token => this._provider.provideWorkspaceSymbols(search, token)).then(value => {
if (!isFalsyOrEmpty(value)) {
for (const item of value) {
const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item));
this._symbolCache[symbol._id] = item;
result.symbols.push(symbol);
if (item) {
const symbol = IdObject.mixin(TypeConverters.fromSymbolInformation(item));
this._symbolCache[symbol._id] = item;
result.symbols.push(symbol);
}
}
}
}).then(() => {
......
......@@ -35,7 +35,7 @@ export interface IWorkbenchContributionsRegistry {
*
* @param phase the lifecycle phase when to instantiate the contribution.
*/
registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase?: LifecyclePhase): void;
registerWorkbenchContribution(contribution: IWorkbenchContributionSignature, phase: LifecyclePhase): void;
/**
* Starts the registry by providing the required services.
......
......@@ -9,13 +9,10 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { BackupModelTracker } from 'vs/workbench/parts/backup/common/backupModelTracker';
import { BackupRestorer } from 'vs/workbench/parts/backup/common/backupRestorer';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// Register Backup Model Tracker
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
BackupModelTracker
);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BackupModelTracker, LifecyclePhase.Starting);
// Register Backup Restorer
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
BackupRestorer
);
\ No newline at end of file
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(BackupRestorer, LifecyclePhase.Starting);
\ No newline at end of file
......@@ -46,6 +46,7 @@ import { DebugViewlet, FocusVariablesViewAction, FocusBreakpointsViewAction, Foc
import { Repl } from 'vs/workbench/parts/debug/electron-browser/repl';
import { DebugQuickOpenHandler } from 'vs/workbench/parts/debug/browser/debugQuickOpen';
import { DebugStatus } from 'vs/workbench/parts/debug/browser/debugStatus';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
class OpenDebugViewletAction extends ToggleViewletAction {
public static ID = VIEWLET_ID;
......@@ -113,10 +114,10 @@ const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryEx
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View"));
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugActionsWidget);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager, LifecyclePhase.Starting);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugActionsWidget, LifecyclePhase.Starting);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, LifecyclePhase.Starting);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Starting);
const debugCategory = nls.localize('debugCategory', "Debug");
registry.registerWorkbenchAction(new SyncActionDescriptor(
......
......@@ -39,6 +39,7 @@ import { KeymapExtensions, BetterMergeDisabled } from 'vs/workbench/parts/extens
import { adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { GalleryExtensionsHandler, ExtensionsHandler } from 'vs/workbench/parts/extensions/browser/extensionsQuickOpen';
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// Singletons
registerSingleton(IExtensionGalleryService, ExtensionGalleryService);
......@@ -46,9 +47,9 @@ registerSingleton(IExtensionTipsService, ExtensionTipsService);
registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService);
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(StatusUpdater);
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions);
workbenchRegistry.registerWorkbenchContribution(BetterMergeDisabled);
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Running);
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Running);
workbenchRegistry.registerWorkbenchContribution(BetterMergeDisabled, LifecyclePhase.Running);
Registry.as<IOutputChannelRegistry>(OutputExtensions.OutputChannels)
.registerChannel(ExtensionsChannelId, ExtensionsLabel);
......
......@@ -294,6 +294,11 @@ export class ExtensionsListView extends ViewsViewletPanel {
.then(workspaceRecommendations => {
const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, workspaceRecommendations);
/* __GDPR__
"extensionAllRecommendations:open" : {
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionAllRecommendations:open', { count: names.length });
if (!names.length) {
return TPromise.as(new PagedModel([]));
......@@ -314,28 +319,34 @@ export class ExtensionsListView extends ViewsViewletPanel {
return this.extensionsWorkbenchService.queryLocal()
.then(result => result.filter(e => e.type === LocalExtensionType.User))
.then(local => {
const installedExtensions = local.map(x => `${x.publisher}.${x.name}`);
let fileBasedRecommendations = this.tipsService.getFileBasedRecommendations();
let others = this.tipsService.getOtherRecommendations();
const installedExtensions = local.map(x => `${x.publisher}.${x.name}`);
return this.tipsService.getWorkspaceRecommendations()
.then(workspaceRecommendations => {
workspaceRecommendations = workspaceRecommendations.map(x => x.toLowerCase());
fileBasedRecommendations = fileBasedRecommendations.filter(x => workspaceRecommendations.indexOf(x.toLowerCase()) === -1);
others = others.filter(x => workspaceRecommendations.indexOf(x.toLowerCase()) === -1);
const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, []);
const names = this.getTrimmedRecommendations(installedExtensions, value, fileBasedRecommendations, others, []);
/* __GDPR__
"extensionRecommendations:open" : {
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:open', { count: names.length });
/* __GDPR__
"extensionRecommendations:open" : {
"count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('extensionRecommendations:open', { count: names.length });
if (!names.length) {
return TPromise.as(new PagedModel([]));
}
options.source = 'recommendations';
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
.then(pager => {
this.sortFirstPage(pager, names);
return new PagedModel(pager || []);
if (!names.length) {
return TPromise.as(new PagedModel([]));
}
options.source = 'recommendations';
return this.extensionsWorkbenchService.queryGallery(assign(options, { names, pageSize: names.length }))
.then(pager => {
this.sortFirstPage(pager, names);
return new PagedModel(pager || []);
});
});
});
}
......
......@@ -32,6 +32,7 @@ import { DirtyFilesTracker } from 'vs/workbench/parts/files/common/dirtyFilesTra
import { ExplorerViewlet } from 'vs/workbench/parts/files/browser/explorerViewlet';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { DataUriEditorInput } from 'vs/workbench/common/editor/dataUriEditorInput';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// Viewlet Action
export class OpenExplorerViewletAction extends ToggleViewletAction {
......@@ -139,19 +140,13 @@ class FileEditorInputFactory implements IEditorInputFactory {
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(FILE_EDITOR_INPUT_ID, FileEditorInputFactory);
// Register File Editor Tracker
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
FileEditorTracker
);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileEditorTracker, LifecyclePhase.Starting);
// Register Save Error Handler
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
SaveErrorHandler
);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(SaveErrorHandler, LifecyclePhase.Starting);
// Register Dirty Files Tracker
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
DirtyFilesTracker
);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesTracker, LifecyclePhase.Starting);
// Configuration
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
......
......@@ -17,6 +17,7 @@ import Severity from 'vs/base/common/severity';
import { editorErrorForeground, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
class MarkersDecorationsProvider implements IDecorationsProvider {
......@@ -95,7 +96,7 @@ class MarkersFileDecorations implements IWorkbenchContribution {
}
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MarkersFileDecorations, LifecyclePhase.Running);
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).registerConfiguration({
'id': 'problems',
......
......@@ -31,10 +31,7 @@ class StartupProfiler implements IWorkbenchContribution {
@IExtensionService extensionService: IExtensionService,
) {
// wait for everything to be ready
TPromise.join<any>([
lifecycleService.when(LifecyclePhase.Running),
extensionService.onReady(),
]).then(() => {
extensionService.onReady().then(() => {
this._stopProfiling();
});
}
......@@ -92,4 +89,4 @@ class StartupProfiler implements IWorkbenchContribution {
}
const registry = Registry.as<IWorkbenchContributionsRegistry>(Extensions.Workbench);
registry.registerWorkbenchContribution(StartupProfiler);
registry.registerWorkbenchContribution(StartupProfiler, LifecyclePhase.Running);
......@@ -30,6 +30,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
registerSingleton(IPreferencesService, PreferencesService);
......@@ -257,7 +258,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContribution);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(PreferencesContribution, LifecyclePhase.Starting);
CommandsRegistry.registerCommand(OPEN_FOLDER_SETTINGS_COMMAND, function (accessor: ServicesAccessor, args?: IWorkspaceFolder) {
const preferencesService = accessor.get(IPreferencesService);
......
......@@ -14,6 +14,7 @@ import { ArrayNavigator, INavigator } from 'vs/base/common/iterator';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { SideBySideEditorInput, EditorOptions, EditorInput } from 'vs/workbench/common/editor';
import { Scope } from 'vs/workbench/common/memento';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel';
import { IEditorControl, Position, Verbosity } from 'vs/platform/editor/common/editor';
......@@ -24,7 +25,7 @@ import { CodeEditor } from 'vs/editor/browser/codeEditor';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import {
IPreferencesService, ISettingsGroup, ISetting, IFilterResult,
CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING
CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, ISettingsEditorModel, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, IFilterMetadata
} from 'vs/workbench/parts/preferences/common/preferences';
import { SettingsEditorModel, DefaultSettingsEditorModel } from 'vs/workbench/parts/preferences/common/preferencesModels';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
......@@ -113,6 +114,7 @@ export class PreferencesEditor extends BaseEditor {
private latestEmptyFilters: string[] = [];
private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget = null;
private memento: any;
constructor(
@IPreferencesService private preferencesService: IPreferencesService,
......@@ -122,6 +124,7 @@ export class PreferencesEditor extends BaseEditor {
@IInstantiationService private instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
@IStorageService storageService: IStorageService,
) {
super(PreferencesEditor.ID, telemetryService, themeService);
this.defaultSettingsEditorContextKey = CONTEXT_SETTINGS_EDITOR.bindTo(this.contextKeyService);
......@@ -129,6 +132,7 @@ export class PreferencesEditor extends BaseEditor {
this.delayedFilterLogging = new Delayer<void>(1000);
this.searchProvider = this.instantiationService.createInstance(PreferencesSearchProvider);
this.filterThrottle = new ThrottledDelayer(200);
this.memento = this.getMemento(storageService, Scope.WORKSPACE);
}
public createEditor(parent: Builder): void {
......@@ -143,6 +147,7 @@ export class PreferencesEditor extends BaseEditor {
focusKey: this.focusSettingsContextKey
}));
this.searchWidget.setFuzzyToggleVisible(this.searchProvider.remoteSearchEnabled);
this.searchWidget.fuzzyEnabled = this.memento['fuzzyEnabled'];
this._register(this.searchProvider.onRemoteSearchEnablementChanged(enabled => this.searchWidget.setFuzzyToggleVisible(enabled)));
this._register(this.searchWidget.onDidChange(value => this.onInputChanged()));
this._register(this.searchWidget.onFocus(() => this.lastFocusedWidget = this.searchWidget));
......@@ -323,14 +328,17 @@ export class PreferencesEditor extends BaseEditor {
}
private filterPreferences(): TPromise<void> {
this.memento['fuzzyEnabled'] = this.searchWidget.fuzzyEnabled;
const filter = this.searchWidget.getValue().trim();
return this.preferencesRenderers.filterPreferences(filter, this.searchProvider, this.searchWidget.fuzzyEnabled).then(count => {
return this.preferencesRenderers.filterPreferences(filter, this.searchProvider, this.searchWidget.fuzzyEnabled).then(result => {
const count = result.count;
const message = filter ? this.showSearchResultsMessage(count) : nls.localize('totalSettingsMessage', "Total {0} Settings", count);
this.searchWidget.showMessage(message, count);
if (count === 0) {
this.latestEmptyFilters.push(filter);
}
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter));
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter, result.metadata));
}, onUnexpectedError);
}
......@@ -340,17 +348,22 @@ export class PreferencesEditor extends BaseEditor {
nls.localize('settingsFound', "{0} Settings matched", count);
}
private reportFilteringUsed(filter: string): void {
private reportFilteringUsed(filter: string, metadata?: IFilterMetadata): void {
if (filter) {
let data = {
filter,
emptyFilters: this.getLatestEmptyFiltersForTelemetry()
emptyFilters: this.getLatestEmptyFiltersForTelemetry(),
fuzzy: !!metadata,
duration: metadata ? metadata.duration : undefined
};
this.latestEmptyFilters = [];
/* __GDPR__
"defaultSettings.filter" : {
"filter": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"fuzzy" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('defaultSettings.filter', data);
......@@ -423,7 +436,7 @@ class PreferencesRenderers extends Disposable {
this._disposables = dispose(this._disposables);
if (this._defaultPreferencesRenderer) {
this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source }) => this._updatePreference(key, value, source, this._editablePreferencesRenderer), this, this._disposables);
this._defaultPreferencesRenderer.onUpdatePreference(({ key, value, source, index }) => this._updatePreference(key, value, source, index, this._editablePreferencesRenderer), this, this._disposables);
this._defaultPreferencesRenderer.onFocusPreference(preference => this._focusPreference(preference, this._editablePreferencesRenderer), this, this._disposables);
this._defaultPreferencesRenderer.onClearFocusPreference(preference => this._clearFocus(preference, this._editablePreferencesRenderer), this, this._disposables);
if (this._defaultPreferencesRenderer.onTriggeredFuzzy) {
......@@ -437,7 +450,7 @@ class PreferencesRenderers extends Disposable {
this._editablePreferencesRenderer = editableSettingsRenderer;
}
public filterPreferences(filter: string, searchProvider: PreferencesSearchProvider, fuzzy: boolean): TPromise<number> {
public filterPreferences(filter: string, searchProvider: PreferencesSearchProvider, fuzzy: boolean): TPromise<{ count: number, metadata: IFilterMetadata }> {
if (this._filtersInProgress) {
// Resolved/rejected promises have no .cancel()
this._filtersInProgress.forEach(p => p.cancel && p.cancel());
......@@ -459,7 +472,7 @@ class PreferencesRenderers extends Disposable {
this._settingsNavigator = new SettingsNavigator(filter ? consolidatedSettings : []);
return consolidatedSettings.length;
return { count: consolidatedSettings.length, metadata: defaultPreferencesFilterResult && defaultPreferencesFilterResult.metadata };
});
}
......@@ -502,9 +515,9 @@ class PreferencesRenderers extends Disposable {
}
}
private _updatePreference(key: string, value: any, source: ISetting, preferencesRenderer: IPreferencesRenderer<ISetting>): void {
private _updatePreference(key: string, value: any, source: ISetting, index: number, preferencesRenderer: IPreferencesRenderer<ISetting>): void {
if (preferencesRenderer) {
preferencesRenderer.updatePreference(key, value, source);
preferencesRenderer.updatePreference(key, value, source, index);
}
}
......
......@@ -40,11 +40,11 @@ export interface IPreferencesRenderer<T> extends IDisposable {
onFocusPreference: Event<T>;
onClearFocusPreference: Event<T>;
onUpdatePreference: Event<{ key: string, value: any, source: T }>;
onUpdatePreference?: Event<{ key: string, value: any, source: T, index: number }>;
onTriggeredFuzzy?: Event<void>;
render(): void;
updatePreference(key: string, value: any, source: T): void;
updatePreference(key: string, value: any, source: T, index: number): void;
filterPreferences(filterResult: IFilterResult, fuzzySearchAvailable: boolean): void;
focusPreference(setting: T): void;
clearFocus(setting: T): void;
......@@ -61,9 +61,6 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
private _onFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
public readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>();
public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting }> = this._onUpdatePreference.event;
private _onClearFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
public readonly onClearFocusPreference: Event<ISetting> = this._onClearFocusPreference.event;
......@@ -79,7 +76,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
this.settingHighlighter = this._register(instantiationService.createInstance(SettingHighlighter, editor, this._onFocusPreference, this._onClearFocusPreference));
this.highlightMatchesRenderer = this._register(instantiationService.createInstance(HighlightMatchesRenderer, editor));
this.editSettingActionRenderer = this._register(this.instantiationService.createInstance(EditSettingRenderer, this.editor, this.preferencesModel, this.settingHighlighter));
this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source }) => this.updatePreference(key, value, source)));
this._register(this.editSettingActionRenderer.onUpdateSetting(({ key, value, source, index }) => this.updatePreference(key, value, source, index, true)));
this._register(this.editor.getModel().onDidChangeContent(() => this.modelChangeDelayer.trigger(() => this.onModelChanged())));
this.createHeader();
......@@ -105,13 +102,30 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
}
}
public updatePreference(key: string, value: any, source: ISetting): void {
public updatePreference(key: string, value: any, source: ISetting, index: number, fromEditableSettings?: boolean): void {
const data = {
userConfigurationKeys: [key]
};
if (this.filterResult) {
data['query'] = this.filterResult.query;
data['fuzzy'] = !!this.filterResult.metadata;
data['duration'] = this.filterResult.metadata && this.filterResult.metadata.duration;
data['index'] = index;
data['editableSide'] = !!fromEditableSettings;
}
/* __GDPR__
"defaultSettingsActions.copySetting" : {
"userConfigurationKeys" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"query" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"fuzzy" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"index" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"editableSide" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [key] });
this.telemetryService.publicLog('defaultSettingsActions.copySetting', data);
const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null;
const resource = this.preferencesModel.uri;
this.configurationService.updateValue(key, value, { overrideIdentifier, resource }, this.preferencesModel.configurationTarget)
......@@ -232,8 +246,8 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR
private editSettingActionRenderer: EditSettingRenderer;
private feedbackWidgetRenderer: FeedbackWidgetRenderer;
private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>();
public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting }> = this._onUpdatePreference.event;
private _onUpdatePreference: Emitter<{ key: string, value: any, source: ISetting, index: number }> = new Emitter<{ key: string, value: any, source: ISetting, index: number }>();
public readonly onUpdatePreference: Event<{ key: string, value: any, source: ISetting, index: number }> = this._onUpdatePreference.event;
private _onFocusPreference: Emitter<ISetting> = new Emitter<ISetting>();
public readonly onFocusPreference: Event<ISetting> = this._onFocusPreference.event;
......@@ -546,7 +560,6 @@ export class HiddenAreasRenderer extends Disposable {
export class FeedbackWidgetRenderer extends Disposable {
private static DEFAULT_COMMENT_TEXT = 'Replace this comment with any text feedback.';
private static DEFAULT_ALTS = ['alt 1', 'alt 2'];
private static INSTRUCTION_TEXT = [
'// Modify the "resultScores" section to contain only your expected results. Assign scores to indicate their relevance.',
'// Results present in "resultScores" will be automatically "boosted" for this query, if they are not already at the top of the result set.',
......@@ -591,7 +604,8 @@ export class FeedbackWidgetRenderer extends Disposable {
}
const result = this._currentResult;
const actualResultNames = Object.keys(result.metadata.scoredResults);
const actualResults = result.metadata.scoredResults;
const actualResultNames = Object.keys(actualResults);
const feedbackQuery: any = {};
feedbackQuery['comment'] = FeedbackWidgetRenderer.DEFAULT_COMMENT_TEXT;
......@@ -600,9 +614,12 @@ export class FeedbackWidgetRenderer extends Disposable {
actualResultNames.forEach(settingKey => {
feedbackQuery['resultScores'][settingKey] = 10;
});
feedbackQuery['alts'] = [FeedbackWidgetRenderer.DEFAULT_ALTS];
feedbackQuery['alts'] = [];
const contents = FeedbackWidgetRenderer.INSTRUCTION_TEXT + '\n' +
JSON.stringify(feedbackQuery, undefined, ' ') + '\n\n' +
actualResultNames.map(name => `// ${name}: ${result.metadata.scoredResults[name]}`).join('\n');
const contents = FeedbackWidgetRenderer.INSTRUCTION_TEXT + '\n' + JSON.stringify(feedbackQuery, undefined, ' ');
this.editorService.openEditor({ contents, language: 'json' }, /*sideBySide=*/true).then(feedbackEditor => {
const sendFeedbackWidget = this._register(this.instantiationService.createInstance(FloatingClickWidget, feedbackEditor.getControl(), 'Send feedback', null));
sendFeedbackWidget.render();
......@@ -638,7 +655,7 @@ export class FeedbackWidgetRenderer extends Disposable {
return TPromise.wrapError(new Error('alts must be an array of 2-element string arrays'));
}
const altsAdded = expectedQuery.alts && expectedQuery.alts[0] && (expectedQuery.alts[0][0] !== FeedbackWidgetRenderer.DEFAULT_ALTS[0] || expectedQuery.alts[0][1] !== FeedbackWidgetRenderer.DEFAULT_ALTS[1]);
const altsAdded = expectedQuery.alts && expectedQuery.alts.length;
const alts = altsAdded ? expectedQuery.alts : undefined;
const workbenchSettings = this.configurationService.getValue<IWorkbenchSettingsConfiguration>().workbench.settings;
const autoIngest = workbenchSettings.experimentalFuzzySearchAutoIngestFeedback;
......@@ -849,17 +866,21 @@ export class HighlightMatchesRenderer extends Disposable {
}
}
interface IIndexedSetting extends ISetting {
index: number;
}
class EditSettingRenderer extends Disposable {
private editPreferenceWidgetForCusorPosition: EditPreferenceWidget<ISetting>;
private editPreferenceWidgetForMouseMove: EditPreferenceWidget<ISetting>;
private editPreferenceWidgetForCusorPosition: EditPreferenceWidget<IIndexedSetting>;
private editPreferenceWidgetForMouseMove: EditPreferenceWidget<IIndexedSetting>;
private settingsGroups: ISettingsGroup[];
public associatedPreferencesModel: IPreferencesEditorModel<ISetting>;
private toggleEditPreferencesForMouseMoveDelayer: Delayer<void>;
private _onUpdateSetting: Emitter<{ key: string, value: any, source: ISetting }> = new Emitter<{ key: string, value: any, source: ISetting }>();
public readonly onUpdateSetting: Event<{ key: string, value: any, source: ISetting }> = this._onUpdateSetting.event;
private _onUpdateSetting: Emitter<{ key: string, value: any, source: ISetting, index: number }> = new Emitter<{ key: string, value: any, source: ISetting, index: number }>();
public readonly onUpdateSetting: Event<{ key: string, value: any, source: ISetting, index: number }> = this._onUpdateSetting.event;
constructor(private editor: ICodeEditor, private masterSettingsModel: ISettingsEditorModel,
private settingHighlighter: SettingHighlighter,
......@@ -920,7 +941,7 @@ class EditSettingRenderer extends Disposable {
return;
}
this.settingHighlighter.clear();
this.toggleEditPreferencesForMouseMoveDelayer.trigger(() => this.toggleEidtPreferenceWidgetForMouseMove(mouseMoveEvent));
this.toggleEditPreferencesForMouseMoveDelayer.trigger(() => this.toggleEditPreferenceWidgetForMouseMove(mouseMoveEvent));
}
private getEditPreferenceWidgetUnderMouse(mouseMoveEvent: IEditorMouseEvent): EditPreferenceWidget<ISetting> {
......@@ -936,7 +957,7 @@ class EditSettingRenderer extends Disposable {
return null;
}
private toggleEidtPreferenceWidgetForMouseMove(mouseMoveEvent: IEditorMouseEvent): void {
private toggleEditPreferenceWidgetForMouseMove(mouseMoveEvent: IEditorMouseEvent): void {
const settings = mouseMoveEvent.target.position ? this.getSettings(mouseMoveEvent.target.position.lineNumber) : null;
if (settings && settings.length) {
this.showEditPreferencesWidget(this.editPreferenceWidgetForMouseMove, settings);
......@@ -945,7 +966,7 @@ class EditSettingRenderer extends Disposable {
}
}
private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget<ISetting>, settings: ISetting[]) {
private showEditPreferencesWidget(editPreferencesWidget: EditPreferenceWidget<ISetting>, settings: IIndexedSetting[]) {
const line = settings[0].valueRange.startLineNumber;
if (this.editor.getConfiguration().viewInfo.glyphMargin && this.marginFreeFromOtherDecorations(line)) {
editPreferencesWidget.show(line, nls.localize('editTtile', "Edit"), settings);
......@@ -966,7 +987,7 @@ class EditSettingRenderer extends Disposable {
return true;
}
private getSettings(lineNumber: number): ISetting[] {
private getSettings(lineNumber: number): IIndexedSetting[] {
const configurationMap = this.getConfigurationsMap();
return this.getSettingsAtLineNumber(lineNumber).filter(setting => {
let configurationNode = configurationMap[setting.key];
......@@ -991,7 +1012,10 @@ class EditSettingRenderer extends Disposable {
});
}
private getSettingsAtLineNumber(lineNumber: number): ISetting[] {
private getSettingsAtLineNumber(lineNumber: number): IIndexedSetting[] {
// index of setting, across all groups/sections
let index = 0;
const settings = [];
for (const group of this.settingsGroups) {
if (group.range.startLineNumber > lineNumber) {
......@@ -1008,13 +1032,15 @@ class EditSettingRenderer extends Disposable {
// Only one level because override settings cannot have override settings
for (const overrideSetting of setting.overrides) {
if (lineNumber >= overrideSetting.range.startLineNumber && lineNumber <= overrideSetting.range.endLineNumber) {
settings.push(overrideSetting);
settings.push({ ...overrideSetting, index });
}
}
} else {
settings.push(setting);
settings.push({ ...setting, index });
}
}
index++;
}
}
}
......@@ -1026,7 +1052,7 @@ class EditSettingRenderer extends Disposable {
this.settingHighlighter.highlight(editPreferenceWidget.preferences[0]);
}
private onEditSettingClicked(editPreferenceWidget: EditPreferenceWidget<ISetting>, e: IEditorMouseEvent): void {
private onEditSettingClicked(editPreferenceWidget: EditPreferenceWidget<IIndexedSetting>, e: IEditorMouseEvent): void {
const anchor = { x: e.event.posx, y: e.event.posy + 10 };
const actions = this.getSettings(editPreferenceWidget.getLine()).length === 1 ? this.getActions(editPreferenceWidget.preferences[0], this.getConfigurationsMap()[editPreferenceWidget.preferences[0].key])
: editPreferenceWidget.preferences.map(setting => new ContextSubMenu(setting.key, this.getActions(setting, this.getConfigurationsMap()[setting.key])));
......@@ -1040,7 +1066,7 @@ class EditSettingRenderer extends Disposable {
return Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
}
private getActions(setting: ISetting, jsonSchema: IJSONSchema): IAction[] {
private getActions(setting: IIndexedSetting, jsonSchema: IJSONSchema): IAction[] {
if (jsonSchema.type === 'boolean') {
return [<IAction>{
id: 'truthyValue',
......@@ -1067,7 +1093,7 @@ class EditSettingRenderer extends Disposable {
return this.getDefaultActions(setting);
}
private getDefaultActions(setting: ISetting): IAction[] {
private getDefaultActions(setting: IIndexedSetting): IAction[] {
if (this.isDefaultSettings()) {
const settingInOtherModel = this.associatedPreferencesModel.getPreference(setting.key);
return [<IAction>{
......@@ -1080,8 +1106,8 @@ class EditSettingRenderer extends Disposable {
return [];
}
private updateSetting(key: string, value: any, source: ISetting): void {
this._onUpdateSetting.fire({ key, value, source });
private updateSetting(key: string, value: any, source: IIndexedSetting): void {
this._onUpdateSetting.fire({ key, value, source, index: source.index });
}
}
......
......@@ -130,7 +130,12 @@ class RemoteSearchProvider {
};
if (remoteResult) {
const sortedNames = Object.keys(remoteResult.scoredResults).sort((a, b) => remoteResult.scoredResults[b] - remoteResult.scoredResults[a]);
let sortedNames = Object.keys(remoteResult.scoredResults).sort((a, b) => remoteResult.scoredResults[b] - remoteResult.scoredResults[a]);
if (sortedNames.length) {
const highScore = remoteResult.scoredResults[sortedNames[0]];
sortedNames = sortedNames.filter(name => remoteResult.scoredResults[name] >= highScore / 2);
}
const result = preferencesModel.filterSettings(this._filter, group => null, settingFilter, sortedNames);
result.metadata = remoteResult;
return result;
......
......@@ -19,6 +19,7 @@ import { RunOnceScheduler } from 'vs/base/common/async';
import URI from 'vs/base/common/uri';
import { isEqual } from 'vs/base/common/resources';
import { isLinux } from 'vs/base/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
interface IConfiguration extends IWindowsConfiguration {
update: { channel: string; };
......@@ -161,4 +162,4 @@ export class SettingsChangeRelauncher implements IWorkbenchContribution {
}
const workbenchRegistry = <IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(SettingsChangeRelauncher);
workbenchRegistry.registerWorkbenchContribution(SettingsChangeRelauncher, LifecyclePhase.Running);
......@@ -18,6 +18,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { StatusUpdater, StatusBarController } from './scmActivity';
import { SCMViewlet } from 'vs/workbench/parts/scm/electron-browser/scmViewlet';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
class OpenSCMViewletAction extends ToggleViewletAction {
......@@ -30,7 +31,7 @@ class OpenSCMViewletAction extends ToggleViewletAction {
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(DirtyDiffWorkbenchController);
.registerWorkbenchContribution(DirtyDiffWorkbenchController, LifecyclePhase.Starting);
const viewletDescriptor = new ViewletDescriptor(
SCMViewlet,
......@@ -44,10 +45,10 @@ Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets)
.registerViewlet(viewletDescriptor);
Registry.as(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(StatusUpdater);
.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Starting);
Registry.as(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(StatusBarController);
.registerWorkbenchContribution(StatusBarController, LifecyclePhase.Starting);
// Register Action to Open Viewlet
Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction(
......
......@@ -7,8 +7,9 @@ import { IReplaceService } from 'vs/workbench/parts/search/common/replace';
import { ReplaceService, ReplacePreviewContentProvider } from 'vs/workbench/parts/search/browser/replaceService';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
export function registerContributions(): void {
registerSingleton(IReplaceService, ReplaceService);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ReplacePreviewContentProvider);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(ReplacePreviewContentProvider, LifecyclePhase.Starting);
}
......@@ -19,6 +19,7 @@ import { FileChangeType, IFileService } from 'vs/platform/files/common/files';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import pkg from 'vs/platform/node/package';
import product, { ISurveyData } from 'vs/platform/node/product';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
class LanguageSurvey {
......@@ -144,5 +145,5 @@ class LanguageSurveysContribution implements IWorkbenchContribution {
if (language === 'en' && product.surveys && product.surveys.length) {
const workbenchRegistry = <IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(LanguageSurveysContribution);
workbenchRegistry.registerWorkbenchContribution(LanguageSurveysContribution, LifecyclePhase.Running);
}
\ No newline at end of file
......@@ -17,6 +17,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import pkg from 'vs/platform/node/package';
import product from 'vs/platform/node/product';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
const PROBABILITY = 0.15;
const SESSION_COUNT_KEY = 'nps/sessionCount';
......@@ -96,5 +97,5 @@ class NPSContribution implements IWorkbenchContribution {
if (language === 'en' && product.npsSurveyUrl) {
const workbenchRegistry = <IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(NPSContribution);
workbenchRegistry.registerWorkbenchContribution(NPSContribution, LifecyclePhase.Running);
}
\ No newline at end of file
......@@ -2384,8 +2384,6 @@ statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(TaskStatusBa
let outputChannelRegistry = <IOutputChannelRegistry>Registry.as(OutputExt.OutputChannels);
outputChannelRegistry.registerChannel(TaskService.OutputChannelId, TaskService.OutputChannelLabel);
// (<IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution(TaskServiceParticipant);
// tasks.json validation
let schemaId = 'vscode://schemas/tasks';
let schema: IJSONSchema = {
......
......@@ -11,7 +11,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { Action } from 'vs/base/common/actions';
import { IWorkbenchContributionsRegistry, IWorkbenchContribution, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { Registry } from 'vs/platform/registry/common/platform';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IMessageService, Severity } from 'vs/platform/message/common/message';
import { IPreferencesService } from 'vs/workbench/parts/preferences/common/preferences';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
......@@ -110,4 +110,4 @@ class UnsupportedWorkspaceSettingsContribution implements IWorkbenchContribution
}
const workbenchRegistry = <IWorkbenchContributionsRegistry>Registry.as(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(UnsupportedWorkspaceSettingsContribution);
workbenchRegistry.registerWorkbenchContribution(UnsupportedWorkspaceSettingsContribution, LifecyclePhase.Running);
......@@ -18,13 +18,14 @@ import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update';
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(ProductContribution);
.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Running);
if (process.platform === 'win32' && process.arch === 'ia32') {
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(Win3264BitContribution);
.registerWorkbenchContribution(Win3264BitContribution, LifecyclePhase.Running);
}
Registry.as<IGlobalActivityRegistry>(GlobalActivityExtensions)
......
......@@ -118,12 +118,10 @@ export class WatermarkContribution implements IWorkbenchContribution {
this.workbenchState = contextService.getWorkbenchState();
lifecycleService.onShutdown(this.dispose, this);
lifecycleService.when(LifecyclePhase.Running).then(() => {
this.enabled = this.configurationService.getValue<boolean>(WORKBENCH_TIPS_ENABLED_KEY);
if (this.enabled) {
this.create();
}
});
this.enabled = this.configurationService.getValue<boolean>(WORKBENCH_TIPS_ENABLED_KEY);
if (this.enabled) {
this.create();
}
this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) {
const enabled = this.configurationService.getValue<boolean>(WORKBENCH_TIPS_ENABLED_KEY);
......@@ -212,7 +210,7 @@ export class WatermarkContribution implements IWorkbenchContribution {
}
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(WatermarkContribution);
.registerWorkbenchContribution(WatermarkContribution, LifecyclePhase.Running);
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
.registerConfiguration({
......
......@@ -7,7 +7,8 @@
import { Registry } from 'vs/platform/registry/common/platform';
import { GettingStarted } from './gettingStarted';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
Registry
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(GettingStarted);
\ No newline at end of file
.registerWorkbenchContribution(GettingStarted, LifecyclePhase.Running);
\ No newline at end of file
......@@ -12,6 +12,7 @@ import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/wor
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
.registerConfiguration({
......@@ -34,7 +35,7 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
});
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(WelcomePageContribution);
.registerWorkbenchContribution(WelcomePageContribution, LifecyclePhase.Running);
Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
.registerWorkbenchAction(new SyncActionDescriptor(WelcomePageAction, WelcomePageAction.ID, WelcomePageAction.LABEL), 'Help: Welcome', localize('help', "Help"));
......
......@@ -28,7 +28,7 @@ import { IMessageService, Severity, CloseAction } from 'vs/platform/message/comm
import { getInstalledExtensions, IExtensionStatus, onExtensionChanged, isKeymapExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsUtils';
import { IExtensionEnablementService, IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { used } from 'vs/workbench/parts/welcome/page/electron-browser/vs_code_welcome_page';
import { ILifecycleService, StartupKind, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { tildify } from 'vs/base/common/labels';
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
......@@ -58,10 +58,7 @@ export class WelcomePageContribution implements IWorkbenchContribution {
) {
const enabled = isWelcomePageEnabled(configurationService);
if (enabled && lifecycleService.startupKind !== StartupKind.ReloadedWindow) {
TPromise.join([
backupFileService.hasBackups(),
lifecycleService.when(LifecyclePhase.Running)
]).then(([hasBackups]) => {
backupFileService.hasBackups().then(hasBackups => {
const activeInput = editorService.getActiveEditorInput();
if (!activeInput && !hasBackups) {
return instantiationService.createInstance(WelcomePage)
......
......@@ -20,6 +20,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
.registerEditor(new EditorDescriptor(
......@@ -37,10 +38,10 @@ Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions)
Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(EditorWalkThroughInputFactory.ID, EditorWalkThroughInputFactory);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(WalkThroughContentProvider);
.registerWorkbenchContribution(WalkThroughContentProvider, LifecyclePhase.Starting);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(WalkThroughSnippetContentProvider);
.registerWorkbenchContribution(WalkThroughSnippetContentProvider, LifecyclePhase.Starting);
Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions)
.registerWorkbenchAction(new SyncActionDescriptor(WalkThroughArrowUpAction, WalkThroughArrowUpAction.ID, WalkThroughArrowUpAction.LABEL, { primary: KeyCode.UpArrow }, ContextKeyExpr.and(WALK_THROUGH_FOCUS, EditorContextKeys.textFocus.toNegated())), 'Interactive Playground: Scroll Up (Line)', localize('interactivePlayground', "Interactive Playground"));
......
......@@ -218,22 +218,14 @@ export class Configuration extends BaseConfiguration {
}
compare(other: Configuration): string[] {
let from = other.allKeys();
let to = this.allKeys();
const added = to.filter(key => from.indexOf(key) === -1);
const removed = from.filter(key => to.indexOf(key) === -1);
const updated = [];
for (const key of from) {
const value1 = this.getValue(key);
const value2 = other.getValue(key);
if (!equals(value1, value2)) {
updated.push(key);
const result = [];
for (const key of this.allKeys()) {
if (!equals(this.getValue(key), other.getValue(key))
|| (this._workspace && this._workspace.folders.some(folder => !equals(this.getValue(key, { resource: folder.uri }), other.getValue(key, { resource: folder.uri }))))) {
result.push(key);
}
}
return [...added, ...removed, ...updated];
return result;
}
allKeys(): string[] {
......
......@@ -265,7 +265,7 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
memory?: T,
value: T
} {
return this._configuration.inspect<T>(key);
return this._configuration.inspect<T>(key, overrides);
}
keys(): {
......@@ -345,34 +345,37 @@ export class WorkspaceService extends Disposable implements IWorkspaceConfigurat
}
private updateWorkspaceAndInitializeConfiguration(workspace: Workspace): TPromise<void> {
let folderChanges: IWorkspaceFoldersChangeEvent;
if (this.workspace) {
const currentState = this.getWorkbenchState();
const currentWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
const currentFolders = this.workspace.folders;
const hasWorkspaceBefore = !!this.workspace;
let previousState;
let previousWorkspacePath;
let previousFolders;
if (hasWorkspaceBefore) {
previousState = this.getWorkbenchState();
previousWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
previousFolders = this.workspace.folders;
this.workspace.update(workspace);
const newState = this.getWorkbenchState();
if (newState !== currentState) {
this._onDidChangeWorkbenchState.fire(newState);
}
const newWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
if (newWorkspacePath !== currentWorkspacePath || newState !== currentState) {
this._onDidChangeWorkspaceName.fire();
}
folderChanges = this.compareFolders(currentFolders, this.workspace.folders);
} else {
this.workspace = workspace;
}
return this.initializeConfiguration().then(() => {
// Trigger folders change after configuration initialization so that configuration is up to date.
if (folderChanges && (folderChanges.added.length || folderChanges.removed.length || folderChanges.changed.length)) {
this._onDidChangeWorkspaceFolders.fire(folderChanges);
// Trigger changes after configuration initialization so that configuration is up to date.
if (hasWorkspaceBefore) {
const newState = this.getWorkbenchState();
if (previousState && newState !== previousState) {
this._onDidChangeWorkbenchState.fire(newState);
}
const newWorkspacePath = this.workspace.configuration ? this.workspace.configuration.fsPath : void 0;
if (previousWorkspacePath && newWorkspacePath !== previousWorkspacePath || newState !== previousState) {
this._onDidChangeWorkspaceName.fire();
}
const folderChanges = this.compareFolders(previousFolders, this.workspace.folders);
if (folderChanges && (folderChanges.added.length || folderChanges.removed.length || folderChanges.changed.length)) {
this._onDidChangeWorkspaceFolders.fire(folderChanges);
}
}
});
}
......
......@@ -23,7 +23,7 @@ import { WorkspaceService } from 'vs/workbench/services/configuration/node/confi
import { ConfigurationEditingErrorCode } from 'vs/workbench/services/configuration/node/configurationEditingService';
import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget, IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { workbenchInstantiationService, TestTextResourceConfigurationService, TestTextFileService, TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
import { FileService } from 'vs/workbench/services/files/node/fileService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
......@@ -33,6 +33,7 @@ import { TextModelResolverService } from 'vs/workbench/services/textmodelResolve
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
import { JSONEditingService } from 'vs/workbench/services/configuration/node/jsonEditingService';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
class SettingsTestEnvironmentService extends EnvironmentService {
......@@ -295,6 +296,258 @@ suite('WorkspaceContextService - Workspace', () => {
});
suite('WorkspaceService - Initialization', () => {
let parentResource: string, workspaceConfigPath: string, testObject: WorkspaceService, globalSettingsFile: string;
const configurationRegistry = <IConfigurationRegistry>Registry.as(ConfigurationExtensions.Configuration);
suiteSetup(() => {
configurationRegistry.registerConfiguration({
'id': '_test',
'type': 'object',
'properties': {
'initialization.testSetting1': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.RESOURCE
},
'initialization.testSetting2': {
'type': 'string',
'default': 'isSet',
scope: ConfigurationScope.RESOURCE
}
}
});
});
setup(() => {
return setUpWorkspace(['1', '2'])
.then(({ parentDir, configPath }) => {
parentResource = parentDir;
workspaceConfigPath = configPath;
globalSettingsFile = path.join(parentDir, 'settings.json');
const instantiationService = <TestInstantiationService>workbenchInstantiationService();
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
const workspaceService = new WorkspaceService(environmentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
return workspaceService.initialize(<IWindowConfiguration>{}).then(() => {
instantiationService.stub(IFileService, new FileService(<IWorkspaceContextService>workspaceService, new TestTextResourceConfigurationService(), workspaceService, new TestLifecycleService(), { disableWatcher: true }));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
workspaceService.setInstantiationService(instantiationService);
testObject = workspaceService;
});
});
});
teardown(done => {
if (testObject) {
(<WorkspaceService>testObject).dispose();
}
if (parentResource) {
extfs.del(parentResource, os.tmpdir(), () => { }, done);
}
});
test('initialize a folder workspace from an empty workspace with no configuration changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "initialization.testSetting1": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
return testObject.initialize(path.join(parentResource, '1'))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'userValue');
assert.equal(target.callCount, 3);
assert.deepEqual(target.args[0], [WorkbenchState.FOLDER]);
assert.deepEqual(target.args[1], [undefined]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[2][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '1')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[2][0]).removed, []);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[2][0]).changed, []);
});
});
});
test('initialize a folder workspace from an empty workspace with configuration changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "initialization.testSetting1": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
fs.writeFileSync(path.join(parentResource, '1', '.vscode', 'settings.json'), '{ "initialization.testSetting1": "workspaceValue" }');
return testObject.initialize(path.join(parentResource, '1'))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'workspaceValue');
assert.equal(target.callCount, 4);
assert.deepEqual((<IConfigurationChangeEvent>target.args[0][0]).affectedKeys, ['initialization.testSetting1']);
assert.deepEqual(target.args[1], [WorkbenchState.FOLDER]);
assert.deepEqual(target.args[2], [undefined]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '1')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).removed, []);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).changed, []);
});
});
});
test('initialize a multi root workspace from an empty workspace with no configuration changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "initialization.testSetting1": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
return testObject.initialize({ id: workspaceConfigPath, configPath: workspaceConfigPath })
.then(() => {
assert.equal(target.callCount, 3);
assert.deepEqual(target.args[0], [WorkbenchState.WORKSPACE]);
assert.deepEqual(target.args[1], [undefined]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[2][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '1')).fsPath, URI.file(path.join(parentResource, '2')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[2][0]).removed, []);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[2][0]).changed, []);
});
});
});
test('initialize a multi root workspace from an empty workspace with configuration changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "initialization.testSetting1": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
fs.writeFileSync(path.join(parentResource, '1', '.vscode', 'settings.json'), '{ "initialization.testSetting1": "workspaceValue1" }');
fs.writeFileSync(path.join(parentResource, '2', '.vscode', 'settings.json'), '{ "initialization.testSetting2": "workspaceValue2" }');
return testObject.initialize({ id: workspaceConfigPath, configPath: workspaceConfigPath })
.then(() => {
assert.equal(target.callCount, 4);
assert.deepEqual((<IConfigurationChangeEvent>target.args[0][0]).affectedKeys, ['initialization.testSetting1', 'initialization.testSetting2']);
assert.deepEqual(target.args[1], [WorkbenchState.WORKSPACE]);
assert.deepEqual(target.args[2], [undefined]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '1')).fsPath, URI.file(path.join(parentResource, '2')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).removed, []);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).changed, []);
});
});
});
test('initialize a folder workspace from a folder workspace with no configuration changes', () => {
return testObject.initialize(path.join(parentResource, '1'))
.then(() => {
fs.writeFileSync(globalSettingsFile, '{ "initialization.testSetting1": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
return testObject.initialize(path.join(parentResource, '2'))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'userValue');
assert.equal(target.callCount, 1);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[0][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '2')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[0][0]).removed.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '1')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[0][0]).changed, []);
});
});
});
});
test('initialize a folder workspace from a folder workspace with configuration changes', () => {
return testObject.initialize(path.join(parentResource, '1'))
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
fs.writeFileSync(path.join(parentResource, '2', '.vscode', 'settings.json'), '{ "initialization.testSetting1": "workspaceValue2" }');
return testObject.initialize(path.join(parentResource, '2'))
.then(() => {
assert.equal(testObject.getValue('initialization.testSetting1'), 'workspaceValue2');
assert.equal(target.callCount, 2);
assert.deepEqual((<IConfigurationChangeEvent>target.args[0][0]).affectedKeys, ['initialization.testSetting1']);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[1][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '2')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[1][0]).removed.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '1')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[1][0]).changed, []);
});
});
});
test('initialize a multi folder workspace from a folder workspacce triggers change events in the right order', () => {
const folderDir = path.join(parentResource, '1');
return testObject.initialize(folderDir)
.then(() => {
const target = sinon.spy();
testObject.onDidChangeWorkbenchState(target);
testObject.onDidChangeWorkspaceName(target);
testObject.onDidChangeWorkspaceFolders(target);
testObject.onDidChangeConfiguration(target);
fs.writeFileSync(path.join(parentResource, '1', '.vscode', 'settings.json'), '{ "initialization.testSetting1": "workspaceValue2" }');
return testObject.initialize({ id: workspaceConfigPath, configPath: workspaceConfigPath })
.then(() => {
assert.equal(target.callCount, 4);
assert.deepEqual((<IConfigurationChangeEvent>target.args[0][0]).affectedKeys, ['initialization.testSetting1']);
assert.deepEqual(target.args[1], [WorkbenchState.WORKSPACE]);
assert.deepEqual(target.args[2], [undefined]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).added.map(folder => folder.uri.fsPath), [URI.file(path.join(parentResource, '2')).fsPath]);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).removed, []);
assert.deepEqual((<IWorkspaceFoldersChangeEvent>target.args[3][0]).changed, []);
});
});
});
});
suite('WorkspaceConfigurationService - Folder', () => {
let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceDir: string, testObject: IWorkspaceConfigurationService, globalSettingsFile: string;
......@@ -307,7 +560,8 @@ suite('WorkspaceConfigurationService - Folder', () => {
'properties': {
'configurationService.folder.testSetting': {
'type': 'string',
'default': 'isSet'
'default': 'isSet',
scope: ConfigurationScope.RESOURCE
},
'configurationService.folder.executableSetting': {
'type': 'string',
......@@ -577,36 +831,6 @@ suite('WorkspaceConfigurationService - Folder', () => {
.then(() => assert.ok(target.called));
});
test('initialize with different folder triggers configuration event if there are changes', () => {
return setUpFolderWorkspace(`testWorkspace${uuid.generateUuid()}`)
.then(({ folderDir }) => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(target);
fs.writeFileSync(path.join(folderDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue2" }');
return (<WorkspaceService>testObject).initialize(folderDir)
.then(() => {
assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue2');
assert.ok(target.called);
});
});
});
test('initialize with different folder triggers configuration event if there are no changes', () => {
fs.writeFileSync(globalSettingsFile, '{ "configurationService.folder.testSetting": "workspaceValue2" }');
return testObject.reloadConfiguration()
.then(() => setUpFolderWorkspace(`testWorkspace${uuid.generateUuid()}`))
.then(({ folderDir }) => {
const target = sinon.spy();
testObject.onDidChangeConfiguration(() => target());
fs.writeFileSync(path.join(folderDir, '.vscode', 'settings.json'), '{ "configurationService.folder.testSetting": "workspaceValue2" }');
return (<WorkspaceService>testObject).initialize(folderDir)
.then(() => {
assert.equal(testObject.getValue('configurationService.folder.testSetting'), 'workspaceValue2');
assert.ok(!target.called);
});
});
});
});
suite('WorkspaceConfigurationService - Multiroot', () => {
......@@ -762,6 +986,55 @@ suite('WorkspaceConfigurationService - Multiroot', () => {
});
});
test('inspect', () => {
let actual = testObject.inspect('something.missing');
assert.equal(actual.default, void 0);
assert.equal(actual.user, void 0);
assert.equal(actual.workspace, void 0);
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, void 0);
actual = testObject.inspect('configurationService.workspace.testResourceSetting');
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, void 0);
assert.equal(actual.workspace, void 0);
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, 'isSet');
fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.testResourceSetting": "userValue" }');
return testObject.reloadConfiguration()
.then(() => {
actual = testObject.inspect('configurationService.workspace.testResourceSetting');
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, 'userValue');
assert.equal(actual.workspace, void 0);
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, 'userValue');
return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration, { key: 'settings', value: { 'configurationService.workspace.testResourceSetting': 'workspaceValue' } }, true)
.then(() => testObject.reloadConfiguration())
.then(() => {
actual = testObject.inspect('configurationService.workspace.testResourceSetting');
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, 'userValue');
assert.equal(actual.workspace, 'workspaceValue');
assert.equal(actual.workspaceFolder, void 0);
assert.equal(actual.value, 'workspaceValue');
fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testResourceSetting": "workspaceFolderValue" }');
return testObject.reloadConfiguration()
.then(() => {
actual = testObject.inspect('configurationService.workspace.testResourceSetting', { resource: workspaceContextService.getWorkspace().folders[0].uri });
assert.equal(actual.default, 'isSet');
assert.equal(actual.user, 'userValue');
assert.equal(actual.workspace, 'workspaceValue');
assert.equal(actual.workspaceFolder, 'workspaceFolderValue');
assert.equal(actual.value, 'workspaceFolderValue');
});
});
});
});
test('update user configuration', () => {
return testObject.updateValue('configurationService.workspace.testSetting', 'userValue', ConfigurationTarget.USER)
......
......@@ -314,8 +314,11 @@ class DecorationProviderWrapper {
private _keepItem(uri: URI, data: IDecorationData): IDecorationData {
let deco = data ? data : null;
this.data.set(uri.toString(), deco);
this._uriEmitter.fire(uri);
let old = this.data.set(uri.toString(), deco);
if (deco || old) {
// only fire event when something changed
this._uriEmitter.fire(uri);
}
return deco;
}
}
......
......@@ -11,13 +11,12 @@ import os = require('os');
import crypto = require('crypto');
import assert = require('assert');
import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, ICreateFileOptions } from 'vs/platform/files/common/files';
import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IFileStat, IStreamContent, FileOperationError, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, ICreateFileOptions, IContentData } from 'vs/platform/files/common/files';
import { isEqualOrParent } from 'vs/base/common/paths';
import { ResourceMap } from 'vs/base/common/map';
import arrays = require('vs/base/common/arrays');
import baseMime = require('vs/base/common/mime');
import { TPromise } from 'vs/base/common/winjs.base';
import types = require('vs/base/common/types');
import objects = require('vs/base/common/objects');
import extfs = require('vs/base/node/extfs');
import { nfcall, ThrottledDelayer } from 'vs/base/common/async';
......@@ -26,10 +25,9 @@ import nls = require('vs/nls');
import { isWindows, isLinux } from 'vs/base/common/platform';
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import pfs = require('vs/base/node/pfs');
import encoding = require('vs/base/node/encoding');
import { detectMimesFromFile } from 'vs/base/node/mime';
import { detectMimeAndEncodingFromBuffer, IMimeAndEncoding } from 'vs/base/node/mime';
import flow = require('vs/base/node/flow');
import { FileWatcher as UnixWatcherService } from 'vs/workbench/services/files/node/watcher/unix/watcherService';
import { FileWatcher as WindowsWatcherService } from 'vs/workbench/services/files/node/watcher/win32/watcherService';
......@@ -38,6 +36,7 @@ import Event, { Emitter } from 'vs/base/common/event';
import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
export interface IEncodingOverride {
......@@ -200,15 +199,28 @@ export class FileService implements IFileService {
}
public resolveContent(resource: uri, options?: IResolveContentOptions): TPromise<IContent> {
return this.doResolveContent(resource, options, (stat, enc) => this.resolveFileContent(stat, enc));
}
return this.resolveStreamContent(resource, options).then(streamContent => {
return new TPromise<IContent>((resolve, reject) => {
const result: IContent = {
resource: streamContent.resource,
name: streamContent.name,
mtime: streamContent.mtime,
etag: streamContent.etag,
encoding: streamContent.encoding,
value: ''
};
streamContent.value.on('data', chunk => result.value += chunk);
streamContent.value.on('error', err => reject(err));
streamContent.value.on('end', _ => resolve(result));
public resolveStreamContent(resource: uri, options?: IResolveContentOptions): TPromise<IStreamContent> {
return this.doResolveContent(resource, options, (stat, enc) => this.resolveFileStreamContent(stat, enc));
return result;
});
});
}
private doResolveContent<IStreamContent>(resource: uri, options: IResolveContentOptions, contentResolver: (stat: IFileStat, enc?: string) => TPromise<IStreamContent>): TPromise<IStreamContent> {
const absolutePath = this.toAbsolutePath(resource);
public resolveStreamContent(resource: uri, options?: IResolveContentOptions): TPromise<IStreamContent> {
// Guard early against attempts to resolve an invalid file path
if (resource.scheme !== 'file' || !resource.fsPath) {
......@@ -218,84 +230,223 @@ export class FileService implements IFileService {
));
}
// 1.) resolve resource
return this.resolve(resource).then((model): TPromise<IStreamContent> => {
const result: IStreamContent = {
resource: undefined,
name: undefined,
mtime: undefined,
etag: undefined,
encoding: undefined,
value: undefined
};
const contentResolverToken = new CancellationTokenSource();
const onStatError = error => {
// error: stop reading the file the stat and content resolve call
// usually race, mostly likely the stat call will win and cancel
// the content call
contentResolverToken.cancel();
// forward error
return TPromise.wrapError(error);
};
const statsPromise = this.resolveFile(resource).then(stat => {
result.resource = stat.resource;
result.name = stat.name;
result.mtime = stat.mtime;
result.etag = stat.etag;
// Return early if resource is a directory
if (model.isDirectory) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(
if (stat.isDirectory) {
return onStatError(new FileOperationError(
nls.localize('fileIsDirectoryError', "File is directory"),
FileOperationResult.FILE_IS_DIRECTORY
));
}
// Return early if file not modified since
if (options && options.etag && options.etag === model.etag) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(nls.localize('fileNotModifiedError', "File not modified since"), FileOperationResult.FILE_NOT_MODIFIED_SINCE));
if (options && options.etag && options.etag === stat.etag) {
return onStatError(new FileOperationError(
nls.localize('fileNotModifiedError', "File not modified since"),
FileOperationResult.FILE_NOT_MODIFIED_SINCE
));
}
// Return early if file is too large to load
if (types.isNumber(model.size) && model.size > MAX_FILE_SIZE) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(nls.localize('fileTooLargeError', "File too large to open"), FileOperationResult.FILE_TOO_LARGE));
if (typeof stat.size === 'number' && stat.size > MAX_FILE_SIZE) {
return onStatError(new FileOperationError(
nls.localize('fileTooLargeError', "File too large to open"),
FileOperationResult.FILE_TOO_LARGE
));
}
return undefined;
}, err => {
// Wrap file not found errors
if (err.code === 'ENOENT') {
return onStatError(new FileOperationError(
nls.localize('fileNotFoundError', "File not found ({0})", resource.toString(true)),
FileOperationResult.FILE_NOT_FOUND
));
}
// 2.) detect mimes
const autoGuessEncoding = (options && options.autoGuessEncoding) || this.configuredAutoGuessEncoding(resource);
return detectMimesFromFile(absolutePath, { autoGuessEncoding }).then(detected => {
const isText = detected.mimes.indexOf(baseMime.MIME_BINARY) === -1;
// Return error early if client only accepts text and this is not text
if (options && options.acceptTextOnly && !isText) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(
nls.localize('fileBinaryError', "File seems to be binary and cannot be opened as text"),
FileOperationResult.FILE_IS_BINARY
));
return onStatError(err);
});
let completePromise: Thenable<any>;
// await the stat iff we already have an etag so that we compare the
// etag from the stat before we actually read the file again.
if (options && options.etag) {
completePromise = statsPromise.then(() => {
return this.fillInContents(result, resource, options, contentResolverToken.token); // Waterfall -> only now resolve the contents
});
}
// a fresh load without a previous etag which means we can resolve the file stat
// and the content at the same time, avoiding the waterfall.
else {
completePromise = Promise.all([statsPromise, this.fillInContents(result, resource, options, contentResolverToken.token)]);
}
return TPromise.wrap(completePromise).then(() => result);
}
private fillInContents(content: IStreamContent, resource: uri, options: IResolveContentOptions, token: CancellationToken): Thenable<any> {
return this.resolveFileData(resource, options, token).then(data => {
content.encoding = data.encoding;
content.value = data.stream;
});
}
//#region data stream
private static chunkSize = 64 * 1024;
private static chunkBuffer = Buffer.allocUnsafe(FileService.chunkSize);
private resolveFileData(resource: uri, options: IResolveContentOptions, token: CancellationToken): Thenable<IContentData> {
const result: IContentData = {
encoding: undefined,
stream: undefined,
};
return new Promise<IContentData>((resolve, reject) => {
fs.open(this.toAbsolutePath(resource), 'r', (err, fd) => {
if (err) {
if (err.code === 'ENOENT') {
// Wrap file not found errors
err = new FileOperationError(
nls.localize('fileNotFoundError', "File not found ({0})", resource.toString(true)),
FileOperationResult.FILE_NOT_FOUND
);
}
return reject(err);
}
let preferredEncoding: string;
if (options && options.encoding) {
if (detected.encoding === encoding.UTF8 && options.encoding === encoding.UTF8) {
preferredEncoding = encoding.UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8
} else {
preferredEncoding = options.encoding; // give passed in encoding highest priority
let decoder: NodeJS.ReadWriteStream;
let totalBytesRead = 0;
const finish = (err?: any) => {
if (err) {
if (err.code === 'EISDIR') {
// Wrap EISDIR errors (fs.open on a directory works, but you cannot read from it)
err = new FileOperationError(
nls.localize('fileIsDirectoryError', "File is directory"),
FileOperationResult.FILE_IS_DIRECTORY
);
}
if (decoder) {
// If the decoder already started, we have to emit the error through it as
// event because the promise is already resolved!
decoder.emit('error', err);
} else {
reject(err);
}
}
} else if (detected.encoding) {
if (detected.encoding === encoding.UTF8) {
preferredEncoding = encoding.UTF8_with_bom; // if we detected UTF-8, it can only be because of a BOM
} else {
preferredEncoding = detected.encoding;
if (decoder) {
decoder.end();
}
} else if (this.configuredEncoding(resource) === encoding.UTF8_with_bom) {
preferredEncoding = encoding.UTF8; // if we did not detect UTF 8 BOM before, this can only be UTF 8 then
}
if (fd) {
fs.close(fd, err => { });
}
};
// 3.) get content
return contentResolver(model, preferredEncoding);
});
}, error => {
const handleChunk = (bytesRead) => {
if (token.isCancellationRequested) {
// cancellation
finish(new Error('cancelled'));
// bubble up existing file operation results
if (!types.isUndefinedOrNull((<FileOperationError>error).fileOperationResult)) {
return TPromise.wrapError<IStreamContent>(error);
}
} else if (bytesRead < FileService.chunkSize) {
// done, write rest, end
decoder.write(FileService.chunkBuffer.slice(0, bytesRead), finish);
// check if the file does not exist
return pfs.exists(absolutePath).then(exists => {
} else {
// read, write, repeat
decoder.write(FileService.chunkBuffer, readChunk);
}
};
const readChunk = () => {
fs.read(fd, FileService.chunkBuffer, 0, FileService.chunkSize, null, (err, bytesRead) => {
totalBytesRead += bytesRead;
if (totalBytesRead > MAX_FILE_SIZE) {
// stop when reading too much
finish(new FileOperationError(
nls.localize('fileTooLargeError', "File too large to open"),
FileOperationResult.FILE_TOO_LARGE
));
} else if (err) {
// some error happened
finish(err);
} else if (decoder) {
// pass on to decoder
handleChunk(bytesRead);
// Return if file not found
if (!exists) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(
nls.localize('fileNotFoundError', "File not found ({0})", resource.toString(true)),
FileOperationResult.FILE_NOT_FOUND
));
}
} else {
// when receiving the first chunk of data we need to create the
// decoding stream which is then used to drive the string stream.
Promise.resolve(detectMimeAndEncodingFromBuffer(
{ buffer: FileService.chunkBuffer, bytesRead },
options && options.autoGuessEncoding || this.configuredAutoGuessEncoding(resource)
)).then(value => {
if (options && options.acceptTextOnly && value.mimes.indexOf(baseMime.MIME_BINARY) >= 0) {
// Return error early if client only accepts text and this is not text
finish(new FileOperationError(
nls.localize('fileBinaryError', "File seems to be binary and cannot be opened as text"),
FileOperationResult.FILE_IS_BINARY
));
} else {
result.encoding = this.getEncoding(resource, this.getPeferredEncoding(resource, options, value));
result.stream = decoder = encoding.decodeStream(result.encoding);
resolve(result);
handleChunk(bytesRead);
}
}).catch(err => {
// failed to get encoding
finish(err);
});
}
});
};
// otherwise just give up
return TPromise.wrapError<IStreamContent>(error);
// start reading
readChunk();
});
});
}
//#endregion
public updateContent(resource: uri, value: string, options: IUpdateContentOptions = Object.create(null)): TPromise<IFileStat> {
const absolutePath = this.toAbsolutePath(resource);
......@@ -582,53 +733,24 @@ export class FileService implements IFileService {
});
}
private resolveFileStreamContent(model: IFileStat, enc?: string): TPromise<IStreamContent> {
// Return early if file is too large to load
if (types.isNumber(model.size) && model.size > MAX_FILE_SIZE) {
return TPromise.wrapError<IStreamContent>(new FileOperationError(nls.localize('fileTooLargeError', "File too large to open"), FileOperationResult.FILE_TOO_LARGE));
private getPeferredEncoding(resource: uri, options: IResolveContentOptions, detected: IMimeAndEncoding): string {
let preferredEncoding: string;
if (options && options.encoding) {
if (detected.encoding === encoding.UTF8 && options.encoding === encoding.UTF8) {
preferredEncoding = encoding.UTF8_with_bom; // indicate the file has BOM if we are to resolve with UTF 8
} else {
preferredEncoding = options.encoding; // give passed in encoding highest priority
}
} else if (detected.encoding) {
if (detected.encoding === encoding.UTF8) {
preferredEncoding = encoding.UTF8_with_bom; // if we detected UTF-8, it can only be because of a BOM
} else {
preferredEncoding = detected.encoding;
}
} else if (this.configuredEncoding(resource) === encoding.UTF8_with_bom) {
preferredEncoding = encoding.UTF8; // if we did not detect UTF 8 BOM before, this can only be UTF 8 then
}
const absolutePath = this.toAbsolutePath(model);
const fileEncoding = this.getEncoding(model.resource, enc);
const reader = fs.createReadStream(absolutePath).pipe(encoding.decodeStream(fileEncoding)); // decode takes care of stripping any BOMs from the file content
const content = model as IFileStat & IStreamContent;
content.value = reader;
content.encoding = fileEncoding; // make sure to store the encoding in the model to restore it later when writing
return TPromise.as(content);
}
private resolveFileContent(model: IFileStat, enc?: string): TPromise<IContent> {
return this.resolveFileStreamContent(model, enc).then(streamContent => {
return new TPromise<IContent>((c, e) => {
let done = false;
const chunks: string[] = [];
streamContent.value.on('data', buf => {
chunks.push(buf);
});
streamContent.value.on('error', error => {
if (!done) {
done = true;
e(error);
}
});
streamContent.value.on('end', () => {
const content: IContent = <any>streamContent;
content.value = chunks.join('');
if (!done) {
done = true;
c(content);
}
});
});
});
return preferredEncoding;
}
public getEncoding(resource: uri, preferredEncoding?: string): string {
......
......@@ -524,7 +524,7 @@ suite('FileService', () => {
test('resolveFile', function (done: () => void) {
service.resolveFile(uri.file(testDir), { resolveTo: [uri.file(path.join(testDir, 'deep'))] }).done(r => {
assert.equal(r.children.length, 6);
assert.equal(r.children.length, 7);
const deep = utils.getByName(r, 'deep');
assert.equal(deep.children.length, 4);
......@@ -540,7 +540,7 @@ suite('FileService', () => {
]).then(res => {
const r1 = res[0].stat;
assert.equal(r1.children.length, 6);
assert.equal(r1.children.length, 7);
const deep = utils.getByName(r1, 'deep');
assert.equal(deep.children.length, 4);
......@@ -625,6 +625,16 @@ suite('FileService', () => {
}, error => onError(error, done));
});
test('resolveContent - large file', function (done: () => void) {
const resource = uri.file(path.join(testDir, 'lorem.txt'));
service.resolveContent(resource).done(c => {
assert.ok(c.value.length > 64000);
done();
}, error => onError(error, done));
});
test('resolveContent - FILE_IS_BINARY', function (done: () => void) {
const resource = uri.file(path.join(testDir, 'binary.txt'));
......
'use strict';
/// <reference path="employee.ts" />
var Workforce;
(function (Workforce_1) {
var Company = (function () {
function Company() {
}
return Company;
})();
(function (property, Workforce, IEmployee) {
if (property === void 0) { property = employees; }
if (IEmployee === void 0) { IEmployee = []; }
property;
calculateMonthlyExpenses();
{
var result = 0;
for (var i = 0; i < employees.length; i++) {
result += employees[i].calculatePay();
}
return result;
}
});
})(Workforce || (Workforce = {}));
'use strict';
var Conway;
(function (Conway) {
var Cell = (function () {
function Cell() {
}
return Cell;
})();
(function (property, number, property, number, property, boolean) {
if (property === void 0) { property = row; }
if (property === void 0) { property = col; }
if (property === void 0) { property = live; }
});
var GameOfLife = (function () {
function GameOfLife() {
}
return GameOfLife;
})();
(function () {
property;
gridSize = 50;
property;
canvasSize = 600;
property;
lineColor = '#cdcdcd';
property;
liveColor = '#666';
property;
deadColor = '#eee';
property;
initialLifeProbability = 0.5;
property;
animationRate = 60;
property;
cellSize = 0;
property;
context: ICanvasRenderingContext2D;
property;
world = createWorld();
circleOfLife();
function createWorld() {
return travelWorld(function (cell) {
cell.live = Math.random() < initialLifeProbability;
return cell;
});
}
function circleOfLife() {
world = travelWorld(function (cell) {
cell = world[cell.row][cell.col];
draw(cell);
return resolveNextGeneration(cell);
});
setTimeout(function () { circleOfLife(); }, animationRate);
}
function resolveNextGeneration(cell) {
var count = countNeighbors(cell);
var newCell = new Cell(cell.row, cell.col, cell.live);
if (count < 2 || count > 3)
newCell.live = false;
else if (count == 3)
newCell.live = true;
return newCell;
}
function countNeighbors(cell) {
var neighbors = 0;
for (var row = -1; row <= 1; row++) {
for (var col = -1; col <= 1; col++) {
if (row == 0 && col == 0)
continue;
if (isAlive(cell.row + row, cell.col + col)) {
neighbors++;
}
}
}
return neighbors;
}
function isAlive(row, col) {
// todo - need to guard with worl[row] exists?
if (row < 0 || col < 0 || row >= gridSize || col >= gridSize)
return false;
return world[row][col].live;
}
function travelWorld(callback) {
var result = [];
for (var row = 0; row < gridSize; row++) {
var rowData = [];
for (var col = 0; col < gridSize; col++) {
rowData.push(callback(new Cell(row, col, false)));
}
result.push(rowData);
}
return result;
}
function draw(cell) {
if (context == null)
context = createDrawingContext();
if (cellSize == 0)
cellSize = canvasSize / gridSize;
context.strokeStyle = lineColor;
context.strokeRect(cell.row * cellSize, cell.col * cellSize, cellSize, cellSize);
context.fillStyle = cell.live ? liveColor : deadColor;
context.fillRect(cell.row * cellSize, cell.col * cellSize, cellSize, cellSize);
}
function createDrawingContext() {
var canvas = document.getElementById('conway-canvas');
if (canvas == null) {
canvas = document.createElement('canvas');
canvas.id = "conway-canvas";
canvas.width = canvasSize;
canvas.height = canvasSize;
document.body.appendChild(canvas);
}
return canvas.getContext('2d');
}
});
})(Conway || (Conway = {}));
var game = new Conway.GameOfLife();
'use strict';
var Workforce;
(function (Workforce) {
var Employee = (function () {
function Employee() {
}
return Employee;
})();
(property);
name: string, property;
basepay: number;
implements;
IEmployee;
{
name;
basepay;
}
var SalesEmployee = (function () {
function SalesEmployee() {
}
return SalesEmployee;
})();
();
Employee(name, basepay);
{
function calculatePay() {
var multiplier = (document.getElementById("mult")), as = any, value;
return _super.calculatePay.call(this) * multiplier + bonus;
}
}
var employee = new Employee('Bob', 1000);
var salesEmployee = new SalesEmployee('Jim', 800, 400);
salesEmployee.calclatePay(); // error: No member 'calclatePay' on SalesEmployee
})(Workforce || (Workforce = {}));
extern;
var $;
var s = Workforce.salesEmployee.calculatePay();
$('#results').text(s);
'use strict';
var M;
(function (M) {
var C = (function () {
function C() {
}
return C;
})();
(function (x, property, number) {
if (property === void 0) { property = w; }
var local = 1;
// unresolved symbol because x is local
//self.x++;
self.w--; // ok because w is a property
property;
f = function (y) {
return y + x + local + w + self.w;
};
function sum(z) {
return z + f(z) + w + self.w;
}
});
})(M || (M = {}));
var c = new M.C(12, 5);
<!DOCTYPE html>
<html>
<head id='headID'>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Strada </title>
<link href="site.css" rel="stylesheet" type="text/css" />
<script src="jquery-1.4.1.js"></script>
<script src="../compiler/dtree.js" type="text/javascript"></script>
<script src="../compiler/typescript.js" type="text/javascript"></script>
<script type="text/javascript">
// Compile strada source into resulting javascript
function compile(prog, libText) {
var outfile = {
source: "",
Write: function (s) { this.source += s; },
WriteLine: function (s) { this.source += s + "\r"; },
}
var parseErrors = []
var compiler=new Tools.TypeScriptCompiler(outfile,true);
compiler.setErrorCallback(function(start,len, message) { parseErrors.push({start:start, len:len, message:message}); });
compiler.addUnit(libText,"lib.ts");
compiler.addUnit(prog,"input.ts");
compiler.typeCheck();
compiler.emit();
if(parseErrors.length > 0 ) {
//throw new Error(parseErrors);
}
while(outfile.source[0] == '/' && outfile.source[1] == '/' && outfile.source[2] == ' ') {
outfile.source = outfile.source.slice(outfile.source.indexOf('\r')+1);
}
var errorPrefix = "";
for(var i = 0;i<parseErrors.length;i++) {
errorPrefix += "// Error: (" + parseErrors[i].start + "," + parseErrors[i].len + ") " + parseErrors[i].message + "\r";
}
return errorPrefix + outfile.source;
}
</script>
<script type="text/javascript">
var libText = "";
$.get("../compiler/lib.ts", function(newLibText) {
libText = newLibText;
});
// execute the javascript in the compiledOutput pane
function execute() {
$('#compilation').text("Running...");
var txt = $('#compiledOutput').val();
var res;
try {
var ret = eval(txt);
res = "Ran successfully!";
} catch(e) {
res = "Exception thrown: " + e;
}
$('#compilation').text(String(res));
}
// recompile the stradaSrc and populate the compiledOutput pane
function srcUpdated() {
var newText = $('#stradaSrc').val();
var compiledSource;
try {
compiledSource = compile(newText, libText);
} catch (e) {
compiledSource = "//Parse error"
for(var i in e)
compiledSource += "\r// " + e[i];
}
$('#compiledOutput').val(compiledSource);
}
// Populate the stradaSrc pane with one of the built in samples
function exampleSelectionChanged() {
var examples = document.getElementById('examples');
var selectedExample = examples.options[examples.selectedIndex].value;
if (selectedExample != "") {
$.get('examples/' + selectedExample, function (srcText) {
$('#stradaSrc').val(srcText);
setTimeout(srcUpdated,100);
}, function (err) {
console.log(err);
});
}
}
</script>
</head>
<body>
<h1>TypeScript</h1>
<br />
<select id="examples" onchange='exampleSelectionChanged()'>
<option value="">Select...</option>
<option value="small.ts">Small</option>
<option value="employee.ts">Employees</option>
<option value="conway.ts">Conway Game of Life</option>
<option value="typescript.ts">TypeScript Compiler</option>
</select>
<div>
<textarea id='stradaSrc' rows='40' cols='80' onchange='srcUpdated()' onkeyup='srcUpdated()' spellcheck="false">
//Type your TypeScript here...
</textarea>
<textarea id='compiledOutput' rows='40' cols='80' spellcheck="false">
//Compiled code will show up here...
</textarea>
<br />
<button onclick='execute()'/>Run</button>
<div id='compilation'>Press 'run' to execute code...</div>
<div id='results'>...write your results into #results...</div>
</div>
<div id='bod' style='display:none'></div>
</body>
</html>
'use strict';
/// <reference path="employee.ts" />
var Workforce;
(function (Workforce_1) {
var Company = (function () {
function Company() {
}
return Company;
})();
(function (property, Workforce, IEmployee) {
if (property === void 0) { property = employees; }
if (IEmployee === void 0) { IEmployee = []; }
property;
calculateMonthlyExpenses();
{
var result = 0;
for (var i = 0; i < employees.length; i++) {
result += employees[i].calculatePay();
}
return result;
}
});
})(Workforce || (Workforce = {}));
'use strict';
var Conway;
(function (Conway) {
var Cell = (function () {
function Cell() {
}
return Cell;
})();
(function (property, number, property, number, property, boolean) {
if (property === void 0) { property = row; }
if (property === void 0) { property = col; }
if (property === void 0) { property = live; }
});
var GameOfLife = (function () {
function GameOfLife() {
}
return GameOfLife;
})();
(function () {
property;
gridSize = 50;
property;
canvasSize = 600;
property;
lineColor = '#cdcdcd';
property;
liveColor = '#666';
property;
deadColor = '#eee';
property;
initialLifeProbability = 0.5;
property;
animationRate = 60;
property;
cellSize = 0;
property;
context: ICanvasRenderingContext2D;
property;
world = createWorld();
circleOfLife();
function createWorld() {
return travelWorld(function (cell) {
cell.live = Math.random() < initialLifeProbability;
return cell;
});
}
function circleOfLife() {
world = travelWorld(function (cell) {
cell = world[cell.row][cell.col];
draw(cell);
return resolveNextGeneration(cell);
});
setTimeout(function () { circleOfLife(); }, animationRate);
}
function resolveNextGeneration(cell) {
var count = countNeighbors(cell);
var newCell = new Cell(cell.row, cell.col, cell.live);
if (count < 2 || count > 3)
newCell.live = false;
else if (count == 3)
newCell.live = true;
return newCell;
}
function countNeighbors(cell) {
var neighbors = 0;
for (var row = -1; row <= 1; row++) {
for (var col = -1; col <= 1; col++) {
if (row == 0 && col == 0)
continue;
if (isAlive(cell.row + row, cell.col + col)) {
neighbors++;
}
}
}
return neighbors;
}
function isAlive(row, col) {
// todo - need to guard with worl[row] exists?
if (row < 0 || col < 0 || row >= gridSize || col >= gridSize)
return false;
return world[row][col].live;
}
function travelWorld(callback) {
var result = [];
for (var row = 0; row < gridSize; row++) {
var rowData = [];
for (var col = 0; col < gridSize; col++) {
rowData.push(callback(new Cell(row, col, false)));
}
result.push(rowData);
}
return result;
}
function draw(cell) {
if (context == null)
context = createDrawingContext();
if (cellSize == 0)
cellSize = canvasSize / gridSize;
context.strokeStyle = lineColor;
context.strokeRect(cell.row * cellSize, cell.col * cellSize, cellSize, cellSize);
context.fillStyle = cell.live ? liveColor : deadColor;
context.fillRect(cell.row * cellSize, cell.col * cellSize, cellSize, cellSize);
}
function createDrawingContext() {
var canvas = document.getElementById('conway-canvas');
if (canvas == null) {
canvas = document.createElement('canvas');
canvas.id = "conway-canvas";
canvas.width = canvasSize;
canvas.height = canvasSize;
document.body.appendChild(canvas);
}
return canvas.getContext('2d');
}
});
})(Conway || (Conway = {}));
var game = new Conway.GameOfLife();
'use strict';
var Workforce;
(function (Workforce) {
var Employee = (function () {
function Employee() {
}
return Employee;
})();
(property);
name: string, property;
basepay: number;
implements;
IEmployee;
{
name;
basepay;
}
var SalesEmployee = (function () {
function SalesEmployee() {
}
return SalesEmployee;
})();
();
Employee(name, basepay);
{
function calculatePay() {
var multiplier = (document.getElementById("mult")), as = any, value;
return _super.calculatePay.call(this) * multiplier + bonus;
}
}
var employee = new Employee('Bob', 1000);
var salesEmployee = new SalesEmployee('Jim', 800, 400);
salesEmployee.calclatePay(); // error: No member 'calclatePay' on SalesEmployee
})(Workforce || (Workforce = {}));
extern;
var $;
var s = Workforce.salesEmployee.calculatePay();
$('#results').text(s);
'use strict';
var M;
(function (M) {
var C = (function () {
function C() {
}
return C;
})();
(function (x, property, number) {
if (property === void 0) { property = w; }
var local = 1;
// unresolved symbol because x is local
//self.x++;
self.w--; // ok because w is a property
property;
f = function (y) {
return y + x + local + w + self.w;
};
function sum(z) {
return z + f(z) + w + self.w;
}
});
})(M || (M = {}));
var c = new M.C(12, 5);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------
The base color for this template is #5c87b2. If you'd like
to use a different color start by replacing all instances of
#5c87b2 with your new color.
----------------------------------------------------------*/
body
{
background-color: #5c87b2;
font-size: .75em;
font-family: Segoe UI, Verdana, Helvetica, Sans-Serif;
margin: 8px;
padding: 0;
color: #696969;
}
h1, h2, h3, h4, h5, h6
{
color: #000;
font-size: 40px;
margin: 0px;
}
textarea
{
font-family: Consolas
}
#results
{
margin-top: 2em;
margin-left: 2em;
color: black;
font-size: medium;
}
......@@ -189,4 +189,4 @@ export class TextFileService extends AbstractTextFileService {
return options;
}
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册