From 3e16b9bc72ebe90578744fa1b8b716238f1a6297 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 7 Apr 2016 19:07:55 +0200 Subject: [PATCH] TypeScript is not a compat mode --- .../standalone/standaloneCodeEditor.ts | 23 +- .../browser/standalone/standaloneEditor.ts | 7 +- src/vs/languages/typescript/common/mode.ts | 228 +++++++++--------- .../common/typescript.contribution.ts | 14 +- .../test/common/tokenization.test.ts | 24 +- 5 files changed, 146 insertions(+), 150 deletions(-) diff --git a/src/vs/editor/browser/standalone/standaloneCodeEditor.ts b/src/vs/editor/browser/standalone/standaloneCodeEditor.ts index 7bf4334f3b2ef..a61d0df31a1bd 100644 --- a/src/vs/editor/browser/standalone/standaloneCodeEditor.ts +++ b/src/vs/editor/browser/standalone/standaloneCodeEditor.ts @@ -440,7 +440,7 @@ export function createCustomMode(language:ILanguage): TPromise { return modeService.getOrCreateMode(modeId); } -export function registerStandaloneLanguage(language:ILanguageExtensionPoint, defModule:string): void { +export function registerMonarchStandaloneLanguage(language:ILanguageExtensionPoint, defModule:string): void { ModesRegistry.registerLanguage(language); ExtensionsRegistry.registerOneTimeActivationEventListener('onLanguage:' + language.id, () => { @@ -463,6 +463,27 @@ export function registerStandaloneLanguage(language:ILanguageExtensionPoint, def }); } +export function registerStandaloneLanguage(language:ILanguageExtensionPoint, defModule:string): void { + ModesRegistry.registerLanguage(language); + + ExtensionsRegistry.registerOneTimeActivationEventListener('onLanguage:' + language.id, () => { + require([defModule], (value:{activate:()=>void}) => { + if (!value.activate) { + console.error('Expected ' + defModule + ' to export an `activate` function'); + return; + } + + startup.initStaticServicesIfNecessary(); + let staticPlatformServices = ensureStaticPlatformServices(null); + let instantiationService = staticPlatformServices.instantiationService; + + instantiationService.invokeFunction(value.activate); + }, (err) => { + console.error('Cannot find module ' + defModule, err); + }); + }); +} + export function registerStandaloneSchema(uri:string, schema:IJSONSchema) { let schemaRegistry = Registry.as(Extensions.JSONContribution); schemaRegistry.registerSchema(uri, schema); diff --git a/src/vs/editor/browser/standalone/standaloneEditor.ts b/src/vs/editor/browser/standalone/standaloneEditor.ts index a1393f8146e3f..3944c9b134b7a 100644 --- a/src/vs/editor/browser/standalone/standaloneEditor.ts +++ b/src/vs/editor/browser/standalone/standaloneEditor.ts @@ -67,7 +67,7 @@ Monaco.Editor.OverlayWidgetPositionPreference = OverlayWidgetPositionPreference; // Register all built-in standalone languages let MonacoEditorLanguages: ILanguageDef[] = this.MonacoEditorLanguages || []; MonacoEditorLanguages.forEach((language) => { - standaloneCodeEditor.registerStandaloneLanguage(language, language.defModule); + standaloneCodeEditor.registerMonarchStandaloneLanguage(language, language.defModule); }); // Register all built-in standalone JSON schemas @@ -75,3 +75,8 @@ let MonacoEditorSchemas: { [url:string]: IJSONSchema } = this.MonacoEditorSchema for (var uri in MonacoEditorSchemas) { standaloneCodeEditor.registerStandaloneSchema(uri, MonacoEditorSchemas[uri]); } + +if (!Monaco.Languages) { + Monaco.Languages = {}; +} +Monaco.Languages.register = standaloneCodeEditor.registerStandaloneLanguage; diff --git a/src/vs/languages/typescript/common/mode.ts b/src/vs/languages/typescript/common/mode.ts index d31a85515f5d2..cb5c352f78a98 100644 --- a/src/vs/languages/typescript/common/mode.ts +++ b/src/vs/languages/typescript/common/mode.ts @@ -6,143 +6,131 @@ import * as modes from 'vs/editor/common/modes'; import * as lifecycle from 'vs/base/common/lifecycle'; -import URI from 'vs/base/common/uri'; -import {TPromise} from 'vs/base/common/winjs.base'; import {createTokenizationSupport, Language} from 'vs/languages/typescript/common/tokenization'; -import {AbstractMode, createWordRegExp} from 'vs/editor/common/modes/abstractMode'; -import {RichEditSupport} from 'vs/editor/common/modes/supports/richEditSupport'; +import {createWordRegExp} from 'vs/editor/common/modes/abstractMode'; +import {RichEditSupport, IRichEditConfiguration} from 'vs/editor/common/modes/supports/richEditSupport'; import {IModelService} from 'vs/editor/common/services/modelService'; +import {IModeService} from 'vs/editor/common/services/modeService'; import {IMarkerService} from 'vs/platform/markers/common/markers'; -import {IThreadService} from 'vs/platform/thread/common/thread'; -import {LanguageServiceDefaults, typeScriptDefaults, javaScriptDefaults, LanguageServiceMode, TypeScriptWorkerProtocol} from './typescript'; +import {LanguageServiceDefaults, typeScriptDefaults, javaScriptDefaults, LanguageServiceMode} from './typescript'; import {register} from './languageFeatures'; +import {ServicesAccessor} from 'vs/platform/instantiation/common/instantiation'; -export abstract class Mode extends AbstractMode implements lifecycle.IDisposable, LanguageServiceMode { +function setupMode(modelService:IModelService, markerService:IMarkerService, modeService:IModeService, defaults:LanguageServiceDefaults, modeId:string, language:Language): void { - public tokenizationSupport: modes.ITokenizationSupport; - public richEditSupport: modes.IRichEditSupport; + let disposables: lifecycle.IDisposable[] = []; + let languageServiceMode: LanguageServiceMode; - private _languageServiceMode: LanguageServiceMode; - private _disposables: lifecycle.IDisposable[] = []; + require(['vs/languages/typescript/common/workerManager'], workerManager => { - constructor( - descriptor: modes.IModeDescriptor, - defaults:LanguageServiceDefaults, - @IThreadService threadService: IThreadService, - @IModelService private _modelService: IModelService, - @IMarkerService private _markerService: IMarkerService - ) { - super(descriptor.id); + const client = workerManager.create(defaults, modelService); - if (threadService.isInMainThread && _modelService && _markerService) { + languageServiceMode = client; + disposables.push(client); - // this is needed as long as this mode is also instantiated in the worker - require(['vs/languages/typescript/common/workerManager'], workerManager => { + const registration = register( + modelService, + markerService, + modeId, + defaults, + (first, ...more) => client.getLanguageServiceWorker(...[first].concat(more)) + ); + disposables.push(registration); - const client = workerManager.create(defaults, this._modelService); - this._languageServiceMode = client; - this._disposables.push(client); + }, err => { + console.error(err); + }); - const registration = register(this._modelService, this._markerService, - this.getId(), defaults, - (first, ...more) => client.getLanguageServiceWorker(...[first].concat(more))); - this._disposables.push(registration); + modeService.registerRichEditSupport(modeId, richEditConfiguration); + modeService.registerTokenizationSupport(modeId, (mode) => { + return createTokenizationSupport(mode, language); + }); +} - }, err => { - console.error(err); - }); +const richEditConfiguration:IRichEditConfiguration = { + wordPattern: createWordRegExp('$'), + + comments: { + lineComment: '//', + blockComment: ['/*', '*/'] + }, + + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + + onEnterRules: [ + { + // e.g. /** | */ + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: modes.IndentAction.IndentOutdent, appendText: ' * ' } + }, + { + // e.g. /** ...| + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction: modes.IndentAction.None, appendText: ' * ' } + }, + { + // e.g. * ...| + beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction: modes.IndentAction.None, appendText: '* ' } + }, + { + // e.g. */| + beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, + action: { indentAction: modes.IndentAction.None, removeText: 1 } } - - this.richEditSupport = new RichEditSupport(this.getId(), null, { - wordPattern: createWordRegExp('$'), - - comments: { - lineComment: '//', - blockComment: ['/*', '*/'] - }, - - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ], - - onEnterRules: [ - { - // e.g. /** | */ - beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, - afterText: /^\s*\*\/$/, - action: { indentAction: modes.IndentAction.IndentOutdent, appendText: ' * ' } - }, - { - // e.g. /** ...| - beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, - action: { indentAction: modes.IndentAction.None, appendText: ' * ' } - }, - { - // e.g. * ...| - beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, - action: { indentAction: modes.IndentAction.None, appendText: '* ' } - }, - { - // e.g. */| - beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, - action: { indentAction: modes.IndentAction.None, removeText: 1 } - } - ], - - __electricCharacterSupport: { - docComment: {scope:'comment.doc', open:'/**', lineStart:' * ', close:' */'} - }, - - __characterPairSupport: { - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"', notIn: ['string'] }, - { open: '\'', close: '\'', notIn: ['string', 'comment'] }, - { open: '`', close: '`' } - ] - } - }); - } - - dispose(): void { - this._disposables = lifecycle.dispose(this._disposables); + ], + + __electricCharacterSupport: { + docComment: {scope:'comment.doc', open:'/**', lineStart:' * ', close:' */'} + }, + + __characterPairSupport: { + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"', notIn: ['string'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '`', close: '`' } + ] } +}; - getLanguageServiceWorker(...resources: URI[]): TPromise { - if (this._languageServiceMode) { - return this._languageServiceMode.getLanguageServiceWorker(...resources); - } - } +export function createRichEditSupport(modeId:string): RichEditSupport { + return new RichEditSupport(modeId, null, richEditConfiguration); } -export class TypeScriptMode extends Mode { - - constructor( - descriptor: modes.IModeDescriptor, - @IThreadService threadService: IThreadService, - @IModelService modelService: IModelService, - @IMarkerService markerService: IMarkerService - ) { - super(descriptor, typeScriptDefaults, threadService, modelService, markerService); - - this.tokenizationSupport = createTokenizationSupport(this, Language.TypeScript); +let isActivated = false; +export function activate(ctx:ServicesAccessor): void { + if (isActivated) { + return; } + isActivated = true; + + let modelService = ctx.get(IModelService); + let markerService = ctx.get(IMarkerService); + let modeService = ctx.get(IModeService); + + setupMode( + modelService, + markerService, + modeService, + typeScriptDefaults, + 'typescript', + Language.TypeScript + ); + + setupMode( + modelService, + markerService, + modeService, + javaScriptDefaults, + 'javascript', + Language.EcmaScript5 + ); } - -export class JavaScriptMode extends Mode { - - constructor( - descriptor: modes.IModeDescriptor, - @IThreadService threadService: IThreadService, - @IModelService modelService: IModelService, - @IMarkerService markerService: IMarkerService - ) { - super(descriptor, javaScriptDefaults, threadService, modelService, markerService); - - this.tokenizationSupport = createTokenizationSupport(this, Language.EcmaScript5); - } -} \ No newline at end of file diff --git a/src/vs/languages/typescript/common/typescript.contribution.ts b/src/vs/languages/typescript/common/typescript.contribution.ts index fb17b215d623a..bf4d10561816d 100644 --- a/src/vs/languages/typescript/common/typescript.contribution.ts +++ b/src/vs/languages/typescript/common/typescript.contribution.ts @@ -4,26 +4,22 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; +import {registerStandaloneLanguage} from 'vs/editor/browser/standalone/standaloneCodeEditor'; // ----- Registration and Configuration -------------------------------------------------------- -ModesRegistry.registerCompatMode({ +registerStandaloneLanguage({ id: 'typescript', extensions: ['.ts'], aliases: ['TypeScript', 'ts', 'typescript'], mimetypes: ['text/typescript'], - moduleId: 'vs/languages/typescript/common/mode', - ctorName: 'TypeScriptMode' -}); +}, 'vs/languages/typescript/common/mode'); -ModesRegistry.registerCompatMode({ +registerStandaloneLanguage({ id: 'javascript', extensions: ['.js', '.es6'], firstLine: '^#!.*\\bnode', filenames: ['jakefile'], aliases: ['JavaScript', 'javascript', 'js'], mimetypes: ['text/javascript'], - moduleId: 'vs/languages/typescript/common/mode', - ctorName: 'JavaScriptMode' -}); +}, 'vs/languages/typescript/common/mode'); diff --git a/src/vs/languages/typescript/test/common/tokenization.test.ts b/src/vs/languages/typescript/test/common/tokenization.test.ts index a1c77e78aad9f..0c436a1a73db6 100644 --- a/src/vs/languages/typescript/test/common/tokenization.test.ts +++ b/src/vs/languages/typescript/test/common/tokenization.test.ts @@ -6,28 +6,14 @@ import Modes = require('vs/editor/common/modes'); import modesUtil = require('vs/editor/test/common/modesUtil'); - -import {NULL_THREAD_SERVICE} from 'vs/platform/test/common/nullThreadService'; -import {JavaScriptMode} from 'vs/languages/typescript/common/mode'; +import {createTokenizationSupport, Language} from 'vs/languages/typescript/common/tokenization'; +import {MockMode} from 'vs/editor/test/common/mocks/mockMode'; +import {createRichEditSupport} from 'vs/languages/typescript/common/mode'; suite('TS/JS - syntax highlighting', () => { - var tokenizationSupport: Modes.ITokenizationSupport; - var assertOnEnter: modesUtil.IOnEnterAsserter; - - setup(() => { - let threadService = NULL_THREAD_SERVICE; - - let mode = new JavaScriptMode( - { id: 'javascript' }, - threadService, - null, - null - ); - - tokenizationSupport = mode.tokenizationSupport; - assertOnEnter = modesUtil.createOnEnterAsserter(mode.getId(), mode.richEditSupport); - }); + var tokenizationSupport = createTokenizationSupport(new MockMode('javascript'), Language.EcmaScript5); + var assertOnEnter = modesUtil.createOnEnterAsserter('javascript', createRichEditSupport('javascript')); test('onEnter', function() { assertOnEnter.nothing('', '', 'var f = function() {');