diff options
Diffstat (limited to 'language-web/src/main/js/editor/EditorStore.ts')
-rw-r--r-- | language-web/src/main/js/editor/EditorStore.ts | 75 |
1 files changed, 62 insertions, 13 deletions
diff --git a/language-web/src/main/js/editor/EditorStore.ts b/language-web/src/main/js/editor/EditorStore.ts index 5da45ac1..1ac2e79f 100644 --- a/language-web/src/main/js/editor/EditorStore.ts +++ b/language-web/src/main/js/editor/EditorStore.ts | |||
@@ -1,19 +1,14 @@ | |||
1 | import { Editor, EditorConfiguration } from 'codemirror'; | 1 | import type { Editor, EditorConfiguration } from 'codemirror'; |
2 | import 'codemirror/addon/selection/active-line'; | ||
3 | import { | 2 | import { |
4 | createAtom, | 3 | createAtom, |
5 | makeAutoObservable, | 4 | makeAutoObservable, |
6 | observable, | 5 | observable, |
6 | runInAction, | ||
7 | } from 'mobx'; | 7 | } from 'mobx'; |
8 | import 'mode-problem'; | 8 | import type { IXtextOptions, IXtextServices } from 'xtext/xtext-codemirror'; |
9 | import { | ||
10 | IXtextOptions, | ||
11 | IXtextServices, | ||
12 | createServices, | ||
13 | removeServices, | ||
14 | } from 'xtext/xtext-codemirror'; | ||
15 | 9 | ||
16 | import { ThemeStore } from '../theme/ThemeStore'; | 10 | import type { IEditorChunk } from './editor'; |
11 | import type { ThemeStore } from '../theme/ThemeStore'; | ||
17 | 12 | ||
18 | const xtextLang = 'problem'; | 13 | const xtextLang = 'problem'; |
19 | 14 | ||
@@ -33,6 +28,8 @@ export class EditorStore { | |||
33 | 28 | ||
34 | atom; | 29 | atom; |
35 | 30 | ||
31 | chunk?: IEditorChunk; | ||
32 | |||
36 | editor?: Editor; | 33 | editor?: Editor; |
37 | 34 | ||
38 | xtextServices?: IXtextServices; | 35 | xtextServices?: IXtextServices; |
@@ -41,15 +38,56 @@ export class EditorStore { | |||
41 | 38 | ||
42 | showLineNumbers = false; | 39 | showLineNumbers = false; |
43 | 40 | ||
41 | initialSelection!: { start: number, end: number, focused: boolean }; | ||
42 | |||
44 | constructor(themeStore: ThemeStore) { | 43 | constructor(themeStore: ThemeStore) { |
45 | this.themeStore = themeStore; | 44 | this.themeStore = themeStore; |
46 | this.atom = createAtom('EditorStore'); | 45 | this.atom = createAtom('EditorStore'); |
46 | this.resetInitialSelection(); | ||
47 | makeAutoObservable(this, { | 47 | makeAutoObservable(this, { |
48 | themeStore: false, | 48 | themeStore: false, |
49 | atom: false, | 49 | atom: false, |
50 | chunk: observable.ref, | ||
50 | editor: observable.ref, | 51 | editor: observable.ref, |
51 | xtextServices: observable.ref, | 52 | xtextServices: observable.ref, |
53 | initialSelection: false, | ||
52 | }); | 54 | }); |
55 | import('./editor').then(({ editorChunk }) => { | ||
56 | runInAction(() => { | ||
57 | this.chunk = editorChunk; | ||
58 | }); | ||
59 | }).catch((error) => { | ||
60 | console.warn('Error while loading editor', error); | ||
61 | }); | ||
62 | } | ||
63 | |||
64 | setInitialSelection(start: number, end: number, focused: boolean): void { | ||
65 | this.initialSelection = { start, end, focused }; | ||
66 | this.applyInitialSelectionToEditor(); | ||
67 | } | ||
68 | |||
69 | private resetInitialSelection(): void { | ||
70 | this.initialSelection = { | ||
71 | start: 0, | ||
72 | end: 0, | ||
73 | focused: false, | ||
74 | }; | ||
75 | } | ||
76 | |||
77 | private applyInitialSelectionToEditor(): void { | ||
78 | if (this.editor) { | ||
79 | const { start, end, focused } = this.initialSelection; | ||
80 | const doc = this.editor.getDoc(); | ||
81 | const startPos = doc.posFromIndex(start); | ||
82 | const endPos = doc.posFromIndex(end); | ||
83 | doc.setSelection(startPos, endPos, { | ||
84 | scroll: true, | ||
85 | }); | ||
86 | if (focused) { | ||
87 | this.editor.focus(); | ||
88 | } | ||
89 | this.resetInitialSelection(); | ||
90 | } | ||
53 | } | 91 | } |
54 | 92 | ||
55 | /** | 93 | /** |
@@ -61,16 +99,23 @@ export class EditorStore { | |||
61 | * @param newEditor The new CodeMirror instance | 99 | * @param newEditor The new CodeMirror instance |
62 | */ | 100 | */ |
63 | editorDidMount(newEditor: Editor): void { | 101 | editorDidMount(newEditor: Editor): void { |
102 | if (!this.chunk) { | ||
103 | throw new Error('Editor not loaded yet'); | ||
104 | } | ||
64 | if (this.editor) { | 105 | if (this.editor) { |
65 | throw new Error('CoreMirror editor mounted before unmounting'); | 106 | throw new Error('CoreMirror editor mounted before unmounting'); |
66 | } | 107 | } |
67 | this.editor = newEditor; | 108 | this.editor = newEditor; |
68 | this.xtextServices = createServices(newEditor, xtextOptions); | 109 | this.xtextServices = this.chunk.createServices(newEditor, xtextOptions); |
110 | this.applyInitialSelectionToEditor(); | ||
69 | } | 111 | } |
70 | 112 | ||
71 | editorWillUnmount(): void { | 113 | editorWillUnmount(): void { |
114 | if (!this.chunk) { | ||
115 | throw new Error('Editor not loaded yet'); | ||
116 | } | ||
72 | if (this.editor) { | 117 | if (this.editor) { |
73 | removeServices(this.editor); | 118 | this.chunk.removeServices(this.editor); |
74 | } | 119 | } |
75 | delete this.editor; | 120 | delete this.editor; |
76 | delete this.xtextServices; | 121 | delete this.xtextServices; |
@@ -93,10 +138,14 @@ export class EditorStore { | |||
93 | this.atom.reportObserved(); | 138 | this.atom.reportObserved(); |
94 | } | 139 | } |
95 | 140 | ||
141 | get codeMirrorTheme(): string { | ||
142 | return `problem-${this.themeStore.className}`; | ||
143 | } | ||
144 | |||
96 | get codeMirrorOptions(): EditorConfiguration { | 145 | get codeMirrorOptions(): EditorConfiguration { |
97 | return { | 146 | return { |
98 | ...codeMirrorGlobalOptions, | 147 | ...codeMirrorGlobalOptions, |
99 | theme: this.themeStore.codeMirrorTheme, | 148 | theme: this.codeMirrorTheme, |
100 | lineNumbers: this.showLineNumbers, | 149 | lineNumbers: this.showLineNumbers, |
101 | }; | 150 | }; |
102 | } | 151 | } |