Load extension resources using IExtensionResourceLoaderService

上级 32662b36
......@@ -12,12 +12,12 @@ import { LanguageIdentifier } from 'vs/editor/common/modes';
import { CharacterPair, CommentRule, FoldingRules, IAutoClosingPair, IAutoClosingPairConditional, IndentationRule, LanguageConfiguration } from 'vs/editor/common/modes/languageConfiguration';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileService } from 'vs/platform/files/common/files';
import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService';
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
interface IRegExp {
pattern: string;
......@@ -69,7 +69,7 @@ export class LanguageConfigurationFileHandler {
constructor(
@ITextMateService textMateService: ITextMateService,
@IModeService private readonly _modeService: IModeService,
@IFileService private readonly _fileService: IFileService,
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
@IExtensionService private readonly _extensionService: IExtensionService
) {
this._done = [];
......@@ -98,9 +98,9 @@ export class LanguageConfigurationFileHandler {
}
private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFileLocation: URI): void {
this._fileService.readFile(configFileLocation).then((contents) => {
this._extensionResourceLoaderService.readExtensionResource(configFileLocation).then((contents) => {
const errors: ParseError[] = [];
let configuration = <ILanguageConfiguration>parse(contents.value.toString(), errors);
let configuration = <ILanguageConfiguration>parse(contents, errors);
if (errors.length) {
console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFileLocation.toString(), errors.map(e => (`[${e.offset}, ${e.length}] ${getParseErrorMessage(e.error)}`)).join('\n')));
}
......
......@@ -14,6 +14,7 @@ import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IdleValue } from 'vs/base/common/async';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
class SnippetBodyInsights {
......@@ -153,7 +154,8 @@ export class SnippetFile {
readonly location: URI,
public defaultScopes: string[] | undefined,
private readonly _extension: IExtensionDescription | undefined,
private readonly _fileService: IFileService
private readonly _fileService: IFileService,
private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService
) {
this.isGlobalSnippets = extname(location.path) === '.code-snippets';
this.isUserSnippets = !this._extension;
......@@ -199,10 +201,19 @@ export class SnippetFile {
}
}
private async _load(): Promise<string> {
if (this._extension) {
return this._extensionResourceLoaderService.readExtensionResource(this.location);
} else {
const content = await this._fileService.readFile(this.location);
return content.value.toString();
}
}
load(): Promise<this> {
if (!this._loadPromise) {
this._loadPromise = Promise.resolve(this._fileService.readFile(this.location)).then(content => {
const data = <JsonSerializedSnippets>jsonParse(content.value.toString());
this._loadPromise = Promise.resolve(this._load()).then(content => {
const data = <JsonSerializedSnippets>jsonParse(content);
if (getNodeType(data) === 'object') {
forEach(data, entry => {
const { key: name, value: scopeOrTemplate } = entry;
......
......@@ -25,6 +25,7 @@ import { Snippet, SnippetFile, SnippetSource } from 'vs/workbench/contrib/snippe
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { languagesExtPoint } from 'vs/workbench/services/mode/common/workbenchModeService';
import { SnippetCompletionProvider } from './snippetCompletionProvider';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
namespace snippetExt {
......@@ -139,6 +140,7 @@ class SnippetsService implements ISnippetsService {
@IModeService private readonly _modeService: IModeService,
@ILogService private readonly _logService: ILogService,
@IFileService private readonly _fileService: IFileService,
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
@ILifecycleService lifecycleService: ILifecycleService,
) {
this._pendingWork.push(Promise.resolve(lifecycleService.when(LifecyclePhase.Restored).then(() => {
......@@ -225,7 +227,7 @@ class SnippetsService implements ISnippetsService {
file.defaultScopes = [];
}
} else {
const file = new SnippetFile(SnippetSource.Extension, validContribution.location, validContribution.language ? [validContribution.language] : undefined, extension.description, this._fileService);
const file = new SnippetFile(SnippetSource.Extension, validContribution.location, validContribution.language ? [validContribution.language] : undefined, extension.description, this._fileService, this._extensionResourceLoaderService);
this._files.set(file.location.toString(), file);
if (this._environmentService.isExtensionDevelopment) {
......@@ -318,9 +320,9 @@ class SnippetsService implements ISnippetsService {
const key = uri.toString();
if (source === SnippetSource.User && ext === '.json') {
const langName = resources.basename(uri).replace(/\.json/, '');
this._files.set(key, new SnippetFile(source, uri, [langName], undefined, this._fileService));
this._files.set(key, new SnippetFile(source, uri, [langName], undefined, this._fileService, this._extensionResourceLoaderService));
} else if (ext === '.code-snippets') {
this._files.set(key, new SnippetFile(source, uri, undefined, undefined, this._fileService));
this._files.set(key, new SnippetFile(source, uri, undefined, undefined, this._fileService, this._extensionResourceLoaderService));
}
return {
dispose: () => this._files.delete(key)
......
......@@ -11,7 +11,7 @@ suite('Snippets', function () {
class TestSnippetFile extends SnippetFile {
constructor(filepath: URI, snippets: Snippet[]) {
super(SnippetSource.Extension, filepath, undefined, undefined, undefined!);
super(SnippetSource.Extension, filepath, undefined, undefined, undefined!, undefined!);
this.data.push(...snippets);
}
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
import * as dom from 'vs/base/browser/dom';
import { Schemas } from 'vs/base/common/network';
class ExtensionResourceLoaderService implements IExtensionResourceLoaderService {
_serviceBrand: undefined;
constructor(
@IFileService private readonly _fileService: IFileService
) { }
async readExtensionResource(uri: URI): Promise<string> {
uri = dom.asDomUri(uri);
if (uri.scheme !== Schemas.http && uri.scheme !== Schemas.https) {
const result = await this._fileService.readFile(uri);
return result.value.toString();
}
const response = await fetch(uri.toString(true));
if (response.status !== 200) {
throw new Error(response.statusText);
}
return response.text();
}
}
registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService);
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export const IExtensionResourceLoaderService = createDecorator<IExtensionResourceLoaderService>('extensionResourceLoaderService');
/**
* A service useful for reading resources from within extensions.
*/
export interface IExtensionResourceLoaderService {
_serviceBrand: undefined;
/**
* Read a certain resource within an extension.
*/
readExtensionResource(uri: URI): Promise<string>;
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
class ExtensionResourceLoaderService implements IExtensionResourceLoaderService {
_serviceBrand: undefined;
constructor(
@IFileService private readonly _fileService: IFileService
) { }
async readExtensionResource(uri: URI): Promise<string> {
const result = await this._fileService.readFile(uri);
return result.value.toString();
}
}
registerSingleton(IExtensionResourceLoaderService, ExtensionResourceLoaderService);
......@@ -16,7 +16,6 @@ import { IState, ITokenizationSupport, LanguageId, TokenMetadata, TokenizationRe
import { nullTokenize2 } from 'vs/editor/common/modes/nullMode';
import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileService } from 'vs/platform/files/common/files';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
......@@ -29,6 +28,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry';
import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
export abstract class AbstractTextMateService extends Disposable implements ITextMateService {
public _serviceBrand: undefined;
......@@ -48,7 +48,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
constructor(
@IModeService private readonly _modeService: IModeService,
@IWorkbenchThemeService private readonly _themeService: IWorkbenchThemeService,
@IFileService protected readonly _fileService: IFileService,
@IExtensionResourceLoaderService protected readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
@INotificationService private readonly _notificationService: INotificationService,
@ILogService private readonly _logService: ILogService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
......@@ -191,10 +191,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex
this._grammarFactory = new TMGrammarFactory({
logTrace: (msg: string) => this._logService.trace(msg),
logError: (msg: string, err: any) => this._logService.error(msg, err),
readFile: async (resource: URI) => {
const content = await this._fileService.readFile(resource);
return content.value.toString();
}
readFile: (resource: URI) => this._extensionResourceLoaderService.readExtensionResource(resource)
}, this._grammarDefinitions || [], vscodeTextmate, this._loadOnigLib());
this._onDidCreateGrammarFactory(this._grammarDefinitions || []);
......
......@@ -8,25 +8,25 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService';
import { IOnigLib } from 'vscode-textmate';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileService } from 'vs/platform/files/common/files';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
export class TextMateService extends AbstractTextMateService {
constructor(
@IModeService modeService: IModeService,
@IWorkbenchThemeService themeService: IWorkbenchThemeService,
@IFileService fileService: IFileService,
@IExtensionResourceLoaderService extensionResourceLoaderService: IExtensionResourceLoaderService,
@INotificationService notificationService: INotificationService,
@ILogService logService: ILogService,
@IConfigurationService configurationService: IConfigurationService,
@IStorageService storageService: IStorageService
) {
super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService);
super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService);
}
protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> {
......
......@@ -8,7 +8,6 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IFileService } from 'vs/platform/files/common/files';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
......@@ -24,6 +23,7 @@ import { MultilineTokensBuilder } from 'vs/editor/common/model/tokensStore';
import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory';
import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
const RUN_TEXTMATE_IN_WORKER = false;
......@@ -117,14 +117,13 @@ export class TextMateWorkerHost {
constructor(
private readonly textMateService: TextMateService,
@IFileService private readonly _fileService: IFileService
@IExtensionResourceLoaderService private readonly _extensionResourceLoaderService: IExtensionResourceLoaderService,
) {
}
async readFile(_resource: UriComponents): Promise<string> {
const resource = URI.revive(_resource);
const content = await this._fileService.readFile(resource);
return content.value.toString();
return this._extensionResourceLoaderService.readExtensionResource(resource);
}
async setTokens(_resource: UriComponents, versionId: number, tokens: Uint8Array): Promise<void> {
......@@ -142,14 +141,14 @@ export class TextMateService extends AbstractTextMateService {
constructor(
@IModeService modeService: IModeService,
@IWorkbenchThemeService themeService: IWorkbenchThemeService,
@IFileService fileService: IFileService,
@IExtensionResourceLoaderService extensionResourceLoaderService: IExtensionResourceLoaderService,
@INotificationService notificationService: INotificationService,
@ILogService logService: ILogService,
@IConfigurationService configurationService: IConfigurationService,
@IStorageService storageService: IStorageService,
@IModelService private readonly _modelService: IModelService,
) {
super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService);
super(modeService, themeService, extensionResourceLoaderService, notificationService, logService, configurationService, storageService);
this._worker = null;
this._workerProxy = null;
this._tokenizers = Object.create(null);
......@@ -190,7 +189,7 @@ export class TextMateService extends AbstractTextMateService {
this._killWorker();
if (RUN_TEXTMATE_IN_WORKER) {
const workerHost = new TextMateWorkerHost(this, this._fileService);
const workerHost = new TextMateWorkerHost(this, this._extensionResourceLoaderService);
const worker = createWebWorker<TextMateWorker>(this._modelService, {
createData: {
grammarDefinitions
......
......@@ -32,6 +32,7 @@ import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
// implementation
......@@ -98,6 +99,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IFileService private readonly fileService: IFileService,
@IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService,
@IWorkbenchLayoutService readonly layoutService: IWorkbenchLayoutService
) {
......@@ -341,7 +343,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
return null;
}
const themeData = data;
return themeData.ensureLoaded(this.fileService).then(_ => {
return themeData.ensureLoaded(this.extensionResourceLoaderService).then(_ => {
if (themeId === this.currentColorTheme.id && !this.currentColorTheme.isLoaded && this.currentColorTheme.hasEqualData(themeData)) {
// the loaded theme is identical to the perisisted theme. Don't need to send an event.
this.currentColorTheme = themeData;
......@@ -360,7 +362,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService {
}
private async reloadCurrentColorTheme() {
await this.currentColorTheme.reload(this.fileService);
await this.currentColorTheme.reload(this.extensionResourceLoaderService);
this.currentColorTheme.setCustomColors(this.colorCustomizations);
this.currentColorTheme.setCustomTokenColors(this.tokenColorCustomizations);
this.updateDynamicCSSRules(this.currentColorTheme);
......
......@@ -17,9 +17,9 @@ import { ThemeType } from 'vs/platform/theme/common/themeService';
import { Registry } from 'vs/platform/registry/common/platform';
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser';
import { startsWith } from 'vs/base/common/strings';
import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader';
let colorRegistry = Registry.as<IColorRegistry>(Extensions.ColorContribution);
......@@ -167,21 +167,21 @@ export class ColorThemeData implements IColorTheme {
}
}
public ensureLoaded(fileService: IFileService): Promise<void> {
return !this.isLoaded ? this.load(fileService) : Promise.resolve(undefined);
public ensureLoaded(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise<void> {
return !this.isLoaded ? this.load(extensionResourceLoaderService) : Promise.resolve(undefined);
}
public reload(fileService: IFileService): Promise<void> {
return this.load(fileService);
public reload(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise<void> {
return this.load(extensionResourceLoaderService);
}
private load(fileService: IFileService): Promise<void> {
private load(extensionResourceLoaderService: IExtensionResourceLoaderService): Promise<void> {
if (!this.location) {
return Promise.resolve(undefined);
}
this.themeTokenColors = [];
this.colorMap = {};
return _loadColorTheme(fileService, this.location, this.themeTokenColors, this.colorMap).then(_ => {
return _loadColorTheme(extensionResourceLoaderService, this.location, this.themeTokenColors, this.colorMap).then(_ => {
this.isLoaded = true;
});
}
......@@ -295,11 +295,11 @@ function toCSSSelector(extensionId: string, path: string) {
return str;
}
function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise<any> {
function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise<any> {
if (resources.extname(themeLocation) === '.json') {
return fileService.readFile(themeLocation).then(content => {
return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => {
let errors: Json.ParseError[] = [];
let contentValue = Json.parse(content.value.toString(), errors);
let contentValue = Json.parse(content, errors);
if (errors.length > 0) {
return Promise.reject(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', '))));
} else if (Json.getNodeType(contentValue) !== 'object') {
......@@ -307,7 +307,7 @@ function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRu
}
let includeCompletes: Promise<any> = Promise.resolve(null);
if (contentValue.include) {
includeCompletes = _loadColorTheme(fileService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), resultRules, resultColors);
includeCompletes = _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), resultRules, resultColors);
}
return includeCompletes.then(_ => {
if (Array.isArray(contentValue.settings)) {
......@@ -333,7 +333,7 @@ function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRu
resultRules.push(...tokenColors);
return null;
} else if (typeof tokenColors === 'string') {
return _loadSyntaxTokens(fileService, resources.joinPath(resources.dirname(themeLocation), tokenColors), resultRules, {});
return _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), resultRules, {});
} else {
return Promise.reject(new Error(nls.localize({ key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a TextMate theme file", themeLocation.toString())));
}
......@@ -342,14 +342,14 @@ function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRu
});
});
} else {
return _loadSyntaxTokens(fileService, themeLocation, resultRules, resultColors);
return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, resultRules, resultColors);
}
}
function _loadSyntaxTokens(fileService: IFileService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise<any> {
return fileService.readFile(themeLocation).then(content => {
function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise<any> {
return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => {
try {
let contentValue = parsePList(content.value.toString());
let contentValue = parsePList(content);
let settings: ITokenColorizationRule[] = contentValue.settings;
if (!Array.isArray(settings)) {
return Promise.reject(new Error(nls.localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array.")));
......
......@@ -61,6 +61,7 @@ import 'vs/workbench/services/clipboard/electron-browser/clipboardService';
import 'vs/workbench/services/update/electron-browser/updateService';
import 'vs/workbench/services/issue/electron-browser/issueService';
import 'vs/workbench/services/menubar/electron-browser/menubarService';
import 'vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
......
......@@ -48,6 +48,7 @@ import 'vs/workbench/services/host/browser/browserHostService';
import 'vs/workbench/services/request/browser/requestService';
import 'vs/workbench/services/lifecycle/browser/lifecycleService';
import 'vs/workbench/services/clipboard/browser/clipboardService';
import 'vs/workbench/services/extensionResourceLoader/browser/extensionResourceLoaderService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册