@difizen/libro-cofine-textmate 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/es/data/monaco-themes/vscode/dark_defaults.json +23 -0
  4. package/es/data/monaco-themes/vscode/dark_editor.json +116 -0
  5. package/es/data/monaco-themes/vscode/dark_plus.json +180 -0
  6. package/es/data/monaco-themes/vscode/dark_vs.json +358 -0
  7. package/es/data/monaco-themes/vscode/hc_black.json +120 -0
  8. package/es/data/monaco-themes/vscode/hc_black_defaults.json +335 -0
  9. package/es/data/monaco-themes/vscode/hc_editor.json +7 -0
  10. package/es/data/monaco-themes/vscode/light_defaults.json +22 -0
  11. package/es/data/monaco-themes/vscode/light_editor.json +11 -0
  12. package/es/data/monaco-themes/vscode/light_plus.json +180 -0
  13. package/es/data/monaco-themes/vscode/light_vs.json +380 -0
  14. package/es/global.d.ts +7 -0
  15. package/es/index.d.ts +7 -0
  16. package/es/index.d.ts.map +1 -0
  17. package/es/index.js +6 -0
  18. package/es/monaco-grammar-registry.d.ts +15 -0
  19. package/es/monaco-grammar-registry.d.ts.map +1 -0
  20. package/es/monaco-grammar-registry.js +130 -0
  21. package/es/monaco-module.d.ts +4 -0
  22. package/es/monaco-module.d.ts.map +1 -0
  23. package/es/monaco-module.js +78 -0
  24. package/es/monaco-textmate-service.d.ts +29 -0
  25. package/es/monaco-textmate-service.d.ts.map +1 -0
  26. package/es/monaco-textmate-service.js +284 -0
  27. package/es/monaco-theme-registry.d.ts +33 -0
  28. package/es/monaco-theme-registry.d.ts.map +1 -0
  29. package/es/monaco-theme-registry.js +227 -0
  30. package/es/monaco-theme-types.d.ts +5 -0
  31. package/es/monaco-theme-types.d.ts.map +1 -0
  32. package/es/monaco-theme-types.js +1 -0
  33. package/es/textmate-contribution.d.ts +9 -0
  34. package/es/textmate-contribution.d.ts.map +1 -0
  35. package/es/textmate-contribution.js +6 -0
  36. package/es/textmate-registry.d.ts +32 -0
  37. package/es/textmate-registry.d.ts.map +1 -0
  38. package/es/textmate-registry.js +130 -0
  39. package/es/textmate-theme-contribution.d.ts +6 -0
  40. package/es/textmate-theme-contribution.d.ts.map +1 -0
  41. package/es/textmate-theme-contribution.js +50 -0
  42. package/es/textmate-tokenizer.d.ts +25 -0
  43. package/es/textmate-tokenizer.d.ts.map +1 -0
  44. package/es/textmate-tokenizer.js +32 -0
  45. package/package.json +59 -0
  46. package/src/data/monaco-themes/vscode/dark_defaults.json +23 -0
  47. package/src/data/monaco-themes/vscode/dark_editor.json +116 -0
  48. package/src/data/monaco-themes/vscode/dark_plus.json +180 -0
  49. package/src/data/monaco-themes/vscode/dark_vs.json +358 -0
  50. package/src/data/monaco-themes/vscode/hc_black.json +120 -0
  51. package/src/data/monaco-themes/vscode/hc_black_defaults.json +335 -0
  52. package/src/data/monaco-themes/vscode/hc_editor.json +7 -0
  53. package/src/data/monaco-themes/vscode/light_defaults.json +22 -0
  54. package/src/data/monaco-themes/vscode/light_editor.json +11 -0
  55. package/src/data/monaco-themes/vscode/light_plus.json +180 -0
  56. package/src/data/monaco-themes/vscode/light_vs.json +380 -0
  57. package/src/global.d.ts +7 -0
  58. package/src/index.spec.ts +8 -0
  59. package/src/index.ts +8 -0
  60. package/src/monaco-grammar-registry.ts +88 -0
  61. package/src/monaco-module.ts +59 -0
  62. package/src/monaco-textmate-service.ts +220 -0
  63. package/src/monaco-theme-registry.ts +201 -0
  64. package/src/monaco-theme-types.ts +5 -0
  65. package/src/textmate-contribution.ts +15 -0
  66. package/src/textmate-registry.ts +134 -0
  67. package/src/textmate-theme-contribution.ts +39 -0
  68. package/src/textmate-tokenizer.ts +55 -0
@@ -0,0 +1,220 @@
1
+ import { EditorHandlerContribution } from '@difizen/libro-cofine-editor-core';
2
+ import type { Contribution } from '@difizen/mana-app';
3
+ import {
4
+ Disposable,
5
+ DisposableCollection,
6
+ contrib,
7
+ inject,
8
+ singleton,
9
+ } from '@difizen/mana-app';
10
+ import * as monaco from '@difizen/monaco-editor-core';
11
+ import { TokenizationRegistry } from '@difizen/monaco-editor-core/esm/vs/editor/common/languages';
12
+ import { ILanguageService } from '@difizen/monaco-editor-core/esm/vs/editor/common/languages/language';
13
+ import { TokenizationSupportAdapter } from '@difizen/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneLanguages';
14
+ import { StandaloneServices } from '@difizen/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
15
+ import { IStandaloneThemeService } from '@difizen/monaco-editor-core/esm/vs/editor/standalone/common/standaloneTheme';
16
+
17
+ import {
18
+ isBasicWasmSupported,
19
+ MonacoGrammarRegistry,
20
+ OnigurumaPromise,
21
+ } from './monaco-grammar-registry.js';
22
+ import { MonacoThemeRegistry } from './monaco-theme-registry.js';
23
+ import {
24
+ getEncodedLanguageId,
25
+ LanguageGrammarDefinitionContribution,
26
+ } from './textmate-contribution.js';
27
+ import { TextmateRegistry } from './textmate-registry.js';
28
+ import type { TokenizerOption } from './textmate-tokenizer.js';
29
+ import { createTextmateTokenizer } from './textmate-tokenizer.js';
30
+
31
+ @singleton({ contrib: EditorHandlerContribution })
32
+ export class MonacoTextmateService implements EditorHandlerContribution {
33
+ protected readonly tokenizerOption: TokenizerOption = {
34
+ lineLimit: 400,
35
+ };
36
+
37
+ protected readonly _activatedLanguages = new Set<string>();
38
+
39
+ @contrib(LanguageGrammarDefinitionContribution)
40
+ protected readonly grammarProviders: Contribution.Provider<LanguageGrammarDefinitionContribution>;
41
+
42
+ @inject(TextmateRegistry)
43
+ protected readonly textmateRegistry: TextmateRegistry;
44
+ @inject(MonacoGrammarRegistry)
45
+ protected readonly grammarRegistry: MonacoGrammarRegistry;
46
+
47
+ @inject(OnigurumaPromise)
48
+ protected readonly onigasmPromise: OnigurumaPromise;
49
+
50
+ @inject(MonacoThemeRegistry)
51
+ protected readonly monacoThemeRegistry: MonacoThemeRegistry;
52
+
53
+ beforeCreate() {
54
+ this.initialize();
55
+ }
56
+ afterCreate() {
57
+ //
58
+ }
59
+ canHandle() {
60
+ return true;
61
+ }
62
+ dispose() {
63
+ //
64
+ }
65
+
66
+ initialize(): void {
67
+ if (!isBasicWasmSupported) {
68
+ console.warn('Textmate support deactivated because WebAssembly is not detected.');
69
+ return;
70
+ }
71
+
72
+ for (const grammarProvider of this.grammarProviders.getContributions()) {
73
+ try {
74
+ grammarProvider.registerTextmateLanguage(this.textmateRegistry);
75
+ } catch (err) {
76
+ console.error(err);
77
+ }
78
+ }
79
+ for (const id of this.textmateRegistry.languages) {
80
+ this.activateLanguage(id);
81
+ }
82
+ // const theme = this.monacoThemeRegistry.getThemeData(this.currentEditorTheme);
83
+ // if (!theme) {
84
+ // return;
85
+ // }
86
+ // this.grammarRegistry.setupRegistry(theme);
87
+ this.monacoThemeRegistry.onThemeChanged(() => {
88
+ this.updateTheme();
89
+ });
90
+ }
91
+
92
+ protected readonly toDisposeOnUpdateTheme = new DisposableCollection();
93
+
94
+ protected updateTheme = (): void => {
95
+ this.toDisposeOnUpdateTheme.dispose();
96
+
97
+ const { currentEditorTheme } = this;
98
+ document.body.classList.add(currentEditorTheme);
99
+ this.toDisposeOnUpdateTheme.push(
100
+ Disposable.create(() => document.body.classList.remove(currentEditorTheme)),
101
+ );
102
+
103
+ // first update registry to run tokenization with the proper theme
104
+ const theme = this.monacoThemeRegistry.getThemeData(currentEditorTheme);
105
+ if (theme) {
106
+ this.grammarRegistry.setupRegistry(theme);
107
+ }
108
+
109
+ // then trigger tokenization by setting monaco theme
110
+ monaco.editor.setTheme(currentEditorTheme);
111
+ };
112
+
113
+ protected get currentEditorTheme(): string {
114
+ return this.monacoThemeRegistry.getMonacoThemeName();
115
+ }
116
+
117
+ activateLanguage(language: string): Disposable {
118
+ const toDispose = new DisposableCollection(
119
+ Disposable.create(() => {
120
+ /* mark as not disposed */
121
+ }),
122
+ );
123
+ toDispose.push(
124
+ this.waitForLanguage(language, () =>
125
+ this.doActivateLanguage(language, toDispose),
126
+ ),
127
+ );
128
+ return toDispose;
129
+ }
130
+
131
+ protected async doActivateLanguage(
132
+ languageId: string,
133
+ toDispose: DisposableCollection,
134
+ ): Promise<void> {
135
+ if (this._activatedLanguages.has(languageId)) {
136
+ return;
137
+ }
138
+ this._activatedLanguages.add(languageId);
139
+ toDispose.push(
140
+ Disposable.create(() => this._activatedLanguages.delete(languageId)),
141
+ );
142
+
143
+ const scopeName = this.textmateRegistry.getScope(languageId);
144
+ if (!scopeName) {
145
+ return;
146
+ }
147
+ const provider = this.textmateRegistry.getProvider(scopeName);
148
+ if (!provider) {
149
+ return;
150
+ }
151
+
152
+ const configuration = this.textmateRegistry.getGrammarConfiguration(languageId);
153
+ const initialLanguage = getEncodedLanguageId(languageId);
154
+
155
+ await this.onigasmPromise;
156
+ if (toDispose.disposed) {
157
+ return;
158
+ }
159
+ if (!this.grammarRegistry.registry) {
160
+ return;
161
+ }
162
+ try {
163
+ const grammar = await this.grammarRegistry.registry.loadGrammarWithConfiguration(
164
+ scopeName,
165
+ initialLanguage,
166
+ configuration,
167
+ );
168
+ if (toDispose.disposed) {
169
+ return;
170
+ }
171
+ if (!grammar) {
172
+ throw new Error(
173
+ `no grammar for ${scopeName}, ${initialLanguage}, ${JSON.stringify(
174
+ configuration,
175
+ )}`,
176
+ );
177
+ }
178
+ const options = configuration.tokenizerOption
179
+ ? configuration.tokenizerOption
180
+ : this.tokenizerOption;
181
+ const tokenizer = createTextmateTokenizer(grammar, options);
182
+ toDispose.push(monaco.languages.setTokensProvider(languageId, tokenizer));
183
+ const support = TokenizationRegistry.get(languageId);
184
+ const themeService = StandaloneServices.get(IStandaloneThemeService);
185
+ const adapter = new TokenizationSupportAdapter(
186
+ themeService,
187
+ {
188
+ language: languageId,
189
+ id: StandaloneServices.get(
190
+ ILanguageService,
191
+ )._registry.languageIdCodec._languageToLanguageId.get(languageId),
192
+ },
193
+ tokenizer,
194
+ );
195
+ support!.tokenize = adapter.tokenize.bind(adapter);
196
+ this.updateTheme();
197
+ } catch (error) {
198
+ console.warn('No grammar for this language id', languageId, error);
199
+ }
200
+ }
201
+
202
+ protected waitForLanguage(
203
+ language: string,
204
+ cb: () => {
205
+ //
206
+ },
207
+ ): Disposable {
208
+ const modeService = StandaloneServices.get(ILanguageService);
209
+ for (const modeId of Object.keys(modeService._instantiatedModes || {})) {
210
+ const mode = modeService._instantiatedModes[modeId];
211
+ if (mode.getId() === language) {
212
+ cb();
213
+ return Disposable.create(() => {
214
+ //
215
+ });
216
+ }
217
+ }
218
+ return monaco.languages.onLanguage(language, cb);
219
+ }
220
+ }
@@ -0,0 +1,201 @@
1
+ import type {
2
+ MixedTheme,
3
+ ITextmateThemeSetting,
4
+ } from '@difizen/libro-cofine-editor-core';
5
+ import {
6
+ MixedThemeRegistry,
7
+ InitializeContribution,
8
+ } from '@difizen/libro-cofine-editor-core';
9
+ import type { Color } from '@difizen/mana-app';
10
+ import { Emitter, inject, singleton } from '@difizen/mana-app';
11
+ import * as monaco from '@difizen/monaco-editor-core';
12
+ import { StandaloneServices } from '@difizen/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
13
+ import { IStandaloneThemeService } from '@difizen/monaco-editor-core/esm/vs/editor/standalone/common/standaloneTheme';
14
+
15
+ import { MonacoGrammarRegistry } from './monaco-grammar-registry.js';
16
+
17
+ export interface MixStandaloneTheme {
18
+ themeData: MixedTheme;
19
+ }
20
+
21
+ @singleton({ contrib: [MixedThemeRegistry, InitializeContribution] })
22
+ export class MonacoThemeRegistry implements MixedThemeRegistry, InitializeContribution {
23
+ @inject(MonacoGrammarRegistry)
24
+ protected readonly grammarRegistry: MonacoGrammarRegistry;
25
+
26
+ protected registedTheme: string[] = [];
27
+
28
+ onInitialize() {
29
+ const standaloneThemeService = StandaloneServices.get(IStandaloneThemeService);
30
+ standaloneThemeService.onDidColorThemeChange(() => {
31
+ this.themeChangedEmitter.fire();
32
+ });
33
+ }
34
+
35
+ protected themeChangedEmitter = new Emitter<void>();
36
+
37
+ onThemeChanged = this.themeChangedEmitter.event;
38
+
39
+ getThemeData(): MixedTheme;
40
+ getThemeData(name: string): MixedTheme | undefined;
41
+ getThemeData(name?: string): MixedTheme | undefined {
42
+ const theme = this.doGetTheme(name);
43
+ return theme && theme.themeData;
44
+ }
45
+
46
+ getTheme(): MixStandaloneTheme;
47
+ getTheme(name: string): MixStandaloneTheme | undefined;
48
+ getTheme(name?: string): MixStandaloneTheme | undefined {
49
+ return this.doGetTheme(name);
50
+ }
51
+
52
+ getMonacoThemeName() {
53
+ const standaloneThemeService = StandaloneServices.get(IStandaloneThemeService);
54
+ return standaloneThemeService.getColorTheme().themeName as string;
55
+ }
56
+
57
+ protected doGetTheme(name: string | undefined): MixStandaloneTheme | undefined {
58
+ const standaloneThemeService = StandaloneServices.get(IStandaloneThemeService);
59
+ const theme = !name
60
+ ? standaloneThemeService.getTheme()
61
+ : standaloneThemeService._knownThemes.get(name);
62
+ return theme as MixStandaloneTheme | undefined;
63
+ }
64
+
65
+ setTheme(name: string, data: MixedTheme): void {
66
+ // monaco auto refreshes a theme with new data
67
+ monaco.editor.defineTheme(name, data);
68
+ }
69
+
70
+ registerThemes(
71
+ themeOptions: Record<string, ITextmateThemeSetting>,
72
+ setTheme: (name: string, data: monaco.editor.IStandaloneThemeData) => void,
73
+ ): void {
74
+ Object.keys(themeOptions).forEach((key) => {
75
+ this.doRegisterThemes(themeOptions[key], themeOptions, setTheme);
76
+ });
77
+ }
78
+ doRegisterThemes(
79
+ option: ITextmateThemeSetting,
80
+ themeOptions: Record<string, ITextmateThemeSetting>,
81
+ setTheme: (name: string, data: monaco.editor.IStandaloneThemeData) => void,
82
+ ): MixedTheme {
83
+ const result: MixedTheme = {
84
+ name: option.name,
85
+ base: option.base || 'vs',
86
+ inherit: true,
87
+ colors: {},
88
+ rules: [],
89
+ settings: [],
90
+ };
91
+ if (typeof option.include !== 'undefined') {
92
+ const themeName = option.include
93
+ .replaceAll('/', '')
94
+ .replaceAll('_', '-')
95
+ .replaceAll('.json', '');
96
+
97
+ const parentOption = themeOptions[themeName];
98
+ if (!parentOption || this.registedTheme.includes(parentOption.name)) {
99
+ console.error(`Couldn't resolve includes theme ${option.include}.`);
100
+ } else {
101
+ const parentTheme = this.doRegisterThemes(parentOption, themeOptions, setTheme);
102
+ Object.assign(result.colors, parentTheme.colors);
103
+ result.rules.push(...parentTheme.rules);
104
+ result.settings.push(...parentTheme.settings);
105
+ }
106
+ }
107
+ const { tokenColors } = option;
108
+ if (Array.isArray(tokenColors)) {
109
+ for (const tokenColor of tokenColors) {
110
+ if (tokenColor.scope && tokenColor.settings) {
111
+ result.settings.push({
112
+ scope: tokenColor.scope,
113
+ settings: {
114
+ foreground: this.normalizeColor(tokenColor.settings.foreground),
115
+ background: this.normalizeColor(tokenColor.settings.background),
116
+ fontStyle: tokenColor.settings.fontStyle,
117
+ },
118
+ });
119
+ }
120
+ }
121
+ }
122
+ if (option.colors) {
123
+ Object.assign(result.colors, option.colors);
124
+ result.encodedTokensColors = Object.keys(result.colors).map(
125
+ (key) => result.colors[key],
126
+ );
127
+ }
128
+ if (option.name && option.base) {
129
+ for (const setting of result.settings) {
130
+ this.transform(setting, (rule) => result.rules.push(rule));
131
+ }
132
+ const standaloneThemeService = StandaloneServices.get(IStandaloneThemeService);
133
+
134
+ // the default rule (scope empty) is always the first rule. Ignore all other default rules.
135
+ const defaultTheme = standaloneThemeService._knownThemes.get(result.base)!;
136
+ const foreground =
137
+ result.colors['editor.foreground'] ||
138
+ defaultTheme.getColor('editor.foreground');
139
+ const background =
140
+ result.colors['editor.background'] ||
141
+ defaultTheme.getColor('editor.background');
142
+ result.settings.unshift({
143
+ settings: {
144
+ foreground: this.normalizeColor(foreground),
145
+ background: this.normalizeColor(background),
146
+ },
147
+ });
148
+
149
+ const reg = this.grammarRegistry.getRegistry(result);
150
+ reg.setTheme(result);
151
+ result.encodedTokensColors = reg.getColorMap();
152
+ // index 0 has to be set to null as it is 'undefined' by default, but monaco code expects it to be null
153
+ if (result.encodedTokensColors) {
154
+ result.encodedTokensColors[0] = null!;
155
+ }
156
+ setTheme(option.name, result);
157
+ }
158
+ return result;
159
+ }
160
+
161
+ protected transform(
162
+ tokenColor: any,
163
+ acceptor: (rule: monaco.editor.ITokenThemeRule) => void,
164
+ ): void {
165
+ if (typeof tokenColor.scope === 'undefined') {
166
+ tokenColor.scope = [''];
167
+ } else if (typeof tokenColor.scope === 'string') {
168
+ tokenColor.scope = tokenColor.scope
169
+ .split(',')
170
+ .map((scope: string) => scope.trim());
171
+ }
172
+
173
+ for (const scope of tokenColor.scope) {
174
+ acceptor({
175
+ ...tokenColor.settings,
176
+ token: scope,
177
+ });
178
+ }
179
+ }
180
+
181
+ protected normalizeColor(color: string | Color | undefined): string | undefined {
182
+ if (!color) {
183
+ return undefined;
184
+ }
185
+ const normalized = String(color).replace(/^#/, '').slice(0, 6);
186
+ if (normalized.length < 6 || !normalized.match(/^[0-9A-Fa-f]{6}$/)) {
187
+ // ignoring not normalized colors to avoid breaking token color indexes between monaco and vscode-textmate
188
+ console.error(
189
+ `Color '${normalized}' is NOT normalized, it must have 6 positions.`,
190
+ );
191
+ return undefined;
192
+ }
193
+ return `#${normalized}`;
194
+ }
195
+ }
196
+
197
+ export namespace MonacoThemeRegistry {
198
+ export const DARK_DEFAULT_THEME = 'e2-dark';
199
+ export const LIGHT_DEFAULT_THEME = 'e2-light';
200
+ export const HC_DEFAULT_THEME = 'e2-hc';
201
+ }
@@ -0,0 +1,5 @@
1
+ import type * as monaco from '@difizen/monaco-editor-core';
2
+
3
+ export interface MonacoTheme extends monaco.editor.IStandaloneThemeData {
4
+ name: string;
5
+ }
@@ -0,0 +1,15 @@
1
+ import { Syringe } from '@difizen/mana-app';
2
+ import * as monaco from '@difizen/monaco-editor-core';
3
+
4
+ import type { TextmateRegistry } from './textmate-registry.js';
5
+
6
+ export const LanguageGrammarDefinitionContribution = Syringe.defineToken(
7
+ 'LanguageGrammarDefinitionContribution',
8
+ );
9
+ export interface LanguageGrammarDefinitionContribution {
10
+ registerTextmateLanguage: (registry: TextmateRegistry) => void;
11
+ _finishRegisterTextmateLanguage?: boolean;
12
+ }
13
+ export function getEncodedLanguageId(languageId: string): number {
14
+ return monaco.languages.getEncodedLanguageId(languageId);
15
+ }
@@ -0,0 +1,134 @@
1
+ /* eslint-disable no-console */
2
+ /* eslint-disable no-restricted-syntax */
3
+
4
+ import { Disposable } from '@difizen/mana-app';
5
+ import { singleton } from '@difizen/mana-app';
6
+ import type { IGrammarConfiguration } from 'vscode-textmate';
7
+
8
+ import type { TokenizerOption } from './textmate-tokenizer.js';
9
+
10
+ export interface TextmateGrammarConfiguration extends IGrammarConfiguration {
11
+ /**
12
+ * Optional options to further refine the tokenization of the grammar.
13
+ */
14
+ readonly tokenizerOption?: TokenizerOption;
15
+ }
16
+
17
+ export interface GrammarDefinitionProvider {
18
+ getGrammarDefinition: () => Promise<GrammarDefinition>;
19
+ getInjections?: (scopeName: string) => string[];
20
+ }
21
+
22
+ export interface GrammarDefinition {
23
+ format: 'json' | 'plist';
24
+ content: Record<string, unknown> | string;
25
+ location?: string;
26
+ }
27
+
28
+ @singleton()
29
+ export class TextmateRegistry {
30
+ protected readonly scopeToProvider = new Map<string, GrammarDefinitionProvider[]>();
31
+ protected readonly languageToConfig = new Map<
32
+ string,
33
+ TextmateGrammarConfiguration[]
34
+ >();
35
+ protected readonly languageIdToScope = new Map<string, string[]>();
36
+
37
+ get languages(): IterableIterator<string> {
38
+ return this.languageIdToScope.keys();
39
+ }
40
+
41
+ registerTextmateGrammarScope(
42
+ scope: string,
43
+ provider: GrammarDefinitionProvider,
44
+ ): Disposable {
45
+ const providers = this.scopeToProvider.get(scope) || [];
46
+ const existingProvider = providers[0];
47
+ if (existingProvider) {
48
+ Promise.all([
49
+ existingProvider.getGrammarDefinition(),
50
+ provider.getGrammarDefinition(),
51
+ ])
52
+ .then(([a, b]) => {
53
+ if (a.location !== b.location || (!a.location && !b.location)) {
54
+ console.warn(
55
+ `a registered grammar provider for '${scope}' scope is overridden`,
56
+ );
57
+ }
58
+ return;
59
+ })
60
+ .catch(console.error);
61
+ }
62
+ providers.unshift(provider);
63
+ this.scopeToProvider.set(scope, providers);
64
+ return Disposable.create(() => {
65
+ const index = providers.indexOf(provider);
66
+ if (index !== -1) {
67
+ providers.splice(index, 1);
68
+ }
69
+ });
70
+ }
71
+
72
+ getProvider(scope: string): GrammarDefinitionProvider | undefined {
73
+ const providers = this.scopeToProvider.get(scope);
74
+ return providers && providers[0];
75
+ }
76
+
77
+ mapLanguageIdToTextmateGrammar(languageId: string, scope: string): Disposable {
78
+ const scopes = this.languageIdToScope.get(languageId) || [];
79
+ const existingScope = scopes[0];
80
+ if (typeof existingScope === 'string') {
81
+ console.warn(
82
+ `'${languageId}' language is remapped from '${existingScope}' to '${scope}' scope`,
83
+ );
84
+ }
85
+ scopes.unshift(scope);
86
+ this.languageIdToScope.set(languageId, scopes);
87
+ return Disposable.create(() => {
88
+ const index = scopes.indexOf(scope);
89
+ if (index !== -1) {
90
+ scopes.splice(index, 1);
91
+ }
92
+ });
93
+ }
94
+
95
+ getScope(languageId: string): string | undefined {
96
+ const scopes = this.languageIdToScope.get(languageId);
97
+ return scopes && scopes[0];
98
+ }
99
+
100
+ getLanguageId(scope: string): string | undefined {
101
+ for (const languageId of this.languageIdToScope.keys()) {
102
+ if (this.getScope(languageId) === scope) {
103
+ return languageId;
104
+ }
105
+ }
106
+ return undefined;
107
+ }
108
+
109
+ registerGrammarConfiguration(
110
+ languageId: string,
111
+ config: TextmateGrammarConfiguration,
112
+ ): Disposable {
113
+ const configs = this.languageToConfig.get(languageId) || [];
114
+ const existingConfig = configs[0];
115
+ if (existingConfig) {
116
+ console.warn(
117
+ `a registered grammar configuration for '${languageId}' language is overridden`,
118
+ );
119
+ }
120
+ configs.unshift(config);
121
+ this.languageToConfig.set(languageId, configs);
122
+ return Disposable.create(() => {
123
+ const index = configs.indexOf(config);
124
+ if (index !== -1) {
125
+ configs.splice(index, 1);
126
+ }
127
+ });
128
+ }
129
+
130
+ getGrammarConfiguration(languageId: string): TextmateGrammarConfiguration {
131
+ const configs = this.languageToConfig.get(languageId);
132
+ return (configs && configs[0]) || {};
133
+ }
134
+ }
@@ -0,0 +1,39 @@
1
+ /* eslint-disable global-require */
2
+ import type { ThemeRegistry } from '@difizen/libro-cofine-editor-core';
3
+ import { ThemeContribution } from '@difizen/libro-cofine-editor-core';
4
+ import { singleton } from '@difizen/mana-app';
5
+
6
+ import darkDefaults from './data/monaco-themes/vscode/dark_defaults.json';
7
+ import darkEditor from './data/monaco-themes/vscode/dark_editor.json';
8
+ import darkPlus from './data/monaco-themes/vscode/dark_plus.json';
9
+ import darkVS from './data/monaco-themes/vscode/dark_vs.json';
10
+ import HCBlack from './data/monaco-themes/vscode/hc_black.json';
11
+ import HCBlackDefault from './data/monaco-themes/vscode/hc_black_defaults.json';
12
+ import HCEditor from './data/monaco-themes/vscode/hc_editor.json';
13
+ import lightDefaults from './data/monaco-themes/vscode/light_defaults.json';
14
+ import lightEditor from './data/monaco-themes/vscode/light_editor.json';
15
+ import lightPlus from './data/monaco-themes/vscode/light_plus.json';
16
+ import lightVS from './data/monaco-themes/vscode/light_vs.json';
17
+
18
+ @singleton({ contrib: ThemeContribution })
19
+ export class TextmateThemeContribution implements ThemeContribution {
20
+ registerItem(registry: ThemeRegistry): void {
21
+ if (!registry.mixedThemeEnable) {
22
+ console.warn('cannot register textmate themes');
23
+ return;
24
+ }
25
+ registry.registerMixedTheme(darkDefaults, 'dark-defaults', 'vs-dark');
26
+ registry.registerMixedTheme(darkVS, 'dark-vs', 'vs-dark');
27
+ registry.registerMixedTheme(darkPlus, 'dark-plus', 'vs-dark');
28
+ registry.registerMixedTheme(darkEditor, 'e2-dark', 'vs-dark');
29
+
30
+ registry.registerMixedTheme(lightDefaults, 'light-defaults', 'vs');
31
+ registry.registerMixedTheme(lightVS, 'light-vs', 'vs');
32
+ registry.registerMixedTheme(lightPlus, 'light-plus', 'vs');
33
+ registry.registerMixedTheme(lightEditor, 'e2-light', 'vs');
34
+
35
+ registry.registerMixedTheme(HCBlackDefault, 'hc-black-defaults', 'hc-black');
36
+ registry.registerMixedTheme(HCBlack, 'hc-black', 'hc-black');
37
+ registry.registerMixedTheme(HCEditor, 'e2-hc', 'hc-black');
38
+ }
39
+ }
@@ -0,0 +1,55 @@
1
+ /* eslint-disable @typescript-eslint/no-namespace */
2
+
3
+ import type monaco from '@difizen/monaco-editor-core';
4
+ import type { IGrammar, StateStack } from 'vscode-textmate';
5
+ import { INITIAL } from 'vscode-textmate';
6
+
7
+ /**
8
+ * Options for the TextMate tokenizer.
9
+ */
10
+ export interface TokenizerOption {
11
+ /**
12
+ * Maximum line length that will be handled by the TextMate tokenizer. If the length of the actual line exceeds this
13
+ * limit, the tokenizer terminates and the tokenization of any subsequent lines might be broken.
14
+ *
15
+ * If the `lineLimit` is not defined, it means, there are no line length limits. Otherwise, it must be a positive
16
+ * integer or an error will be thrown.
17
+ */
18
+ lineLimit?: number;
19
+ }
20
+
21
+ export namespace TokenizerOption {
22
+ /**
23
+ * The default TextMate tokenizer option.
24
+ *
25
+ * @deprecated Use the current value of `editor.maxTokenizationLineLength` preference instead.
26
+ */
27
+ export const DEFAULT: TokenizerOption = {
28
+ lineLimit: 400,
29
+ };
30
+ }
31
+
32
+ export function createTextmateTokenizer(
33
+ grammar: IGrammar,
34
+ options: TokenizerOption,
35
+ ): monaco.languages.EncodedTokensProvider {
36
+ if (
37
+ options.lineLimit !== undefined &&
38
+ (options.lineLimit <= 0 || !Number.isInteger(options.lineLimit))
39
+ ) {
40
+ throw new Error(
41
+ `The 'lineLimit' must be a positive integer. It was ${options.lineLimit}.`,
42
+ );
43
+ }
44
+ return {
45
+ getInitialState: () => INITIAL,
46
+ tokenizeEncoded(
47
+ line: string,
48
+ state: monaco.languages.IState,
49
+ ): monaco.languages.IEncodedLineTokens {
50
+ const tokenizeLineResult2 = grammar.tokenizeLine2(line, state as StateStack);
51
+ const { tokens, ruleStack: endState } = tokenizeLineResult2;
52
+ return { tokens, endState };
53
+ },
54
+ };
55
+ }