diff --git a/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts index 3287988b9ce..6b4aef605b0 100644 --- a/src/vs/editor/common/services/languagesRegistry.ts +++ b/src/vs/editor/common/services/languagesRegistry.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { onUnexpectedError } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; import * as mime from 'vs/base/common/mime'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; @@ -26,7 +28,10 @@ export interface IResolvedLanguage { configurationFiles: URI[]; } -export class LanguagesRegistry { +export class LanguagesRegistry extends Disposable { + + private readonly _onDidChange: Emitter = this._register(new Emitter()); + public readonly onDidChange: Event = this._onDidChange.event; private _nextLanguageId: number; private _languages: { [id: string]: IResolvedLanguage; }; @@ -39,6 +44,7 @@ export class LanguagesRegistry { private _warnOnOverwrite: boolean; constructor(useModesRegistry = true, warnOnOverwrite = false) { + super(); this._nextLanguageId = 1; this._languages = {}; this._mimeTypesMap = {}; @@ -49,7 +55,7 @@ export class LanguagesRegistry { if (useModesRegistry) { this._registerLanguages(ModesRegistry.getLanguages()); - ModesRegistry.onDidAddLanguages((m) => this._registerLanguages(m)); + this._register(ModesRegistry.onDidAddLanguages((m) => this._registerLanguages(m))); } } @@ -80,6 +86,8 @@ export class LanguagesRegistry { }); Registry.as(Extensions.Configuration).registerOverrideIdentifiers(ModesRegistry.getLanguages().map(language => language.id)); + + this._onDidChange.fire(); } private _registerLanguage(lang: ILanguageExtensionPoint): void { diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index 687045df69b..2c456c57828 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -21,6 +22,11 @@ export interface ILanguageExtensionPoint { configuration?: URI; } +export interface ILanguageSelection extends IDisposable { + readonly languageIdentifier: LanguageIdentifier; + readonly onDidChange: Event; +} + export interface IModeService { _serviceBrand: any; @@ -41,8 +47,9 @@ export interface IModeService { getConfigurationFiles(modeId: string): URI[]; // --- instantiation - getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): IMode | null; - getOrCreateMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): Promise; - getOrCreateModeByLanguageName(languageName: string): Promise; - getOrCreateModeByFilepathOrFirstLine(filepath: string, firstLine?: string): Promise; + create(commaSeparatedMimetypesOrCommaSeparatedIds: string): ILanguageSelection; + createByLanguageName(languageName: string): ILanguageSelection; + createByFilepathOrFirstLine(filepath: string, firstLine?: string): ILanguageSelection; + + triggerMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): void; } diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index e8082e186e3..5f76d658c39 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -3,14 +3,41 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IMode, LanguageId, LanguageIdentifier } from 'vs/editor/common/modes'; import { FrankensteinMode } from 'vs/editor/common/modes/abstractMode'; import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode'; import { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { ILanguageSelection, IModeService } from 'vs/editor/common/services/modeService'; + +class LanguageSelection extends Disposable implements ILanguageSelection { + + public languageIdentifier: LanguageIdentifier; + + private readonly _selector: () => LanguageIdentifier; + + private readonly _onDidChange: Emitter = this._register(new Emitter()); + public readonly onDidChange: Event = this._onDidChange.event; + + constructor(languagesRegistry: LanguagesRegistry, selector: () => LanguageIdentifier) { + super(); + this._selector = selector; + this.languageIdentifier = this._selector(); + this._register(languagesRegistry.onDidChange(() => this._evaluate())); + } + + private _evaluate(): void { + let languageIdentifier = this._selector(); + if (languageIdentifier.id === this.languageIdentifier.id) { + // no change + return; + } + this.languageIdentifier = languageIdentifier; + this._onDidChange.fire(this.languageIdentifier); + } +} export class ModeServiceImpl implements IModeService { public _serviceBrand: any; @@ -93,44 +120,44 @@ export class ModeServiceImpl implements IModeService { // --- instantiation - public getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): IMode | null { - const modeIds = this._registry.extractModeIds(commaSeparatedMimetypesOrCommaSeparatedIds); - - let isPlainText = false; - for (let i = 0; i < modeIds.length; i++) { - if (this._instantiatedModes.hasOwnProperty(modeIds[i])) { - return this._instantiatedModes[modeIds[i]]; - } - isPlainText = isPlainText || (modeIds[i] === 'plaintext'); - } - - if (isPlainText) { - // Try to do it synchronously - let r: IMode | null = null; - this.getOrCreateMode(commaSeparatedMimetypesOrCommaSeparatedIds).then((mode) => { - r = mode; - }, onUnexpectedError); - return r; - } - return null; - } - - public getOrCreateMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): Promise { - return this._onReady().then(() => { + public create(commaSeparatedMimetypesOrCommaSeparatedIds: string): ILanguageSelection { + return new LanguageSelection(this._registry, () => { const modeId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds); - // Fall back to plain text if no mode was found - return this._getOrCreateMode(modeId || 'plaintext'); + return this._createModeAndGetLanguageIdentifier(modeId); }); } - public getOrCreateModeByLanguageName(languageName: string): Promise { - return this._onReady().then(() => { + public createByLanguageName(languageName: string): ILanguageSelection { + return new LanguageSelection(this._registry, () => { const modeId = this._getModeIdByLanguageName(languageName); - // Fall back to plain text if no mode was found - return this._getOrCreateMode(modeId || 'plaintext'); + return this._createModeAndGetLanguageIdentifier(modeId); }); } + public createByFilepathOrFirstLine(filepath: string, firstLine?: string): ILanguageSelection { + return new LanguageSelection(this._registry, () => { + const modeId = this.getModeIdByFilepathOrFirstLine(filepath, firstLine); + return this._createModeAndGetLanguageIdentifier(modeId); + }); + } + + private _createModeAndGetLanguageIdentifier(modeId: string | null): LanguageIdentifier { + // Fall back to plain text if no mode was found + const languageIdentifier = this.getLanguageIdentifier(modeId || 'plaintext') || NULL_LANGUAGE_IDENTIFIER; + this._getOrCreateMode(languageIdentifier.language); + return languageIdentifier; + } + + public triggerMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): void { + const modeId = this.getModeId(commaSeparatedMimetypesOrCommaSeparatedIds); + // Fall back to plain text if no mode was found + this._getOrCreateMode(modeId || 'plaintext'); + } + + public waitForLanguageRegistration(): Promise { + return this._onReady().then(() => { }); + } + private _getModeIdByLanguageName(languageName: string): string | null { const modeIds = this._registry.getModeIdsFromLanguageName(languageName); @@ -141,14 +168,6 @@ export class ModeServiceImpl implements IModeService { return null; } - public getOrCreateModeByFilepathOrFirstLine(filepath: string, firstLine?: string): Promise { - return this._onReady().then(() => { - const modeId = this.getModeIdByFilepathOrFirstLine(filepath, firstLine); - // Fall back to plain text if no mode was found - return this._getOrCreateMode(modeId || 'plaintext'); - }); - } - private _getOrCreateMode(modeId: string): IMode { if (!this._instantiatedModes.hasOwnProperty(modeId)) { let languageIdentifier = this.getLanguageIdentifier(modeId) || NULL_LANGUAGE_IDENTIFIER; diff --git a/src/vs/editor/common/services/modelService.ts b/src/vs/editor/common/services/modelService.ts index 13f72ee515d..a75af8a1f49 100644 --- a/src/vs/editor/common/services/modelService.ts +++ b/src/vs/editor/common/services/modelService.ts @@ -6,7 +6,7 @@ import { Event } from 'vs/base/common/event'; import { URI } from 'vs/base/common/uri'; import { ITextBufferFactory, ITextModel, ITextModelCreationOptions } from 'vs/editor/common/model'; -import { IMode } from 'vs/editor/common/modes'; +import { ILanguageSelection } from 'vs/editor/common/services/modeService'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const IModelService = createDecorator('modelService'); @@ -14,11 +14,11 @@ export const IModelService = createDecorator('modelService'); export interface IModelService { _serviceBrand: any; - createModel(value: string | ITextBufferFactory, modeOrPromise: Promise | IMode, resource: URI | undefined, isForSimpleWidget?: boolean): ITextModel; + createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource: URI, isForSimpleWidget?: boolean): ITextModel; updateModel(model: ITextModel, value: string | ITextBufferFactory): void; - setMode(model: ITextModel, modeOrPromise: Promise | IMode): void; + setMode(model: ITextModel, languageSelection: ILanguageSelection): void; destroyModel(resource: URI): void; diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index e68601b9a09..b8386637f8c 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -5,7 +5,6 @@ import * as nls from 'vs/nls'; import { isFalsyOrEmpty } from 'vs/base/common/arrays'; -import { isThenable } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -20,8 +19,9 @@ import { DefaultEndOfLine, EndOfLinePreference, EndOfLineSequence, IIdentifiedSi import { ClassName } from 'vs/editor/common/model/intervalTree'; import { TextModel, createTextBuffer } from 'vs/editor/common/model/textModel'; import { IModelLanguageChangedEvent } from 'vs/editor/common/model/textModelEvents'; -import { IMode, LanguageIdentifier } from 'vs/editor/common/modes'; +import { LanguageIdentifier } from 'vs/editor/common/modes'; import { PLAINTEXT_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/modesRegistry'; +import { ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { overviewRulerError, overviewRulerInfo, overviewRulerWarning } from 'vs/editor/common/view/editorColorRegistry'; @@ -34,7 +34,10 @@ function MODEL_ID(resource: URI): string { } class ModelData implements IDisposable { - model: ITextModel; + public readonly model: ITextModel; + + private _languageSelection: ILanguageSelection | null; + private _languageSelectionListener: IDisposable | null; private _markerDecorations: string[]; private _modelEventListeners: IDisposable[]; @@ -46,6 +49,9 @@ class ModelData implements IDisposable { ) { this.model = model; + this._languageSelection = null; + this._languageSelectionListener = null; + this._markerDecorations = []; this._modelEventListeners = []; @@ -53,14 +59,33 @@ class ModelData implements IDisposable { this._modelEventListeners.push(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e))); } + private _disposeLanguageSelection(): void { + if (this._languageSelectionListener) { + this._languageSelectionListener.dispose(); + this._languageSelectionListener = null; + } + if (this._languageSelection) { + this._languageSelection.dispose(); + this._languageSelection = null; + } + } + public dispose(): void { this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, []); this._modelEventListeners = dispose(this._modelEventListeners); + this._disposeLanguageSelection(); } public acceptMarkerDecorations(newDecorations: IModelDeltaDecoration[]): void { this._markerDecorations = this.model.deltaDecorations(this._markerDecorations, newDecorations); } + + public setLanguage(languageSelection: ILanguageSelection): void { + this._disposeLanguageSelection(); + this._languageSelection = languageSelection; + this._languageSelectionListener = this._languageSelection.onDidChange(() => this.model.setMode(languageSelection.languageIdentifier)); + this.model.setMode(languageSelection.languageIdentifier); + } } class ModelMarkerHandler { @@ -508,14 +533,14 @@ export class ModelServiceImpl extends Disposable implements IModelService { return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))]; } - public createModel(value: string | ITextBufferFactory, modeOrPromise: Promise | IMode, resource: URI, isForSimpleWidget: boolean = false): ITextModel { + public createModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource: URI, isForSimpleWidget: boolean = false): ITextModel { let modelData: ModelData; - if (!modeOrPromise || isThenable(modeOrPromise)) { - modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget); - this.setMode(modelData.model, modeOrPromise); + if (languageSelection) { + modelData = this._createModelData(value, languageSelection.languageIdentifier, resource, isForSimpleWidget); + this.setMode(modelData.model, languageSelection); } else { - modelData = this._createModelData(value, modeOrPromise.getLanguageIdentifier(), resource, isForSimpleWidget); + modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget); } // handle markers (marker service => model) @@ -528,19 +553,15 @@ export class ModelServiceImpl extends Disposable implements IModelService { return modelData.model; } - public setMode(model: ITextModel, modeOrPromise: Promise | IMode): void { - if (!modeOrPromise) { + public setMode(model: ITextModel, languageSelection: ILanguageSelection): void { + if (!languageSelection) { return; } - if (isThenable(modeOrPromise)) { - modeOrPromise.then((mode) => { - if (!model.isDisposed()) { - model.setMode(mode.getLanguageIdentifier()); - } - }); - } else { - model.setMode(modeOrPromise.getLanguageIdentifier()); + let modelData = this._models[MODEL_ID(model.uri)]; + if (!modelData) { + return; } + modelData.setLanguage(languageSelection); } public destroyModel(resource: URI): void { diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index b9f7970cbce..62208620c8c 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -48,7 +48,8 @@ export class MarkdownRenderer { } } - return this._modeService.getOrCreateMode(modeId || '').then(_ => { + this._modeService.triggerMode(modeId || ''); + return Promise.resolve(true).then(_ => { const promise = TokenizationRegistry.getPromise(modeId || ''); if (promise) { return promise.then(support => tokenizeToString(value, support)); diff --git a/src/vs/editor/contrib/smartSelect/test/tokenSelectionSupport.test.ts b/src/vs/editor/contrib/smartSelect/test/tokenSelectionSupport.test.ts index 633ce503192..bab374e26c7 100644 --- a/src/vs/editor/contrib/smartSelect/test/tokenSelectionSupport.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/tokenSelectionSupport.test.ts @@ -8,7 +8,7 @@ import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { LanguageIdentifier } from 'vs/editor/common/modes'; import { TokenSelectionSupport } from 'vs/editor/contrib/smartSelect/tokenSelectionSupport'; -import { MockMode } from 'vs/editor/test/common/mocks/mockMode'; +import { MockMode, StaticLanguageSelector } from 'vs/editor/test/common/mocks/mockMode'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; @@ -56,7 +56,7 @@ suite('TokenSelectionSupport', () => { function assertGetRangesToPosition(text: string[], lineNumber: number, column: number, ranges: Range[]): void { let uri = URI.file('test.js'); - modelService.createModel(text.join('\n'), mode, uri); + modelService.createModel(text.join('\n'), new StaticLanguageSelector(mode.getLanguageIdentifier()), uri); let actual = tokenSelectionSupport.getRangesToPositionSync(uri, new Position(lineNumber, column)); diff --git a/src/vs/editor/standalone/browser/colorizer.ts b/src/vs/editor/standalone/browser/colorizer.ts index 621861e264f..e085b2e80ed 100644 --- a/src/vs/editor/standalone/browser/colorizer.ts +++ b/src/vs/editor/standalone/browser/colorizer.ts @@ -60,7 +60,7 @@ export class Colorizer { } // Send out the event to create the mode - modeService.getOrCreateMode(language); + modeService.triggerMode(language); let tokenizationSupport = TokenizationRegistry.get(language); if (tokenizationSupport) { diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 5802e10b911..3a221ffbf51 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -18,6 +18,7 @@ import { FindMatch, ITextModel, TextModelResolvedOptions } from 'vs/editor/commo import * as modes from 'vs/editor/common/modes'; import { NULL_STATE, nullTokenize } from 'vs/editor/common/modes/nullMode'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { ILanguageSelection } from 'vs/editor/common/services/modeService'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IWebWorkerOptions, MonacoWebWorker, createWebWorker as actualCreateWebWorker } from 'vs/editor/common/services/webWorker'; import * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums'; @@ -134,8 +135,8 @@ export function createDiffNavigator(diffEditor: IStandaloneDiffEditor, opts?: ID return new DiffNavigator(diffEditor, opts); } -function doCreateModel(value: string, mode: Promise, uri?: URI): ITextModel { - return StaticServices.modelService.get().createModel(value, mode, uri); +function doCreateModel(value: string, languageSelection: ILanguageSelection, uri?: URI): ITextModel { + return StaticServices.modelService.get().createModel(value, languageSelection, uri); } /** @@ -154,16 +155,16 @@ export function createModel(value: string, language?: string, uri?: URI): ITextM firstLine = value.substring(0, firstLF); } - return doCreateModel(value, StaticServices.modeService.get().getOrCreateModeByFilepathOrFirstLine(path, firstLine), uri); + return doCreateModel(value, StaticServices.modeService.get().createByFilepathOrFirstLine(path, firstLine), uri); } - return doCreateModel(value, StaticServices.modeService.get().getOrCreateMode(language), uri); + return doCreateModel(value, StaticServices.modeService.get().create(language), uri); } /** * Change the language for a model. */ export function setModelLanguage(model: ITextModel, languageId: string): void { - StaticServices.modelService.get().setMode(model, StaticServices.modeService.get().getOrCreateMode(languageId)); + StaticServices.modelService.get().setMode(model, StaticServices.modeService.get().create(languageId)); } /** @@ -277,7 +278,7 @@ function getSafeTokenizationSupport(language: string): modes.ITokenizationSuppor export function tokenize(text: string, languageId: string): Token[][] { let modeService = StaticServices.modeService.get(); // Needed in order to get the mode registered for subsequent look-ups - modeService.getOrCreateMode(languageId); + modeService.triggerMode(languageId); let tokenizationSupport = getSafeTokenizationSupport(languageId); let lines = text.split(/\r\n|\r|\n/); diff --git a/src/vs/editor/standalone/common/monarch/monarchLexer.ts b/src/vs/editor/standalone/common/monarch/monarchLexer.ts index 7142c905fef..35c9e5b1c50 100644 --- a/src/vs/editor/standalone/common/monarch/monarchLexer.ts +++ b/src/vs/editor/standalone/common/monarch/monarchLexer.ts @@ -787,38 +787,31 @@ class MonarchTokenizer implements modes.ITokenizationSupport { } private _getNestedEmbeddedModeData(mimetypeOrModeId: string): EmbeddedModeData { - let nestedMode = this._locateMode(mimetypeOrModeId); - if (nestedMode) { - let tokenizationSupport = modes.TokenizationRegistry.get(nestedMode.getId()); + let nestedModeId = this._locateMode(mimetypeOrModeId); + if (nestedModeId) { + let tokenizationSupport = modes.TokenizationRegistry.get(nestedModeId); if (tokenizationSupport) { - return new EmbeddedModeData(nestedMode.getId(), tokenizationSupport.getInitialState()); + return new EmbeddedModeData(nestedModeId, tokenizationSupport.getInitialState()); } } - let nestedModeId = nestedMode ? nestedMode.getId() : NULL_MODE_ID; - return new EmbeddedModeData(nestedModeId, NULL_STATE); + return new EmbeddedModeData(nestedModeId || NULL_MODE_ID, NULL_STATE); } - private _locateMode(mimetypeOrModeId: string): modes.IMode { + private _locateMode(mimetypeOrModeId: string): string | null { if (!mimetypeOrModeId || !this._modeService.isRegisteredMode(mimetypeOrModeId)) { return null; } let modeId = this._modeService.getModeId(mimetypeOrModeId); - // Fire mode loading event - this._modeService.getOrCreateMode(modeId); - - let mode = this._modeService.getMode(modeId); - if (mode) { - // Re-emit tokenizationSupport change events from all modes that I ever embedded + if (modeId) { + // Fire mode loading event + this._modeService.triggerMode(modeId); this._embeddedModes[modeId] = true; - return mode; } - this._embeddedModes[modeId] = true; - - return null; + return modeId; } } diff --git a/src/vs/editor/test/common/mocks/mockMode.ts b/src/vs/editor/test/common/mocks/mockMode.ts index 7d5ce73d972..bf24cc35ceb 100644 --- a/src/vs/editor/test/common/mocks/mockMode.ts +++ b/src/vs/editor/test/common/mocks/mockMode.ts @@ -3,8 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { IMode, LanguageIdentifier } from 'vs/editor/common/modes'; +import { ILanguageSelection } from 'vs/editor/common/services/modeService'; export class MockMode extends Disposable implements IMode { private _languageIdentifier: LanguageIdentifier; @@ -22,3 +24,9 @@ export class MockMode extends Disposable implements IMode { return this._languageIdentifier; } } + +export class StaticLanguageSelector implements ILanguageSelection { + readonly onDidChange: Event = Event.None; + constructor(public readonly languageIdentifier: LanguageIdentifier) { } + public dispose(): void { } +} diff --git a/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts b/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts index c42d2894288..ef57f28a65a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDocumentContentProviders.ts @@ -46,8 +46,8 @@ export class MainThreadDocumentContentProviders implements MainThreadDocumentCon return this._proxy.$provideTextDocumentContent(handle, uri).then(value => { if (typeof value === 'string') { const firstLineText = value.substr(0, 1 + value.search(/\r?\n/)); - const mode = this._modeService.getOrCreateModeByFilepathOrFirstLine(uri.fsPath, firstLineText); - return this._modelService.createModel(value, mode, uri); + const languageSelection = this._modeService.createByFilepathOrFirstLine(uri.fsPath, firstLineText); + return this._modelService.createModel(value, languageSelection, uri); } return undefined; }); diff --git a/src/vs/workbench/api/electron-browser/mainThreadLanguages.ts b/src/vs/workbench/api/electron-browser/mainThreadLanguages.ts index 77d0885224a..6ea6e3b3524 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadLanguages.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadLanguages.ts @@ -33,12 +33,11 @@ export class MainThreadLanguages implements MainThreadLanguagesShape { if (!model) { return Promise.reject(new Error('Invalid uri')); } - return this._modeService.getOrCreateMode(languageId).then(mode => { - if (mode.getId() !== languageId) { - return Promise.reject(new Error(`Unknown language id: ${languageId}`)); - } - this._modelService.setMode(model, mode); - return undefined; - }); + const languageIdentifier = this._modeService.getLanguageIdentifier(languageId); + if (!languageIdentifier || languageIdentifier.language !== languageId) { + return Promise.reject(new Error(`Unknown language id: ${languageId}`)); + } + this._modelService.setMode(model, this._modeService.create(languageId)); + return Promise.resolve(undefined); } } diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 1545851c286..c4129406956 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -15,7 +15,6 @@ import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { Action } from 'vs/base/common/actions'; import { language, LANGUAGE_DEFAULT, AccessibilitySupport } from 'vs/base/common/platform'; import * as browser from 'vs/base/browser/browser'; -import { IMode } from 'vs/editor/common/modes'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput } from 'vs/workbench/common/editor'; import { IDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -32,7 +31,7 @@ import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; import { SUPPORTED_ENCODINGS, IFileService, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; @@ -977,16 +976,16 @@ export class ChangeModeAction extends Action { } // Find mode - let mode: Promise; + let languageSelection: ILanguageSelection; if (pick === autoDetectMode) { - mode = this.modeService.getOrCreateModeByFilepathOrFirstLine(toResource(activeEditor, { supportSideBySide: true }).fsPath, textModel.getLineContent(1)); + languageSelection = this.modeService.createByFilepathOrFirstLine(toResource(activeEditor, { supportSideBySide: true }).fsPath, textModel.getLineContent(1)); } else { - mode = this.modeService.getOrCreateModeByLanguageName(pick.label); + languageSelection = this.modeService.createByLanguageName(pick.label); } // Change mode models.forEach(textModel => { - this.modelService.setMode(textModel, mode); + this.modelService.setMode(textModel, languageSelection); }); }); } diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index 6ae29b06ebf..db7432b7ff6 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -5,11 +5,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ITextModel, ITextBufferFactory } from 'vs/editor/common/model'; -import { IMode } from 'vs/editor/common/modes'; import { EditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ITextSnapshot } from 'vs/platform/files/common/files'; @@ -72,22 +71,22 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd */ protected createTextEditorModel(value: ITextBufferFactory, resource?: URI, modeId?: string): TPromise { const firstLineText = this.getFirstLineText(value); - const mode = this.getOrCreateMode(this.modeService, modeId, firstLineText); + const languageSelection = this.getOrCreateMode(this.modeService, modeId, firstLineText); - return TPromise.as(this.doCreateTextEditorModel(value, mode, resource)); + return TPromise.as(this.doCreateTextEditorModel(value, languageSelection, resource)); } - private doCreateTextEditorModel(value: ITextBufferFactory, mode: Promise, resource: URI): EditorModel { + private doCreateTextEditorModel(value: ITextBufferFactory, languageSelection: ILanguageSelection, resource: URI): EditorModel { let model = resource && this.modelService.getModel(resource); if (!model) { - model = this.modelService.createModel(value, mode, resource); + model = this.modelService.createModel(value, languageSelection, resource); this.createdEditorModel = true; // Make sure we clean up when this model gets disposed this.registerModelDisposeListener(model); } else { this.modelService.updateModel(model, value); - this.modelService.setMode(model, mode); + this.modelService.setMode(model, languageSelection); } this.textEditorModelHandle = model.uri; @@ -113,8 +112,8 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd * * @param firstLineText optional first line of the text buffer to set the mode on. This can be used to guess a mode from content. */ - protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): Promise { - return modeService.getOrCreateMode(modeId); + protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection { + return modeService.create(modeId); } /** diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index 936c4732993..91c66b68e74 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -9,9 +9,8 @@ import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel' import { URI } from 'vs/base/common/uri'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { IMode } from 'vs/editor/common/modes'; import { Event, Emitter } from 'vs/base/common/event'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -58,9 +57,9 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin this.registerListeners(); } - protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): Promise { + protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): ILanguageSelection { if (!modeId || modeId === PLAINTEXT_MODE_ID) { - return modeService.getOrCreateModeByFilepathOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific + return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific } return super.getOrCreateMode(modeService, modeId, firstLineText); diff --git a/src/vs/workbench/parts/comments/electron-browser/commentNode.ts b/src/vs/workbench/parts/comments/electron-browser/commentNode.ts index ed0f88781a2..c29429ff159 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentNode.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentNode.ts @@ -123,7 +123,7 @@ export class CommentNode extends Disposable { const container = dom.append(this._commentEditContainer, dom.$('.edit-textarea')); this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions()); const resource = URI.parse(`comment:commentinput-${this.comment.commentId}-${Date.now()}.md`); - this._commentEditorModel = this.modelService.createModel('', this.modeService.getOrCreateModeByFilepathOrFirstLine(resource.path), resource, true); + this._commentEditorModel = this.modelService.createModel('', this.modeService.createByFilepathOrFirstLine(resource.path), resource, true); this._commentEditor.setModel(this._commentEditorModel); this._commentEditor.setValue(this.comment.body.value); diff --git a/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts b/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts index 2e20f65049a..371ba684c3b 100644 --- a/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts +++ b/src/vs/workbench/parts/comments/electron-browser/commentThreadWidget.ts @@ -279,7 +279,7 @@ export class ReviewZoneWidget extends ZoneWidget { this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, this._commentForm, SimpleCommentEditor.getEditorOptions()); const modeId = hasExistingComments ? this._commentThread.threadId : ++INMEM_MODEL_ID; const resource = URI.parse(`${COMMENT_SCHEME}:commentinput-${modeId}.md`); - const model = this.modelService.createModel(this._pendingComment || '', this.modeService.getOrCreateModeByFilepathOrFirstLine(resource.path), resource, true); + const model = this.modelService.createModel(this._pendingComment || '', this.modeService.createByFilepathOrFirstLine(resource.path), resource, true); this._localToDispose.push(model); this._commentEditor.setModel(model); this._localToDispose.push(this._commentEditor); diff --git a/src/vs/workbench/parts/debug/browser/debugContentProvider.ts b/src/vs/workbench/parts/debug/browser/debugContentProvider.ts index 710c3a9756b..b43020c8727 100644 --- a/src/vs/workbench/parts/debug/browser/debugContentProvider.ts +++ b/src/vs/workbench/parts/debug/browser/debugContentProvider.ts @@ -58,19 +58,19 @@ export class DebugContentProvider implements IWorkbenchContribution, ITextModelC } const createErrModel = (errMsg?: string) => { this.debugService.sourceIsNotAvailable(resource); - const modePromise = this.modeService.getOrCreateMode(MIME_TEXT); + const languageSelection = this.modeService.create(MIME_TEXT); const message = errMsg ? localize('canNotResolveSourceWithError', "Could not load source '{0}': {1}.", resource.path, errMsg) : localize('canNotResolveSource', "Could not load source '{0}'.", resource.path); - return this.modelService.createModel(message, modePromise, resource); + return this.modelService.createModel(message, languageSelection, resource); }; return session.loadSource(resource).then(response => { if (response && response.body) { const mime = response.body.mimeType || guessMimeTypes(resource.path)[0]; - const modePromise = this.modeService.getOrCreateMode(mime); - return this.modelService.createModel(response.body.content, modePromise, resource); + const languageSelection = this.modeService.create(mime); + return this.modelService.createModel(response.body.content, languageSelection, resource); } return createErrModel(); diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index da81a19d848..36660df4223 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -13,9 +13,8 @@ import { ITextModelContentProvider } from 'vs/editor/common/services/resolverSer import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { TPromise } from 'vs/base/common/winjs.base'; import { ITextModel } from 'vs/editor/common/model'; -import { IMode } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { InputFocusedContextKey } from 'vs/platform/workbench/common/contextkeys'; @@ -190,14 +189,14 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { } else if (createAsNeeded) { const fileOnDiskModel = this.modelService.getModel(fileOnDiskResource); - let mode: Promise; + let languageSelector: ILanguageSelection; if (fileOnDiskModel) { - mode = this.modeService.getOrCreateMode(fileOnDiskModel.getModeId()); + languageSelector = this.modeService.create(fileOnDiskModel.getModeId()); } else { - mode = this.modeService.getOrCreateModeByFilepathOrFirstLine(fileOnDiskResource.fsPath); + languageSelector = this.modeService.createByFilepathOrFirstLine(fileOnDiskResource.fsPath); } - codeEditorModel = this.modelService.createModel(content.value, mode, resource); + codeEditorModel = this.modelService.createModel(content.value, languageSelector, resource); } return codeEditorModel; diff --git a/src/vs/workbench/parts/files/electron-browser/fileActions.ts b/src/vs/workbench/parts/files/electron-browser/fileActions.ts index 8cdac0809a1..a77c906d968 100644 --- a/src/vs/workbench/parts/files/electron-browser/fileActions.ts +++ b/src/vs/workbench/parts/files/electron-browser/fileActions.ts @@ -1546,7 +1546,7 @@ class ClipboardContentProvider implements ITextModelContentProvider { ) { } provideTextContent(resource: URI): TPromise { - const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.getOrCreateMode('text/plain'), resource); + const model = this.modelService.createModel(this.clipboardService.readText(), this.modeService.create('text/plain'), resource); return Promise.resolve(model); } diff --git a/src/vs/workbench/parts/output/electron-browser/outputServices.ts b/src/vs/workbench/parts/output/electron-browser/outputServices.ts index 3a502c0c846..d347b6a9487 100644 --- a/src/vs/workbench/parts/output/electron-browser/outputServices.ts +++ b/src/vs/workbench/parts/output/electron-browser/outputServices.ts @@ -131,7 +131,7 @@ abstract class AbstractFileOutputChannel extends Disposable implements OutputCha if (this.model) { this.model.setValue(content); } else { - this.model = this.modelService.createModel(content, this.modeService.getOrCreateMode(this.mimeType), this.modelUri); + this.model = this.modelService.createModel(content, this.modeService.create(this.mimeType), this.modelUri); this.onModelCreated(this.model); const disposables: IDisposable[] = []; disposables.push(this.model.onWillDispose(() => { @@ -744,7 +744,7 @@ class BufferredOutputChannel extends Disposable implements OutputChannel { } private createModel(content: string): ITextModel { - const model = this.modelService.createModel(content, this.modeService.getOrCreateMode(OUTPUT_MIME), URI.from({ scheme: OUTPUT_SCHEME, path: this.id })); + const model = this.modelService.createModel(content, this.modeService.create(OUTPUT_MIME), URI.from({ scheme: OUTPUT_SCHEME, path: this.id })); const disposables: IDisposable[] = []; disposables.push(model.onWillDispose(() => { this.model = null; diff --git a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts index db35ad97128..d216c48ec44 100644 --- a/src/vs/workbench/parts/preferences/browser/preferencesActions.ts +++ b/src/vs/workbench/parts/preferences/browser/preferencesActions.ts @@ -278,8 +278,8 @@ export class ConfigureLanguageBasedSettingsAction extends Action { return this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguage', "Select Language") }) .then(pick => { if (pick) { - return this.modeService.getOrCreateModeByLanguageName(pick.label) - .then(mode => this.preferencesService.configureSettingsForLanguage(mode.getLanguageIdentifier().language)); + const modeId = this.modeService.getModeIdForLanguageName(pick.label.toLowerCase()); + return this.preferencesService.configureSettingsForLanguage(modeId); } return undefined; }); diff --git a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts index c6c339df2ee..7fed426e5eb 100644 --- a/src/vs/workbench/parts/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/parts/preferences/common/preferencesContribution.ts @@ -128,8 +128,8 @@ export class PreferencesContribution implements IWorkbenchContribution { let schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; if (schema) { const modelContent = JSON.stringify(schema); - const mode = this.modeService.getOrCreateMode('jsonc'); - const model = this.modelService.createModel(modelContent, mode, uri); + const languageSelection = this.modeService.create('jsonc'); + const model = this.modelService.createModel(modelContent, languageSelection, uri); let disposables: IDisposable[] = []; disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => { diff --git a/src/vs/workbench/parts/search/browser/replaceService.ts b/src/vs/workbench/parts/search/browser/replaceService.ts index 54ff7977da3..ea4de3b3dee 100644 --- a/src/vs/workbench/parts/search/browser/replaceService.ts +++ b/src/vs/workbench/parts/search/browser/replaceService.ts @@ -73,7 +73,7 @@ class ReplacePreviewModel extends Disposable { ref = this._register(ref); const sourceModel = ref.object.textEditorModel; const sourceModelModeId = sourceModel.getLanguageIdentifier().language; - const replacePreviewModel = this.modelService.createModel(createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot()), this.modeService.getOrCreateMode(sourceModelModeId), replacePreviewUri); + const replacePreviewModel = this.modelService.createModel(createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot()), this.modeService.create(sourceModelModeId), replacePreviewUri); this._register(fileMatch.onChange(modelChange => this.update(sourceModel, replacePreviewModel, fileMatch, modelChange))); this._register(this.searchWorkbenchService.searchModel.onReplaceTermChanged(() => this.update(sourceModel, replacePreviewModel, fileMatch))); this._register(fileMatch.onDispose(() => replacePreviewModel.dispose())); // TODO@Sandeep we should not dispose a model directly but rather the reference (depends on https://github.com/Microsoft/vscode/issues/17073) diff --git a/src/vs/workbench/parts/themes/test/electron-browser/themes.test.contribution.ts b/src/vs/workbench/parts/themes/test/electron-browser/themes.test.contribution.ts index 8ac211ef77d..f2696c752d3 100644 --- a/src/vs/workbench/parts/themes/test/electron-browser/themes.test.contribution.ts +++ b/src/vs/workbench/parts/themes/test/electron-browser/themes.test.contribution.ts @@ -215,15 +215,14 @@ class Snapper { } public captureSyntaxTokens(fileName: string, content: string): Thenable { - return this.modeService.getOrCreateModeByFilepathOrFirstLine(fileName).then(mode => { - return this.textMateService.createGrammar(mode.getId()).then((grammar) => { - let lines = content.split(/\r\n|\r|\n/); + const modeId = this.modeService.getModeIdByFilepathOrFirstLine(fileName); + return this.textMateService.createGrammar(modeId).then((grammar) => { + let lines = content.split(/\r\n|\r|\n/); - let result = this._tokenize(grammar, lines); - return this._getThemesResult(grammar, lines).then((themesResult) => { - this._enrichResult(result, themesResult); - return result.filter(t => t.c.length > 0); - }); + let result = this._tokenize(grammar, lines); + return this._getThemesResult(grammar, lines).then((themesResult) => { + this._enrichResult(result, themesResult); + return result.filter(t => t.c.length > 0); }); }); } diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts index f12c4ed45df..cbabfd24a9c 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts @@ -26,6 +26,7 @@ import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/commo import { WebviewEditorInput } from 'vs/workbench/parts/webview/electron-browser/webviewEditorInput'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; function renderBody( body: string, @@ -60,7 +61,8 @@ export class ReleaseNotesManager { @IRequestService private readonly _requestService: IRequestService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @IEditorService private readonly _editorService: IEditorService, - @IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService + @IWebviewEditorService private readonly _webviewEditorService: IWebviewEditorService, + @IExtensionService private readonly _extensionService: IExtensionService ) { TokenizationRegistry.onDidChange(async () => { if (!this._currentReleaseNotes || !this._lastText) { @@ -194,7 +196,10 @@ export class ReleaseNotesManager { const renderer = new marked.Renderer(); renderer.code = (code, lang) => { const modeId = this._modeService.getModeIdForLanguageName(lang); - result.push(this._modeService.getOrCreateMode(modeId).then(_ => TokenizationRegistry.getPromise(modeId))); + result.push(this._extensionService.whenInstalledExtensionsRegistered().then(_ => { + this._modeService.triggerMode(modeId); + return TokenizationRegistry.getPromise(modeId); + })); return ''; }; diff --git a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts index 7895c98f556..f093b63e4de 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/node/walkThroughContentProvider.ts @@ -40,7 +40,7 @@ export class WalkThroughContentProvider implements ITextModelContentProvider, IW return content.then(content => { let codeEditorModel = this.modelService.getModel(resource); if (!codeEditorModel) { - codeEditorModel = this.modelService.createModel(content, this.modeService.getOrCreateModeByFilepathOrFirstLine(resource.fsPath), resource); + codeEditorModel = this.modelService.createModel(content, this.modeService.createByFilepathOrFirstLine(resource.fsPath), resource); } else { this.modelService.updateModel(codeEditorModel, content); } @@ -85,9 +85,9 @@ export class WalkThroughSnippetContentProvider implements ITextModelContentProvi const markdown = textBuffer.getValueInRange(range, EndOfLinePreference.TextDefined); marked(markdown, { renderer }); - const modeId = this.modeService.getModeIdForLanguageName(languageName); - const mode = this.modeService.getOrCreateMode(modeId); - codeEditorModel = this.modelService.createModel(codeSnippet, mode, resource); + const languageId = this.modeService.getModeIdForLanguageName(languageName); + const languageSelection = this.modeService.create(languageId); + codeEditorModel = this.modelService.createModel(codeSnippet, languageSelection, resource); } else { this.modelService.updateModel(codeEditorModel, content.value); } diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 820b9377bec..d8f3b152fa8 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -108,8 +108,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic if (this.isDefaultSettingsResource(uri)) { const target = this.getConfigurationTargetFromDefaultSettingsResource(uri); - const mode = this.modeService.getOrCreateMode('jsonc'); - const model = this._register(this.modelService.createModel('', mode, uri)); + const languageSelection = this.modeService.create('jsonc'); + const model = this._register(this.modelService.createModel('', languageSelection, uri)); let defaultSettings: DefaultSettings; this.configurationService.onDidChangeConfiguration(e => { @@ -136,15 +136,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic if (this.defaultSettingsRawResource.toString() === uri.toString()) { let defaultSettings: DefaultSettings = this.getDefaultSettings(ConfigurationTarget.USER); - const mode = this.modeService.getOrCreateMode('jsonc'); - const model = this._register(this.modelService.createModel(defaultSettings.raw, mode, uri)); + const languageSelection = this.modeService.create('jsonc'); + const model = this._register(this.modelService.createModel(defaultSettings.raw, languageSelection, uri)); return TPromise.as(model); } if (this.defaultKeybindingsResource.toString() === uri.toString()) { const defaultKeybindingsEditorModel = this.instantiationService.createInstance(DefaultKeybindingsEditorModel, uri); - const mode = this.modeService.getOrCreateMode('jsonc'); - const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, mode, uri)); + const languageSelection = this.modeService.create('jsonc'); + const model = this._register(this.modelService.createModel(defaultKeybindingsEditorModel.content, languageSelection, uri)); return TPromise.as(model); } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index d0efefbbbfd..9bc56c2fce5 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -11,7 +11,6 @@ import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { URI } from 'vs/base/common/uri'; import { isUndefinedOrNull } from 'vs/base/common/types'; -import { IMode } from 'vs/editor/common/modes'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, IRawTextContent, ILoadOptions, LoadReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -20,7 +19,7 @@ import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel' import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IFileService, IFileStat, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { RunOnceScheduler, timeout } from 'vs/base/common/async'; @@ -197,9 +196,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } const firstLineText = this.getFirstLineText(this.textEditorModel); - const mode = this.getOrCreateMode(this.modeService, void 0, firstLineText); + const languageSelection = this.getOrCreateMode(this.modeService, void 0, firstLineText); - this.modelService.setMode(this.textEditorModel, mode); + this.modelService.setMode(this.textEditorModel, languageSelection); } getVersionId(): number { @@ -493,8 +492,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.backupFileService.resolveBackupContent(backup).then(backupContent => backupContent, error => null /* ignore errors */); } - protected getOrCreateMode(modeService: IModeService, preferredModeIds: string, firstLineText?: string): Promise { - return modeService.getOrCreateModeByFilepathOrFirstLine(this.resource.fsPath, firstLineText); + protected getOrCreateMode(modeService: IModeService, preferredModeIds: string, firstLineText?: string): ILanguageSelection { + return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); } private onModelContentChanged(): void { diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index acf1e5bfce1..aef5632358a 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -59,8 +59,8 @@ suite('Workbench - TextModelResolverService', () => { provideTextContent: function (resource: URI): TPromise { if (resource.scheme === 'test') { let modelContent = 'Hello Test'; - let mode = accessor.modeService.getOrCreateMode('json'); - return TPromise.as(accessor.modelService.createModel(modelContent, mode, resource)); + let languageSelection = accessor.modeService.create('json'); + return TPromise.as(accessor.modelService.createModel(modelContent, languageSelection, resource)); } return TPromise.as(null); @@ -137,8 +137,8 @@ suite('Workbench - TextModelResolverService', () => { provideTextContent: (resource: URI): TPromise => { return waitForIt.then(_ => { let modelContent = 'Hello Test'; - let mode = accessor.modeService.getOrCreateMode('json'); - return accessor.modelService.createModel(modelContent, mode, resource); + let languageSelection = accessor.modeService.create('json'); + return accessor.modelService.createModel(modelContent, languageSelection, resource); }); } }); diff --git a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts index 68953e620bc..4594a22b024 100644 --- a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts @@ -41,8 +41,8 @@ suite('Workbench editor model', () => { provideTextContent: function (resource: URI): TPromise { if (resource.scheme === 'test') { let modelContent = 'Hello Test'; - let mode = accessor.modeService.getOrCreateMode('json'); - return TPromise.as(accessor.modelService.createModel(modelContent, mode, resource)); + let languageSelection = accessor.modeService.create('json'); + return TPromise.as(accessor.modelService.createModel(modelContent, languageSelection, resource)); } return TPromise.as(null); diff --git a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts index b43a41d5264..873c498d0aa 100644 --- a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts +++ b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts @@ -33,7 +33,7 @@ suite('Workbench resource editor input', () => { test('simple', () => { let resource = URI.from({ scheme: 'inmemory', authority: null, path: 'thePath' }); - accessor.modelService.createModel('function test() {}', accessor.modeService.getOrCreateMode('text'), resource); + accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); return input.resolve().then((model: ResourceEditorModel) => {