aboutsummaryrefslogtreecommitdiffstats
path: root/language-web
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-10-10 01:11:33 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-10-31 19:26:09 +0100
commit2ada4a06167b3a00a4c4c69e1b0c78b00ef1db5f (patch)
tree24f0b0bf8f8959ebcf0722456da2d6260c6f1421 /language-web
parentMerge pull request #7 from golej-marci/language-to-store (diff)
downloadrefinery-2ada4a06167b3a00a4c4c69e1b0c78b00ef1db5f.tar.gz
refinery-2ada4a06167b3a00a4c4c69e1b0c78b00ef1db5f.tar.zst
refinery-2ada4a06167b3a00a4c4c69e1b0c78b00ef1db5f.zip
feat(web): add CodeMirror 6 editor
Diffstat (limited to 'language-web')
-rw-r--r--language-web/package.json17
-rw-r--r--language-web/src/main/css/index.scss213
-rw-r--r--language-web/src/main/js/RootStore.tsx4
-rw-r--r--language-web/src/main/js/editor/EditorArea.tsx142
-rw-r--r--language-web/src/main/js/editor/EditorButtons.tsx35
-rw-r--r--language-web/src/main/js/editor/EditorParent.ts61
-rw-r--r--language-web/src/main/js/editor/EditorStore.ts294
-rw-r--r--language-web/src/main/js/editor/editor.ts18
-rw-r--r--language-web/src/main/js/index.tsx3
-rw-r--r--language-web/src/main/js/theme/ThemeStore.ts4
-rw-r--r--language-web/yarn.lock220
11 files changed, 588 insertions, 423 deletions
diff --git a/language-web/package.json b/language-web/package.json
index 7a931d95..d55968ee 100644
--- a/language-web/package.json
+++ b/language-web/package.json
@@ -62,20 +62,33 @@
62 "dependencies": { 62 "dependencies": {
63 "ansi-styles": "^6.1.0", 63 "ansi-styles": "^6.1.0",
64 "@babel/runtime": "^7.15.4", 64 "@babel/runtime": "^7.15.4",
65 "@codemirror/autocomplete": "^0.19.3",
66 "@codemirror/closebrackets": "^0.19.0",
67 "@codemirror/commands": "^0.19.5",
68 "@codemirror/comment": "^0.19.0",
69 "@codemirror/fold": "^0.19.0",
70 "@codemirror/gutter": "^0.19.2",
71 "@codemirror/highlight": "^0.19.6",
72 "@codemirror/history": "^0.19.0",
73 "@codemirror/language": "^0.19.3",
74 "@codemirror/lint": "^0.19.2",
75 "@codemirror/matchbrackets": "^0.19.3",
76 "@codemirror/rectangular-selection": "^0.19.1",
77 "@codemirror/search": "^0.19.2",
78 "@codemirror/state": "^0.19.0",
79 "@codemirror/view": "^0.19.9",
65 "@emotion/react": "^11.4.1", 80 "@emotion/react": "^11.4.1",
66 "@emotion/styled": "^11.3.0", 81 "@emotion/styled": "^11.3.0",
67 "@fontsource/jetbrains-mono": "^4.5.0", 82 "@fontsource/jetbrains-mono": "^4.5.0",
68 "@fontsource/roboto": "^4.5.0", 83 "@fontsource/roboto": "^4.5.0",
69 "@mui/material": "5.0.2", 84 "@mui/material": "5.0.2",
70 "@mui/icons-material": "5.0.1", 85 "@mui/icons-material": "5.0.1",
71 "codemirror": "^5.63.1",
72 "jquery": "^3.6.0", 86 "jquery": "^3.6.0",
73 "loglevel": "^1.7.1", 87 "loglevel": "^1.7.1",
74 "loglevel-plugin-prefix": "^0.8.4", 88 "loglevel-plugin-prefix": "^0.8.4",
75 "mobx": "^6.3.3", 89 "mobx": "^6.3.3",
76 "mobx-react-lite": "^3.2.1", 90 "mobx-react-lite": "^3.2.1",
77 "react": "^17.0.2", 91 "react": "^17.0.2",
78 "react-codemirror2": "npm:react17-codemirror2@^7.2.3",
79 "react-dom": "^17.0.2" 92 "react-dom": "^17.0.2"
80 } 93 }
81} 94}
diff --git a/language-web/src/main/css/index.scss b/language-web/src/main/css/index.scss
index 54f3a654..ad876aaf 100644
--- a/language-web/src/main/css/index.scss
+++ b/language-web/src/main/css/index.scss
@@ -1,13 +1,6 @@
1@use 'sass:map';
2@use '@fontsource/roboto/scss/mixins' as Roboto; 1@use '@fontsource/roboto/scss/mixins' as Roboto;
3@use '@fontsource/jetbrains-mono/scss/mixins' as JetbrainsMono; 2@use '@fontsource/jetbrains-mono/scss/mixins' as JetbrainsMono;
4 3
5@import 'codemirror/lib/codemirror';
6@import 'codemirror/addon/hint/show-hint';
7@import 'codemirror/theme/material-darker';
8
9@import './themes';
10
11$fontWeights: 300, 400, 500, 700; 4$fontWeights: 300, 400, 500, 700;
12@each $weight in $fontWeights { 5@each $weight in $fontWeights {
13 @include Roboto.fontFace($fontName: 'Roboto', $weight: $weight); 6 @include Roboto.fontFace($fontName: 'Roboto', $weight: $weight);
@@ -21,209 +14,3 @@ $monoFontWeights: 400, 700;
21} 14}
22@include JetbrainsMono.fontFaceVariable($fontName: 'JetBrains MonoVariable'); 15@include JetbrainsMono.fontFaceVariable($fontName: 'JetBrains MonoVariable');
23@include JetbrainsMono.fontFaceVariable($fontName: 'JetBrains MonoVariable', $style: italic); 16@include JetbrainsMono.fontFaceVariable($fontName: 'JetBrains MonoVariable', $style: italic);
24
25body {
26 font-family: 'Roboto', sans-serif;
27}
28
29.CodeMirror {
30 height: 100%;
31}
32
33.problem-fallback-editor {
34 display: block;
35 height: 100%;
36 width: 100%;
37 resize: none;
38 border: none;
39 outline: none;
40 padding: 4px 4px 4px 16px;
41 white-space: pre;
42 overflow-wrap: normal;
43 overflow: auto;
44}
45
46.CodeMirror, .CodeMirror-hints, .problem-fallback-editor {
47 font-size: 16px;
48 font-family: 'JetBrains MonoVariable', 'JetBrains Mono', monospace;
49 font-feature-settings: 'liga', 'calt';
50 font-weight: 400;
51 text-rendering: optimizeLegibility;
52 line-height: 1.35;
53 letter-spacing: 0;
54}
55
56@each $themeName, $theme in $themes {
57 .cm-s-problem-#{$themeName} {
58 &.CodeMirror {
59 background: map.get($theme, 'background');
60 color: map.get($theme, 'foreground');
61 }
62
63 &.problem-fallback-editor {
64 background: map.get($theme, 'background');
65 color: map.get($theme, 'foreground');
66 caret-color: map.get($theme, 'cursor');
67
68 &::selection {
69 background: map.get($theme, 'selection');
70 }
71 }
72
73 .CodeMirror-gutters {
74 background: map.get($theme, 'background');
75 border: none;
76 }
77
78 .CodeMirror-cursor {
79 border-left: 1px solid map.get($theme, 'cursor');
80 }
81
82 div.CodeMirror-selected,
83 &.CodeMirror-focused div.CodeMirror-selected,
84 .CodeMirror-line::selection,
85 .CodeMirror-line > span::selection,
86 .CodeMirror-line > span > span::selection {
87 background: map.get($theme, 'selection');
88 }
89
90 .CodeMirror-guttermarker,
91 .CodeMirror-guttermarker-subtle,
92 .CodeMirror-linenumber {
93 color: map.get($theme, 'lineNumber');
94 }
95
96 .CodeMirror-activeline-background {
97 background: map.get($theme, 'currentLine');
98 }
99
100 .CodeMirror-activeline-gutter {
101 background: map.get($theme, 'currentLine');
102
103 .CodeMirror-guttermarker,
104 .CodeMirror-guttermarker-subtle,
105 .CodeMirror-linenumber {
106 color: map.get($theme, 'foreground');
107 }
108 }
109
110 .cm-keyword {
111 color: map.get($theme, 'keyword');
112 }
113
114 .cm-number {
115 color: map.get($theme, 'number');
116 }
117
118 .cm-lparen, .cm-rparen {
119 color: map.get($theme, 'delimiter');
120 }
121
122 .cm-comment {
123 color: map.get($theme, 'comment');
124 font-style: italic;
125 }
126
127 .problem-predicate, .problem-class, .problem-reference, .problem-enum {
128 color: map.get($theme, 'predicate');
129 }
130
131 .problem-unique-node {
132 color: map.get($theme, 'uniqueNode');
133 }
134
135 .problem-variable {
136 color: map.get($theme, 'variable');
137 }
138 }
139}
140
141.CodeMirror-hints {
142 background: #333;
143 border: 0;
144 border-radius: 4px;
145 box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2),
146 0 5px 8px 0 rgba(0, 0, 0, 0.14),
147 0 1px 8px 0 rgba(0, 0, 0, 0.12);
148 padding: 0;
149}
150
151.CodeMirror-hint {
152 color: #fff;
153 border-radius: 0;
154}
155
156li.CodeMirror-hint-active {
157 background: rgba(128, 203, 196, 0.2);
158}
159
160.annotations-gutter {
161 width: 12px;
162}
163
164.xtext-annotation_error {
165 width: 12px;
166 height: 1em;
167 background-image: url('images/error_an.gif');
168 background-repeat: no-repeat;
169 background-position: bottom;
170}
171
172.xtext-annotation_warning {
173 width: 12px;
174 height: 1em;
175 background-image: url('images/warning_an.gif');
176 background-repeat: no-repeat;
177 background-position: bottom;
178}
179
180.xtext-annotation_info {
181 width: 12px;
182 height: 1em;
183 background-image: url('images/info_an.gif');
184 background-repeat: no-repeat;
185 background-position: bottom;
186}
187
188.xtext-marker_error {
189 z-index: 30;
190 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAABmJLR0QA/wD/AP+gvaeTAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==");
191 background-repeat: repeat-x;
192 background-position: left bottom;
193}
194
195.xtext-marker_warning {
196 z-index: 20;
197 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAABmJLR0QA/wD/AP+gvaeTAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII=");
198 background-repeat: repeat-x;
199 background-position: left bottom;
200}
201
202.xtext-marker_info {
203 z-index: 10;
204 background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAABmJLR0QA/wD/AP+gvaeTAAAANklEQVQI12NkgIIVRx8tZGBg6GZccfRRKAMDgw8DA0M3AwPDIiYGBoZKBgaG7ghruSsMDAwpABH5CoqwzCoTAAAAAElFTkSuQmCC");
205 background-repeat: repeat-x;
206 background-position: left bottom;
207}
208
209.xtext-marker_read {
210 background: rgba(128, 203, 196, 0.2);
211 display: inline-block;
212}
213
214
215.xtext-marker_write {
216 background: rgba(255, 229, 100, 0.2);
217 display: inline-block;
218}
219
220.problem-abstract {
221 font-style: italic;
222}
223
224.problem-containment {
225 font-weight: 700;
226}
227.problem-new-node {
228 font-style: italic;
229}
diff --git a/language-web/src/main/js/RootStore.tsx b/language-web/src/main/js/RootStore.tsx
index 88b8a445..96e1b26a 100644
--- a/language-web/src/main/js/RootStore.tsx
+++ b/language-web/src/main/js/RootStore.tsx
@@ -8,9 +8,9 @@ export class RootStore {
8 8
9 themeStore; 9 themeStore;
10 10
11 constructor() { 11 constructor(initialValue: string) {
12 this.themeStore = new ThemeStore(); 12 this.themeStore = new ThemeStore();
13 this.editorStore = new EditorStore(this.themeStore); 13 this.editorStore = new EditorStore(initialValue, this.themeStore);
14 } 14 }
15} 15}
16 16
diff --git a/language-web/src/main/js/editor/EditorArea.tsx b/language-web/src/main/js/editor/EditorArea.tsx
index 531a57c9..58d65184 100644
--- a/language-web/src/main/js/editor/EditorArea.tsx
+++ b/language-web/src/main/js/editor/EditorArea.tsx
@@ -1,41 +1,123 @@
1import { Command, EditorView } from '@codemirror/view';
2import { closeSearchPanel, openSearchPanel } from '@codemirror/search';
3import { closeLintPanel, openLintPanel } from '@codemirror/lint';
1import { observer } from 'mobx-react-lite'; 4import { observer } from 'mobx-react-lite';
2import React, { useRef } from 'react'; 5import React, { useEffect, useRef, useState } from 'react';
3 6
7import { EditorParent } from './EditorParent';
8import { getLogger } from '../logging';
4import { useRootStore } from '../RootStore'; 9import { useRootStore } from '../RootStore';
5 10
11const log = getLogger('EditorArea');
12
13function usePanel(
14 label: string,
15 stateToSet: boolean,
16 editorView: EditorView | null,
17 openCommand: Command,
18 closeCommand: Command,
19) {
20 const [cachedViewState, setCachedViewState] = useState<boolean>(false);
21 useEffect(() => {
22 if (editorView === null || cachedViewState === stateToSet) {
23 return;
24 }
25 const success = stateToSet ? openCommand(editorView) : closeCommand(editorView);
26 if (!success) {
27 log.error(
28 'Failed to synchronize',
29 label,
30 'panel state - store state:',
31 cachedViewState,
32 'view state:',
33 stateToSet,
34 );
35 }
36 setCachedViewState(stateToSet);
37 }, [
38 stateToSet,
39 editorView,
40 cachedViewState,
41 label,
42 openCommand,
43 closeCommand,
44 ]);
45 return setCachedViewState;
46}
47
6export const EditorArea = observer(() => { 48export const EditorArea = observer(() => {
7 const { editorStore } = useRootStore(); 49 const { editorStore } = useRootStore();
8 const { CodeMirror } = editorStore.chunk || {}; 50 const editorParentRef = useRef<HTMLDivElement | null>(null);
9 const fallbackTextarea = useRef<HTMLTextAreaElement>(null); 51 const [editorViewState, setEditorViewState] = useState<EditorView | null>(null);
10 52
11 if (!CodeMirror) { 53 const setSearchPanelOpen = usePanel(
12 return ( 54 'search',
13 <textarea 55 editorStore.showSearchPanel,
14 value={editorStore.value} 56 editorViewState,
15 onChange={(e) => editorStore.updateValue(e.target.value)} 57 openSearchPanel,
16 ref={fallbackTextarea} 58 closeSearchPanel,
17 className={`problem-fallback-editor cm-s-${editorStore.codeMirrorTheme}`} 59 );
18 /> 60
19 ); 61 const setLintPanelOpen = usePanel(
20 } 62 'lint',
21 63 editorStore.showLintPanel,
22 const textarea = fallbackTextarea.current; 64 editorViewState,
23 if (textarea) { 65 openLintPanel,
24 editorStore.setInitialSelection( 66 closeLintPanel,
25 textarea.selectionStart, 67 );
26 textarea.selectionEnd, 68
27 document.activeElement === textarea, 69 useEffect(() => {
28 ); 70 if (editorParentRef.current === null) {
29 } 71 // Nothing to clean up.
72 return () => {};
73 }
74
75 const editorView = new EditorView({
76 state: editorStore.state,
77 parent: editorParentRef.current,
78 dispatch: (transaction) => {
79 editorStore.onTransaction(transaction);
80 editorView.update([transaction]);
81 if (editorView.state !== editorStore.state) {
82 log.error(
83 'Failed to synchronize editor state - store state:',
84 editorStore.state,
85 'view state:',
86 editorView.state,
87 );
88 }
89 },
90 });
91 setEditorViewState(editorView);
92 setSearchPanelOpen(false);
93 setLintPanelOpen(false);
94 // `dispatch` is bound to the view instance,
95 // so it does not have to be called as a method.
96 // eslint-disable-next-line @typescript-eslint/unbound-method
97 editorStore.updateDispatcher(editorView.dispatch);
98 log.info('Editor created');
99
100 return () => {
101 editorStore.updateDispatcher(null);
102 editorView.destroy();
103 log.info('Editor destroyed');
104 };
105 }, [
106 editorParentRef,
107 editorStore,
108 setSearchPanelOpen,
109 setLintPanelOpen,
110 ]);
30 111
31 return ( 112 return (
32 <CodeMirror 113 <EditorParent
33 value={editorStore.value} 114 className="dark"
34 options={editorStore.codeMirrorOptions} 115 sx={{
35 editorDidMount={(editor) => editorStore.editorDidMount(editor)} 116 '.cm-lineNumbers': editorStore.showLineNumbers ? {} : {
36 editorWillUnmount={() => editorStore.editorWillUnmount()} 117 display: 'none !important',
37 onBeforeChange={(_editor, _data, value) => editorStore.updateValue(value)} 118 },
38 onChange={() => editorStore.reportChanged()} 119 }}
120 ref={editorParentRef}
39 /> 121 />
40 ); 122 );
41}); 123});
diff --git a/language-web/src/main/js/editor/EditorButtons.tsx b/language-web/src/main/js/editor/EditorButtons.tsx
index 56577e82..9622475c 100644
--- a/language-web/src/main/js/editor/EditorButtons.tsx
+++ b/language-web/src/main/js/editor/EditorButtons.tsx
@@ -2,8 +2,10 @@ import { observer } from 'mobx-react-lite';
2import Stack from '@mui/material/Stack'; 2import Stack from '@mui/material/Stack';
3import ToggleButton from '@mui/material/ToggleButton'; 3import ToggleButton from '@mui/material/ToggleButton';
4import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; 4import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
5import CheckIcon from '@mui/icons-material/Check';
5import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered'; 6import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';
6import RedoIcon from '@mui/icons-material/Redo'; 7import RedoIcon from '@mui/icons-material/Redo';
8import SearchIcon from '@mui/icons-material/Search';
7import UndoIcon from '@mui/icons-material/Undo'; 9import UndoIcon from '@mui/icons-material/Undo';
8import React from 'react'; 10import React from 'react';
9 11
@@ -37,15 +39,34 @@ export const EditorButtons = observer(() => {
37 <RedoIcon fontSize="small" /> 39 <RedoIcon fontSize="small" />
38 </ToggleButton> 40 </ToggleButton>
39 </ToggleButtonGroup> 41 </ToggleButtonGroup>
40 <ToggleButton 42 <ToggleButtonGroup
41 selected={editorStore.showLineNumbers}
42 onChange={() => editorStore.toggleLineNumbers()}
43 size="small" 43 size="small"
44 aria-label="Show line numbers"
45 value="show-line-numbers"
46 > 44 >
47 <FormatListNumberedIcon fontSize="small" /> 45 <ToggleButton
48 </ToggleButton> 46 selected={editorStore.showLineNumbers}
47 onClick={() => editorStore.toggleLineNumbers()}
48 aria-label="Show line numbers"
49 value="show-line-numbers"
50 >
51 <FormatListNumberedIcon fontSize="small" />
52 </ToggleButton>
53 <ToggleButton
54 selected={editorStore.showSearchPanel}
55 onClick={() => editorStore.toggleSearchPanel()}
56 aria-label="Show find/replace"
57 value="show-search-panel"
58 >
59 <SearchIcon fontSize="small" />
60 </ToggleButton>
61 <ToggleButton
62 selected={editorStore.showLintPanel}
63 onClick={() => editorStore.toggleLintPanel()}
64 aria-label="Show errors and warnings"
65 value="show-lint-panel"
66 >
67 <CheckIcon fontSize="small" />
68 </ToggleButton>
69 </ToggleButtonGroup>
49 </Stack> 70 </Stack>
50 ); 71 );
51}); 72});
diff --git a/language-web/src/main/js/editor/EditorParent.ts b/language-web/src/main/js/editor/EditorParent.ts
new file mode 100644
index 00000000..bf67522b
--- /dev/null
+++ b/language-web/src/main/js/editor/EditorParent.ts
@@ -0,0 +1,61 @@
1import { styled } from '@mui/material/styles';
2
3export const EditorParent = styled('div')(({ theme }) => ({
4 background: theme.palette.background.default,
5 '&, .cm-editor': {
6 height: '100%',
7 },
8 '.cm-scroller': {
9 fontSize: 16,
10 fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace',
11 fontFeatureSettings: '"liga", "calt"',
12 fontWeight: 400,
13 letterSpacing: 0,
14 textRendering: 'optimizeLegibility',
15 color: theme.palette.text.secondary,
16 },
17 '.cm-gutters': {
18 background: theme.palette.background.default,
19 color: theme.palette.text.disabled,
20 border: 'none',
21 },
22 '.cm-specialChar': {
23 color: theme.palette.secondary.main,
24 },
25 '.cm-activeLine': {
26 background: 'rgba(0, 0, 0, 0.3)',
27 },
28 '.cm-activeLineGutter': {
29 background: 'rgba(0, 0, 0, 0.3)',
30 color: theme.palette.text.primary,
31 },
32 '.cm-cursor, .cm-cursor-primary': {
33 borderColor: theme.palette.primary.main,
34 background: theme.palette.common.black,
35 },
36 '.cm-selectionBackground': {
37 background: '#3e4453',
38 },
39 '.cm-focused': {
40 outline: 'none',
41 '.cm-selectionBackground': {
42 background: '#3e4453',
43 },
44 },
45 '.cm-panels-top': {
46 color: theme.palette.text.secondary,
47 },
48 '.cm-panel': {
49 background: theme.palette.background.paper,
50 borderTop: `1px solid ${theme.palette.divider}`,
51 'button[name="close"]': {
52 // HACK We can't hook the panel close button to go through `EditorStore`,
53 // so we hide it altogether.
54 display: 'none',
55 },
56 },
57 '.cmt-comment': {
58 fontVariant: 'italic',
59 color: theme.palette.text.disabled,
60 },
61}));
diff --git a/language-web/src/main/js/editor/EditorStore.ts b/language-web/src/main/js/editor/EditorStore.ts
index 705020b9..326c02a1 100644
--- a/language-web/src/main/js/editor/EditorStore.ts
+++ b/language-web/src/main/js/editor/EditorStore.ts
@@ -1,201 +1,217 @@
1import type { Editor, EditorConfiguration } from 'codemirror'; 1import { autocompletion, completionKeymap } from '@codemirror/autocomplete';
2import { closeBrackets, closeBracketsKeymap } from '@codemirror/closebrackets';
3import { defaultKeymap, indentWithTab } from '@codemirror/commands';
4import { commentKeymap } from '@codemirror/comment';
5import { foldGutter, foldKeymap } from '@codemirror/fold';
6import { highlightActiveLineGutter, lineNumbers } from '@codemirror/gutter';
7import { classHighlightStyle } from '@codemirror/highlight';
8import {
9 history,
10 historyKeymap,
11 redo,
12 redoDepth,
13 undo,
14 undoDepth,
15} from '@codemirror/history';
16import { indentOnInput } from '@codemirror/language';
17import { lintKeymap } from '@codemirror/lint';
18import { bracketMatching } from '@codemirror/matchbrackets';
19import { rectangularSelection } from '@codemirror/rectangular-selection';
20import { searchConfig, searchKeymap } from '@codemirror/search';
21import {
22 EditorState,
23 StateCommand,
24 StateEffect,
25 Transaction,
26 TransactionSpec,
27} from '@codemirror/state';
28import {
29 drawSelection,
30 EditorView,
31 highlightActiveLine,
32 highlightSpecialChars,
33 keymap,
34} from '@codemirror/view';
2import { 35import {
3 createAtom,
4 makeAutoObservable, 36 makeAutoObservable,
5 observable, 37 observable,
6 runInAction, 38 reaction,
7} from 'mobx'; 39} from 'mobx';
8import type { IXtextOptions, IXtextServices } from 'xtext/xtext-codemirror';
9 40
10import type { IEditorChunk } from './editor';
11import { getLogger } from '../logging'; 41import { getLogger } from '../logging';
12import type { ThemeStore } from '../theme/ThemeStore'; 42import type { ThemeStore } from '../theme/ThemeStore';
13 43
14const log = getLogger('EditorStore'); 44const log = getLogger('EditorStore');
15 45
16const xtextLang = 'problem';
17
18const xtextOptions: IXtextOptions = {
19 xtextLang,
20 enableFormattingAction: true,
21};
22
23const codeMirrorGlobalOptions: EditorConfiguration = {
24 mode: `xtext/${xtextLang}`,
25 indentUnit: 2,
26 styleActiveLine: true,
27 screenReaderLabel: 'Model source code',
28 inputStyle: 'contenteditable',
29};
30
31export class EditorStore { 46export class EditorStore {
32 themeStore; 47 themeStore;
33 48
34 atom; 49 state: EditorState;
35 50
36 chunk?: IEditorChunk; 51 emptyHistory: unknown;
37 52
38 editor?: Editor; 53 showLineNumbers = false;
39 54
40 xtextServices?: IXtextServices; 55 showSearchPanel = false;
41 56
42 value = ''; 57 showLintPanel = false;
43 58
44 showLineNumbers = false; 59 readonly defaultDispatcher = (tr: Transaction): void => {
60 this.onTransaction(tr);
61 };
45 62
46 initialSelection!: { start: number, end: number, focused: boolean }; 63 dispatcher = this.defaultDispatcher;
47 64
48 constructor(themeStore: ThemeStore) { 65 constructor(initialValue: string, themeStore: ThemeStore) {
49 this.themeStore = themeStore; 66 this.themeStore = themeStore;
50 this.atom = createAtom('EditorStore'); 67 this.state = EditorState.create({
51 this.resetInitialSelection(); 68 doc: initialValue,
69 extensions: [
70 autocompletion(),
71 classHighlightStyle.extension,
72 closeBrackets(),
73 bracketMatching(),
74 drawSelection(),
75 EditorState.allowMultipleSelections.of(true),
76 EditorView.theme({}, {
77 dark: this.themeStore.darkMode,
78 }),
79 highlightActiveLine(),
80 highlightActiveLineGutter(),
81 highlightSpecialChars(),
82 history(),
83 indentOnInput(),
84 rectangularSelection(),
85 searchConfig({
86 top: true,
87 matchCase: true,
88 }),
89 // We add the gutters to `extensions` in the order we want them to appear.
90 foldGutter(),
91 lineNumbers(),
92 keymap.of([
93 ...closeBracketsKeymap,
94 ...commentKeymap,
95 ...completionKeymap,
96 ...foldKeymap,
97 ...historyKeymap,
98 indentWithTab,
99 // Override keys in `lintKeymap` to go through the `EditorStore`.
100 { key: 'Mod-Shift-m', run: () => this.setLintPanelOpen(true) },
101 ...lintKeymap,
102 // Override keys in `searchKeymap` to go through the `EditorStore`.
103 { key: 'Mod-f', run: () => this.setSearchPanelOpen(true), scope: 'editor search-panel' },
104 { key: 'Escape', run: () => this.setSearchPanelOpen(false), scope: 'editor search-panel' },
105 ...searchKeymap,
106 ...defaultKeymap,
107 ]),
108 ],
109 });
110 reaction(
111 () => this.themeStore.darkMode,
112 (darkMode) => {
113 log.debug('Update editor dark mode', darkMode);
114 this.dispatch({
115 effects: [
116 StateEffect.appendConfig.of(EditorView.theme({}, {
117 dark: darkMode,
118 })),
119 ],
120 });
121 },
122 );
52 makeAutoObservable(this, { 123 makeAutoObservable(this, {
53 themeStore: false, 124 themeStore: false,
54 atom: false, 125 state: observable.ref,
55 chunk: observable.ref, 126 defaultDispatcher: false,
56 editor: observable.ref, 127 dispatcher: false,
57 xtextServices: observable.ref,
58 initialSelection: false,
59 }); 128 });
60 this.loadChunk();
61 } 129 }
62 130
63 private loadChunk(): void { 131 updateDispatcher(newDispatcher: ((tr: Transaction) => void) | null): void {
64 const loadingStartMillis = Date.now(); 132 this.dispatcher = newDispatcher || this.defaultDispatcher;
65 log.info('Requesting editor chunk');
66 import('./editor').then(({ editorChunk }) => {
67 runInAction(() => {
68 this.chunk = editorChunk;
69 });
70 const loadingDurationMillis = Date.now() - loadingStartMillis;
71 log.info('Loaded editor chunk in', loadingDurationMillis, 'ms');
72 }).catch((error) => {
73 log.error('Error while loading editor', error);
74 });
75 } 133 }
76 134
77 setInitialSelection(start: number, end: number, focused: boolean): void { 135 onTransaction(tr: Transaction): void {
78 this.initialSelection = { start, end, focused }; 136 log.trace('Editor transaction', tr);
79 this.applyInitialSelectionToEditor(); 137 this.state = tr.state;
80 } 138 }
81 139
82 private resetInitialSelection(): void { 140 dispatch(...specs: readonly TransactionSpec[]): void {
83 this.initialSelection = { 141 this.dispatcher(this.state.update(...specs));
84 start: 0,
85 end: 0,
86 focused: false,
87 };
88 } 142 }
89 143
90 private applyInitialSelectionToEditor(): void { 144 doStateCommand(command: StateCommand): boolean {
91 if (this.editor) { 145 return command({
92 const { start, end, focused } = this.initialSelection; 146 state: this.state,
93 const doc = this.editor.getDoc(); 147 dispatch: this.dispatcher,
94 const startPos = doc.posFromIndex(start); 148 });
95 const endPos = doc.posFromIndex(end);
96 doc.setSelection(startPos, endPos, {
97 scroll: true,
98 });
99 if (focused) {
100 this.editor.focus();
101 }
102 this.resetInitialSelection();
103 }
104 } 149 }
105 150
106 /** 151 /**
107 * Attaches a new CodeMirror instance and creates Xtext services. 152 * @returns `true` if there is history to undo
108 *
109 * The store will not subscribe to any CodeMirror events. Instead,
110 * the editor component should subscribe to them and relay them to the store.
111 *
112 * @param newEditor The new CodeMirror instance
113 */ 153 */
114 editorDidMount(newEditor: Editor): void { 154 get canUndo(): boolean {
115 if (!this.chunk) { 155 return undoDepth(this.state) > 0;
116 throw new Error('Editor not loaded yet');
117 }
118 if (this.editor) {
119 throw new Error('CoreMirror editor mounted before unmounting');
120 }
121 this.editor = newEditor;
122 this.xtextServices = this.chunk.createServices(newEditor, xtextOptions);
123 this.applyInitialSelectionToEditor();
124 } 156 }
125 157
126 editorWillUnmount(): void { 158 // eslint-disable-next-line class-methods-use-this
127 if (!this.chunk) { 159 undo(): void {
128 throw new Error('Editor not loaded yet'); 160 log.debug('Undo', this.doStateCommand(undo));
129 }
130 if (this.editor) {
131 this.chunk.removeServices(this.editor);
132 }
133 delete this.editor;
134 delete this.xtextServices;
135 } 161 }
136 162
137 /** 163 /**
138 * Updates the contents of the editor. 164 * @returns `true` if there is history to redo
139 *
140 * @param newValue The new contents of the editor
141 */ 165 */
142 updateValue(newValue: string): void { 166 get canRedo(): boolean {
143 this.value = newValue; 167 return redoDepth(this.state) > 0;
144 }
145
146 reportChanged(): void {
147 this.atom.reportChanged();
148 }
149
150 protected observeEditorChanges(): void {
151 this.atom.reportObserved();
152 } 168 }
153 169
154 get codeMirrorTheme(): string { 170 // eslint-disable-next-line class-methods-use-this
155 return `problem-${this.themeStore.className}`; 171 redo(): void {
172 log.debug('Redo', this.doStateCommand(redo));
156 } 173 }
157 174
158 get codeMirrorOptions(): EditorConfiguration { 175 toggleLineNumbers(): void {
159 return { 176 this.showLineNumbers = !this.showLineNumbers;
160 ...codeMirrorGlobalOptions, 177 log.debug('Show line numbers', this.showLineNumbers);
161 theme: this.codeMirrorTheme,
162 lineNumbers: this.showLineNumbers,
163 };
164 } 178 }
165 179
166 /** 180 /**
167 * @returns `true` if there is history to undo 181 * Sets whether the CodeMirror search panel should be open.
182 *
183 * This method can be used as a CodeMirror command,
184 * because it returns `false` if it didn't execute,
185 * allowing other commands for the same keybind to run instead.
186 * This matches the behavior of the `openSearchPanel` and `closeSearchPanel`
187 * commands from `'@codemirror/search'`.
188 *
189 * @param newShosSearchPanel whether we should show the search panel
190 * @returns `true` if the state was changed, `false` otherwise
168 */ 191 */
169 get canUndo(): boolean { 192 setSearchPanelOpen(newShowSearchPanel: boolean): boolean {
170 this.observeEditorChanges(); 193 if (this.showSearchPanel === newShowSearchPanel) {
171 if (!this.editor) {
172 return false; 194 return false;
173 } 195 }
174 const { undo: undoSize } = this.editor.historySize(); 196 this.showSearchPanel = newShowSearchPanel;
175 return undoSize > 0; 197 log.debug('Show search panel', this.showSearchPanel);
198 return true;
176 } 199 }
177 200
178 undo(): void { 201 toggleSearchPanel(): void {
179 this.editor?.undo(); 202 this.setSearchPanelOpen(!this.showSearchPanel);
180 } 203 }
181 204
182 /** 205 setLintPanelOpen(newShowLintPanel: boolean): boolean {
183 * @returns `true` if there is history to redo 206 if (this.showLintPanel === newShowLintPanel) {
184 */
185 get canRedo(): boolean {
186 this.observeEditorChanges();
187 if (!this.editor) {
188 return false; 207 return false;
189 } 208 }
190 const { redo: redoSize } = this.editor.historySize(); 209 this.showLintPanel = newShowLintPanel;
191 return redoSize > 0; 210 log.debug('Show lint panel', this.showLintPanel);
211 return true;
192 } 212 }
193 213
194 redo(): void { 214 toggleLintPanel(): void {
195 this.editor?.redo(); 215 this.setLintPanelOpen(!this.showLintPanel);
196 }
197
198 toggleLineNumbers(): void {
199 this.showLineNumbers = !this.showLineNumbers;
200 } 216 }
201} 217}
diff --git a/language-web/src/main/js/editor/editor.ts b/language-web/src/main/js/editor/editor.ts
deleted file mode 100644
index fbf8796b..00000000
--- a/language-web/src/main/js/editor/editor.ts
+++ /dev/null
@@ -1,18 +0,0 @@
1import 'codemirror/addon/selection/active-line';
2import 'mode-problem';
3import { Controlled } from 'react-codemirror2';
4import { createServices, removeServices } from 'xtext/xtext-codemirror';
5
6export interface IEditorChunk {
7 CodeMirror: typeof Controlled;
8
9 createServices: typeof createServices;
10
11 removeServices: typeof removeServices;
12}
13
14export const editorChunk: IEditorChunk = {
15 CodeMirror: Controlled,
16 createServices,
17 removeServices,
18};
diff --git a/language-web/src/main/js/index.tsx b/language-web/src/main/js/index.tsx
index 80c70f23..66ad1f28 100644
--- a/language-web/src/main/js/index.tsx
+++ b/language-web/src/main/js/index.tsx
@@ -44,8 +44,7 @@ age(bob, bobAge).
44scope Family = 1, Person += 5..10. 44scope Family = 1, Person += 5..10.
45`; 45`;
46 46
47const rootStore = new RootStore(); 47const rootStore = new RootStore(initialValue);
48rootStore.editorStore.updateValue(initialValue);
49 48
50const app = ( 49const app = (
51 <RootStoreProvider rootStore={rootStore}> 50 <RootStoreProvider rootStore={rootStore}>
diff --git a/language-web/src/main/js/theme/ThemeStore.ts b/language-web/src/main/js/theme/ThemeStore.ts
index 3bbea3a1..db94d9f7 100644
--- a/language-web/src/main/js/theme/ThemeStore.ts
+++ b/language-web/src/main/js/theme/ThemeStore.ts
@@ -51,6 +51,10 @@ export class ThemeStore {
51 return responsiveFontSizes(materialUiTheme); 51 return responsiveFontSizes(materialUiTheme);
52 } 52 }
53 53
54 get darkMode(): boolean {
55 return this.currentThemeData.paletteMode === 'dark';
56 }
57
54 get className(): string { 58 get className(): string {
55 return this.currentThemeData.className; 59 return this.currentThemeData.className;
56 } 60 }
diff --git a/language-web/yarn.lock b/language-web/yarn.lock
index e87bc6ee..51c551a7 100644
--- a/language-web/yarn.lock
+++ b/language-web/yarn.lock
@@ -972,6 +972,189 @@
972 "@babel/helper-validator-identifier" "^7.14.9" 972 "@babel/helper-validator-identifier" "^7.14.9"
973 to-fast-properties "^2.0.0" 973 to-fast-properties "^2.0.0"
974 974
975"@codemirror/autocomplete@^0.19.3":
976 version "0.19.3"
977 resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-0.19.3.tgz#0266ac29617277d2d8cc7dcfb600c1e50c332d35"
978 integrity sha512-5juP6hVrHAogzQ0JUTQuibE8j1seqeGNJ98qLUPuliI6kLBg5INS4qvUI1Brqye+wYPFu7UHqrrn13RLh5YSzw==
979 dependencies:
980 "@codemirror/language" "^0.19.0"
981 "@codemirror/state" "^0.19.0"
982 "@codemirror/text" "^0.19.2"
983 "@codemirror/tooltip" "^0.19.0"
984 "@codemirror/view" "^0.19.0"
985 "@lezer/common" "^0.15.0"
986
987"@codemirror/closebrackets@^0.19.0":
988 version "0.19.0"
989 resolved "https://registry.yarnpkg.com/@codemirror/closebrackets/-/closebrackets-0.19.0.tgz#69fdcee85779d638a00a42becd9f53a33a26d77f"
990 integrity sha512-dFWX5OEVYWRNtGaifSbwIAlymnRRjxWMiMbffbAjF7p0zfGHDbdGkiT56q3Xud63h5/tQdSo5dK1iyNTzHz5vg==
991 dependencies:
992 "@codemirror/language" "^0.19.0"
993 "@codemirror/rangeset" "^0.19.0"
994 "@codemirror/state" "^0.19.0"
995 "@codemirror/text" "^0.19.0"
996 "@codemirror/view" "^0.19.0"
997
998"@codemirror/commands@^0.19.5":
999 version "0.19.5"
1000 resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-0.19.5.tgz#2607b5c12c5c96df2cabce2e43f6285c07cfaf11"
1001 integrity sha512-8PZOtx7d/GbKhFYA88zs2wINDtaUgj3pEjLYScKTd/Vsyw8qOp86tJQQNnMFTRZj/ISQl9Lbg3aAmHvroMqspw==
1002 dependencies:
1003 "@codemirror/language" "^0.19.0"
1004 "@codemirror/matchbrackets" "^0.19.0"
1005 "@codemirror/state" "^0.19.2"
1006 "@codemirror/text" "^0.19.0"
1007 "@codemirror/view" "^0.19.0"
1008 "@lezer/common" "^0.15.0"
1009
1010"@codemirror/comment@^0.19.0":
1011 version "0.19.0"
1012 resolved "https://registry.yarnpkg.com/@codemirror/comment/-/comment-0.19.0.tgz#4f23497924e9346898c2e0123011acc535a0bea6"
1013 integrity sha512-3hqAd0548fxqOBm4khFMcXVIivX8p0bSlbAuZJ6PNoUn/0wXhxkxowPp0FmFzU2+y37Z+ZQF5cRB5EREWPRIiQ==
1014 dependencies:
1015 "@codemirror/state" "^0.19.0"
1016 "@codemirror/text" "^0.19.0"
1017 "@codemirror/view" "^0.19.0"
1018
1019"@codemirror/fold@^0.19.0":
1020 version "0.19.0"
1021 resolved "https://registry.yarnpkg.com/@codemirror/fold/-/fold-0.19.0.tgz#cd57537870ff581ae57199a7658abe3f9908f2ed"
1022 integrity sha512-cHbr2hqKe2pMls1Ia1a4IwXly87ljpmvPUKkul6H/Uv9kCwpQLOP3dGMPXbMGm/1hGjBF/0wnc+m2iba9iJBTQ==
1023 dependencies:
1024 "@codemirror/gutter" "^0.19.0"
1025 "@codemirror/language" "^0.19.0"
1026 "@codemirror/rangeset" "^0.19.0"
1027 "@codemirror/state" "^0.19.0"
1028 "@codemirror/view" "^0.19.0"
1029
1030"@codemirror/gutter@^0.19.0", "@codemirror/gutter@^0.19.2":
1031 version "0.19.2"
1032 resolved "https://registry.yarnpkg.com/@codemirror/gutter/-/gutter-0.19.2.tgz#afc61dbe2977ff83aff8675200deab6d04244c5c"
1033 integrity sha512-xiayxhc9uq1UXiG/r/E3AAYXZt+EtSdgdQXC4nlMHvbfw2EmtryfzGO3HrgasHRyAW8uNCaO9JO4n7mU7rm1rQ==
1034 dependencies:
1035 "@codemirror/rangeset" "^0.19.0"
1036 "@codemirror/state" "^0.19.0"
1037 "@codemirror/view" "^0.19.0"
1038
1039"@codemirror/highlight@^0.19.6":
1040 version "0.19.6"
1041 resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.6.tgz#7f2e066f83f5649e8e0748a3abe0aaeaf64b8ac2"
1042 integrity sha512-+eibu6on9quY8uN3xJ/n3rH+YIDLlpX7YulVmFvqAIz/ukRQ5tWaBmB7fMixHmnmRIRBRZgB8rNtonuMwZSAHQ==
1043 dependencies:
1044 "@codemirror/language" "^0.19.0"
1045 "@codemirror/rangeset" "^0.19.0"
1046 "@codemirror/state" "^0.19.0"
1047 "@codemirror/view" "^0.19.0"
1048 "@lezer/common" "^0.15.0"
1049 style-mod "^4.0.0"
1050
1051"@codemirror/history@^0.19.0":
1052 version "0.19.0"
1053 resolved "https://registry.yarnpkg.com/@codemirror/history/-/history-0.19.0.tgz#cc8095c927c9566f7b69fa404074edde4c54d39c"
1054 integrity sha512-E0H+lncH66IMDhaND9jgkjE7s0dhYfjCPmS+Ig2Yes9I8+UIEecIdObj8c8HPCFGctGg3fxXqRAw2mdHl2Wouw==
1055 dependencies:
1056 "@codemirror/state" "^0.19.0"
1057 "@codemirror/view" "^0.19.0"
1058
1059"@codemirror/language@^0.19.0", "@codemirror/language@^0.19.3":
1060 version "0.19.3"
1061 resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-0.19.3.tgz#e4f61555dec0787f757b78348a54a00f3bb23c9c"
1062 integrity sha512-6vjkRYHRJg/z9wdAk75nU2fQwCJBsh2HpkIjKXIHfzISSgLt5qSDxVhPd8Uu8PD5WMmFFP8tX7I9kdIt873o0A==
1063 dependencies:
1064 "@codemirror/state" "^0.19.0"
1065 "@codemirror/text" "^0.19.0"
1066 "@codemirror/view" "^0.19.0"
1067 "@lezer/common" "^0.15.5"
1068 "@lezer/lr" "^0.15.0"
1069
1070"@codemirror/lint@^0.19.2":
1071 version "0.19.2"
1072 resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-0.19.2.tgz#1c3932cffd635da796bea3384256b0a315b6fe1e"
1073 integrity sha512-477qvXWwuf24YsBi1DzjrGyzM+qfPe5L4xEHGxQTGOMq6R0+QAFKppOJsxN3y7gzDpLrZSYZdhJzWevOuliZQg==
1074 dependencies:
1075 "@codemirror/panel" "^0.19.0"
1076 "@codemirror/state" "^0.19.0"
1077 "@codemirror/tooltip" "^0.19.0"
1078 "@codemirror/view" "^0.19.0"
1079 crelt "^1.0.5"
1080
1081"@codemirror/matchbrackets@^0.19.0", "@codemirror/matchbrackets@^0.19.3":
1082 version "0.19.3"
1083 resolved "https://registry.yarnpkg.com/@codemirror/matchbrackets/-/matchbrackets-0.19.3.tgz#1f430ada6fa21af2205280ff344ef57bb95dd3cb"
1084 integrity sha512-ljkrBxaLgh8jesroUiBa57pdEwqJamxkukXrJpL9LdyFZVJaF+9TldhztRaMsMZO1XnCSSHQ9sg32iuHo7Sc2g==
1085 dependencies:
1086 "@codemirror/language" "^0.19.0"
1087 "@codemirror/state" "^0.19.0"
1088 "@codemirror/view" "^0.19.0"
1089 "@lezer/common" "^0.15.0"
1090
1091"@codemirror/panel@^0.19.0":
1092 version "0.19.0"
1093 resolved "https://registry.yarnpkg.com/@codemirror/panel/-/panel-0.19.0.tgz#18c7a253a7a1ef686bece1ef13ec0e5eb6603265"
1094 integrity sha512-LJuu49xnuhaAztlhnLJQ57ddOirSyf8/lnl7twsQUG/05RkxodBZ9F7q8r5AOLqOkaQOy9WySEKX1Ur8lD9Q5w==
1095 dependencies:
1096 "@codemirror/state" "^0.19.0"
1097 "@codemirror/view" "^0.19.0"
1098
1099"@codemirror/rangeset@^0.19.0":
1100 version "0.19.1"
1101 resolved "https://registry.yarnpkg.com/@codemirror/rangeset/-/rangeset-0.19.1.tgz#03ab6f93fb60d9ba98f810b98ed9471cba1e3854"
1102 integrity sha512-WaKTEw8JB/3QFlQzpdgRoklopcWvG8O/Xp+rxxOfFKYTaeaejpY/tjpyBBg+Ea65Ka3m7+pPp9d5j/oR2rd9NA==
1103 dependencies:
1104 "@codemirror/state" "^0.19.0"
1105
1106"@codemirror/rectangular-selection@^0.19.1":
1107 version "0.19.1"
1108 resolved "https://registry.yarnpkg.com/@codemirror/rectangular-selection/-/rectangular-selection-0.19.1.tgz#5a88ece4fb68ce5682539497db8a64fc015aae63"
1109 integrity sha512-9ElnqOg3mpZIWe0prPRd1SZ48Q9QB3bR8Aocq8UtjboJSUG8ABhRrbuTZMW/rMqpBPSjVpCe9xkCCkEQMYQVmw==
1110 dependencies:
1111 "@codemirror/state" "^0.19.0"
1112 "@codemirror/text" "^0.19.4"
1113 "@codemirror/view" "^0.19.0"
1114
1115"@codemirror/search@^0.19.2":
1116 version "0.19.2"
1117 resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-0.19.2.tgz#d549c3daa527e17c173cdfc90b7c1b02deab1502"
1118 integrity sha512-TrRxUxyJ/a7HXtUvMZhgkOUbKE1xO33UhXjn1XACEHKWhgovw1vEeEEti9dZejN8/QOOFJed39InUxmp7oQ8HA==
1119 dependencies:
1120 "@codemirror/panel" "^0.19.0"
1121 "@codemirror/rangeset" "^0.19.0"
1122 "@codemirror/state" "^0.19.2"
1123 "@codemirror/text" "^0.19.0"
1124 "@codemirror/view" "^0.19.0"
1125 crelt "^1.0.5"
1126
1127"@codemirror/state@^0.19.0", "@codemirror/state@^0.19.2":
1128 version "0.19.2"
1129 resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-0.19.2.tgz#81de81f89e87b9362b8bc6d51135637dddd4d33d"
1130 integrity sha512-dDqCrtkb0c/LYUlvQBLyLfkISEskbZnhvBbcVOF4j2AusJ1ptJ3EGMxBL9G16GP1TOdC1T613gA1J1qc3pbfGQ==
1131 dependencies:
1132 "@codemirror/text" "^0.19.0"
1133
1134"@codemirror/text@^0.19.0", "@codemirror/text@^0.19.2", "@codemirror/text@^0.19.4":
1135 version "0.19.4"
1136 resolved "https://registry.yarnpkg.com/@codemirror/text/-/text-0.19.4.tgz#522cbe93becdf7637ca7148b67f628b3d8b8fdf5"
1137 integrity sha512-Msd1ImS+Mmref28+oyoOrBwqjH4lbCVO/5ol2jRaCEYH7+KaMocxFADZomPLnMPgDW6Gc4mu/K2lj8IjAOFdTA==
1138
1139"@codemirror/tooltip@^0.19.0":
1140 version "0.19.2"
1141 resolved "https://registry.yarnpkg.com/@codemirror/tooltip/-/tooltip-0.19.2.tgz#a8f6b703edb64748106e136ec1f099a981a3f1d4"
1142 integrity sha512-FMMGGLrr62Ck54NEz8yTGpgo8ihobAsC3sbeQg+OpY4jv9dt1yIP5B9LzsIV+TXQB57JZQZxtTqzkhnFq76haw==
1143 dependencies:
1144 "@codemirror/state" "^0.19.0"
1145 "@codemirror/view" "^0.19.0"
1146
1147"@codemirror/view@^0.19.0", "@codemirror/view@^0.19.9":
1148 version "0.19.9"
1149 resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-0.19.9.tgz#cbdcbc398818e7c9603c81e4b2a2868ec0a1f954"
1150 integrity sha512-d2Z2rFl53yTwvhsRYtS97xT7ce1f/Q/NNE2uDg/Be1MVjP2v1OlwUTyTosBmxiCt4oUvMklfa+EdPGOATVJhtg==
1151 dependencies:
1152 "@codemirror/rangeset" "^0.19.0"
1153 "@codemirror/state" "^0.19.2"
1154 "@codemirror/text" "^0.19.0"
1155 style-mod "^4.0.0"
1156 w3c-keyname "^2.2.4"
1157
975"@discoveryjs/json-ext@^0.5.0": 1158"@discoveryjs/json-ext@^0.5.0":
976 version "0.5.5" 1159 version "0.5.5"
977 resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3" 1160 resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.5.tgz#9283c9ce5b289a3c4f61c12757469e59377f81f3"
@@ -1117,6 +1300,18 @@
1117 resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf" 1300 resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
1118 integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w== 1301 integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
1119 1302
1303"@lezer/common@^0.15.0", "@lezer/common@^0.15.5":
1304 version "0.15.7"
1305 resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.7.tgz#8b445dae9777f689783132cf490770ece3c03d7b"
1306 integrity sha512-Rw8TDJnBzZnkyzIXs1Tmmd241FrBLJBj8gkdy3y0joGFb8Z4I/joKEsR+gv1pb13o1TMsZxm3fmP+d/wPt2CTQ==
1307
1308"@lezer/lr@^0.15.0":
1309 version "0.15.4"
1310 resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.4.tgz#634670d7224040fddac1370af01211eecd9ac0a0"
1311 integrity sha512-vwgG80sihEGJn6wJp6VijXrnzVai/KPva/OzYKaWvIx0IiXKjoMQ8UAwcgpSBwfS4Fbz3IKOX/cCNXU3r1FvpQ==
1312 dependencies:
1313 "@lezer/common" "^0.15.0"
1314
1120"@mui/core@5.0.0-alpha.49": 1315"@mui/core@5.0.0-alpha.49":
1121 version "5.0.0-alpha.49" 1316 version "5.0.0-alpha.49"
1122 resolved "https://registry.yarnpkg.com/@mui/core/-/core-5.0.0-alpha.49.tgz#e74d6ec7f83f85b55d48aa05ea6b7cefff88ce1b" 1317 resolved "https://registry.yarnpkg.com/@mui/core/-/core-5.0.0-alpha.49.tgz#e74d6ec7f83f85b55d48aa05ea6b7cefff88ce1b"
@@ -2294,11 +2489,6 @@ clsx@^1.1.1:
2294 resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" 2489 resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
2295 integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== 2490 integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
2296 2491
2297codemirror@^5.63.1:
2298 version "5.63.1"
2299 resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.63.1.tgz#b0b9e8444206fd6a43a58a4b31d5740bb891fa57"
2300 integrity sha512-baivaNZreZOGh1/tYyTvCupC9NeWk7qlZeGUDi4nFKj/J0JU8FYKZND4QqLw70P7HOttlCt4JJAOj9GoIhHEkA==
2301
2302color-convert@^1.9.0: 2492color-convert@^1.9.0:
2303 version "1.9.3" 2493 version "1.9.3"
2304 resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 2494 resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -2470,6 +2660,11 @@ cosmiconfig@^7.0.0:
2470 path-type "^4.0.0" 2660 path-type "^4.0.0"
2471 yaml "^1.10.0" 2661 yaml "^1.10.0"
2472 2662
2663crelt@^1.0.5:
2664 version "1.0.5"
2665 resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.5.tgz#57c0d52af8c859e354bace1883eb2e1eb182bb94"
2666 integrity sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==
2667
2473cross-spawn@^5.0.1: 2668cross-spawn@^5.0.1:
2474 version "5.1.0" 2669 version "5.1.0"
2475 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" 2670 resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -6095,11 +6290,6 @@ raw-body@2.4.0:
6095 iconv-lite "0.4.24" 6290 iconv-lite "0.4.24"
6096 unpipe "1.0.0" 6291 unpipe "1.0.0"
6097 6292
6098"react-codemirror2@npm:react17-codemirror2@^7.2.3":
6099 version "7.2.3"
6100 resolved "https://registry.yarnpkg.com/react17-codemirror2/-/react17-codemirror2-7.2.3.tgz#ff1ec8f5feadf9c03fb25095c40326971f3ce106"
6101 integrity sha512-XOIu5k3IFH6ajunRw5HO9BX9N6u9T7tby7BN4tKi/sz0Yq3pvd0xylbvq5PbScl2oowRMcyiJXkpPRI8+h0H9Q==
6102
6103react-dom@^17.0.2: 6293react-dom@^17.0.2:
6104 version "17.0.2" 6294 version "17.0.2"
6105 resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" 6295 resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
@@ -6947,6 +7137,11 @@ style-loader@^3.3.0:
6947 resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.0.tgz#d66ea95fc50b22f8b79b69a9e414760fcf58d8d8" 7137 resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.0.tgz#d66ea95fc50b22f8b79b69a9e414760fcf58d8d8"
6948 integrity sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ== 7138 integrity sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ==
6949 7139
7140style-mod@^4.0.0:
7141 version "4.0.0"
7142 resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.0.0.tgz#97e7c2d68b592975f2ca7a63d0dd6fcacfe35a01"
7143 integrity sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==
7144
6950style-search@^0.1.0: 7145style-search@^0.1.0:
6951 version "0.1.0" 7146 version "0.1.0"
6952 resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" 7147 resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
@@ -7480,6 +7675,11 @@ vfile@^4.0.0:
7480 unist-util-stringify-position "^2.0.0" 7675 unist-util-stringify-position "^2.0.0"
7481 vfile-message "^2.0.0" 7676 vfile-message "^2.0.0"
7482 7677
7678w3c-keyname@^2.2.4:
7679 version "2.2.4"
7680 resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.4.tgz#4ade6916f6290224cdbd1db8ac49eab03d0eef6b"
7681 integrity sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==
7682
7483watchpack@^2.2.0: 7683watchpack@^2.2.0:
7484 version "2.2.0" 7684 version "2.2.0"
7485 resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce" 7685 resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce"