@difizen/libro-cofine-editor-core 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 (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/es/default-worker-contribution.d.ts +9 -0
  4. package/es/default-worker-contribution.d.ts.map +1 -0
  5. package/es/default-worker-contribution.js +32 -0
  6. package/es/e2-editor.d.ts +30 -0
  7. package/es/e2-editor.d.ts.map +1 -0
  8. package/es/e2-editor.js +131 -0
  9. package/es/editor-handler-registry.d.ts +12 -0
  10. package/es/editor-handler-registry.d.ts.map +1 -0
  11. package/es/editor-handler-registry.js +59 -0
  12. package/es/editor-provider.d.ts +15 -0
  13. package/es/editor-provider.d.ts.map +1 -0
  14. package/es/editor-provider.js +1 -0
  15. package/es/editor.worker.d.ts +2 -0
  16. package/es/editor.worker.d.ts.map +1 -0
  17. package/es/editor.worker.js +23 -0
  18. package/es/global.d.ts +7 -0
  19. package/es/index.d.ts +18 -0
  20. package/es/index.d.ts.map +1 -0
  21. package/es/index.js +23 -0
  22. package/es/initialize-provider.d.ts +18 -0
  23. package/es/initialize-provider.d.ts.map +1 -0
  24. package/es/initialize-provider.js +120 -0
  25. package/es/mana-export.d.ts +4 -0
  26. package/es/mana-export.d.ts.map +1 -0
  27. package/es/mana-export.js +23 -0
  28. package/es/monaco-compability.esm.d.ts +4 -0
  29. package/es/monaco-compability.esm.d.ts.map +1 -0
  30. package/es/monaco-compability.esm.js +10 -0
  31. package/es/monaco-environment.d.ts +29 -0
  32. package/es/monaco-environment.d.ts.map +1 -0
  33. package/es/monaco-environment.js +276 -0
  34. package/es/monaco-loader.d.ts +22 -0
  35. package/es/monaco-loader.d.ts.map +1 -0
  36. package/es/monaco-loader.js +139 -0
  37. package/es/monaco-module.d.ts +5 -0
  38. package/es/monaco-module.d.ts.map +1 -0
  39. package/es/monaco-module.js +71 -0
  40. package/es/snippets-suggest-registry.d.ts +31 -0
  41. package/es/snippets-suggest-registry.d.ts.map +1 -0
  42. package/es/snippets-suggest-registry.js +110 -0
  43. package/es/theme-registry.d.ts +58 -0
  44. package/es/theme-registry.d.ts.map +1 -0
  45. package/es/theme-registry.js +91 -0
  46. package/package.json +64 -0
  47. package/src/default-worker-contribution.ts +25 -0
  48. package/src/e2-editor.ts +161 -0
  49. package/src/editor-handler-registry.ts +47 -0
  50. package/src/editor-provider.ts +29 -0
  51. package/src/editor.worker.ts +25 -0
  52. package/src/global.d.ts +7 -0
  53. package/src/index.spec.ts +8 -0
  54. package/src/index.ts +46 -0
  55. package/src/initialize-provider.ts +54 -0
  56. package/src/mana-export.ts +8 -0
  57. package/src/monaco-compability.esm.ts +4 -0
  58. package/src/monaco-environment.ts +115 -0
  59. package/src/monaco-loader.ts +100 -0
  60. package/src/monaco-module.ts +101 -0
  61. package/src/snippets-suggest-registry.ts +101 -0
  62. package/src/theme-registry.ts +116 -0
@@ -0,0 +1,47 @@
1
+ import { EditorHandlerContribution } from '@difizen/libro-cofine-editor-contribution';
2
+ import type { Contribution } from '@difizen/mana-app';
3
+ import { contrib, singleton } from '@difizen/mana-app';
4
+ import * as monaco from '@difizen/monaco-editor-core';
5
+
6
+ @singleton()
7
+ export class EditorHanlerRegistry {
8
+ contributions: EditorHandlerContribution[];
9
+ effected: EditorHandlerContribution[] = [];
10
+ provider: Contribution.Provider<EditorHandlerContribution>;
11
+ constructor(
12
+ @contrib(EditorHandlerContribution)
13
+ provider: Contribution.Provider<EditorHandlerContribution>,
14
+ ) {
15
+ this.provider = provider;
16
+ this.contributions = provider.getContributions();
17
+ }
18
+
19
+ handleAfter(
20
+ languege: string,
21
+ editor: monaco.editor.IStandaloneCodeEditor | monaco.editor.IStandaloneDiffEditor,
22
+ ): void {
23
+ this.effected.forEach((contribution) => contribution.dispose());
24
+ this.effected = [];
25
+ this.contributions = this.provider.getContributions({ cache: false });
26
+ const canHanleList = this.contributions.filter((handler) =>
27
+ handler.canHandle(languege),
28
+ );
29
+ canHanleList.forEach((contribution) => {
30
+ contribution.afterCreate(editor, monaco);
31
+ this.effected.push(contribution);
32
+ });
33
+ }
34
+
35
+ handleBefore(languege: string): void {
36
+ this.contributions = this.provider.getContributions({ cache: false });
37
+ this.effected.forEach((contribution) => contribution.dispose());
38
+ this.effected = [];
39
+ const canHanleList = this.contributions.filter((handler) =>
40
+ handler.canHandle(languege),
41
+ );
42
+ canHanleList.forEach((contribution) => {
43
+ contribution.beforeCreate(monaco);
44
+ this.effected.push(contribution);
45
+ });
46
+ }
47
+ }
@@ -0,0 +1,29 @@
1
+ import type monaco from '@difizen/monaco-editor-core';
2
+
3
+ import type { E2Editor } from './e2-editor.js';
4
+
5
+ export const EditorProvider = Symbol('EditorProvider');
6
+ export type Options = monaco.editor.IStandaloneEditorConstructionOptions &
7
+ monaco.editor.IDiffEditorConstructionOptions & {
8
+ modified?: string;
9
+ original?: string;
10
+ } & {
11
+ uri?: monaco.Uri;
12
+ };
13
+
14
+ export interface EditorProvider {
15
+ create: (
16
+ node: HTMLElement,
17
+ options: Options,
18
+ callback?: LazyCallbackType,
19
+ ) => E2Editor<monaco.editor.IStandaloneCodeEditor>;
20
+ createDiff: (
21
+ node: HTMLElement,
22
+ options: Options,
23
+ callback?: LazyCallbackType,
24
+ ) => E2Editor<monaco.editor.IStandaloneDiffEditor>;
25
+ }
26
+
27
+ export type LazyCallbackType = (
28
+ editor: monaco.editor.IStandaloneCodeEditor | monaco.editor.IStandaloneDiffEditor,
29
+ ) => void;
@@ -0,0 +1,25 @@
1
+ import { SimpleWorkerServer } from '@difizen/monaco-editor-core/esm/vs/base/common/worker/simpleWorker.js';
2
+ import { EditorSimpleWorker } from '@difizen/monaco-editor-core/esm/vs/editor/common/services/editorSimpleWorker.js';
3
+
4
+ let initialized = false;
5
+ export function initialize(foreignModule: any) {
6
+ if (initialized) {
7
+ return;
8
+ }
9
+ initialized = true;
10
+ const simpleWorker = new SimpleWorkerServer(
11
+ (msg: string) => {
12
+ globalThis.postMessage(msg);
13
+ },
14
+ (host: string) => new EditorSimpleWorker(host, foreignModule),
15
+ );
16
+ globalThis.onmessage = (e) => {
17
+ simpleWorker.onmessage(e.data);
18
+ };
19
+ }
20
+ globalThis.onmessage = (e) => {
21
+ // Ignore first message in this case and initialize if not yet initialized
22
+ if (!initialized) {
23
+ initialize(null);
24
+ }
25
+ };
@@ -0,0 +1,7 @@
1
+ declare module '@difizen/monaco-editor-core/esm/vs/base/common/worker/simpleWorker.js';
2
+ declare module '@difizen/monaco-editor-core/esm/vs/editor/common/services/editorSimpleWorker.js';
3
+ declare module '*.json';
4
+ interface Window {
5
+ _Monaco: any;
6
+ MonacoEnvironment: any;
7
+ }
@@ -0,0 +1,8 @@
1
+ import 'reflect-metadata';
2
+ import assert from 'assert';
3
+
4
+ describe('libro-cofine-editor-core', () => {
5
+ it('#import', () => {
6
+ assert(true);
7
+ });
8
+ });
package/src/index.ts ADDED
@@ -0,0 +1,46 @@
1
+ import type monaco from '@difizen/monaco-editor-core';
2
+
3
+ import type { E2Editor } from './e2-editor.js';
4
+ import { EditorProvider } from './editor-provider.js';
5
+ import { MonacoEnvironment } from './monaco-environment.js';
6
+
7
+ export {
8
+ EditorHandlerContribution,
9
+ LanguageOptionsRegistry,
10
+ LanguageWorkerContribution,
11
+ LanguageWorkerRegistry,
12
+ } from '@difizen/libro-cofine-editor-contribution';
13
+ export type { E2Editor } from './e2-editor.js';
14
+ export { EditorHanlerRegistry } from './editor-handler-registry.js';
15
+ export { EditorProvider } from './editor-provider.js';
16
+ export { InitializeContribution } from './initialize-provider.js';
17
+ export { MonacoEnvironment } from './monaco-environment.js';
18
+ export { MonacoLoaderConfig } from './monaco-loader.js';
19
+ export {
20
+ SnippetSuggestContribution,
21
+ SnippetSuggestRegistry,
22
+ } from './snippets-suggest-registry.js';
23
+ export {
24
+ MixedThemeRegistry,
25
+ ThemeContribution,
26
+ ThemeRegistry,
27
+ } from './theme-registry.js';
28
+ export type {
29
+ MixedTheme,
30
+ ITextmateThemeSetting,
31
+ IRawThemeSetting,
32
+ IRawTheme,
33
+ } from './theme-registry.js';
34
+ export class Editor {
35
+ editor: E2Editor<monaco.editor.IStandaloneCodeEditor>;
36
+ codeEditor: monaco.editor.IStandaloneCodeEditor;
37
+ constructor(
38
+ node: HTMLElement,
39
+ options: monaco.editor.IStandaloneEditorConstructionOptions = {},
40
+ ) {
41
+ const editorProvider =
42
+ MonacoEnvironment.container.get<EditorProvider>(EditorProvider);
43
+ this.editor = editorProvider.create(node, options);
44
+ this.codeEditor = this.editor.codeEditor;
45
+ }
46
+ }
@@ -0,0 +1,54 @@
1
+ import type { Contribution } from '@difizen/mana-app';
2
+ import {
3
+ contrib,
4
+ DefaultContributionProvider,
5
+ singleton,
6
+ Syringe,
7
+ } from '@difizen/mana-app';
8
+ import type monaco from '@difizen/monaco-editor-core';
9
+
10
+ export const InitializeContribution = Syringe.defineToken('InitializeContribution');
11
+ export interface InitializeContribution {
12
+ initialized?: boolean;
13
+ onInitialize?: (coreMonaco: typeof monaco) => void | Promise<void>;
14
+ awaysInitialized?: boolean;
15
+ }
16
+ @singleton()
17
+ export class InitializeProvider {
18
+ provider: Contribution.Provider<InitializeContribution>;
19
+ constructor(
20
+ @contrib(InitializeContribution)
21
+ provider: Contribution.Provider<InitializeContribution>,
22
+ ) {
23
+ this.provider = provider;
24
+ }
25
+
26
+ async initialize(coreMonaco: typeof monaco): Promise<void> {
27
+ const contributions = this.provider.getContributions({ cache: false });
28
+ for (const contribution of contributions) {
29
+ if (contribution.onInitialize) {
30
+ try {
31
+ if (!contribution.initialized) {
32
+ const inited = contribution.onInitialize(coreMonaco);
33
+ if (inited) {
34
+ // eslint-disable-next-line no-await-in-loop
35
+ await inited;
36
+ }
37
+ if (!contribution.awaysInitialized) {
38
+ contribution.initialized = true;
39
+ }
40
+ }
41
+ } catch (error) {
42
+ // noop
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ export class InitializeContributionProvider extends DefaultContributionProvider<InitializeContribution> {
50
+ override getContributions() {
51
+ this.services = undefined;
52
+ return super.getContributions();
53
+ }
54
+ }
@@ -0,0 +1,8 @@
1
+ import type { Container } from '@difizen/mana-app';
2
+
3
+ import { MonacoEnvironment } from './monaco-environment.js';
4
+
5
+ export default async (container: Container): Promise<void> => {
6
+ MonacoEnvironment.setContainer(container);
7
+ await MonacoEnvironment.init();
8
+ };
@@ -0,0 +1,4 @@
1
+ import * as monaco from '@difizen/monaco-editor-core';
2
+
3
+ export default monaco;
4
+ export const { Emitter, MarkerSeverity, Range, Uri, editor, languages } = monaco || {};
@@ -0,0 +1,115 @@
1
+ import {
2
+ LanguageWorkerRegistry,
3
+ LazyLoaderRegistry,
4
+ } from '@difizen/libro-cofine-editor-contribution';
5
+ import type { Syringe } from '@difizen/mana-app';
6
+ import { Deferred } from '@difizen/mana-app';
7
+ import { GlobalContainer } from '@difizen/mana-app';
8
+ import * as monaco from '@difizen/monaco-editor-core';
9
+
10
+ import { InitializeProvider } from './initialize-provider.js';
11
+ import {
12
+ DefaultLoaderConfig,
13
+ MonacoLoader,
14
+ MonacoLoaderConfig,
15
+ } from './monaco-loader.js';
16
+ import BaseModule from './monaco-module.js';
17
+
18
+ export const MonacoEnvironmentBound = 'MonacoEnvironmentBound';
19
+
20
+ export type ModuleLoader = (container: Syringe.Container) => void;
21
+ type InitType = {
22
+ lazy: boolean;
23
+ cdnUrl?: string;
24
+ };
25
+ export class MonacoEnvironment {
26
+ static container: Syringe.Container;
27
+ static loaders: ModuleLoader[] = [];
28
+ static preLoaders: ModuleLoader[] = [];
29
+ static monaco: typeof monaco;
30
+ protected static loader?: MonacoLoader;
31
+ protected static moduleLoadStart = false;
32
+ protected static moduleInitDeferred: Deferred<void> = new Deferred<void>();
33
+ protected static baseModule?: Syringe.Module;
34
+ static lazy = false;
35
+
36
+ static setContainer = (container: Syringe.Container) => {
37
+ MonacoEnvironment.container = container;
38
+ if (!container.isBound(MonacoEnvironmentBound)) {
39
+ container.register(MonacoEnvironmentBound, { useValue: true });
40
+ MonacoEnvironment.container.register(MonacoLoaderConfig, {
41
+ useValue: DefaultLoaderConfig,
42
+ });
43
+ container.register(MonacoLoader);
44
+ }
45
+ };
46
+ static async load(cdnUrl?: string) {
47
+ if (!MonacoEnvironment.container) {
48
+ MonacoEnvironment.setContainer(GlobalContainer);
49
+ }
50
+ if (!MonacoEnvironment.loader) {
51
+ MonacoEnvironment.loader = MonacoEnvironment.container.get(MonacoLoader);
52
+ }
53
+ await MonacoEnvironment.loader.load(cdnUrl);
54
+ }
55
+ static async init(
56
+ { lazy, cdnUrl }: InitType | undefined = { lazy: false, cdnUrl: '' },
57
+ ): Promise<void> {
58
+ if (!MonacoEnvironment.monaco) {
59
+ await MonacoEnvironment.load(cdnUrl!);
60
+ }
61
+ window.MonacoEnvironment = {
62
+ getWorkerUrl: (moduleId: string, label: string) => {
63
+ const workerRegistry = MonacoEnvironment.container.get(LanguageWorkerRegistry);
64
+ return workerRegistry.getLanguageWorker(label, moduleId);
65
+ },
66
+ };
67
+ try {
68
+ if (!MonacoEnvironment.baseModule) {
69
+ MonacoEnvironment.baseModule = BaseModule;
70
+ MonacoEnvironment.container.load(MonacoEnvironment.baseModule);
71
+ }
72
+ MonacoEnvironment.lazy = lazy;
73
+ if (!lazy) {
74
+ await MonacoEnvironment.initModule();
75
+ } else {
76
+ for (const loader of MonacoEnvironment.preLoaders) {
77
+ await loader(MonacoEnvironment.container);
78
+ }
79
+ const initialize = MonacoEnvironment.container.get(InitializeProvider);
80
+ await initialize.initialize(monaco);
81
+ }
82
+ } catch (ex) {
83
+ console.error(ex);
84
+ }
85
+ }
86
+
87
+ static async initModule() {
88
+ if (!MonacoEnvironment.loaders.length) {
89
+ return;
90
+ }
91
+ for (const loader of MonacoEnvironment.loaders) {
92
+ await loader(MonacoEnvironment.container);
93
+ }
94
+ MonacoEnvironment.loaders = [];
95
+ try {
96
+ const initialize = MonacoEnvironment.container.get(InitializeProvider);
97
+ await initialize.initialize(monaco);
98
+ if (MonacoEnvironment.lazy) {
99
+ const layzInit = MonacoEnvironment.container.get(LazyLoaderRegistry);
100
+ await layzInit.handleLazyLoder();
101
+ }
102
+ } catch (e) {
103
+ console.error(e);
104
+ }
105
+ }
106
+
107
+ static async loadModule(loader: ModuleLoader) {
108
+ MonacoEnvironment.loaders.push(loader);
109
+ }
110
+
111
+ // 提前加载(懒加载模式下需要提前加载的模块)
112
+ static async preLoadModule(loader: ModuleLoader) {
113
+ MonacoEnvironment.preLoaders.push(loader);
114
+ }
115
+ }
@@ -0,0 +1,100 @@
1
+ import { inject, singleton } from '@difizen/mana-app';
2
+ import * as monaco from '@difizen/monaco-editor-core';
3
+
4
+ export const MonacoLoaderConfig = Symbol('MonacoLoaderConfig');
5
+ export interface MonacoLoaderConfig {
6
+ requireConfig: {
7
+ paths: {
8
+ vs: string;
9
+ [key: string]: string;
10
+ };
11
+ };
12
+ }
13
+
14
+ export const DefaultLoaderConfig: MonacoLoaderConfig = {
15
+ requireConfig: {
16
+ paths: {
17
+ vs: 'https://unpkg.com/@difizen/monaco-editor-core@0.39.4/min/vs/',
18
+ },
19
+ },
20
+ };
21
+
22
+ @singleton()
23
+ export class MonacoLoader {
24
+ loaded = false;
25
+ protected start = false;
26
+ protected vsRequire: any;
27
+ protected readonly config;
28
+ constructor(@inject(MonacoLoaderConfig) config: MonacoLoaderConfig) {
29
+ this.config = config;
30
+ }
31
+ cdnUrl = '';
32
+
33
+ async load(cdnUrl?: string) {
34
+ if (cdnUrl) {
35
+ this.cdnUrl = cdnUrl;
36
+ }
37
+ if (!this.start) {
38
+ this.start = true;
39
+ await this.doLoad();
40
+ }
41
+ }
42
+ protected async doLoad(): Promise<void> {
43
+ if (!this.loaded) {
44
+ await this.initMonaco();
45
+ }
46
+ }
47
+ // 初始化,将monaco挂在到window上
48
+ initMonaco() {
49
+ return new Promise((resolve, reject) => {
50
+ if (this.cdnUrl) {
51
+ const beforeExist = document.getElementById('e2-monaco-id');
52
+ if (beforeExist) {
53
+ if (window._Monaco) {
54
+ const global: any = window;
55
+ global.monaco = window._Monaco;
56
+ this.loaded = true;
57
+ resolve(true);
58
+ return;
59
+ }
60
+ beforeExist.onload = () => {
61
+ const global: any = window;
62
+ global.monaco = window._Monaco;
63
+ this.loaded = true;
64
+ resolve(true);
65
+ };
66
+ return;
67
+ }
68
+ const script = document.createElement('script');
69
+ script.id = 'e2-monaco-id';
70
+ script.src = this.cdnUrl;
71
+ // script.src =
72
+ document.head.appendChild(script);
73
+ script.onload = () => {
74
+ const global: any = window;
75
+ global.monaco = window._Monaco;
76
+ this.loaded = true;
77
+ resolve(true);
78
+ };
79
+ script.onerror = () => {
80
+ document.head.removeChild(script);
81
+ // 如果第一次失败的话,就再次加载monaco
82
+ const script2 = document.createElement('script');
83
+ script2.src = this.cdnUrl;
84
+ document.head.appendChild(script2);
85
+ script2.onload = () => {
86
+ const global: any = window;
87
+ global.monaco = window._Monaco;
88
+ this.loaded = true;
89
+ resolve(true);
90
+ };
91
+ };
92
+ } else {
93
+ const global: any = window;
94
+ global.monaco = monaco;
95
+ this.loaded = true;
96
+ resolve(true);
97
+ }
98
+ });
99
+ }
100
+ }
@@ -0,0 +1,101 @@
1
+ import {
2
+ EditorHandlerContribution,
3
+ EditorOptionsRegistry,
4
+ LanguageOptionsRegistry,
5
+ LanguageWorkerContribution,
6
+ LanguageWorkerRegistry,
7
+ LazyLoaderRegistry,
8
+ LazyLoaderRegistryContribution,
9
+ } from '@difizen/libro-cofine-editor-contribution';
10
+ import { Contribution, Module, Syringe } from '@difizen/mana-app';
11
+
12
+ import 'reflect-metadata';
13
+ import { DefaultWorkerContribution } from './default-worker-contribution.js';
14
+ import {
15
+ E2Editor,
16
+ EditorNode,
17
+ IsDiff,
18
+ LazyCallback,
19
+ MonacoOptions,
20
+ } from './e2-editor.js';
21
+ import { EditorHanlerRegistry } from './editor-handler-registry.js';
22
+ import type { Options } from './editor-provider.js';
23
+ import { EditorProvider } from './editor-provider.js';
24
+ import {
25
+ InitializeContribution,
26
+ InitializeContributionProvider,
27
+ InitializeProvider,
28
+ } from './initialize-provider.js';
29
+ import {
30
+ SnippetSuggestContribution,
31
+ SnippetSuggestRegistry,
32
+ } from './snippets-suggest-registry.js';
33
+ import {
34
+ MixedThemeRegistry,
35
+ ThemeContribution,
36
+ ThemeRegistry,
37
+ } from './theme-registry.js';
38
+
39
+ export const MonacoModule = Module()
40
+ .register(
41
+ {
42
+ token: { token: Contribution.Provider, named: InitializeContribution },
43
+ useDynamic: (ctx) =>
44
+ new InitializeContributionProvider(InitializeContribution, ctx.container),
45
+ lifecycle: Syringe.Lifecycle.singleton,
46
+ },
47
+ InitializeProvider,
48
+ LanguageWorkerRegistry,
49
+ LanguageOptionsRegistry,
50
+ EditorOptionsRegistry,
51
+ DefaultWorkerContribution,
52
+ SnippetSuggestRegistry,
53
+ LazyLoaderRegistry,
54
+ {
55
+ token: MixedThemeRegistry,
56
+ useValue: {},
57
+ },
58
+ ThemeRegistry,
59
+ {
60
+ token: EditorProvider,
61
+ lifecycle: Syringe.Lifecycle.singleton,
62
+ useDynamic: (ctx) => {
63
+ return {
64
+ create: (node: HTMLElement, options: Options, lazyCallback?: () => void) => {
65
+ const child = ctx.container.createChild();
66
+ child.register(EditorNode, { useValue: node });
67
+ child.register(MonacoOptions, { useValue: options });
68
+ child.register(LazyCallback, { useValue: lazyCallback });
69
+ child.register({ token: IsDiff, useValue: false });
70
+ child.register(EditorHanlerRegistry);
71
+ child.register(E2Editor);
72
+ return child.get(E2Editor);
73
+ },
74
+ createDiff: (
75
+ node: HTMLElement,
76
+ options: Options,
77
+ lazyCallback?: () => void,
78
+ ) => {
79
+ const child = ctx.container.createChild();
80
+ child.register(EditorNode, { useValue: node });
81
+ child.register(MonacoOptions, { useValue: options });
82
+ child.register(LazyCallback, { useValue: lazyCallback });
83
+ child.register({ token: IsDiff, useValue: true });
84
+ child.register(EditorHanlerRegistry);
85
+ child.register(E2Editor);
86
+ return child.get(E2Editor);
87
+ },
88
+ };
89
+ },
90
+ },
91
+ )
92
+ // 语言 worker 扩展点
93
+ .contribution(
94
+ LanguageWorkerContribution,
95
+ EditorHandlerContribution,
96
+ ThemeContribution,
97
+ SnippetSuggestContribution,
98
+ LazyLoaderRegistryContribution,
99
+ );
100
+
101
+ export default MonacoModule;
@@ -0,0 +1,101 @@
1
+ import type { Contribution } from '@difizen/mana-app';
2
+ import { contrib, singleton, Syringe } from '@difizen/mana-app';
3
+ import * as monaco from '@difizen/monaco-editor-core';
4
+
5
+ import { InitializeContribution } from './initialize-provider.js';
6
+
7
+ export interface SnippetLoadOptions {
8
+ language?: string | string[];
9
+ source: string;
10
+ }
11
+
12
+ export type JsonSerializedSnippets = Record<string, JsonSerializedSnippet>;
13
+ export interface JsonSerializedSnippet {
14
+ body: string[];
15
+ scope: string;
16
+ prefix: string;
17
+ description: string;
18
+ }
19
+
20
+ export interface SnippetSuggestContribution {
21
+ registerSnippetSuggest: (registry: SnippetSuggestRegistry) => void;
22
+ _initRegisterSnippetSuggest?: boolean;
23
+ }
24
+
25
+ export const SnippetSuggestContribution = Syringe.defineToken(
26
+ 'SnippetSuggestContribution',
27
+ );
28
+
29
+ @singleton({ contrib: InitializeContribution })
30
+ export class SnippetSuggestRegistry implements InitializeContribution {
31
+ registerCompletion = false;
32
+ awaysInitialized = true;
33
+ onInitialize() {
34
+ this.snippetsSuggestContrbutions
35
+ .getContributions({ cache: false })
36
+ .forEach((contribution) => {
37
+ if (contribution._initRegisterSnippetSuggest) {
38
+ return;
39
+ }
40
+ contribution.registerSnippetSuggest(this);
41
+ contribution._initRegisterSnippetSuggest = true;
42
+ });
43
+ }
44
+ protected languageSnippets: Record<string, JsonSerializedSnippet[]> = {};
45
+
46
+ snippetsSuggestContrbutions: Contribution.Provider<SnippetSuggestContribution>;
47
+ constructor(
48
+ @contrib(SnippetSuggestContribution)
49
+ snippetsSuggestContrbutions: Contribution.Provider<SnippetSuggestContribution>,
50
+ ) {
51
+ this.snippetsSuggestContrbutions = snippetsSuggestContrbutions;
52
+ }
53
+
54
+ async provideCompletionItems(
55
+ model: monaco.editor.ITextModel,
56
+ ): Promise<monaco.languages.CompletionList | undefined> {
57
+ const _language = model.getLanguageId();
58
+ const _snippets: JsonSerializedSnippet[] = this.languageSnippets[_language] || [];
59
+ const suggestions = _snippets.map((it) => {
60
+ return {
61
+ label: it.prefix,
62
+ insertText: it.body.join('\n'),
63
+ documentation: it.description,
64
+ detail: 'snippet',
65
+ insertTextRules: 4,
66
+ kind: 27,
67
+ range: undefined as unknown as monaco.IRange,
68
+ };
69
+ });
70
+ return { suggestions };
71
+ }
72
+
73
+ fromJSON(
74
+ snippets: JsonSerializedSnippets | undefined,
75
+ { language }: SnippetLoadOptions,
76
+ ) {
77
+ if (!language || !language?.length || !snippets) {
78
+ return;
79
+ }
80
+ const _languages = typeof language === 'string' ? [language] : language;
81
+ _languages.forEach((it) => {
82
+ if (!this.languageSnippets[it]) {
83
+ this.languageSnippets[it] = [];
84
+ }
85
+ this.languageSnippets[it].push(
86
+ ...(Object.values(snippets) as JsonSerializedSnippet[]),
87
+ );
88
+ });
89
+ // 采集数据
90
+ if (this.registerCompletion) {
91
+ return;
92
+ }
93
+ this.registerCompletion = true;
94
+ monaco.languages.registerCompletionItemProvider(
95
+ { pattern: '**' },
96
+ {
97
+ provideCompletionItems: this.provideCompletionItems.bind(this),
98
+ },
99
+ );
100
+ }
101
+ }