diff --git a/.vscode/settings.json b/.vscode/settings.json index 824ad313adb1a..294ab5be9c929 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,7 +28,8 @@ "packages/python/coverage/lcov.info", "packages/terminal/coverage/lcov.info", "packages/workspace/coverage/lcov.info", - "packages/task/coverage/lcov.info" + "packages/task/coverage/lcov.info", + "packages/monaco-textmate/coverage/lcov.info" ], "lcov.watch": [ { @@ -44,4 +45,4 @@ "editor.tabSize": 2 }, "typescript.tsdk": "node_modules/typescript/lib" -} +} \ No newline at end of file diff --git a/dev-packages/application-manager/package-lock.json b/dev-packages/application-manager/package-lock.json new file mode 100644 index 0000000000000..8f1a0fe2d38e4 --- /dev/null +++ b/dev-packages/application-manager/package-lock.json @@ -0,0 +1,12 @@ +{ + "name": "@theia/application-manager", + "version": "0.3.10", + "lockfileVersion": 1, + "dependencies": { + "monaco-editor-webpack-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.2.0.tgz", + "integrity": "sha512-hqZs9pT+j0GjHLglKquSTWQvE1RUG2Zelcavo91vVExRL9NPbDP6w7eySahMqysOF1eBob8n+ZVkrPsnxJrQYQ==" + } + } +} diff --git a/dev-packages/application-manager/src/generator/frontend-generator.ts b/dev-packages/application-manager/src/generator/frontend-generator.ts index 4026c43cc53c2..0537e32f532ee 100644 --- a/dev-packages/application-manager/src/generator/frontend-generator.ts +++ b/dev-packages/application-manager/src/generator/frontend-generator.ts @@ -47,6 +47,7 @@ const { FrontendApplication } = require('@theia/core/lib/browser'); const { frontendApplicationModule } = require('@theia/core/lib/browser/frontend-application-module'); const { messagingFrontendModule } = require('@theia/core/lib/browser/messaging/messaging-frontend-module'); const { loggerFrontendModule } = require('@theia/core/lib/browser/logger-frontend-module'); +const { ThemeService } = require('@theia/core/lib/browser/theming'); const container = new Container(); container.load(frontendApplicationModule); @@ -60,6 +61,9 @@ function load(raw) { } function start() { + const themeService = ThemeService.get() + themeService.loadUserTheme(); + const application = container.get(FrontendApplication); application.start(); } diff --git a/dev-packages/application-manager/src/generator/webpack-generator.ts b/dev-packages/application-manager/src/generator/webpack-generator.ts index 9c6262c41407f..4b848e37a4bcd 100644 --- a/dev-packages/application-manager/src/generator/webpack-generator.ts +++ b/dev-packages/application-manager/src/generator/webpack-generator.ts @@ -38,7 +38,7 @@ const { mode } = yargs.option('mode', { }).argv; const development = mode === 'development';${this.ifMonaco(() => ` -const monacoEditorPath = development ? '${this.resolve('monaco-editor-core', 'dev/vs')}' : '${this.resolve('monaco-editor-core', 'min/vs')}'; +const monacoEditorCorePath = development ? '${this.resolve('monaco-editor-core', 'dev/vs')}' : '${this.resolve('monaco-editor-core', 'min/vs')}'; const monacoLanguagesPath = '${this.resolve('monaco-languages', 'release/min')}'; const monacoCssLanguagePath = '${this.resolve('monaco-css', 'release/min')}'; const monacoJsonLanguagePath = '${this.resolve('monaco-json', 'release/min')}'; @@ -98,7 +98,7 @@ module.exports = { test: /\\.js$/, enforce: 'pre', loader: 'source-map-loader', - exclude: /jsonc-parser/ + exclude: /jsonc-parser|fast-plist|onigasm|(monaco-editor.*)/ }, { test: /\\.woff(2)?(\\?v=[0-9]\\.[0-9]\\.[0-9])?$/, @@ -107,20 +107,25 @@ module.exports = { { test: /node_modules[\\\\|\/](vscode-languageserver-types|vscode-uri|jsonc-parser)/, use: { loader: 'umd-compat-loader' } + }, + { + test: /\.wasm$/, + loader: "file-loader", + type: "javascript/auto", } ] }, resolve: { extensions: ['.js']${this.ifMonaco(() => `, alias: { - 'vs': path.resolve(outputPath, monacoEditorPath) + 'vs': path.resolve(outputPath, monacoEditorCorePath) }`)} }, devtool: 'source-map', plugins: [ new CopyWebpackPlugin([${this.ifMonaco(() => ` { - from: monacoEditorPath, + from: monacoEditorCorePath, to: 'vs' }, { @@ -143,7 +148,7 @@ module.exports = { new CircularDependencyPlugin({ exclude: /(node_modules|examples)\\/./, failOnError: false // https://github.com/nodejs/readable-stream/issues/280#issuecomment-297076462 - }) + }), ], stats: { warnings: true diff --git a/packages/core/src/browser/frontend-application-module.ts b/packages/core/src/browser/frontend-application-module.ts index 61915e03df9f8..e6a2038ea1cf7 100644 --- a/packages/core/src/browser/frontend-application-module.ts +++ b/packages/core/src/browser/frontend-application-module.ts @@ -36,9 +36,10 @@ import { LabelParser } from './label-parser'; import { LabelProvider, LabelProviderContribution, DefaultUriLabelProviderContribution } from "./label-provider"; import { PreferenceProviders, PreferenceProvider, - PreferenceScope, PreferenceService, PreferenceServiceImpl } from './preferences'; + PreferenceScope, PreferenceService, PreferenceServiceImpl +} from './preferences'; import { ContextMenuRenderer } from './context-menu-renderer'; -import { ThemingCommandContribution, ThemeService } from './theming'; +import { ThemingCommandContribution, ThemeService, BuiltinThemeProvider } from './theming'; import { ConnectionStatusService, FrontendConnectionStatusService, ApplicationConnectionStatusContribution } from './connection-status-service'; import { DiffUriLabelProviderContribution } from './diff-uris'; import { ApplicationServer, applicationPath } from "../common/application-protocol"; @@ -48,6 +49,10 @@ import { EnvVariablesServer, envVariablesPath } from "./../common/env-variables" import { FrontendApplicationStateService } from './frontend-application-state'; export const frontendApplicationModule = new ContainerModule((bind, unbind, isBound, rebind) => { + const themeService = ThemeService.get(); + themeService.register(...BuiltinThemeProvider.themes); + themeService.startupTheme(); + bind(FrontendApplication).toSelf().inSingletonScope(); bind(FrontendApplicationStateService).toSelf().inSingletonScope(); bind(DefaultFrontendApplicationContribution).toSelf(); @@ -121,8 +126,6 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo bind(LabelProviderContribution).to(DefaultUriLabelProviderContribution).inSingletonScope(); bind(LabelProviderContribution).to(DiffUriLabelProviderContribution).inSingletonScope(); - bind(CommandContribution).to(ThemingCommandContribution).inSingletonScope(); - bind(PreferenceProvider).toSelf().inSingletonScope().whenTargetNamed(PreferenceScope.User); bind(PreferenceProvider).toSelf().inSingletonScope().whenTargetNamed(PreferenceScope.Workspace); bind(PreferenceProviders).toFactory(ctx => (scope: PreferenceScope) => ctx.container.getNamed(PreferenceProvider, scope)); @@ -149,7 +152,7 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo const connection = ctx.container.get(WebSocketConnectionProvider); return connection.createProxy(envVariablesPath); }).inSingletonScope(); -}); -const theme = ThemeService.get().getCurrentTheme().id; -ThemeService.get().setCurrentTheme(theme); + bind(ThemeService).toDynamicValue(() => ThemeService.get()); + bind(CommandContribution).to(ThemingCommandContribution).inSingletonScope(); +}); diff --git a/packages/core/src/browser/theming.ts b/packages/core/src/browser/theming.ts index eeff20929180c..3f9333e86d8f0 100644 --- a/packages/core/src/browser/theming.ts +++ b/packages/core/src/browser/theming.ts @@ -7,12 +7,12 @@ import { injectable, inject } from 'inversify'; import { CommandRegistry, CommandContribution, CommandHandler, Command } from '../common/command'; -import { QuickOpenService } from './quick-open/quick-open-service'; -import { QuickOpenModel, QuickOpenItem, QuickOpenMode } from './quick-open/quick-open-model'; +import { ThemeProvider } from '../common/theming-protocol'; import { Emitter, Event } from '../common/event'; +import { QuickOpenModel, QuickOpenItem, QuickOpenMode } from './quick-open/quick-open-model'; +import { QuickOpenService } from './quick-open/quick-open-service'; -const dark = require('../../src/browser/style/variables-dark.useable.css'); -const light = require('../../src/browser/style/variables-bright.useable.css'); +export const ThemeServiceSymbol = Symbol('ThemeService'); export interface Theme { id: string; @@ -28,46 +28,35 @@ export interface ThemeChangeEvent { oldTheme?: Theme; } -const darkTheme: Theme = { - id: 'dark', - label: 'Dark Theme', - description: 'Bright fonts on dark backgrounds.', - editorTheme: 'vs-dark', - activate() { - dark.use(); - }, - deactivate() { - dark.unuse(); - } -}; - -const lightTheme: Theme = { - id: 'light', - label: 'Light Theme', - description: 'Dark fonts on light backgrounds.', - editorTheme: 'vs', - activate() { - light.use(); - }, - deactivate() { - light.unuse(); - } -}; - -export class ThemeService { +export class ThemeService implements ThemeProvider { private themes: { [id: string]: Theme } = {}; private activeTheme: Theme | undefined; private readonly themeChange = new Emitter(); - public readonly onThemeChange: Event = this.themeChange.event; + private readonly themeProviders: ThemeProvider[] = []; + + readonly onThemeChange: Event = this.themeChange.event; + readonly ready: Promise = this.gatherThemes().then(() => undefined); + + static get() { + const global = window as any; // tslint:disable-line + return global[ThemeServiceSymbol] || new ThemeService(); + } - protected constructor(private defaultTheme: string) { } + protected constructor( + public defaultTheme: string = 'dark' + ) { + const global = window as any; // tslint:disable-line + global[ThemeServiceSymbol] = this; + } - register(theme: Theme) { - this.themes[theme.id] = theme; + register(...themes: Theme[]) { + for (const theme of themes) { + this.themes[theme.id] = theme; + } } - getThemes(): Theme[] { + getThemes() { const result = []; for (const o in this.themes) { if (this.themes.hasOwnProperty(o)) { @@ -77,8 +66,44 @@ export class ThemeService { return result; } + getTheme(themeId: string) { + return this.themes[themeId] || this.themes[this.defaultTheme]; + } + + async gatherThemes() { + const gathered: Theme[] = []; + + // Concurrent gathering of the themes + await Promise.all( + this.themeProviders.map( + provider => provider.gatherThemes() + .catch(error => { + console.error(error); + return []; + }) + .then(themes => { + gathered.push(...themes); + }) + ) + ); + + // Update theme cache in one synchronous execution + this.register(...gathered); + return gathered; + } + + startupTheme() { + const theme = this.getCurrentTheme(); + theme.activate(); + } + + loadUserTheme() { + const theme = this.getCurrentTheme(); + this.setCurrentTheme(theme.id); + } + setCurrentTheme(themeId: string) { - const newTheme = this.themes[themeId] || this.themes[this.defaultTheme]; + const newTheme = this.getTheme(themeId); const oldTheme = this.activeTheme; if (oldTheme) { oldTheme.deactivate(); @@ -96,18 +121,7 @@ export class ThemeService { return this.themes[themeId] || this.themes[this.defaultTheme]; } - static get() { - // tslint:disable-next-line:no-any - const wnd = window as any; - if (!wnd.__themeService) { - const themeService = new ThemeService('dark'); - wnd.__themeService = themeService; - } - return wnd.__themeService as ThemeService; - } } -ThemeService.get().register(darkTheme); -ThemeService.get().register(lightTheme); @injectable() export class ThemingCommandContribution implements CommandContribution, CommandHandler, Command, QuickOpenModel { @@ -115,9 +129,12 @@ export class ThemingCommandContribution implements CommandContribution, CommandH id = 'change_theme'; label = 'Change Color Theme'; private resetTo: string | undefined; - private themeService = ThemeService.get(); - constructor( @inject(QuickOpenService) protected openService: QuickOpenService) { } + @inject(ThemeService) + protected readonly themeService: ThemeService; + + @inject(QuickOpenService) + protected readonly openService: QuickOpenService; registerCommands(commands: CommandRegistry): void { commands.registerCommand(this, this); @@ -140,12 +157,7 @@ export class ThemingCommandContribution implements CommandContribution, CommandH private activeIndex() { const current = this.themeService.getCurrentTheme().id; const themes = this.themeService.getThemes(); - for (let i = 0; i < themes.length; i++) { - if (themes[i].id === current) { - return i; - } - } - return -1; + return themes.findIndex(theme => theme.id === current); } onType(lookFor: string, acceptor: (items: QuickOpenItem[]) => void): void { @@ -164,3 +176,45 @@ export class ThemingCommandContribution implements CommandContribution, CommandH acceptor(items); } } + +export class BuiltinThemeProvider implements ThemeProvider { + + // Webpack converts these `require` in some Javascript object that wraps the `.css` files + static readonly darkCss = require('../../src/browser/style/variables-dark.useable.css'); + static readonly lightCss = require('../../src/browser/style/variables-bright.useable.css'); + + static readonly darkTheme = { + id: 'dark', + label: 'Dark Theme', + description: 'Bright fonts on dark backgrounds.', + editorTheme: 'vs-dark', + activate() { + BuiltinThemeProvider.darkCss.use(); + }, + deactivate() { + BuiltinThemeProvider.darkCss.unuse(); + } + }; + + static readonly lightTheme = { + id: 'light', + label: 'Light Theme', + description: 'Dark fonts on light backgrounds.', + editorTheme: 'vs', + activate() { + BuiltinThemeProvider.lightCss.use(); + }, + deactivate() { + BuiltinThemeProvider.lightCss.unuse(); + } + }; + + static readonly themes = [ + BuiltinThemeProvider.darkTheme, + BuiltinThemeProvider.lightTheme, + ]; + + async gatherThemes() { + return BuiltinThemeProvider.themes; + } +} diff --git a/packages/core/src/common/index.ts b/packages/core/src/common/index.ts index d6483c6add2f6..9a6893335525f 100644 --- a/packages/core/src/common/index.ts +++ b/packages/core/src/common/index.ts @@ -24,3 +24,4 @@ export * from './message-service'; export * from './message-service-protocol'; export * from './selection'; export * from './strings'; +export * from './theming-protocol'; diff --git a/packages/core/src/common/promise-util.ts b/packages/core/src/common/promise-util.ts index 5c874c69854f8..c55b49d573009 100644 --- a/packages/core/src/common/promise-util.ts +++ b/packages/core/src/common/promise-util.ts @@ -11,7 +11,7 @@ */ export class Deferred { resolve: (value?: T) => void; - reject: (err?: any) => void; + reject: (err?: any) => void; // tslint:disable-line promise = new Promise((resolve, reject) => { this.resolve = resolve; diff --git a/packages/core/src/common/theming-protocol.ts b/packages/core/src/common/theming-protocol.ts new file mode 100644 index 0000000000000..fa1d886a3bf95 --- /dev/null +++ b/packages/core/src/common/theming-protocol.ts @@ -0,0 +1,16 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ +import { Theme } from '../browser/theming'; + +export const ThemeProvider = Symbol('ThemeProvider'); +export interface ThemeProvider { + + /** + * Asynchronous call, this is used to make the I/O required to fetch the themes. + */ + gatherThemes(): Promise; +} diff --git a/packages/monaco/data/monaco-themes/vscode/dark_defaults.json b/packages/monaco/data/monaco-themes/vscode/dark_defaults.json new file mode 100644 index 0000000000000..cb9e20066b557 --- /dev/null +++ b/packages/monaco/data/monaco-themes/vscode/dark_defaults.json @@ -0,0 +1,15 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Dark Default Colors", + "colors": { + "editor.background": "#1E1E1E", + "editor.foreground": "#D4D4D4", + "editor.inactiveSelectionBackground": "#3A3D41", + "editorIndentGuide.background": "#404040", + "editorIndentGuide.activeBackground": "#707070", + "editor.selectionHighlightBackground": "#ADD6FF26", + "list.dropBackground": "#383B3D", + "activityBarBadge.background": "#007ACC", + "sideBarTitle.foreground": "#BBBBBB" + } +} \ No newline at end of file diff --git a/packages/monaco/data/monaco-themes/vscode/dark_plus.json b/packages/monaco/data/monaco-themes/vscode/dark_plus.json new file mode 100644 index 0000000000000..536b32d2a9ef3 --- /dev/null +++ b/packages/monaco/data/monaco-themes/vscode/dark_plus.json @@ -0,0 +1,163 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Dark+ (default dark)", + "include": "./dark_vs.json", + "tokenColors": [ + { + "name": "Function declarations", + "scope": [ + "entity.name.function", + "support.function", + "support.constant.handlebars" + ], + "settings": { + "foreground": "#DCDCAA" + } + }, + { + "name": "Types declaration and references", + "scope": [ + "meta.return-type", + "support.class", + "support.type", + "entity.name.type", + "entity.name.class", + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.cs", + "storage.type.generic.cs", + "storage.type.modifier.cs", + "storage.type.variable.cs", + "storage.type.annotation.java", + "storage.type.generic.java", + "storage.type.java", + "storage.type.object.array.java", + "storage.type.primitive.array.java", + "storage.type.primitive.java", + "storage.type.token.java", + "storage.type.groovy", + "storage.type.annotation.groovy", + "storage.type.parameters.groovy", + "storage.type.generic.groovy", + "storage.type.object.array.groovy", + "storage.type.primitive.array.groovy", + "storage.type.primitive.groovy" + ], + "settings": { + "foreground": "#4EC9B0" + } + }, + { + "name": "Types declaration and references, TS grammar specific", + "scope": [ + "meta.type.cast.expr", + "meta.type.new.expr", + "support.constant.math", + "support.constant.dom", + "support.constant.json", + "entity.other.inherited-class" + ], + "settings": { + "foreground": "#4EC9B0" + } + }, + { + "name": "Control flow keywords", + "scope": "keyword.control", + "settings": { + "foreground": "#C586C0" + } + }, + { + "name": "Variable and parameter name", + "scope": [ + "variable", + "meta.definition.variable.name", + "support.variable" + ], + "settings": { + "foreground": "#9CDCFE" + } + }, + { + "name": "Object keys, TS grammar specific", + "scope": [ + "meta.object-literal.key" + ], + "settings": { + "foreground": "#9CDCFE" + } + }, + { + "name": "CSS property value", + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "#CE9178" + } + }, + { + "name": "Regular expression groups", + "scope": [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp" + ], + "settings": { + "foreground": "#CE9178" + } + }, + { + "scope": [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp" + ], + "settings": { + "foreground": "#d16969" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "#DCDCAA" + } + }, + { + "scope": "keyword.operator.quantifier.regexp", + "settings": { + "foreground": "#d7ba7d" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "#d7ba7d" + } + } + ] +} diff --git a/packages/monaco/data/monaco-themes/vscode/dark_vs.json b/packages/monaco/data/monaco-themes/vscode/dark_vs.json new file mode 100644 index 0000000000000..c2a15addb8db2 --- /dev/null +++ b/packages/monaco/data/monaco-themes/vscode/dark_vs.json @@ -0,0 +1,356 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Dark (Visual Studio)", + "include": "./dark_defaults.json", + "tokenColors": [ + { + "scope": [ + "meta.embedded", + "source.groovy.embedded" + ], + "settings": { + "foreground": "#D4D4D4" + } + }, + { + "scope": "emphasis", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "strong", + "settings": { + "fontStyle": "bold" + } + }, + { + "scope": "header", + "settings": { + "foreground": "#000080" + } + }, + { + "scope": "comment", + "settings": { + "foreground": "#608b4e" + } + }, + { + "scope": "constant.language", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": [ + "constant.numeric" + ], + "settings": { + "foreground": "#b5cea8" + } + }, + { + "scope": "constant.regexp", + "settings": { + "foreground": "#646695" + } + }, + { + "scope": "entity.name.tag", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "entity.name.tag.css", + "settings": { + "foreground": "#d7ba7d" + } + }, + { + "scope": "entity.other.attribute-name", + "settings": { + "foreground": "#9cdcfe" + } + }, + { + "scope": [ + "entity.other.attribute-name.class.css", + "entity.other.attribute-name.class.mixin.css", + "entity.other.attribute-name.id.css", + "entity.other.attribute-name.parent-selector.css", + "entity.other.attribute-name.pseudo-class.css", + "entity.other.attribute-name.pseudo-element.css", + "source.css.less entity.other.attribute-name.id", + "entity.other.attribute-name.attribute.scss", + "entity.other.attribute-name.scss" + ], + "settings": { + "foreground": "#d7ba7d" + } + }, + { + "scope": "invalid", + "settings": { + "foreground": "#f44747" + } + }, + { + "scope": "markup.underline", + "settings": { + "fontStyle": "underline" + } + }, + { + "scope": "markup.bold", + "settings": { + "fontStyle": "bold", + "foreground": "#569cd6" + } + }, + { + "scope": "markup.heading", + "settings": { + "fontStyle": "bold", + "foreground": "#569cd6" + } + }, + { + "scope": "markup.italic", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "markup.inserted", + "settings": { + "foreground": "#b5cea8" + } + }, + { + "scope": "markup.deleted", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "markup.changed", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "beginning.punctuation.definition.quote.markdown", + "settings": { + "foreground": "#608b4e" + } + }, + { + "scope": "beginning.punctuation.definition.list.markdown", + "settings": { + "foreground": "#6796e6" + } + }, + { + "scope": "markup.inline.raw", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "meta.selector", + "settings": { + "foreground": "#d7ba7d" + } + }, + { + "name": "brackets of XML/HTML tags", + "scope": "punctuation.definition.tag", + "settings": { + "foreground": "#808080" + } + }, + { + "scope": "meta.preprocessor", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "meta.preprocessor.string", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "meta.preprocessor.numeric", + "settings": { + "foreground": "#b5cea8" + } + }, + { + "scope": "meta.structure.dictionary.key.python", + "settings": { + "foreground": "#9cdcfe" + } + }, + { + "scope": "meta.diff.header", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "storage", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "storage.type", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "storage.modifier", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "string", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "string.tag", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "string.value", + "settings": { + "foreground": "#ce9178" + } + }, + { + "scope": "string.regexp", + "settings": { + "foreground": "#d16969" + } + }, + { + "name": "String interpolation", + "scope": [ + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.section.embedded" + ], + "settings": { + "foreground": "#569cd6" + } + }, + { + "name": "Reset JavaScript string interpolation expression", + "scope": [ + "meta.template.expression" + ], + "settings": { + "foreground": "#d4d4d4" + } + }, + { + "scope": [ + "support.type.vendored.property-name", + "support.type.property-name", + "variable.css", + "variable.scss", + "variable.other.less", + "source.coffee.embedded" + ], + "settings": { + "foreground": "#9cdcfe" + } + }, + { + "scope": "keyword", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "keyword.control", + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "keyword.operator", + "settings": { + "foreground": "#d4d4d4" + } + }, + { + "scope": [ + "keyword.operator.new", + "keyword.operator.expression", + "keyword.operator.cast", + "keyword.operator.sizeof", + "keyword.operator.instanceof", + "keyword.operator.logical.python" + ], + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "keyword.other.unit", + "settings": { + "foreground": "#b5cea8" + } + }, + { + "scope": [ + "punctuation.section.embedded.begin.php", + "punctuation.section.embedded.end.php" + ], + "settings": { + "foreground": "#569cd6" + } + }, + { + "scope": "support.function.git-rebase", + "settings": { + "foreground": "#9cdcfe" + } + }, + { + "scope": "constant.sha.git-rebase", + "settings": { + "foreground": "#b5cea8" + } + }, + { + "name": "coloring of the Java import and package identifiers", + "scope": [ + "storage.modifier.import.java", + "variable.language.wildcard.java", + "storage.modifier.package.java" + ], + "settings": { + "foreground": "#d4d4d4" + } + }, + { + "name": "this.self", + "scope": "variable.language", + "settings": { + "foreground": "#569cd6" + } + } + ] +} \ No newline at end of file diff --git a/packages/monaco/data/monaco-themes/vscode/light_defaults.json b/packages/monaco/data/monaco-themes/vscode/light_defaults.json new file mode 100644 index 0000000000000..2ee46debb3a1f --- /dev/null +++ b/packages/monaco/data/monaco-themes/vscode/light_defaults.json @@ -0,0 +1,17 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Light Default Colors", + "colors": { + "editor.background": "#FFFFFF", + "editor.foreground": "#000000", + "editor.inactiveSelectionBackground": "#E5EBF1", + "editorIndentGuide.background": "#D3D3D3", + "editorIndentGuide.activeBackground": "#939393", + "editor.selectionHighlightBackground": "#ADD6FF4D", + "editorSuggestWidget.background": "#F3F3F3", + "activityBarBadge.background": "#007ACC", + "sideBarTitle.foreground": "#6F6F6F", + "list.hoverBackground": "#E8E8E8", + "input.placeholderForeground": "#ADADAD" + } +} \ No newline at end of file diff --git a/packages/monaco/data/monaco-themes/vscode/light_plus.json b/packages/monaco/data/monaco-themes/vscode/light_plus.json new file mode 100644 index 0000000000000..a3b31dcc05d32 --- /dev/null +++ b/packages/monaco/data/monaco-themes/vscode/light_plus.json @@ -0,0 +1,164 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Light+ (default light)", + "include": "./light_vs.json", + "tokenColors": [ + { + "name": "Function declarations", + "scope": [ + "entity.name.function", + "support.function", + "support.constant.handlebars" + ], + "settings": { + "foreground": "#795E26" + } + }, + { + "name": "Types declaration and references", + "scope": [ + "meta.return-type", + "support.class", + "support.type", + "entity.name.type", + "entity.name.class", + "storage.type.numeric.go", + "storage.type.byte.go", + "storage.type.boolean.go", + "storage.type.string.go", + "storage.type.uintptr.go", + "storage.type.cs", + "storage.type.generic.cs", + "storage.type.modifier.cs", + "storage.type.variable.cs", + "storage.type.annotation.java", + "storage.type.generic.java", + "storage.type.java", + "storage.type.object.array.java", + "storage.type.primitive.array.java", + "storage.type.primitive.java", + "storage.type.token.java", + "storage.type.groovy", + "storage.type.annotation.groovy", + "storage.type.parameters.groovy", + "storage.type.generic.groovy", + "storage.type.object.array.groovy", + "storage.type.primitive.array.groovy", + "storage.type.primitive.groovy" + ], + "settings": { + "foreground": "#267f99" + } + }, + { + "name": "Types declaration and references, TS grammar specific", + "scope": [ + "meta.type.cast.expr", + "meta.type.new.expr", + "support.constant.math", + "support.constant.dom", + "support.constant.json", + "entity.other.inherited-class" + ], + "settings": { + "foreground": "#267f99" + } + }, + { + "name": "Control flow keywords", + "scope": "keyword.control", + "settings": { + "foreground": "#AF00DB" + } + }, + { + "name": "Variable and parameter name", + "scope": [ + "variable", + "meta.definition.variable.name", + "support.variable" + ], + "settings": { + "foreground": "#001080" + } + }, + { + "name": "Object keys, TS grammar specific", + "scope": [ + "meta.object-literal.key" + ], + "settings": { + "foreground": "#001080" + } + }, + { + "name": "CSS property value", + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "#0451a5" + } + }, + { + "name": "Regular expression groups", + "scope": [ + "punctuation.definition.group.regexp", + "punctuation.definition.group.assertion.regexp", + "punctuation.definition.character-class.regexp", + "punctuation.character.set.begin.regexp", + "punctuation.character.set.end.regexp", + "keyword.operator.negation.regexp", + "support.other.parenthesis.regexp" + ], + "settings": { + "foreground": "#d16969" + } + }, + { + "scope": [ + "constant.character.character-class.regexp", + "constant.other.character-class.set.regexp", + "constant.other.character-class.regexp", + "constant.character.set.regexp" + ], + "settings": { + "foreground": "#811f3f" + } + }, + { + "scope": "keyword.operator.quantifier.regexp", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "keyword.operator.or.regexp", + "keyword.control.anchor.regexp" + ], + "settings": { + "foreground": "#ff0000" + } + }, + { + "scope": "constant.character", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "constant.character.escape", + "settings": { + "foreground": "#ff0000" + } + } + + ] +} \ No newline at end of file diff --git a/packages/monaco/data/monaco-themes/vscode/light_vs.json b/packages/monaco/data/monaco-themes/vscode/light_vs.json new file mode 100644 index 0000000000000..0fafec366456d --- /dev/null +++ b/packages/monaco/data/monaco-themes/vscode/light_vs.json @@ -0,0 +1,375 @@ +{ + "$schema": "vscode://schemas/color-theme", + "name": "Light (Visual Studio)", + "include": "./light_defaults.json", + "tokenColors": [ + { + "scope": ["meta.embedded", "source.groovy.embedded"], + "settings": { + "foreground": "#000000ff" + } + }, + { + "scope": "emphasis", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "strong", + "settings": { + "fontStyle": "bold" + } + }, + { + "scope": "meta.diff.header", + "settings": { + "foreground": "#000080" + } + }, + { + "scope": "comment", + "settings": { + "foreground": "#008000" + } + }, + { + "scope": "constant.language", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": [ + "constant.numeric" + ], + "settings": { + "foreground": "#09885a" + } + }, + { + "scope": "constant.regexp", + "settings": { + "foreground": "#811f3f" + } + }, + { + "name": "css tags in selectors, xml tags", + "scope": "entity.name.tag", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "entity.name.selector", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "entity.other.attribute-name", + "settings": { + "foreground": "#ff0000" + } + }, + { + "scope": [ + "entity.other.attribute-name.class.css", + "entity.other.attribute-name.class.mixin.css", + "entity.other.attribute-name.id.css", + "entity.other.attribute-name.parent-selector.css", + "entity.other.attribute-name.pseudo-class.css", + "entity.other.attribute-name.pseudo-element.css", + "source.css.less entity.other.attribute-name.id", + "entity.other.attribute-name.attribute.scss", + "entity.other.attribute-name.scss" + ], + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "invalid", + "settings": { + "foreground": "#cd3131" + } + }, + { + "scope": "markup.underline", + "settings": { + "fontStyle": "underline" + } + }, + { + "scope": "markup.bold", + "settings": { + "fontStyle": "bold", + "foreground": "#000080" + } + }, + { + "scope": "markup.heading", + "settings": { + "fontStyle": "bold", + "foreground": "#800000" + } + }, + { + "scope": "markup.italic", + "settings": { + "fontStyle": "italic" + } + }, + { + "scope": "markup.inserted", + "settings": { + "foreground": "#09885a" + } + }, + { + "scope": "markup.deleted", + "settings": { + "foreground": "#a31515" + } + }, + { + "scope": "markup.changed", + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": [ + "beginning.punctuation.definition.quote.markdown", + "beginning.punctuation.definition.list.markdown" + ], + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": "markup.inline.raw", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "meta.selector", + "settings": { + "foreground": "#800000" + } + }, + { + "name": "brackets of XML/HTML tags", + "scope": "punctuation.definition.tag", + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "meta.preprocessor", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "meta.preprocessor.string", + "settings": { + "foreground": "#a31515" + } + }, + { + "scope": "meta.preprocessor.numeric", + "settings": { + "foreground": "#09885a" + } + }, + { + "scope": "meta.structure.dictionary.key.python", + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": "storage", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "storage.type", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "storage.modifier", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "string", + "settings": { + "foreground": "#a31515" + } + }, + { + "scope": [ + "string.comment.buffered.block.pug", + "string.quoted.pug", + "string.interpolated.pug", + "string.unquoted.plain.in.yaml", + "string.unquoted.plain.out.yaml", + "string.unquoted.block.yaml", + "string.quoted.single.yaml", + "string.quoted.double.xml", + "string.quoted.single.xml", + "string.unquoted.cdata.xml", + "string.quoted.double.html", + "string.quoted.single.html", + "string.unquoted.html", + "string.quoted.single.handlebars", + "string.quoted.double.handlebars" + ], + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "string.regexp", + "settings": { + "foreground": "#811f3f" + } + }, + { + "name": "String interpolation", + "scope": [ + "punctuation.definition.template-expression.begin", + "punctuation.definition.template-expression.end", + "punctuation.section.embedded" + ], + "settings": { + "foreground": "#0000ff" + } + }, + { + "name": "Reset JavaScript string interpolation expression", + "scope": [ + "meta.template.expression" + ], + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "support.constant.property-value", + "support.constant.font-name", + "support.constant.media-type", + "support.constant.media", + "constant.other.color.rgb-value", + "constant.other.rgb-value", + "support.constant.color" + ], + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": [ + "support.type.vendored.property-name", + "support.type.property-name", + "variable.css", + "variable.scss", + "variable.other.less", + "source.coffee.embedded" + ], + "settings": { + "foreground": "#ff0000" + } + }, + { + "scope": "support.type.property-name.json", + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": "keyword", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "keyword.control", + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "keyword.operator", + "settings": { + "foreground": "#000000" + } + }, + { + "scope": [ + "keyword.operator.new", + "keyword.operator.expression", + "keyword.operator.cast", + "keyword.operator.sizeof", + "keyword.operator.instanceof", + "keyword.operator.logical.python" + ], + "settings": { + "foreground": "#0000ff" + } + }, + { + "scope": "keyword.other.unit", + "settings": { + "foreground": "#09885a" + } + }, + { + "scope": [ + "punctuation.section.embedded.begin.php", + "punctuation.section.embedded.end.php" + ], + "settings": { + "foreground": "#800000" + } + }, + { + "scope": "support.function.git-rebase", + "settings": { + "foreground": "#0451a5" + } + }, + { + "scope": "constant.sha.git-rebase", + "settings": { + "foreground": "#09885a" + } + }, + { + "name": "coloring of the Java import and package identifiers", + "scope": [ + "storage.modifier.import.java", + "variable.language.wildcard.java", + "storage.modifier.package.java" + ], + "settings": { + "foreground": "#000000" + } + }, + { + "name": "this.self", + "scope": "variable.language", + "settings": { + "foreground": "#0000ff" + } + } + ] +} \ No newline at end of file diff --git a/packages/monaco/package.json b/packages/monaco/package.json index 39862226dfa76..76a6cae59aa86 100644 --- a/packages/monaco/package.json +++ b/packages/monaco/package.json @@ -14,7 +14,9 @@ "monaco-html": "^2.0.2", "monaco-json": "^2.0.1", "monaco-languageclient": "0.6.3", - "monaco-languages": "^1.0.4" + "monaco-languages": "^1.0.4", + "monaco-textmate": "^3.0.0", + "onigasm": "^2.1.0" }, "publishConfig": { "access": "public" @@ -39,7 +41,8 @@ "homepage": "https://github.com/theia-ide/theia", "files": [ "lib", - "src" + "src", + "data" ], "scripts": { "prepare": "yarn run clean && yarn run build", diff --git a/packages/monaco/src/browser/monaco-editor-provider.ts b/packages/monaco/src/browser/monaco-editor-provider.ts index 9282d52dbf546..ec411ffd594dd 100644 --- a/packages/monaco/src/browser/monaco-editor-provider.ts +++ b/packages/monaco/src/browser/monaco-editor-provider.ts @@ -6,13 +6,12 @@ */ // tslint:disable:no-any -import { DisposableCollection } from '@theia/core/lib/common'; import URI from '@theia/core/lib/common/uri'; import { EditorPreferenceChange, EditorPreferences, TextEditor, DiffNavigator } from '@theia/editor/lib/browser'; import { DiffUris } from '@theia/core/lib/browser/diff-uris'; import { inject, injectable } from 'inversify'; +import { DisposableCollection } from '@theia/core/lib/common'; import { MonacoToProtocolConverter, ProtocolToMonacoConverter } from 'monaco-languageclient'; - import { MonacoCommandServiceFactory } from './monaco-command-service'; import { MonacoContextMenuService } from './monaco-context-menu'; import { MonacoDiffEditor } from './monaco-diff-editor'; @@ -23,18 +22,9 @@ import { MonacoEditorService } from './monaco-editor-service'; import { MonacoQuickOpenService } from './monaco-quick-open-service'; import { MonacoTextModelService } from './monaco-text-model-service'; import { MonacoWorkspace } from './monaco-workspace'; -import { ThemeService } from '@theia/core/lib/browser/theming'; import IEditorOverrideServices = monaco.editor.IEditorOverrideServices; -function changeTheme(editorTheme: string | undefined) { - const monacoTheme = editorTheme || 'vs-dark'; - monaco.editor.setTheme(monacoTheme); - document.body.classList.add(monacoTheme); -} -changeTheme(ThemeService.get().getCurrentTheme().editorTheme); -ThemeService.get().onThemeChange(event => changeTheme(event.newTheme.editorTheme)); - @injectable() export class MonacoEditorProvider { diff --git a/packages/monaco/src/browser/monaco-frontend-application-contribution.ts b/packages/monaco/src/browser/monaco-frontend-application-contribution.ts new file mode 100644 index 0000000000000..597c51d5354c7 --- /dev/null +++ b/packages/monaco/src/browser/monaco-frontend-application-contribution.ts @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { injectable, inject } from 'inversify'; +import { FrontendApplicationContribution } from "@theia/core/lib/browser"; +import { ThemeService } from '@theia/core/lib/browser/theming'; + +@injectable() +export class MonacoFrontendApplicationContribution implements FrontendApplicationContribution { + + @inject(ThemeService) + protected readonly themeService: ThemeService; + + async initialize() { + await this.themeService.ready; + const currentTheme = this.themeService.getCurrentTheme(); + this.changeTheme(currentTheme.editorTheme); + this.themeService.onThemeChange(event => this.changeTheme(event.newTheme.editorTheme)); + } + + protected changeTheme(editorTheme: string | undefined) { + const monacoTheme = editorTheme || this.themeService.defaultTheme; + monaco.editor.setTheme(monacoTheme); + document.body.classList.add(monacoTheme); + } +} diff --git a/packages/monaco/src/browser/monaco-frontend-module.ts b/packages/monaco/src/browser/monaco-frontend-module.ts index 8c87f81bc48e8..9f7eb72d80d72 100644 --- a/packages/monaco/src/browser/monaco-frontend-module.ts +++ b/packages/monaco/src/browser/monaco-frontend-module.ts @@ -28,6 +28,8 @@ import { MonacoCommandRegistry } from './monaco-command-registry'; import { MonacoQuickOpenService } from './monaco-quick-open-service'; import { MonacoDiffNavigatorFactory } from './monaco-diff-navigator-factory'; import { MonacoStrictEditorTextFocusContext } from './monaco-keybinding-contexts'; +import { MonacoFrontendApplicationContribution } from './monaco-frontend-application-contribution'; +import MonacoTextmateModuleBinder from './textmate/monaco-textmate-frontend-bindings'; decorate(injectable(), MonacoToProtocolConverter); decorate(injectable(), ProtocolToMonacoConverter); @@ -37,6 +39,8 @@ import '../../src/browser/style/symbol-sprite.svg'; import '../../src/browser/style/symbol-icons.css'; export default new ContainerModule((bind, unbind, isBound, rebind) => { + bind(FrontendApplicationContribution).to(MonacoFrontendApplicationContribution).inSingletonScope(); + bind(MonacoToProtocolConverter).toSelf().inSingletonScope(); bind(ProtocolToMonacoConverter).toSelf().inSingletonScope(); @@ -76,4 +80,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { rebind(QuickOpenService).toDynamicValue(ctx => ctx.container.get(MonacoQuickOpenService) ).inSingletonScope(); + + MonacoTextmateModuleBinder(bind, unbind, isBound, rebind); }); diff --git a/packages/typescript/src/browser/monaco-tokenization/typescriptServices.d.ts b/packages/monaco/src/browser/textmate/index.ts old mode 100755 new mode 100644 similarity index 51% rename from packages/typescript/src/browser/monaco-tokenization/typescriptServices.d.ts rename to packages/monaco/src/browser/textmate/index.ts index e68e1acbb6b33..664b61397cca1 --- a/packages/typescript/src/browser/monaco-tokenization/typescriptServices.d.ts +++ b/packages/monaco/src/browser/textmate/index.ts @@ -1,7 +1,11 @@ /* - * Copyright (C) 2017 TypeFox and others. + * Copyright (C) 2018 Ericsson and others. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ -declare module 'monaco-typescript/release/min/lib/typescriptServices'; \ No newline at end of file + +export * from './textmate-registry'; +export * from './textmate-contribution'; +export * from './monaco-textmate-service'; +export * from './monaco-textmate-frontend-bindings'; diff --git a/packages/monaco/src/browser/textmate/monaco-builtin-theme-provider.ts b/packages/monaco/src/browser/textmate/monaco-builtin-theme-provider.ts new file mode 100644 index 0000000000000..12845dd608d19 --- /dev/null +++ b/packages/monaco/src/browser/textmate/monaco-builtin-theme-provider.ts @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { MonacoTheme } from '../../common/monaco-theme-protocol'; + +export class BuiltinMonacoThemeProvider { + + protected static readonly rawThemes: { [file: string]: object } = { + './dark_default.json': require('../../../data/monaco-themes/vscode/dark_defaults.json'), + './dark_vs.json': require('../../../data/monaco-themes/vscode/dark_vs.json'), + './dark_plus.json': require('../../../data/monaco-themes/vscode/dark_plus.json'), + + './light_default.json': require('../../../data/monaco-themes/vscode/light_defaults.json'), + './light_vs.json': require('../../../data/monaco-themes/vscode/light_vs.json'), + './light_plus.json': require('../../../data/monaco-themes/vscode/light_plus.json'), + }; + + protected static readonly nameMap: { [name: string]: string } = { + 'light-plus': 'light_plus', + 'dark-plus': 'dark_plus', + }; + + protected static readonly baseMap: { [name: string]: monaco.editor.BuiltinTheme } = { + 'light-plus': 'vs', + }; + + static compileMonacoThemes() { + [ + 'light-plus', 'dark-plus', + ].forEach(name => { + const rawName = this.nameMap[name] || name; + const theme = this.convertVscodeToMonaco( + this.rawThemes[`./${rawName}.json`], + { + name, + base: this.baseMap[name] || 'vs-dark', + inherit: true, + rules: [], + colors: {}, + } + ); + + monaco.editor.defineTheme(theme.name, theme); + }); + } + + // tslint:disable-next-line:no-any + protected static convertVscodeToMonaco(vscodeTheme: any, monacoTheme: MonacoTheme): MonacoTheme { + + // Recursion in order to follow the theme dependencies that vscode has... + if (typeof vscodeTheme.include !== 'undefined') { + const subTheme = this.rawThemes[vscodeTheme.include]; + if (subTheme) { + this.convertVscodeToMonaco(subTheme, monacoTheme); + } + } + + Object.assign(monacoTheme.colors, vscodeTheme.colors); + + if (typeof vscodeTheme.tokenColors !== 'undefined') { + for (const tokenColor of vscodeTheme.tokenColors) { + + if (typeof tokenColor.scope === 'undefined') { + tokenColor.scope = ['']; + } else if (typeof tokenColor.scope === 'string') { + // tokenColor.scope = tokenColor.scope.split(',').map((scope: string) => scope.trim()); // ? + tokenColor.scope = [tokenColor.scope]; + } + + for (const scope of tokenColor.scope) { + + // Converting numbers into a format that monaco understands + const settings = Object.keys(tokenColor.settings).reduce((previous: { [key: string]: string }, current) => { + let value: string = tokenColor.settings[current]; + if (typeof value === typeof '') { + value = value.replace(/^\#/, '').slice(0, 6); + } + previous[current] = value; + return previous; + }, {}); + + monacoTheme.rules.push({ + ...settings, token: scope + }); + } + } + } + + return monacoTheme; + } + +} diff --git a/packages/monaco/src/browser/textmate/monaco-textmate-builtin-theme-provider.ts b/packages/monaco/src/browser/textmate/monaco-textmate-builtin-theme-provider.ts new file mode 100644 index 0000000000000..10ac2d504916b --- /dev/null +++ b/packages/monaco/src/browser/textmate/monaco-textmate-builtin-theme-provider.ts @@ -0,0 +1,23 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { BuiltinThemeProvider } from '@theia/core/lib/browser/theming'; + +export class BuiltinTextmateThemeProvider { + + static readonly theiaTextmateThemes = [ + { + ...BuiltinThemeProvider.darkTheme, + editorTheme: 'dark-plus', + }, + { + ...BuiltinThemeProvider.lightTheme, + editorTheme: 'light-plus', + }, + ]; + +} diff --git a/packages/monaco/src/browser/textmate/monaco-textmate-frontend-bindings.ts b/packages/monaco/src/browser/textmate/monaco-textmate-frontend-bindings.ts new file mode 100644 index 0000000000000..c8bee60f6c4b9 --- /dev/null +++ b/packages/monaco/src/browser/textmate/monaco-textmate-frontend-bindings.ts @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { interfaces } from 'inversify'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser'; +import { bindContributionProvider } from '@theia/core'; +import { ThemeService } from '@theia/core/lib/browser/theming'; +import { BuiltinTextmateThemeProvider } from './monaco-textmate-builtin-theme-provider'; +import { BuiltinMonacoThemeProvider } from './monaco-builtin-theme-provider'; +import { TextmateRegistry, TextmateRegistryImpl } from './textmate-registry'; +import { LanguageGrammarDefinitionContribution } from './textmate-contribution'; +import { MonacoTextmateService, OnigasmPromise } from './monaco-textmate-service'; +import { loadWASM } from 'onigasm'; + +export default (bind: interfaces.Bind, unbind: interfaces.Unbind, isBound: interfaces.IsBound, rebind: interfaces.Rebind) => { + const onigasmPromise = loadWASM(require('onigasm/lib/onigasm.wasm')); + bind(OnigasmPromise).toConstantValue(onigasmPromise); + + bind(MonacoTextmateService).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(MonacoTextmateService); + bindContributionProvider(bind, LanguageGrammarDefinitionContribution); + bind(TextmateRegistry).to(TextmateRegistryImpl).inSingletonScope(); + + const themeService = ThemeService.get(); + BuiltinMonacoThemeProvider.compileMonacoThemes(); + themeService.register(...BuiltinTextmateThemeProvider.theiaTextmateThemes); +}; diff --git a/packages/monaco/src/browser/textmate/monaco-textmate-service.ts b/packages/monaco/src/browser/textmate/monaco-textmate-service.ts new file mode 100644 index 0000000000000..8420db63ea49e --- /dev/null +++ b/packages/monaco/src/browser/textmate/monaco-textmate-service.ts @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018 Redhat, Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { injectable, inject, named } from "inversify"; +import { Registry } from 'monaco-textmate'; +import { ILogger, DisposableCollection, ContributionProvider } from "@theia/core"; +import { FrontendApplicationContribution } from "@theia/core/lib/browser"; +import { MonacoTextModelService } from "../monaco-text-model-service"; +import { LanguageGrammarDefinitionContribution } from "./textmate-contribution"; +import { createTextmateTokenizer } from "./textmate-tokenizer"; +import { TextmateRegistry } from "./textmate-registry"; + +export const OnigasmPromise = Symbol('OnigasmPromise'); +export type OnigasmPromise = Promise; + +@injectable() +export class MonacoTextmateService implements FrontendApplicationContribution { + + protected readonly toDispose = new DisposableCollection(); + + protected readonly activatedLanguages = new Set(); + protected grammarRegistry: Registry; + + @inject(ContributionProvider) @named(LanguageGrammarDefinitionContribution) + protected readonly grammarProviders: ContributionProvider; + + @inject(TextmateRegistry) + protected readonly textmateRegistry: TextmateRegistry; + + @inject(MonacoTextModelService) + protected readonly monacoModelService: MonacoTextModelService; + + @inject(ILogger) + protected readonly logger: ILogger; + + @inject(OnigasmPromise) + protected readonly onigasmPromise: OnigasmPromise; + + initialize() { + for (const grammarProvider of this.grammarProviders.getContributions()) { + grammarProvider.registerTextmateLanguage(this.textmateRegistry); + } + + this.grammarRegistry = new Registry({ + getGrammarDefinition: async (scopeName: string, dependentScope: string) => { + if (this.textmateRegistry.hasProvider(scopeName)) { + const provider = this.textmateRegistry.getProvider(scopeName); + return await provider!.getGrammarDefinition(scopeName, dependentScope); + } + return { + format: 'json', + content: '' + }; + } + }); + + this.toDispose.push(this.monacoModelService.onDidCreate(model => { + if (!this.activatedLanguages.has(model.languageId)) { + this.activatedLanguages.add(model.languageId); + this.activateLanguage(model.languageId); + } + })); + } + + async activateLanguage(languageId: string) { + const scopeName = this.textmateRegistry.getScope(languageId); + if (!scopeName) { + return; + } + const provider = this.textmateRegistry.getProvider(scopeName); + if (!provider) { + return; + } + + await this.onigasmPromise; + try { + monaco.languages.setTokensProvider(languageId, createTextmateTokenizer( + await this.grammarRegistry.loadGrammar(scopeName) + )); + } catch (err) { + this.logger.warn('No grammar for this language id', languageId); + } + } + + resetLanguage(languageId: string) { + this.activatedLanguages.delete(languageId); + } + + onStop(): void { + this.toDispose.dispose(); + } +} diff --git a/packages/monaco/src/browser/textmate/textmate-contribution.ts b/packages/monaco/src/browser/textmate/textmate-contribution.ts new file mode 100644 index 0000000000000..05ead649c5878 --- /dev/null +++ b/packages/monaco/src/browser/textmate/textmate-contribution.ts @@ -0,0 +1,16 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { TextmateRegistry } from "./textmate-registry"; + +/** + * Callback for extensions to contribute language grammar definitions + */ +export const LanguageGrammarDefinitionContribution = Symbol('LanguageGrammarDefinitionContribution'); +export interface LanguageGrammarDefinitionContribution { + registerTextmateLanguage(registry: TextmateRegistry): void; +} diff --git a/packages/monaco/src/browser/textmate/textmate-registry.ts b/packages/monaco/src/browser/textmate/textmate-registry.ts new file mode 100644 index 0000000000000..839b2e5baeeff --- /dev/null +++ b/packages/monaco/src/browser/textmate/textmate-registry.ts @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { injectable } from "inversify"; +import { RegistryOptions } from "monaco-textmate"; + +export const TextmateRegistry = Symbol('TextmateRegistry'); +export interface TextmateRegistry { + registerTextMateGrammarScope(scopeName: string, provider: RegistryOptions): void; + mapLanguageIdToTextmateGrammar(language: string, scopeName: string): void; + + hasProvider(scopeName: string): boolean; + getProvider(scopeName: string): RegistryOptions | undefined; + + hasScope(languageId: string): boolean; + getScope(languageId: string): string | undefined; +} + +@injectable() +export class TextmateRegistryImpl implements TextmateRegistry { + public readonly scopeToProvider = new Map(); + public readonly languageIdToScope = new Map(); + + registerTextMateGrammarScope(scopeName: string, provider: RegistryOptions): void { + this.scopeToProvider.set(scopeName, provider); + } + + mapLanguageIdToTextmateGrammar(language: string, scopeName: string): void { + this.languageIdToScope.set(language, scopeName); + } + + hasProvider(scopeName: string): boolean { + return this.scopeToProvider.has(scopeName); + } + + getProvider(scopeName: string): RegistryOptions | undefined { + return this.scopeToProvider.get(scopeName); + } + + hasScope(languageId: string): boolean { + return this.languageIdToScope.has(languageId); + } + + getScope(languageId: string): string | undefined { + return this.languageIdToScope.get(languageId); + } +} diff --git a/packages/monaco/src/browser/textmate/textmate-tokenizer.ts b/packages/monaco/src/browser/textmate/textmate-tokenizer.ts new file mode 100644 index 0000000000000..68c62d5924f3a --- /dev/null +++ b/packages/monaco/src/browser/textmate/textmate-tokenizer.ts @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { INITIAL, StackElement, IGrammar } from "monaco-textmate"; + +export class State implements monaco.languages.IState { + + constructor( + public ruleStack: StackElement + ) { } + + clone(): monaco.languages.IState { + return new State(this.ruleStack); + } + + equals(other: monaco.languages.IState): boolean { + return other && + (other instanceof State) && + (other === this || other.ruleStack === this.ruleStack) + ; + } + +} + +export function createTextmateTokenizer(grammar: IGrammar): monaco.languages.TokensProvider { + return { + getInitialState: () => new State(INITIAL), + tokenize(line: string, state: State) { + const result = grammar.tokenizeLine(line, state.ruleStack); + return { + endState: new State(result.ruleStack), + tokens: result.tokens.map(token => { + const scopes = token.scopes.slice(0); + let scope = scopes.pop(); + + // TODO: update this temporary fix once `monaco-editor` supports full scopes arrays + while (scope && scope.startsWith('punctuation.')) { + scope = scopes.pop(); + } + + return { + ...token, + scopes: scope!, + }; + }), + }; + } + }; +} diff --git a/packages/monaco/src/common/monaco-theme-protocol.ts b/packages/monaco/src/common/monaco-theme-protocol.ts new file mode 100644 index 0000000000000..d23141710dcd9 --- /dev/null +++ b/packages/monaco/src/common/monaco-theme-protocol.ts @@ -0,0 +1,23 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +// Aliases for monaco.editor.{theme-interfaces} +export import MonacoThemeColor = monaco.editor.IColors; +export import MonacoTokenRule = monaco.editor.ITokenThemeRule; +export import MonacoBuiltinTheme = monaco.editor.BuiltinTheme; +export interface MonacoTheme extends monaco.editor.IStandaloneThemeData { + name: string; +} + +export const MonacoThemeProvider = Symbol('MonacoThemeProvider'); +export interface MonacoThemeProvider { + + /** + * Asynchronous call, this fetches all the available themes for the monaco editor. + */ + gatherMonacoThemes(): Promise; +} diff --git a/packages/preview/src/browser/preview-widget.ts b/packages/preview/src/browser/preview-widget.ts index 15dcbceb99e2c..4fb22b9338940 100644 --- a/packages/preview/src/browser/preview-widget.ts +++ b/packages/preview/src/browser/preview-widget.ts @@ -41,6 +41,7 @@ export class PreviewWidget extends BaseWidget { constructor( @inject(PreviewWidgetOptions) protected readonly options: PreviewWidgetOptions, @inject(PreviewHandlerProvider) protected readonly previewHandlerProvider: PreviewHandlerProvider, + @inject(ThemeService) protected readonly themeService: ThemeService, @inject(Workspace) protected readonly workspace: Workspace, @inject(EditorPreferences) protected readonly editorPreferences: EditorPreferences, ) { @@ -86,7 +87,7 @@ export class PreviewWidget extends BaseWidget { this.toDispose.push(this.workspace.onDidOpenTextDocument(document => updateIfAffected(document.uri))); this.toDispose.push(this.workspace.onDidChangeTextDocument(params => updateIfAffected(params.textDocument.uri))); this.toDispose.push(this.workspace.onDidCloseTextDocument(document => updateIfAffected(document.uri))); - this.toDispose.push(ThemeService.get().onThemeChange(() => this.update())); + this.toDispose.push(this.themeService.onThemeChange(() => this.update())); this.firstUpdate = () => { this.revealFragment(this.uri); }; diff --git a/packages/terminal/src/browser/terminal-widget.ts b/packages/terminal/src/browser/terminal-widget.ts index 1b80ad1afa626..6966bd9ca80d9 100644 --- a/packages/terminal/src/browser/terminal-widget.ts +++ b/packages/terminal/src/browser/terminal-widget.ts @@ -62,6 +62,7 @@ export class TerminalWidget extends BaseWidget implements StatefulWidget { @inject(TerminalWidgetOptions) options: TerminalWidgetOptions; @inject(ShellTerminalServerProxy) protected readonly shellTerminalServer: ShellTerminalServerProxy; @inject(TerminalWatcher) protected readonly terminalWatcher: TerminalWatcher; + @inject(ThemeService) protected readonly themeService: ThemeService; @inject(ILogger) @named('terminal') protected readonly logger: ILogger; protected readonly toDisposeOnConnect = new DisposableCollection(); @@ -97,7 +98,7 @@ export class TerminalWidget extends BaseWidget implements StatefulWidget { }, }); - this.toDispose.push(ThemeService.get().onThemeChange(c => { + this.toDispose.push(this.themeService.onThemeChange(c => { const changedProps = this.getCSSPropertiesFromPage(); this.term.setOption('theme', { foreground: changedProps.foreground, diff --git a/packages/typescript/data/grammars/javascript.tmlanguage.json b/packages/typescript/data/grammars/javascript.tmlanguage.json new file mode 100644 index 0000000000000..16cfcfad6b25b --- /dev/null +++ b/packages/typescript/data/grammars/javascript.tmlanguage.json @@ -0,0 +1,516 @@ +{ + "comment": "JavaScript Syntax: version 2.0", + "fileTypes": [ + "js", + "htc", + "jsx" + ], + "firstLineMatch": "^#!.*\\bnode", + "keyEquivalent": "^~J", + "name": "JavaScript", + "patterns": [ + { + "captures": { + "1": { + "name": "support.class.js" + }, + "2": { + "name": "support.constant.js" + }, + "3": { + "name": "keyword.operator.js" + } + }, + "comment": "match stuff like: Sound.prototype = { … } when extending an object", + "match": "([a-zA-Z_?.$][\\w?.$]*)\\.(prototype)\\s*(=)\\s*", + "name": "meta.class.js" + }, + { + "begin": "([a-zA-Z_?.$][\\w?.$]*)\\.(prototype)\\.([a-zA-Z_?.$][\\w?.$]*)\\s*(=)\\s*(function)?\\s*(\\()", + "beginCaptures": { + "1": { + "name": "support.class.js" + }, + "2": { + "name": "support.constant.js" + }, + "3": { + "name": "entity.name.function.js" + }, + "4": { + "name": "keyword.operator.js" + }, + "5": { + "name": "storage.type.function.js" + }, + "6": { + "name": "punctuation.definition.parameters.begin.js" + } + }, + "comment": "match stuff like: Sound.prototype.play = function() { … }", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.js" + } + }, + "name": "meta.function.prototype.js", + "patterns": [ + { + "include": "#function-params" + } + ] + }, + { + "captures": { + "1": { + "name": "support.class.js" + }, + "2": { + "name": "support.constant.js" + }, + "3": { + "name": "entity.name.function.js" + }, + "4": { + "name": "keyword.operator.js" + } + }, + "comment": "match stuff like: Sound.prototype.play = myfunc", + "match": "([a-zA-Z_?.$][\\w?.$]*)\\.(prototype)\\.([a-zA-Z_?.$][\\w?.$]*)\\s*(=)\\s*", + "name": "meta.function.js" + }, + { + "begin": "([a-zA-Z_?.$][\\w?.$]*)\\.([a-zA-Z_?.$][\\w?.$]*)\\s*(=)\\s*(function)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "support.class.js" + }, + "2": { + "name": "entity.name.function.js" + }, + "3": { + "name": "keyword.operator.js" + }, + "4": { + "name": "storage.type.function.js" + }, + "5": { + "name": "punctuation.definition.parameters.begin.js" + } + }, + "comment": "match stuff like: Sound.play = function() { … }", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.js" + } + }, + "name": "meta.function.js", + "patterns": [ + { + "include": "#function-params" + } + ] + }, + { + "begin": "([a-zA-Z_?$][\\w?$]*)\\s*(=)\\s*(function)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.js" + }, + "2": { + "name": "keyword.operator.js" + }, + "3": { + "name": "storage.type.function.js" + }, + "4": { + "name": "punctuation.definition.parameters.begin.js" + } + }, + "comment": "match stuff like: play = function() { … }", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.js" + } + }, + "name": "meta.function.js", + "patterns": [ + { + "include": "#function-params" + } + ] + }, + { + "begin": "\\b(function)\\s+([a-zA-Z_$]\\w*)?\\s*(\\()", + "beginCaptures": { + "1": { + "name": "storage.type.function.js" + }, + "2": { + "name": "entity.name.function.js" + }, + "3": { + "name": "punctuation.definition.parameters.begin.js" + } + }, + "comment": "match regular function like: function myFunc(arg) { … }", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.js" + } + }, + "name": "meta.function.js", + "patterns": [ + { + "include": "#function-params" + } + ] + }, + { + "begin": "\\b([a-zA-Z_?.$][\\w?.$]*)\\s*:\\s*\\b(function)?\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.js" + }, + "2": { + "name": "storage.type.function.js" + }, + "3": { + "name": "punctuation.definition.parameters.begin.js" + } + }, + "comment": "match stuff like: foobar: function() { … }", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.js" + } + }, + "name": "meta.function.json.js", + "patterns": [ + { + "include": "#function-params" + } + ] + }, + { + "begin": "(?:((')(.*?)('))|((\")(.*?)(\")))\\s*:\\s*\\b(function)?\\s*(\\()", + "beginCaptures": { + "1": { + "name": "string.quoted.single.js" + }, + "2": { + "name": "punctuation.definition.string.begin.js" + }, + "3": { + "name": "entity.name.function.js" + }, + "4": { + "name": "punctuation.definition.string.end.js" + }, + "5": { + "name": "string.quoted.double.js" + }, + "6": { + "name": "punctuation.definition.string.begin.js" + }, + "7": { + "name": "entity.name.function.js" + }, + "8": { + "name": "punctuation.definition.string.end.js" + }, + "9": { + "name": "entity.name.function.js" + }, + "10": { + "name": "punctuation.definition.parameters.begin.js" + } + }, + "comment": "Attempt to match \"foo\": function", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.js" + } + }, + "name": "meta.function.json.js", + "patterns": [ + { + "include": "#function-params" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.operator.new.js" + }, + "2": { + "name": "entity.name.type.instance.js" + } + }, + "match": "(new)\\s+(\\w+(?:\\.\\w*)?)", + "name": "meta.class.instance.constructor" + }, + { + "match": "\\b(console)\\b", + "name": "entity.name.type.object.js.firebug" + }, + { + "match": "\\.(warn|info|log|error|time|timeEnd|assert)\\b", + "name": "support.function.js.firebug" + }, + { + "match": "\\b((0(x|X)[0-9a-fA-F]+)|([0-9]+(\\.[0-9]+)?))\\b", + "name": "constant.numeric.js" + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "name": "string.quoted.single.js", + "patterns": [ + { + "match": "\\\\(x\\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.)", + "name": "constant.character.escape.js" + } + ] + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "name": "string.quoted.double.js", + "patterns": [ + { + "match": "\\\\(x\\h{2}|[0-2][0-7]{,2}|3[0-6][0-7]|37[0-7]?|[4-7][0-7]?|.)", + "name": "constant.character.escape.js" + } + ] + }, + { + "begin": "/\\*\\*(?!/)", + "captures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "\\*/", + "name": "comment.block.documentation.js" + }, + { + "begin": "/\\*", + "captures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "\\*/", + "name": "comment.block.js" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.js" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.js" + } + }, + "end": "\\n", + "name": "comment.line.double-slash.js" + } + ] + }, + { + "captures": { + "0": { + "name": "punctuation.definition.comment.html.js" + }, + "2": { + "name": "punctuation.definition.comment.html.js" + } + }, + "match": "()", + "name": "comment.block.html.js" + }, + { + "match": "(?=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts entity.name.function.ts" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.ts", + "begin": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts variable.other.constant.ts" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + }, + { + "name": "meta.var-single-variable.expr.ts", + "begin": "([_$[:alpha:]][_$[:alnum:]]*)", + "beginCaptures": { + "1": { + "name": "meta.definition.variable.ts variable.other.readwrite.ts" + } + }, + "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "patterns": [ + { + "include": "#var-single-variable-type-annotation" + } + ] + } + ] + }, + "var-single-variable-type-annotation": { + "patterns": [ + { + "include": "#type-annotation" + }, + { + "include": "#string" + }, + { + "include": "#comment" + } + ] + }, + "destructuring-variable": { + "patterns": [ + { + "name": "meta.object-binding-pattern-variable.ts", + "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "keyword.operator.rest.ts" + }, + "3": { + "name": "entity.name.function.ts variable.language.this.ts" + }, + "4": { + "name": "entity.name.function.ts" + }, + "5": { + "name": "keyword.operator.optional.ts" + } + } + }, + { + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*(=>|(\\([^\\(\\)]*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))" + }, + { + "name": "meta.definition.property.ts variable.object.property.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.ts", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "variable.parameter.ts" + } + } + }, + { + "name": "meta.arrow.ts", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.ts", + "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + }, + "1": { + "name": "entity.name.function.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", + "captures": { + "0": { + "name": "meta.object-literal.key.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "\\.\\.\\.", + "beginCaptures": { + "0": { + "name": "keyword.operator.spread.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", + "captures": { + "1": { + "name": "variable.other.readwrite.ts" + } + } + }, + { + "name": "meta.object.member.ts", + "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", + "end": "(?=,|\\}|$)", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "name": "meta.object.member.ts", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" + } + }, + "end": "(?=,|\\})", + "patterns": [ + { + "include": "#expression" + } + ] + }, + { + "include": "#punctuation-comma" + } + ] + }, + "ternary-expression": { + "begin": "(?!\\?\\.\\s*[^[:digit:]])(\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.ts" + } + }, + "end": "(:)", + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.ts" + } + }, + "patterns": [ + { + "include": "#expression" + } + ] + }, + "function-call": { + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "end": "(?<=\\))(?!(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "patterns": [ + { + "name": "meta.function-call.ts", + "begin": "(?=(([_$[:alpha:]][_$[:alnum:]]*\\s*\\??\\.\\s*)*|(\\??\\.\\s*)?)([_$[:alpha:]][_$[:alnum:]]*))", + "end": "(?=\\s*(\\?\\.\\s*)?(<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>|\\<\\s*(([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))|(\\'[^\\']*\\')|(\\\"[^\\\"]*\\\")|(\\`[^\\`]*\\`))([^<>\\(]|(\\([^\\(\\)]*\\))|(?<==)\\>)*(?!=)\\>)*(?!=)>\\s*)?\\()", + "patterns": [ + { + "include": "#literal" + }, + { + "include": "#support-objects" + }, + { + "include": "#object-identifiers" + }, + { + "include": "#punctuation-accessor" + }, + { + "name": "keyword.operator.expression.import.ts", + "match": "(?:(?", + "endCaptures": { + "0": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + { + "include": "#paren-expression" + } + ] + }, + "new-expr": { + "name": "new.expr.ts", + "begin": "(?*?\\&\\|\\^]|[^_$[:alnum:]](?:\\+\\+|\\-\\-)|[^\\+]\\+|[^\\-]\\-))\\s*(<)(?!)\\s*", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "cast.expr.ts", + "begin": "(?:(?<=^))\\s*(<)(?=[_$[:alpha:]][_$[:alnum:]]*\\s*>)", + "beginCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "end": "(\\>)\\s*", + "endCaptures": { + "1": { + "name": "meta.brace.angle.ts" + } + }, + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "expression-operators": { + "patterns": [ + { + "name": "keyword.control.flow.ts", + "match": "(?>=|>>>=|\\|=" + }, + { + "name": "keyword.operator.bitwise.shift.ts", + "match": "<<|>>>|>>" + }, + { + "name": "keyword.operator.comparison.ts", + "match": "===|!==|==|!=" + }, + { + "name": "keyword.operator.relational.ts", + "match": "<=|>=|<>|<|>" + }, + { + "name": "keyword.operator.logical.ts", + "match": "\\!|&&|\\|\\|" + }, + { + "name": "keyword.operator.bitwise.ts", + "match": "\\&|~|\\^|\\|" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "\\=" + }, + { + "name": "keyword.operator.decrement.ts", + "match": "--" + }, + { + "name": "keyword.operator.increment.ts", + "match": "\\+\\+" + }, + { + "name": "keyword.operator.arithmetic.ts", + "match": "%|\\*|/|-|\\+" + }, + { + "match": "(?<=[_$[:alnum:])])\\s*(/)(?![/*])", + "captures": { + "1": { + "name": "keyword.operator.arithmetic.ts" + } + } + } + ] + }, + "typeof-operator": { + "name": "keyword.operator.expression.typeof.ts", + "match": "(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "support.constant.dom.ts" + }, + "4": { + "name": "support.variable.property.dom.ts" + } + } + }, + { + "name": "support.class.node.ts", + "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{[^\\{\\}]*\\})|(\\([^\\(\\)]*\\))|(\\[[^\\[\\]]*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*([_$[:alpha:]\\{\\[]([^()]|\\((\\s*[^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "entity.name.function.ts" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "variable.other.constant.property.ts" + } + } + }, + { + "match": "(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "variable.other.property.ts" + } + } + }, + { + "name": "variable.other.constant.ts", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\??\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "punctuation.accessor.optional.ts" + }, + "3": { + "name": "variable.other.constant.object.property.ts" + }, + "4": { + "name": "variable.other.object.property.ts" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\??\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.ts" + }, + "2": { + "name": "variable.other.object.ts" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.ts", + "begin": "(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + }, + { + "name": "meta.type.annotation.ts", + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", + "patterns": [ + { + "include": "#type" + } + ] + } + ] + }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.ts", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "begin": "(?<=[:])(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-parameters": { + "name": "meta.type.parameters.ts", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.begin.ts" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.ts", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] + }, + "type-primitive": { + "name": "support.type.primitive.ts", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.ts", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.ts", + "match": "(?|&&|\\|\\||\\*\\/)\\s*(\\/)(?![\\/*])(?=(?:[^\\/\\\\\\[]|\\\\.|\\[([^\\]\\\\]|\\\\.)+\\])+\\/(?![\\/*])[gimuy]*(?!\\s*[a-zA-Z0-9_$]))", + "beginCaptures": { + "1": { + "name": "punctuation.definition.string.begin.ts" + } + }, + "end": "(/)([gimuy]*)", + "endCaptures": { + "1": { + "name": "punctuation.definition.string.end.ts" + }, + "2": { + "name": "keyword.other.ts" + } + }, + "patterns": [ + { + "include": "#regexp" + } + ] + }, + { + "name": "string.regexp.ts", + "begin": "(?\\s*$)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.comment.ts" + } + }, + "end": "(?=^)", + "patterns": [ + { + "name": "meta.tag.ts", + "begin": "(<)(reference|amd-dependency|amd-module)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.tag.directive.ts" + }, + "2": { + "name": "entity.name.tag.directive.ts" + } + }, + "end": "/>", + "endCaptures": { + "0": { + "name": "punctuation.definition.tag.directive.ts" + } + }, + "patterns": [ + { + "name": "entity.other.attribute-name.directive.ts", + "match": "path|types|no-default-lib|name" + }, + { + "name": "keyword.operator.assignment.ts", + "match": "=" + }, + { + "include": "#string" + } + ] + } + ] + }, + "docblock": { + "patterns": [ + { + "match": "(?x)\n((@)(?:access|api))\n\\s+\n(private|protected|public)\n\\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.access-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)author)\n\\s+\n(\n [^@\\s<>*/]\n (?:[^@<>*/]|\\*[^/])*\n)\n(?:\n \\s*\n (<)\n ([^>\\s]+)\n (>)\n)?", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "5": { + "name": "constant.other.email.link.underline.jsdoc" + }, + "6": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)borrows) \\s+\n((?:[^@\\s*/]|\\*[^/])+) # \n\\s+ (as) \\s+ # as\n((?:[^@\\s*/]|\\*[^/])+) # ", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + }, + "4": { + "name": "keyword.operator.control.jsdoc" + }, + "5": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "name": "meta.example.jsdoc", + "begin": "((@)example)\\s+", + "end": "(?=@|\\*/)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "patterns": [ + { + "match": "^\\s\\*\\s+" + }, + { + "contentName": "constant.other.description.jsdoc", + "begin": "\\G(<)caption(>)", + "beginCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + }, + "end": "()|(?=\\*/)", + "endCaptures": { + "0": { + "name": "entity.name.tag.inline.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.angle.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.angle.end.jsdoc" + } + } + }, + { + "match": "[^\\s@*](?:[^*]|\\*[^/])*", + "captures": { + "0": { + "name": "source.embedded.ts" + } + } + } + ] + }, + { + "match": "(?x) ((@)kind) \\s+ (class|constant|event|external|file|function|member|mixin|module|namespace|typedef) \\b", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "constant.language.symbol-type.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)see)\n\\s+\n(?:\n # URL\n (\n (?=https?://)\n (?:[^\\s*]|\\*[^/])+\n )\n |\n # JSDoc namepath\n (\n (?!\n # Avoid matching bare URIs (also acceptable as links)\n https?://\n |\n # Avoid matching {@inline tags}; we match those below\n (?:\\[[^\\[\\]]*\\])? # Possible description [preceding]{@tag}\n {@(?:link|linkcode|linkplain|tutorial)\\b\n )\n # Matched namepath\n (?:[^@\\s*/]|\\*[^/])+\n )\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.link.underline.jsdoc" + }, + "4": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "match": "(?x)\n((@)template)\n\\s+\n# One or more valid identifiers\n(\n [A-Za-z_$] # First character: non-numeric word character\n [\\w$.\\[\\]]* # Rest of identifier\n (?: # Possible list of additional identifiers\n \\s* , \\s*\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n )*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "match": "(?x)\n(\n (@)\n (?:arg|argument|const|constant|member|namespace|param|var)\n)\n\\s+\n(\n [A-Za-z_$]\n [\\w$.\\[\\]]*\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "begin": "((@)typedef)\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "entity.name.type.instance.jsdoc", + "match": "(?:[^@\\s*/]|\\*[^/])+" + } + ] + }, + { + "begin": "((@)(?:arg|argument|const|constant|member|namespace|param|prop|property|var))\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + }, + { + "name": "variable.other.jsdoc", + "match": "([A-Za-z_$][\\w$.\\[\\]]*)" + }, + { + "name": "variable.other.jsdoc", + "match": "(?x)\n(\\[)\\s*\n[\\w$]+\n(?:\n (?:\\[\\])? # Foo[ ].bar properties within an array\n \\. # Foo.Bar namespaced parameter\n [\\w$]+\n)*\n(?:\n \\s*\n (=) # [foo=bar] Default parameter value\n \\s*\n (\n # The inner regexes are to stop the match early at */ and to not stop at escaped quotes\n (?>\n \"(?:(?:\\*(?!/))|(?:\\\\(?!\"))|[^*\\\\])*?\" | # [foo=\"bar\"] Double-quoted\n '(?:(?:\\*(?!/))|(?:\\\\(?!'))|[^*\\\\])*?' | # [foo='bar'] Single-quoted\n \\[ (?:(?:\\*(?!/))|[^*])*? \\] | # [foo=[1,2]] Array literal\n (?:(?:\\*(?!/))|\\s(?!\\s*\\])|\\[.*?(?:\\]|(?=\\*/))|[^*\\s\\[\\]])* # Everything else\n )*\n )\n)?\n\\s*(?:(\\])((?:[^*\\s]|\\*[^\\s/])+)?|(?=\\*/))", + "captures": { + "1": { + "name": "punctuation.definition.optional-value.begin.bracket.square.jsdoc" + }, + "2": { + "name": "keyword.operator.assignment.jsdoc" + }, + "3": { + "name": "source.embedded.ts" + }, + "4": { + "name": "punctuation.definition.optional-value.end.bracket.square.jsdoc" + }, + "5": { + "name": "invalid.illegal.syntax.jsdoc" + } + } + } + ] + }, + { + "begin": "(?x)\n(\n (@)\n (?:define|enum|exception|export|extends|lends|implements|modifies\n |namespace|private|protected|returns?|suppress|this|throws|type\n |yields?)\n)\n\\s+(?={)", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + } + }, + "end": "(?=\\s|\\*/|[^{}\\[\\]A-Za-z_$])", + "patterns": [ + { + "include": "#jsdoctype" + } + ] + }, + { + "match": "(?x)\n(\n (@)\n (?:alias|augments|callback|constructs|emits|event|fires|exports?\n |extends|external|function|func|host|lends|listens|interface|memberof!?\n |method|module|mixes|mixin|name|requires|see|this|typedef|uses)\n)\n\\s+\n(\n (?:\n [^{}@\\s*] | \\*[^/]\n )+\n)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "entity.name.type.instance.jsdoc" + } + } + }, + { + "contentName": "variable.other.jsdoc", + "begin": "((@)(?:default(?:value)?|license|version))\\s+(([''\"]))", + "beginCaptures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + }, + "4": { + "name": "punctuation.definition.string.begin.jsdoc" + } + }, + "end": "(\\3)|(?=$|\\*/)", + "endCaptures": { + "0": { + "name": "variable.other.jsdoc" + }, + "1": { + "name": "punctuation.definition.string.end.jsdoc" + } + } + }, + { + "match": "((@)(?:default(?:value)?|license|tutorial|variation|version))\\s+([^\\s*]+)", + "captures": { + "1": { + "name": "storage.type.class.jsdoc" + }, + "2": { + "name": "punctuation.definition.block.tag.jsdoc" + }, + "3": { + "name": "variable.other.jsdoc" + } + } + }, + { + "name": "storage.type.class.jsdoc", + "match": "(?x) (@) (?:abstract|access|alias|api|arg|argument|async|attribute|augments|author|beta|borrows|bubbles |callback|chainable|class|classdesc|code|config|const|constant|constructor|constructs|copyright |default|defaultvalue|define|deprecated|desc|description|dict|emits|enum|event|example|exception |exports?|extends|extension(?:_?for)?|external|externs|file|fileoverview|final|fires|for|func |function|generator|global|hideconstructor|host|ignore|implements|implicitCast|inherit[Dd]oc |inner|instance|interface|internal|kind|lends|license|listens|main|member|memberof!?|method |mixes|mixins?|modifies|module|name|namespace|noalias|nocollapse|nocompile|nosideeffects |override|overview|package|param|polymer(?:Behavior)?|preserve|private|prop|property|protected |public|read[Oo]nly|record|require[ds]|returns?|see|since|static|struct|submodule|summary |suppress|template|this|throws|todo|tutorial|type|typedef|unrestricted|uses|var|variation |version|virtual|writeOnce|yields?) \\b", + "captures": { + "1": { + "name": "punctuation.definition.block.tag.jsdoc" + } + } + }, + { + "include": "#inline-tags" + } + ] + }, + "brackets": { + "patterns": [ + { + "begin": "{", + "end": "}|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + }, + { + "begin": "\\[", + "end": "\\]|(?=\\*/)", + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + }, + "inline-tags": { + "patterns": [ + { + "name": "constant.other.description.jsdoc", + "match": "(\\[)[^\\]]+(\\])(?={@(?:link|linkcode|linkplain|tutorial))", + "captures": { + "1": { + "name": "punctuation.definition.bracket.square.begin.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.square.end.jsdoc" + } + } + }, + { + "name": "entity.name.type.instance.jsdoc", + "begin": "({)((@)(?:link(?:code|plain)?|tutorial))\\s*", + "beginCaptures": { + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + }, + "2": { + "name": "storage.type.class.jsdoc" + }, + "3": { + "name": "punctuation.definition.inline.tag.jsdoc" + } + }, + "end": "}|(?=\\*/)", + "endCaptures": { + "0": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "match": "\\G((?=https?://)(?:[^|}\\s*]|\\*[/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.link.underline.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + }, + { + "match": "\\G((?:[^{}@\\s|*]|\\*[^/])+)(\\|)?", + "captures": { + "1": { + "name": "variable.other.description.jsdoc" + }, + "2": { + "name": "punctuation.separator.pipe.jsdoc" + } + } + } + ] + } + ] + }, + "jsdoctype": { + "patterns": [ + { + "name": "invalid.illegal.type.jsdoc", + "match": "\\G{(?:[^}*]|\\*[^/}])+$" + }, + { + "contentName": "entity.name.type.instance.jsdoc", + "begin": "\\G({)", + "beginCaptures": { + "0": { + "name": "entity.name.type.instance.jsdoc" + }, + "1": { + "name": "punctuation.definition.bracket.curly.begin.jsdoc" + } + }, + "end": "((}))\\s*|(?=\\*/)", + "endCaptures": { + "1": { + "name": "entity.name.type.instance.jsdoc" + }, + "2": { + "name": "punctuation.definition.bracket.curly.end.jsdoc" + } + }, + "patterns": [ + { + "include": "#brackets" + } + ] + } + ] + } + } +} \ No newline at end of file diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 54c02337f9f95..4596153ca4fe8 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -7,7 +7,6 @@ "@theia/core": "^0.3.11", "@theia/languages": "^0.3.11", "@theia/monaco": "^0.3.11", - "monaco-typescript": "^3.0.2", "typescript-language-server": "^0.1.14" }, "publishConfig": { @@ -33,7 +32,8 @@ "homepage": "https://github.com/theia-ide/theia", "files": [ "lib", - "src" + "src", + "data" ], "scripts": { "prepare": "yarn run clean && yarn run build", diff --git a/packages/typescript/src/browser/monaco-tokenization/tokenization.ts b/packages/typescript/src/browser/monaco-tokenization/tokenization.ts deleted file mode 100755 index 804179ba38677..0000000000000 --- a/packages/typescript/src/browser/monaco-tokenization/tokenization.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2017 TypeFox and others. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. - * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - */ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -// copied from https://github.com/Microsoft/monaco-typescript/tree/v2.3.0 and only slightly modified (imports and linting) - -'use strict'; - -// tslint:disable:indent -// tslint:disable:no-var-keyword -// tslint:disable:one-variable-per-declaration -// tslint:disable:prefer-const -import ts = require('monaco-typescript/release/min/lib/typescriptServices'); - -export enum Language { - TypeScript, - EcmaScript5 -} - -export function createTokenizationSupport(language: Language): monaco.languages.TokensProvider { - - var classifier = ts.createClassifier(), - bracketTypeTable = language === Language.TypeScript ? tsBracketTypeTable : jsBracketTypeTable, - tokenTypeTable = language === Language.TypeScript ? tsTokenTypeTable : jsTokenTypeTable; - - return { - getInitialState: () => new State(language, ts.EndOfLineState.None, false), - tokenize: (line, state) => tokenize(bracketTypeTable, tokenTypeTable, classifier, state, line) - }; -} - -class State implements monaco.languages.IState { - - public language: Language; - public eolState: /*ts.EndOfLineState*/ any; - public inJsDocComment: boolean; - - constructor(language: Language, eolState: /*ts.EndOfLineState*/ any, inJsDocComment: boolean) { - this.language = language; - this.eolState = eolState; - this.inJsDocComment = inJsDocComment; - } - - public clone(): State { - return new State(this.language, this.eolState, this.inJsDocComment); - } - - public equals(other: monaco.languages.IState): boolean { - if (other === this) { - return true; - } - if (!other || !(other instanceof State)) { - return false; - } - if (this.eolState !== (other).eolState) { - return false; - } - if (this.inJsDocComment !== (other).inJsDocComment) { - return false; - } - return true; - } -} - -function tokenize(bracketTypeTable: { [i: number]: string }, tokenTypeTable: { [i: number]: string }, - classifier: /*ts.Classifier*/ any, state: State, text: string): monaco.languages.ILineTokens { - - // Create result early and fill in tokens - var ret = { - tokens: [], - endState: new State(state.language, ts.EndOfLineState.None, false) - }; - - function appendFn(startIndex: number, tokenType: string): void { - if (ret.tokens.length === 0 || ret.tokens[ret.tokens.length - 1].scopes !== tokenType) { - ret.tokens.push({ - startIndex: startIndex, - scopes: tokenType - }); - } - } - - var isTypeScript = state.language === Language.TypeScript; - - // shebang statement, #! /bin/node - if (!isTypeScript && checkSheBang(0, text, appendFn)) { - return ret; - } - - var result = classifier.getClassificationsForLine(text, state.eolState, true), - offset = 0; - - ret.endState.eolState = result.finalLexState; - ret.endState.inJsDocComment = result.finalLexState === ts.EndOfLineState.InMultiLineCommentTrivia && (state.inJsDocComment || /\/\*\*.*$/.test(text)); - - for (let entry of result.entries) { - - var type: string; - - if (entry.classification === ts.TokenClass.Punctuation) { - // punctions: check for brackets: (){}[] - var ch = text.charCodeAt(offset); - type = bracketTypeTable[ch] || tokenTypeTable[entry.classification]; - appendFn(offset, type); - - } else if (entry.classification === ts.TokenClass.Comment) { - // comments: check for JSDoc, block, and line comments - if (ret.endState.inJsDocComment || /\/\*\*.*\*\//.test(text.substr(offset, entry.length))) { - appendFn(offset, isTypeScript ? 'comment.doc.ts' : 'comment.doc.js'); - } else { - appendFn(offset, isTypeScript ? 'comment.ts' : 'comment.js'); - } - } else { - // everything else - appendFn(offset, - tokenTypeTable[entry.classification] || ''); - } - - offset += entry.length; - } - - return ret; -} - -interface INumberStringDictionary { - [idx: number]: string; -} - -var tsBracketTypeTable: INumberStringDictionary = Object.create(null); -tsBracketTypeTable['('.charCodeAt(0)] = 'delimiter.parenthesis.ts'; -tsBracketTypeTable[')'.charCodeAt(0)] = 'delimiter.parenthesis.ts'; -tsBracketTypeTable['{'.charCodeAt(0)] = 'delimiter.bracket.ts'; -tsBracketTypeTable['}'.charCodeAt(0)] = 'delimiter.bracket.ts'; -tsBracketTypeTable['['.charCodeAt(0)] = 'delimiter.array.ts'; -tsBracketTypeTable[']'.charCodeAt(0)] = 'delimiter.array.ts'; - -var tsTokenTypeTable: INumberStringDictionary = Object.create(null); -tsTokenTypeTable[ts.TokenClass.Identifier] = 'identifier.ts'; -tsTokenTypeTable[ts.TokenClass.Keyword] = 'keyword.ts'; -tsTokenTypeTable[ts.TokenClass.Operator] = 'delimiter.ts'; -tsTokenTypeTable[ts.TokenClass.Punctuation] = 'delimiter.ts'; -tsTokenTypeTable[ts.TokenClass.NumberLiteral] = 'number.ts'; -tsTokenTypeTable[ts.TokenClass.RegExpLiteral] = 'regexp.ts'; -tsTokenTypeTable[ts.TokenClass.StringLiteral] = 'string.ts'; - -var jsBracketTypeTable: INumberStringDictionary = Object.create(null); -jsBracketTypeTable['('.charCodeAt(0)] = 'delimiter.parenthesis.js'; -jsBracketTypeTable[')'.charCodeAt(0)] = 'delimiter.parenthesis.js'; -jsBracketTypeTable['{'.charCodeAt(0)] = 'delimiter.bracket.js'; -jsBracketTypeTable['}'.charCodeAt(0)] = 'delimiter.bracket.js'; -jsBracketTypeTable['['.charCodeAt(0)] = 'delimiter.array.js'; -jsBracketTypeTable[']'.charCodeAt(0)] = 'delimiter.array.js'; - -var jsTokenTypeTable: INumberStringDictionary = Object.create(null); -jsTokenTypeTable[ts.TokenClass.Identifier] = 'identifier.js'; -jsTokenTypeTable[ts.TokenClass.Keyword] = 'keyword.js'; -jsTokenTypeTable[ts.TokenClass.Operator] = 'delimiter.js'; -jsTokenTypeTable[ts.TokenClass.Punctuation] = 'delimiter.js'; -jsTokenTypeTable[ts.TokenClass.NumberLiteral] = 'number.js'; -jsTokenTypeTable[ts.TokenClass.RegExpLiteral] = 'regexp.js'; -jsTokenTypeTable[ts.TokenClass.StringLiteral] = 'string.js'; - -function checkSheBang(deltaOffset: number, line: string, appendFn: (startIndex: number, type: string) => void): boolean { - if (line.indexOf('#!') === 0) { - appendFn(deltaOffset, 'comment.shebang'); - return true; - } - return false; -} diff --git a/packages/typescript/src/browser/typescript-frontend-module.ts b/packages/typescript/src/browser/typescript-frontend-module.ts index b0f2109456c83..eb7d2a51056e6 100644 --- a/packages/typescript/src/browser/typescript-frontend-module.ts +++ b/packages/typescript/src/browser/typescript-frontend-module.ts @@ -1,27 +1,31 @@ /* - * Copyright (C) 2017 TypeFox and others. + * Copyright (C) 2018 TypeFox, Ericsson and others. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ import { ContainerModule } from "inversify"; +import { LanguageGrammarDefinitionContribution } from "@theia/monaco/lib/browser/textmate"; import { LanguageClientContribution } from "@theia/languages/lib/browser"; +import { CallHierarchyService } from "@theia/callhierarchy/lib/browser"; import { TypeScriptClientContribution, JavaScriptClientContribution } from "./typescript-client-contribution"; -import { registerTypeScript, registerJavaScript } from './typescript-language-config'; import { TypeScriptCallHierarchyService } from "./typescript-callhierarchy-service"; -import { CallHierarchyService } from "@theia/callhierarchy/lib/browser"; +import { MonacoTextmateBuiltinGrammarContribution } from "./typescript-textmate-grammar-contribution"; +import { registerTypeScript, registerJavaScript } from "./typescript-language-config"; export default new ContainerModule(bind => { - registerTypeScript(); - registerJavaScript(); - bind(TypeScriptClientContribution).toSelf().inSingletonScope(); - bind(LanguageClientContribution).toDynamicValue(ctx => ctx.container.get(TypeScriptClientContribution)); + bind(LanguageClientContribution).toService(TypeScriptClientContribution); bind(JavaScriptClientContribution).toSelf().inSingletonScope(); - bind(LanguageClientContribution).toDynamicValue(ctx => ctx.container.get(JavaScriptClientContribution)); + bind(LanguageClientContribution).toService(JavaScriptClientContribution); bind(TypeScriptCallHierarchyService).toSelf().inSingletonScope(); - bind(CallHierarchyService).toDynamicValue(ctx => ctx.container.get(TypeScriptCallHierarchyService)).inSingletonScope(); + bind(CallHierarchyService).toService(TypeScriptCallHierarchyService); + + bind(LanguageGrammarDefinitionContribution).to(MonacoTextmateBuiltinGrammarContribution).inSingletonScope(); + + registerJavaScript(); + registerTypeScript(); }); diff --git a/packages/typescript/src/browser/typescript-language-config.ts b/packages/typescript/src/browser/typescript-language-config.ts index 457985853f438..1d420e1162ddd 100644 --- a/packages/typescript/src/browser/typescript-language-config.ts +++ b/packages/typescript/src/browser/typescript-language-config.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 TypeFox and others. + * Copyright (C) 2018 TypeFox, Ericsson and others. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -12,7 +12,6 @@ // some parts are copied from https://github.com/Microsoft/monaco-typescript/blob/v2.3.0/src/mode.ts import { TYPESCRIPT_LANGUAGE_ID, TYPESCRIPT_LANGUAGE_NAME, JAVASCRIPT_LANGUAGE_ID, JAVASCRIPT_LANGUAGE_NAME } from "../common"; -import { createTokenizationSupport, Language } from "./monaco-tokenization/tokenization"; const genericEditConfiguration: monaco.languages.LanguageConfiguration = { wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, @@ -71,7 +70,6 @@ export function registerTypeScript() { }); monaco.languages.onLanguage(TYPESCRIPT_LANGUAGE_ID, () => { monaco.languages.setLanguageConfiguration(TYPESCRIPT_LANGUAGE_ID, genericEditConfiguration); - monaco.languages.setTokensProvider(TYPESCRIPT_LANGUAGE_ID, createTokenizationSupport(Language.TypeScript)); }); } @@ -84,6 +82,5 @@ export function registerJavaScript() { }); monaco.languages.onLanguage(JAVASCRIPT_LANGUAGE_ID, () => { monaco.languages.setLanguageConfiguration(JAVASCRIPT_LANGUAGE_ID, genericEditConfiguration); - monaco.languages.setTokensProvider(JAVASCRIPT_LANGUAGE_ID, createTokenizationSupport(Language.EcmaScript5)); }); } diff --git a/packages/typescript/src/browser/typescript-textmate-grammar-contribution.ts b/packages/typescript/src/browser/typescript-textmate-grammar-contribution.ts new file mode 100644 index 0000000000000..205553595e255 --- /dev/null +++ b/packages/typescript/src/browser/typescript-textmate-grammar-contribution.ts @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2018 Ericsson and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { injectable } from 'inversify'; +import { LanguageGrammarDefinitionContribution, TextmateRegistry } from '@theia/monaco/lib/browser/textmate'; + +export interface BuiltinGrammar { + format: 'json' | 'plist'; + language: string; + scope: string; + grammar?: object | string; +} + +@injectable() +export class MonacoTextmateBuiltinGrammarContribution implements LanguageGrammarDefinitionContribution { + + protected readonly builtins: BuiltinGrammar[] = [ + { + format: 'json', + language: 'typescript', + scope: 'source.ts', + grammar: require('../../data/grammars/typescript.tmlanguage.json'), + }, + { + format: 'json', + language: 'javascript', + scope: 'source.js', + grammar: require('../../data/grammars/javascript.tmlanguage.json'), + } + ]; + + registerTextmateLanguage(registry: TextmateRegistry) { + for (const grammar of this.builtins) { + registry.registerTextMateGrammarScope(grammar.scope, { + async getGrammarDefinition() { + return { + format: grammar.format, + content: grammar.grammar || '', + }; + } + }); + + registry.mapLanguageIdToTextmateGrammar(grammar.language, grammar.scope); + } + } +} diff --git a/packages/typescript/src/common/index.ts b/packages/typescript/src/common/index.ts index 6c335b0203405..2dcbefb51678d 100644 --- a/packages/typescript/src/common/index.ts +++ b/packages/typescript/src/common/index.ts @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 TypeFox and others. + * Copyright (C) 2018 TypeFox, Ericsson and others. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/yarn.lock b/yarn.lock index d25bf5cc109f0..458cf2a2367eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3611,6 +3611,10 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" +fast-plist@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/fast-plist/-/fast-plist-0.1.2.tgz#a45aff345196006d406ca6cdcd05f69051ef35b8" + fastparse@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" @@ -6307,9 +6311,11 @@ monaco-languages@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/monaco-languages/-/monaco-languages-1.2.0.tgz#125e6b6fb5e51239493e1a6d5cc99b7572382f75" -monaco-typescript@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/monaco-typescript/-/monaco-typescript-3.1.0.tgz#522c7e578a358bd855e4161227e5e258e2c9b1c7" +monaco-textmate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/monaco-textmate/-/monaco-textmate-3.0.0.tgz#abfbce7d7ff000954ae3206e512f325db6e7b8a8" + dependencies: + fast-plist "^0.1.2" moo-server@*, moo-server@1.3.x: version "1.3.0" @@ -6795,6 +6801,12 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +onigasm@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/onigasm/-/onigasm-2.1.0.tgz#706fa29c80a2fdae7dc6ed8c8ae71c123d10d510" + dependencies: + lru-cache "^4.1.1" + optimist@^0.6.1, optimist@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"