@eccenca/gui-elements 24.0.0 → 24.1.0-featureimprovepublishingprocesscmem6356.0
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.
- package/CHANGELOG.md +95 -0
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/cjs/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +3 -3
- package/dist/cjs/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js +13 -3
- package/dist/cjs/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js +3 -3
- package/dist/cjs/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js +4 -2
- package/dist/cjs/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/cjs/components/Card/CardActions.js +2 -1
- package/dist/cjs/components/Card/CardActions.js.map +1 -1
- package/dist/cjs/components/Card/CardContent.js +4 -6
- package/dist/cjs/components/Card/CardContent.js.map +1 -1
- package/dist/cjs/components/ContentGroup/ContentGroup.js +95 -0
- package/dist/cjs/components/ContentGroup/ContentGroup.js.map +1 -0
- package/dist/cjs/components/Dialog/SimpleDialog.js +3 -3
- package/dist/cjs/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/cjs/components/Icon/canonicalIconNames.js +12 -0
- package/dist/cjs/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/cjs/components/Label/Label.js +8 -3
- package/dist/cjs/components/Label/Label.js.map +1 -1
- package/dist/cjs/components/Menu/MenuItem.js +3 -2
- package/dist/cjs/components/Menu/MenuItem.js.map +1 -1
- package/dist/cjs/components/MultiSelect/MultiSelect.js +1 -0
- package/dist/cjs/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/cjs/components/OverviewItem/OverviewItem.js +5 -2
- package/dist/cjs/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/cjs/components/OverviewItem/OverviewItemList.js +2 -2
- package/dist/cjs/components/OverviewItem/OverviewItemList.js.map +1 -1
- package/dist/cjs/components/Switch/Switch.js +6 -4
- package/dist/cjs/components/Switch/Switch.js.map +1 -1
- package/dist/cjs/components/Tag/TagList.js +1 -1
- package/dist/cjs/components/Tag/TagList.js.map +1 -1
- package/dist/cjs/components/TextField/SearchField.js +19 -2
- package/dist/cjs/components/TextField/SearchField.js.map +1 -1
- package/dist/cjs/components/Typography/OverflowText.js +1 -1
- package/dist/cjs/components/Typography/OverflowText.js.map +1 -1
- package/dist/cjs/components/index.js +1 -0
- package/dist/cjs/components/index.js.map +1 -1
- package/dist/cjs/extensions/codemirror/CodeMirror.js +93 -11
- package/dist/cjs/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/cjs/extensions/codemirror/debouncedLinter.js +18 -0
- package/dist/cjs/extensions/codemirror/debouncedLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js +23 -14
- package/dist/cjs/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js.map +1 -1
- package/dist/cjs/extensions/codemirror/linters/jsLinter.js +36 -0
- package/dist/cjs/extensions/codemirror/linters/jsLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/linters/turtleLinter.js +81 -0
- package/dist/cjs/extensions/codemirror/linters/turtleLinter.js.map +1 -0
- package/dist/cjs/extensions/codemirror/tests/codemirrorTestHelper.js +4 -1
- package/dist/cjs/extensions/codemirror/tests/codemirrorTestHelper.js.map +1 -1
- package/dist/cjs/extensions/codemirror/toolbars/commands/markdown.command.js +278 -0
- package/dist/cjs/extensions/codemirror/toolbars/commands/markdown.command.js.map +1 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js +47 -0
- package/dist/cjs/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -0
- package/dist/cjs/extensions/codemirror/types.js +3 -0
- package/dist/cjs/extensions/codemirror/types.js.map +1 -0
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js +140 -41
- package/dist/cjs/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/cjs/extensions/react-flow/nodes/nodeUtils.js +5 -6
- package/dist/cjs/extensions/react-flow/nodes/nodeUtils.js.map +1 -1
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js +7 -2
- package/dist/esm/cmem/ActivityControl/ActivityControlWidget.js.map +1 -1
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js +4 -4
- package/dist/esm/cmem/react-flow/StickyNoteModal/StickyNoteModal.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js +13 -3
- package/dist/esm/components/AutoSuggestion/AutoSuggestion.js.map +1 -1
- package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js +14 -3
- package/dist/esm/components/AutoSuggestion/ExtendedCodeEditor.js.map +1 -1
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js +4 -3
- package/dist/esm/components/AutocompleteField/AutoCompleteField.js.map +1 -1
- package/dist/esm/components/Card/CardActions.js +2 -1
- package/dist/esm/components/Card/CardActions.js.map +1 -1
- package/dist/esm/components/Card/CardContent.js +4 -5
- package/dist/esm/components/Card/CardContent.js.map +1 -1
- package/dist/esm/components/ContentGroup/ContentGroup.js +100 -0
- package/dist/esm/components/ContentGroup/ContentGroup.js.map +1 -0
- package/dist/esm/components/Dialog/SimpleDialog.js +4 -4
- package/dist/esm/components/Dialog/SimpleDialog.js.map +1 -1
- package/dist/esm/components/Icon/canonicalIconNames.js +12 -0
- package/dist/esm/components/Icon/canonicalIconNames.js.map +1 -1
- package/dist/esm/components/Label/Label.js +8 -3
- package/dist/esm/components/Label/Label.js.map +1 -1
- package/dist/esm/components/Menu/MenuItem.js +3 -2
- package/dist/esm/components/Menu/MenuItem.js.map +1 -1
- package/dist/esm/components/MultiSelect/MultiSelect.js +1 -0
- package/dist/esm/components/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/OverviewItem/OverviewItem.js +5 -2
- package/dist/esm/components/OverviewItem/OverviewItem.js.map +1 -1
- package/dist/esm/components/OverviewItem/OverviewItemList.js +2 -2
- package/dist/esm/components/OverviewItem/OverviewItemList.js.map +1 -1
- package/dist/esm/components/Switch/Switch.js +7 -5
- package/dist/esm/components/Switch/Switch.js.map +1 -1
- package/dist/esm/components/Tag/TagList.js +1 -1
- package/dist/esm/components/Tag/TagList.js.map +1 -1
- package/dist/esm/components/TextField/SearchField.js +35 -2
- package/dist/esm/components/TextField/SearchField.js.map +1 -1
- package/dist/esm/components/Typography/OverflowText.js +1 -1
- package/dist/esm/components/Typography/OverflowText.js.map +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/extensions/codemirror/CodeMirror.js +94 -13
- package/dist/esm/extensions/codemirror/CodeMirror.js.map +1 -1
- package/dist/esm/extensions/codemirror/debouncedLinter.js +15 -0
- package/dist/esm/extensions/codemirror/debouncedLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js +20 -11
- package/dist/esm/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.js.map +1 -1
- package/dist/esm/extensions/codemirror/linters/jsLinter.js +32 -0
- package/dist/esm/extensions/codemirror/linters/jsLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/linters/turtleLinter.js +77 -0
- package/dist/esm/extensions/codemirror/linters/turtleLinter.js.map +1 -0
- package/dist/esm/extensions/codemirror/tests/codemirrorTestHelper.js +4 -0
- package/dist/esm/extensions/codemirror/tests/codemirrorTestHelper.js.map +1 -1
- package/dist/esm/extensions/codemirror/toolbars/commands/markdown.command.js +283 -0
- package/dist/esm/extensions/codemirror/toolbars/commands/markdown.command.js.map +1 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js +41 -0
- package/dist/esm/extensions/codemirror/toolbars/markdown.toolbar.js.map +1 -0
- package/dist/esm/extensions/codemirror/types.js +2 -0
- package/dist/esm/extensions/codemirror/types.js.map +1 -0
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js +149 -48
- package/dist/esm/extensions/react-flow/nodes/NodeContent.js.map +1 -1
- package/dist/esm/extensions/react-flow/nodes/nodeUtils.js +5 -6
- package/dist/esm/extensions/react-flow/nodes/nodeUtils.js.map +1 -1
- package/dist/types/cmem/ActivityControl/ActivityControlWidget.d.ts +1 -1
- package/dist/types/cmem/react-flow/StickyNoteModal/StickyNoteModal.d.ts +5 -1
- package/dist/types/components/AutoSuggestion/ExtendedCodeEditor.d.ts +11 -6
- package/dist/types/components/Card/CardActions.d.ts +5 -1
- package/dist/types/components/Card/CardContent.d.ts +1 -2
- package/dist/types/components/ContentGroup/ContentGroup.d.ts +78 -0
- package/dist/types/components/Dialog/SimpleDialog.d.ts +4 -1
- package/dist/types/components/Icon/canonicalIconNames.d.ts +12 -0
- package/dist/types/components/Label/Label.d.ts +7 -1
- package/dist/types/components/Menu/MenuItem.d.ts +8 -1
- package/dist/types/components/OverviewItem/OverviewItem.d.ts +13 -1
- package/dist/types/components/OverviewItem/OverviewItemList.d.ts +3 -2
- package/dist/types/components/ProgressBar/ProgressBar.d.ts +2 -2
- package/dist/types/components/Structure/TitleSubsection.d.ts +9 -1
- package/dist/types/components/Switch/Switch.d.ts +3 -3
- package/dist/types/components/Tabs/Tab.d.ts +20 -4
- package/dist/types/components/TextField/SearchField.d.ts +1 -1
- package/dist/types/components/Typography/OverflowText.d.ts +23 -2
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/extensions/codemirror/CodeMirror.d.ts +32 -5
- package/dist/types/extensions/codemirror/debouncedLinter.d.ts +4 -0
- package/dist/types/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.d.ts +7 -5
- package/dist/types/extensions/codemirror/linters/jsLinter.d.ts +5 -0
- package/dist/types/extensions/codemirror/linters/turtleLinter.d.ts +5 -0
- package/dist/types/extensions/codemirror/tests/codemirrorTestHelper.d.ts +1 -0
- package/dist/types/extensions/codemirror/toolbars/commands/markdown.command.d.ts +55 -0
- package/dist/types/extensions/codemirror/toolbars/markdown.toolbar.d.ts +12 -0
- package/dist/types/extensions/codemirror/types.d.ts +5 -0
- package/dist/types/extensions/react-flow/nodes/NodeContent.d.ts +18 -4
- package/dist/types/extensions/react-flow/nodes/nodeUtils.d.ts +7 -6
- package/dist/types/extensions/react-flow/versionsupport.d.ts +1 -1
- package/package.json +59 -47
- package/src/cmem/ActivityControl/ActivityControlWidget.tsx +5 -2
- package/src/cmem/react-flow/StickyNoteModal/StickyNoteModal.tsx +16 -2
- package/src/cmem/react-flow/configuration/_colors-graph.scss +4 -1
- package/src/cmem/react-flow/configuration/_colors-workflow.scss +3 -0
- package/src/components/AutoSuggestion/AutoSuggestion.tsx +14 -3
- package/src/components/AutoSuggestion/ExtendedCodeEditor.tsx +29 -6
- package/src/components/AutocompleteField/AutoCompleteField.tsx +5 -3
- package/src/components/Card/CardActions.tsx +6 -0
- package/src/components/Card/CardContent.tsx +8 -4
- package/src/components/Card/card.scss +15 -0
- package/src/components/CodeAutocompleteField/CodeAutocompleteField.stories.tsx +3 -2
- package/src/components/ContentGroup/ContentGroup.stories.tsx +47 -0
- package/src/components/ContentGroup/ContentGroup.tsx +256 -0
- package/src/components/ContentGroup/_contentgroup.scss +56 -0
- package/src/components/ContextOverlay/ContextOverlay.stories.tsx +15 -4
- package/src/components/Depiction/depiction.scss +7 -0
- package/src/components/Dialog/SimpleDialog.tsx +9 -2
- package/src/components/Dialog/stories/AlertDialog.stories.tsx +5 -1
- package/src/components/Dialog/stories/Modal.stories.tsx +4 -2
- package/src/components/Dialog/stories/SimpleDialog.stories.tsx +5 -2
- package/src/components/Icon/canonicalIconNames.tsx +12 -0
- package/src/components/Label/Label.stories.tsx +2 -1
- package/src/components/Label/Label.tsx +17 -1
- package/src/components/Label/label.scss +5 -1
- package/src/components/Menu/MenuItem.tsx +27 -1
- package/src/components/Menu/menu.scss +1 -0
- package/src/components/MultiSelect/MultiSelect.tsx +1 -0
- package/src/components/OverviewItem/OverviewItem.tsx +24 -1
- package/src/components/OverviewItem/OverviewItemList.tsx +3 -2
- package/src/components/OverviewItem/overviewitem.scss +4 -1
- package/src/components/OverviewItem/stories/OverviewItem.stories.tsx +6 -12
- package/src/components/Select/Select.stories.tsx +4 -1
- package/src/components/Switch/Switch.tsx +27 -8
- package/src/components/Tag/TagList.tsx +2 -2
- package/src/components/TextField/SearchField.tsx +37 -9
- package/src/components/TextField/stories/SearchField.stories.tsx +15 -1
- package/src/components/TextField/stories/TextField.stories.tsx +2 -1
- package/src/components/TextField/textfield.scss +17 -3
- package/src/components/Typography/OverflowText.tsx +24 -3
- package/src/components/Typography/stories/OverflowText.stories.tsx +33 -0
- package/src/components/index.scss +1 -0
- package/src/components/index.ts +1 -0
- package/src/extensions/codemirror/CodeMirror.stories.tsx +19 -1
- package/src/extensions/codemirror/CodeMirror.tsx +154 -16
- package/src/extensions/codemirror/_codemirror.scss +130 -1
- package/src/extensions/codemirror/debouncedLinter.ts +26 -0
- package/src/extensions/codemirror/hooks/useCodemirrorModeExtension.hooks.ts +21 -12
- package/src/extensions/codemirror/linters/jsLinter.ts +38 -0
- package/src/extensions/codemirror/linters/turtleLinter.ts +102 -0
- package/src/extensions/codemirror/tests/codemirrorTestHelper.ts +4 -0
- package/src/extensions/codemirror/toolbars/commands/markdown.command.ts +340 -0
- package/src/extensions/codemirror/toolbars/markdown.toolbar.tsx +117 -0
- package/src/extensions/codemirror/types.ts +7 -0
- package/src/extensions/react-flow/_config.scss +1 -0
- package/src/extensions/react-flow/nodes/NodeContent.tsx +170 -52
- package/src/extensions/react-flow/nodes/_nodes.scss +71 -35
- package/src/extensions/react-flow/nodes/nodeUtils.tsx +16 -14
- package/src/extensions/react-flow/nodes/stories/NodeContent.stories.tsx +51 -12
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import React, { useRef } from "react";
|
|
1
|
+
import React, { useMemo, useRef } from "react";
|
|
2
2
|
import { defaultKeymap, indentWithTab } from "@codemirror/commands";
|
|
3
3
|
import { foldKeymap } from "@codemirror/language";
|
|
4
4
|
import { EditorState, Extension } from "@codemirror/state";
|
|
5
5
|
import { DOMEventHandlers, EditorView, KeyBinding, keymap, Rect, ViewUpdate } from "@codemirror/view";
|
|
6
6
|
import { minimalSetup } from "codemirror";
|
|
7
7
|
|
|
8
|
+
import { IntentTypes } from "../../common/Intent";
|
|
8
9
|
import { markField } from "../../components/AutoSuggestion/extensions/markText";
|
|
10
|
+
import { TestableComponent } from "../../components/interfaces";
|
|
11
|
+
import { MarkdownToolbar } from "./toolbars/markdown.toolbar";
|
|
12
|
+
import { Markdown } from "../../cmem/markdown/Markdown";
|
|
9
13
|
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
|
|
10
14
|
|
|
11
15
|
//hooks
|
|
@@ -14,6 +18,8 @@ import {
|
|
|
14
18
|
supportedCodeEditorModes,
|
|
15
19
|
useCodeMirrorModeExtension,
|
|
16
20
|
} from "./hooks/useCodemirrorModeExtension.hooks";
|
|
21
|
+
import { jsLinter } from "./linters/jsLinter";
|
|
22
|
+
import { turtleLinter } from "./linters/turtleLinter";
|
|
17
23
|
//adaptations
|
|
18
24
|
import {
|
|
19
25
|
adaptedCodeFolding,
|
|
@@ -23,12 +29,14 @@ import {
|
|
|
23
29
|
adaptedHighlightActiveLine,
|
|
24
30
|
adaptedHighlightSpecialChars,
|
|
25
31
|
adaptedLineNumbers,
|
|
32
|
+
adaptedLintGutter,
|
|
26
33
|
adaptedPlaceholder,
|
|
27
34
|
} from "./tests/codemirrorTestHelper";
|
|
35
|
+
import { ExtensionCreator } from "./types";
|
|
28
36
|
|
|
29
|
-
export interface CodeEditorProps {
|
|
37
|
+
export interface CodeEditorProps extends TestableComponent {
|
|
30
38
|
// Is called with the editor instance that allows access via the CodeMirror API
|
|
31
|
-
setEditorView?: (editor: EditorView | undefined) =>
|
|
39
|
+
setEditorView?: (editor: EditorView | undefined) => void;
|
|
32
40
|
/**
|
|
33
41
|
* `name` attribute of connected textarea element.
|
|
34
42
|
*/
|
|
@@ -50,7 +58,7 @@ export interface CodeEditorProps {
|
|
|
50
58
|
/**
|
|
51
59
|
* Called when the focus status changes
|
|
52
60
|
*/
|
|
53
|
-
onFocusChange?: (focused: boolean) =>
|
|
61
|
+
onFocusChange?: (focused: boolean) => void;
|
|
54
62
|
/**
|
|
55
63
|
* Called when the user presses a key
|
|
56
64
|
*/
|
|
@@ -62,7 +70,7 @@ export interface CodeEditorProps {
|
|
|
62
70
|
/**
|
|
63
71
|
* Called when the user selects text
|
|
64
72
|
*/
|
|
65
|
-
onSelection?: (ranges: { from: number; to: number }[]) =>
|
|
73
|
+
onSelection?: (ranges: { from: number; to: number }[]) => void;
|
|
66
74
|
/**
|
|
67
75
|
* Called when the cursor position changes
|
|
68
76
|
*/
|
|
@@ -71,7 +79,6 @@ export interface CodeEditorProps {
|
|
|
71
79
|
/**
|
|
72
80
|
* Syntax mode of the code editor.
|
|
73
81
|
*/
|
|
74
|
-
|
|
75
82
|
mode?: SupportedCodeEditorModes;
|
|
76
83
|
/**
|
|
77
84
|
* Default value used first when the editor is instanciated.
|
|
@@ -133,6 +140,32 @@ export interface CodeEditorProps {
|
|
|
133
140
|
* If the <Tab> key is enabled as normal input, i.e. it won't have the behavior of changing to the next input element, expected in a web app.
|
|
134
141
|
*/
|
|
135
142
|
enableTab?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Enables linting feature in the editor ("turtle" and "javascript" modes can use linting currently).
|
|
145
|
+
*/
|
|
146
|
+
useLinting?: boolean;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Autofocus the editor when it is rendered
|
|
150
|
+
*/
|
|
151
|
+
autoFocus?: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Intent state of the code editor.
|
|
154
|
+
*/
|
|
155
|
+
intent?: IntentTypes | "edited" | "removed";
|
|
156
|
+
/**
|
|
157
|
+
* Disables the editor.
|
|
158
|
+
*/
|
|
159
|
+
disabled?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Add toolbar for mode.
|
|
162
|
+
* Currently only `markdown` is supported.
|
|
163
|
+
*/
|
|
164
|
+
useToolbar?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Get the translation for a specific key
|
|
167
|
+
*/
|
|
168
|
+
translate?: (key: string) => string | false;
|
|
136
169
|
}
|
|
137
170
|
|
|
138
171
|
const addExtensionsFor = (flag: boolean, ...extensions: Extension[]) => (flag ? [...extensions] : []);
|
|
@@ -140,6 +173,13 @@ const addToKeyMapConfigFor = (flag: boolean, ...keys: any) => (flag ? [...keys]
|
|
|
140
173
|
const addHandlersFor = (flag: boolean, handlerName: string, handler: any) =>
|
|
141
174
|
flag ? ({ [handlerName]: handler } as DOMEventHandlers<any>) : {};
|
|
142
175
|
|
|
176
|
+
const ModeLinterMap: ReadonlyMap<SupportedCodeEditorModes, ReadonlyArray<ExtensionCreator>> = new Map([
|
|
177
|
+
["turtle", [turtleLinter]],
|
|
178
|
+
["javascript", [jsLinter]],
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
const ModeToolbarSupport: ReadonlyArray<SupportedCodeEditorModes> = ["markdown"];
|
|
182
|
+
|
|
143
183
|
/**
|
|
144
184
|
* Includes a code editor, currently we use CodeMirror library as base.
|
|
145
185
|
*/
|
|
@@ -170,8 +210,33 @@ export const CodeEditor = ({
|
|
|
170
210
|
tabForceSpaceForModes = ["python", "yaml"],
|
|
171
211
|
enableTab = false,
|
|
172
212
|
height,
|
|
213
|
+
useLinting = false,
|
|
214
|
+
"data-test-id": dataTestId,
|
|
215
|
+
autoFocus = false,
|
|
216
|
+
disabled = false,
|
|
217
|
+
intent,
|
|
218
|
+
useToolbar,
|
|
219
|
+
translate,
|
|
220
|
+
...otherCodeEditorProps
|
|
173
221
|
}: CodeEditorProps) => {
|
|
174
222
|
const parent = useRef<any>(undefined);
|
|
223
|
+
const [view, setView] = React.useState<EditorView | undefined>();
|
|
224
|
+
const [showPreview, setShowPreview] = React.useState<boolean>(false);
|
|
225
|
+
|
|
226
|
+
const linters = useMemo(() => {
|
|
227
|
+
if (!mode) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const values = [adaptedLintGutter()];
|
|
232
|
+
|
|
233
|
+
const linters = ModeLinterMap.get(mode);
|
|
234
|
+
if (linters) {
|
|
235
|
+
values.push(...linters.map((linter) => linter()));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return values;
|
|
239
|
+
}, [mode]);
|
|
175
240
|
|
|
176
241
|
const onKeyDownHandler = (event: KeyboardEvent, view: EditorView) => {
|
|
177
242
|
if (onKeyDown && !onKeyDown(event)) {
|
|
@@ -192,6 +257,14 @@ export const CodeEditor = ({
|
|
|
192
257
|
}
|
|
193
258
|
};
|
|
194
259
|
|
|
260
|
+
const getTranslation = (key: string): string | false => {
|
|
261
|
+
if (translate && typeof translate === "function") {
|
|
262
|
+
return translate(key);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return false;
|
|
266
|
+
};
|
|
267
|
+
|
|
195
268
|
React.useEffect(() => {
|
|
196
269
|
const tabIndent =
|
|
197
270
|
!!(tabIntentStyle === "tab" && mode && !(tabForceSpaceForModes ?? []).includes(mode)) || enableTab;
|
|
@@ -219,13 +292,23 @@ export const CodeEditor = ({
|
|
|
219
292
|
keymap?.of(keyMapConfigs),
|
|
220
293
|
EditorState?.tabSize.of(tabIntentSize),
|
|
221
294
|
EditorState?.readOnly.of(readOnly),
|
|
295
|
+
EditorView?.editable.of(!disabled),
|
|
222
296
|
AdaptedEditorViewDomEventHandlers(domEventHandlers) as Extension,
|
|
223
297
|
EditorView?.updateListener.of((v: ViewUpdate) => {
|
|
224
|
-
|
|
298
|
+
if (disabled) return;
|
|
299
|
+
|
|
300
|
+
if (onChange && v.docChanged) {
|
|
301
|
+
// Only fire if the text has actually been changed
|
|
302
|
+
onChange(v.state.doc.toString());
|
|
303
|
+
}
|
|
225
304
|
|
|
226
305
|
if (onSelection)
|
|
227
306
|
onSelection(v.state.selection.ranges.filter((r) => !r.empty).map(({ from, to }) => ({ from, to })));
|
|
228
307
|
|
|
308
|
+
if (onFocusChange && intent && !v.view.dom.classList?.contains(`${eccgui}-intent--${intent}`)) {
|
|
309
|
+
v.view.dom.classList.add(`${eccgui}-intent--${intent}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
229
312
|
if (onCursorChange) {
|
|
230
313
|
const cursorPosition = v.state.selection.main.head ?? 0;
|
|
231
314
|
const editorRect = v.view.dom.getBoundingClientRect();
|
|
@@ -250,6 +333,7 @@ export const CodeEditor = ({
|
|
|
250
333
|
addExtensionsFor(shouldHighlightActiveLine, adaptedHighlightActiveLine()),
|
|
251
334
|
addExtensionsFor(wrapLines, EditorView?.lineWrapping),
|
|
252
335
|
addExtensionsFor(supportCodeFolding, adaptedFoldGutter(), adaptedCodeFolding()),
|
|
336
|
+
addExtensionsFor(useLinting, ...linters),
|
|
253
337
|
additionalExtensions,
|
|
254
338
|
];
|
|
255
339
|
|
|
@@ -260,18 +344,67 @@ export const CodeEditor = ({
|
|
|
260
344
|
}),
|
|
261
345
|
parent: parent.current,
|
|
262
346
|
});
|
|
347
|
+
setView(view);
|
|
263
348
|
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
349
|
+
if (view?.dom) {
|
|
350
|
+
if (height) {
|
|
351
|
+
view.dom.style.height = typeof height === "string" ? height : `${height}px`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (disabled) {
|
|
355
|
+
view.dom.className += ` ${eccgui}-disabled`;
|
|
356
|
+
}
|
|
267
357
|
|
|
268
|
-
|
|
358
|
+
if (intent) {
|
|
359
|
+
view.dom.className += ` ${eccgui}-intent--${intent}`;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (autoFocus) {
|
|
363
|
+
view.focus();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (setEditorView) {
|
|
367
|
+
setEditorView(view);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
269
370
|
|
|
270
371
|
return () => {
|
|
271
372
|
view.destroy();
|
|
272
|
-
|
|
373
|
+
if (setEditorView) {
|
|
374
|
+
setEditorView(undefined);
|
|
375
|
+
setView(undefined);
|
|
376
|
+
}
|
|
273
377
|
};
|
|
274
|
-
}, [parent.current, mode, preventLineNumbers]);
|
|
378
|
+
}, [parent.current, mode, preventLineNumbers, wrapLines]);
|
|
379
|
+
|
|
380
|
+
const hasToolbarSupport = mode && ModeToolbarSupport.indexOf(mode) > -1 && useToolbar;
|
|
381
|
+
|
|
382
|
+
const editorToolbar = (mode?: SupportedCodeEditorModes): JSX.Element => {
|
|
383
|
+
switch (mode) {
|
|
384
|
+
case "markdown":
|
|
385
|
+
return (
|
|
386
|
+
<div>
|
|
387
|
+
<div className={`${eccgui}-codeeditor__toolbar`}>
|
|
388
|
+
<MarkdownToolbar
|
|
389
|
+
view={view}
|
|
390
|
+
togglePreviewStatus={() => setShowPreview((p) => !p)}
|
|
391
|
+
showPreview={showPreview}
|
|
392
|
+
translate={getTranslation}
|
|
393
|
+
disabled={disabled}
|
|
394
|
+
readonly={readOnly}
|
|
395
|
+
/>
|
|
396
|
+
</div>
|
|
397
|
+
{showPreview && (
|
|
398
|
+
<div className={`${eccgui}-codeeditor__preview`}>
|
|
399
|
+
<Markdown>{view?.state.doc.toString() ?? ""}</Markdown>
|
|
400
|
+
</div>
|
|
401
|
+
)}
|
|
402
|
+
</div>
|
|
403
|
+
);
|
|
404
|
+
default:
|
|
405
|
+
return <></>;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
275
408
|
|
|
276
409
|
return (
|
|
277
410
|
<div
|
|
@@ -279,12 +412,17 @@ export const CodeEditor = ({
|
|
|
279
412
|
// overwrite/extend some attributes
|
|
280
413
|
id={id ? id : name ? `codemirror-${name}` : undefined}
|
|
281
414
|
ref={parent}
|
|
282
|
-
|
|
415
|
+
// @deprecated (v25) fallback with static test id will be removed
|
|
416
|
+
data-test-id={dataTestId ? dataTestId : "codemirror-wrapper"}
|
|
283
417
|
className={
|
|
284
418
|
`${eccgui}-codeeditor ${eccgui}-codeeditor--mode-${mode}` +
|
|
285
|
-
(outerDivAttributes?.className ? ` ${outerDivAttributes?.className}` : "")
|
|
419
|
+
(outerDivAttributes?.className ? ` ${outerDivAttributes?.className}` : "") +
|
|
420
|
+
(hasToolbarSupport ? ` ${eccgui}-codeeditor--has-toolbar` : "")
|
|
286
421
|
}
|
|
287
|
-
|
|
422
|
+
{...otherCodeEditorProps}
|
|
423
|
+
>
|
|
424
|
+
{hasToolbarSupport && editorToolbar(mode)}
|
|
425
|
+
</div>
|
|
288
426
|
);
|
|
289
427
|
};
|
|
290
428
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
@use "sass:color";
|
|
2
|
+
|
|
1
3
|
// own vars
|
|
2
4
|
$eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default;
|
|
5
|
+
$eccgui-color-codeeditor-separation: $eccgui-color-separation-divider !default;
|
|
6
|
+
$eccgui-size-codeeditor-height: 20rem !default;
|
|
7
|
+
$eccgui-size-codeeditor-toolbar-height: $button-height !default;
|
|
3
8
|
|
|
4
9
|
// adjustments
|
|
5
10
|
// stylelint-disable selector-class-pattern
|
|
@@ -12,9 +17,39 @@ $eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default
|
|
|
12
17
|
width: 100%;
|
|
13
18
|
}
|
|
14
19
|
|
|
20
|
+
&__toolbar {
|
|
21
|
+
position: absolute;
|
|
22
|
+
z-index: 3;
|
|
23
|
+
left: 1px;
|
|
24
|
+
right: 1px;
|
|
25
|
+
top: 1px;
|
|
26
|
+
border-radius: $pt-border-radius $pt-border-radius 0 0;
|
|
27
|
+
border-bottom: solid 1px $eccgui-color-codeeditor-separation;
|
|
28
|
+
background-color: $eccgui-color-codeeditor-background;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&--has-toolbar {
|
|
32
|
+
.cm-scroller {
|
|
33
|
+
margin-top: $eccgui-size-codeeditor-toolbar-height !important;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&__preview {
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: calc(#{$eccgui-size-codeeditor-toolbar-height} + 1px) !important;
|
|
40
|
+
left: 1px;
|
|
41
|
+
right: 1px;
|
|
42
|
+
bottom: 1px;
|
|
43
|
+
z-index: 2;
|
|
44
|
+
padding: $button-padding;
|
|
45
|
+
overflow-y: auto;
|
|
46
|
+
background-color: $eccgui-color-codeeditor-background;
|
|
47
|
+
border-radius: 0 0 $pt-border-radius $pt-border-radius;
|
|
48
|
+
}
|
|
49
|
+
|
|
15
50
|
.cm-editor {
|
|
16
51
|
width: 100%;
|
|
17
|
-
height:
|
|
52
|
+
height: $eccgui-size-codeeditor-height;
|
|
18
53
|
clip-path: unset !important; // we may check later why they set inset(0) now
|
|
19
54
|
background-color: $eccgui-color-codeeditor-background;
|
|
20
55
|
border-radius: $pt-border-radius;
|
|
@@ -22,6 +57,63 @@ $eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default
|
|
|
22
57
|
// get them a "border" like input boxes from blueprintjs
|
|
23
58
|
box-shadow: input-transition-shadow($input-shadow-color-focus), $pt-input-box-shadow;
|
|
24
59
|
|
|
60
|
+
&.#{eccgui}-disabled {
|
|
61
|
+
@extend .#{$ns}-input, .#{$ns}-disabled;
|
|
62
|
+
|
|
63
|
+
height: $eccgui-size-codeeditor-height;
|
|
64
|
+
padding: 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&[class*="#{$eccgui}-intent--"] {
|
|
68
|
+
animation-duration: 1s;
|
|
69
|
+
animation-delay: 0.5s;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@each $each-intent, $each-bgcolor in $eccgui-map-intent-bgcolors {
|
|
73
|
+
&.#{eccgui}-intent--#{$each-intent} {
|
|
74
|
+
background-color: color.mix($each-bgcolor, $eccgui-color-textfield-background, 24%);
|
|
75
|
+
animation-name: intent-state-flash-#{$each-intent};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.#{eccgui}-intent--warning {
|
|
80
|
+
@include pt-input-intent($eccgui-color-warning-text);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&.#{eccgui}-intent--success {
|
|
84
|
+
@include pt-input-intent($eccgui-color-success-text);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&.#{eccgui}-intent--danger {
|
|
88
|
+
@include pt-input-intent($eccgui-color-danger-text);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&.#{eccgui}-intent--primary {
|
|
92
|
+
@include pt-input-intent($eccgui-color-info-text);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
&.#{eccgui}-intent--info {
|
|
96
|
+
@include pt-input-intent($eccgui-color-info-text);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&.#{eccgui}-intent--accent {
|
|
100
|
+
@include pt-input-intent($eccgui-color-primary);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&.#{eccgui}-intent--neutral {
|
|
104
|
+
@include pt-input-intent($eccgui-color-workspace-text);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&.#{eccgui}-intent--edited {
|
|
108
|
+
@include pt-input-intent($eccgui-color-info-text);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&.#{eccgui}-intent--removed {
|
|
112
|
+
@include pt-input-intent($eccgui-color-danger-text);
|
|
113
|
+
|
|
114
|
+
text-decoration: line-through $eccgui-color-danger-text 2px;
|
|
115
|
+
}
|
|
116
|
+
|
|
25
117
|
.cm-scroller {
|
|
26
118
|
width: calc(100% - 2px);
|
|
27
119
|
height: calc(100% - 2px);
|
|
@@ -34,6 +126,43 @@ $eccgui-color-codeeditor-background: $eccgui-color-textfield-background !default
|
|
|
34
126
|
&.cm-focused {
|
|
35
127
|
outline: none;
|
|
36
128
|
box-shadow: input-transition-shadow($input-shadow-color-focus, true), $input-box-shadow-focus;
|
|
129
|
+
|
|
130
|
+
&.#{eccgui}-intent--warning {
|
|
131
|
+
box-shadow: input-transition-shadow($eccgui-color-warning-text, true), $input-box-shadow-focus;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&.#{eccgui}-intent--success {
|
|
135
|
+
box-shadow: input-transition-shadow($eccgui-color-success-text, true), $input-box-shadow-focus;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&.#{eccgui}-intent--danger {
|
|
139
|
+
box-shadow: input-transition-shadow($eccgui-color-danger-text, true), $input-box-shadow-focus;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&.#{eccgui}-intent--primary {
|
|
143
|
+
box-shadow: input-transition-shadow($eccgui-color-info-text, true), $input-box-shadow-focus;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
&.#{eccgui}-intent--info {
|
|
147
|
+
box-shadow: input-transition-shadow($eccgui-color-info-text, true), $input-box-shadow-focus;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
&.#{eccgui}-intent--accent {
|
|
151
|
+
box-shadow: input-transition-shadow($eccgui-color-warning-text, true), $input-box-shadow-focus;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&.#{eccgui}-intent--neutral {
|
|
155
|
+
box-shadow: input-transition-shadow($eccgui-color-workspace-text, true), $input-box-shadow-focus;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
&.#{eccgui}-intent--edited {
|
|
159
|
+
box-shadow: input-transition-shadow($eccgui-color-info-text, true), $input-box-shadow-focus;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
&.#{eccgui}-intent--removed {
|
|
163
|
+
text-decoration: line-through $eccgui-color-danger-text 2px;
|
|
164
|
+
box-shadow: input-transition-shadow($eccgui-color-danger-text, true), $input-box-shadow-focus;
|
|
165
|
+
}
|
|
37
166
|
}
|
|
38
167
|
|
|
39
168
|
.CodeMirror-hscrollbar {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Diagnostic } from "@codemirror/lint";
|
|
2
|
+
import { EditorView } from "@codemirror/view";
|
|
3
|
+
import { debounce } from "lodash";
|
|
4
|
+
|
|
5
|
+
import { Linter } from "./types";
|
|
6
|
+
|
|
7
|
+
const DEBOUNCE_TIME = 500;
|
|
8
|
+
|
|
9
|
+
export const debouncedLinter = (lintFunction: Linter, time = DEBOUNCE_TIME) => {
|
|
10
|
+
const debouncedFn = debounce(
|
|
11
|
+
(
|
|
12
|
+
view: EditorView,
|
|
13
|
+
resolve: (diagnostics: ReadonlyArray<Diagnostic> | Promise<ReadonlyArray<Diagnostic>>) => void
|
|
14
|
+
) => {
|
|
15
|
+
const diagnostics = lintFunction(view);
|
|
16
|
+
resolve(diagnostics);
|
|
17
|
+
},
|
|
18
|
+
time
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
return (view: EditorView) => {
|
|
22
|
+
return new Promise<ReadonlyArray<Diagnostic>>((resolve) => {
|
|
23
|
+
debouncedFn(view, resolve);
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//modes imports
|
|
4
|
-
import { markdown } from "@codemirror/lang-markdown";
|
|
1
|
+
//adapted v6 modes imports
|
|
2
|
+
import { javascript } from "@codemirror/lang-javascript";
|
|
5
3
|
import { json } from "@codemirror/lang-json";
|
|
4
|
+
import { markdown } from "@codemirror/lang-markdown";
|
|
5
|
+
import { sql } from "@codemirror/lang-sql";
|
|
6
6
|
import { xml } from "@codemirror/lang-xml";
|
|
7
|
-
import {
|
|
7
|
+
import { yaml } from "@codemirror/lang-yaml";
|
|
8
|
+
import { defaultHighlightStyle, LanguageSupport, StreamLanguage, StreamParser } from "@codemirror/language";
|
|
9
|
+
//legacy mode imports
|
|
10
|
+
import { jinja2 } from "@codemirror/legacy-modes/mode/jinja2";
|
|
11
|
+
import { mathematica } from "@codemirror/legacy-modes/mode/mathematica";
|
|
12
|
+
import { ntriples } from "@codemirror/legacy-modes/mode/ntriples";
|
|
8
13
|
import { python } from "@codemirror/legacy-modes/mode/python";
|
|
9
14
|
import { sparql } from "@codemirror/legacy-modes/mode/sparql";
|
|
10
|
-
import { sql } from "@codemirror/legacy-modes/mode/sql";
|
|
11
15
|
import { turtle } from "@codemirror/legacy-modes/mode/turtle";
|
|
12
|
-
import { jinja2 } from "@codemirror/legacy-modes/mode/jinja2";
|
|
13
|
-
import { yaml } from "@codemirror/legacy-modes/mode/yaml";
|
|
14
|
-
import { ntriples } from "@codemirror/legacy-modes/mode/ntriples";
|
|
15
|
-
import { mathematica } from "@codemirror/legacy-modes/mode/mathematica";
|
|
16
16
|
|
|
17
17
|
//adaptations
|
|
18
18
|
import { adaptedSyntaxHighlighting } from "../tests/codemirrorTestHelper";
|
|
@@ -35,10 +35,19 @@ const supportedModes = {
|
|
|
35
35
|
export const supportedCodeEditorModes = Object.keys(supportedModes) as Array<keyof typeof supportedModes>;
|
|
36
36
|
export type SupportedCodeEditorModes = (typeof supportedCodeEditorModes)[number];
|
|
37
37
|
|
|
38
|
+
const v6AdaptedModes: ReadonlyMap<SupportedCodeEditorModes, boolean> = new Map([
|
|
39
|
+
["json", true],
|
|
40
|
+
["markdown", true],
|
|
41
|
+
["xml", true],
|
|
42
|
+
["sql", true],
|
|
43
|
+
["yaml", true],
|
|
44
|
+
["javascript", true],
|
|
45
|
+
]);
|
|
46
|
+
|
|
38
47
|
export const useCodeMirrorModeExtension = (mode?: SupportedCodeEditorModes) => {
|
|
39
48
|
return !mode
|
|
40
49
|
? adaptedSyntaxHighlighting(defaultHighlightStyle)
|
|
41
|
-
:
|
|
42
|
-
? ((typeof supportedModes[mode] === "function" ? supportedModes[mode] : () =>
|
|
50
|
+
: v6AdaptedModes.has(mode)
|
|
51
|
+
? ((typeof supportedModes[mode] === "function" ? supportedModes[mode] : () => null) as () => LanguageSupport)()
|
|
43
52
|
: StreamLanguage?.define(supportedModes[mode] as StreamParser<unknown>);
|
|
44
53
|
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Diagnostic, linter } from "@codemirror/lint";
|
|
2
|
+
import { JSHINT as jshint } from "jshint";
|
|
3
|
+
|
|
4
|
+
import { ExtensionCreator } from "../types";
|
|
5
|
+
|
|
6
|
+
const lintOptions = {
|
|
7
|
+
esversion: 11,
|
|
8
|
+
browser: true,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sets up the javascript linter. Documentation: https://codemirror.net/examples/lint/
|
|
13
|
+
*/
|
|
14
|
+
export const jsLinter: ExtensionCreator = () => {
|
|
15
|
+
return linter((view) => {
|
|
16
|
+
const diagnostics: Array<Diagnostic> = [];
|
|
17
|
+
const codeText = view.state.doc.toJSON();
|
|
18
|
+
jshint(codeText, lintOptions);
|
|
19
|
+
const errors = jshint?.data()?.errors;
|
|
20
|
+
|
|
21
|
+
if (errors && errors.length > 0) {
|
|
22
|
+
errors.forEach((error) => {
|
|
23
|
+
const selectedLine = view.state.doc.line(error.line);
|
|
24
|
+
|
|
25
|
+
const diagnostic: Diagnostic = {
|
|
26
|
+
from: selectedLine.from,
|
|
27
|
+
to: selectedLine.to,
|
|
28
|
+
severity: "error",
|
|
29
|
+
message: error.reason,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
diagnostics.push(diagnostic);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return diagnostics;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Diagnostic, linter } from "@codemirror/lint";
|
|
2
|
+
import { EditorView } from "@codemirror/view";
|
|
3
|
+
import { Parser } from "n3";
|
|
4
|
+
|
|
5
|
+
import { debouncedLinter } from "../debouncedLinter";
|
|
6
|
+
import { ExtensionCreator, Linter } from "../types";
|
|
7
|
+
|
|
8
|
+
const parser = new Parser();
|
|
9
|
+
|
|
10
|
+
const EMPTY_RESOURCE = "<>";
|
|
11
|
+
|
|
12
|
+
const getError = (message: string, view: EditorView) => {
|
|
13
|
+
const lineMatch = message.match(/(?<=line )\d{1,}/);
|
|
14
|
+
const valueMatch = message.match(/"([^"]*)"/);
|
|
15
|
+
|
|
16
|
+
const lineNumber = lineMatch ? Number(lineMatch[0]) : 1;
|
|
17
|
+
// the [1] index is used to get the caputre group
|
|
18
|
+
const errorContent = valueMatch && valueMatch[1];
|
|
19
|
+
|
|
20
|
+
const line = view.state.doc.line(lineNumber);
|
|
21
|
+
const position = line.text.search(errorContent ?? /\S/);
|
|
22
|
+
|
|
23
|
+
const from = line.from + position;
|
|
24
|
+
const errorLength = errorContent?.length;
|
|
25
|
+
|
|
26
|
+
return { from, to: errorLength ? from + errorLength : line.to };
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getQuadError = (view: EditorView) => {
|
|
30
|
+
const lines = view.state.doc.toJSON();
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
33
|
+
const input = lines[i].trim();
|
|
34
|
+
|
|
35
|
+
if (!input) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (input.includes(EMPTY_RESOURCE)) {
|
|
40
|
+
// i + 1 is used here because the codemirror uses 1-indexes
|
|
41
|
+
const line = view.state.doc.line(i + 1);
|
|
42
|
+
const position = line.text.search(EMPTY_RESOURCE);
|
|
43
|
+
|
|
44
|
+
const from = line.from + position;
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
from,
|
|
48
|
+
to: from + EMPTY_RESOURCE.length,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { from: 0, to: view.state.doc.length };
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const n3Linter: Linter = (view) => {
|
|
57
|
+
const diagnostics: Array<Diagnostic> = [];
|
|
58
|
+
const value = view.state.doc.toString();
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const quads = parser.parse(value);
|
|
62
|
+
|
|
63
|
+
quads.forEach((quad) => {
|
|
64
|
+
if (!quad.subject || !quad.predicate || !quad.object) {
|
|
65
|
+
const { from, to } = getQuadError(view);
|
|
66
|
+
|
|
67
|
+
view.dispatch({
|
|
68
|
+
scrollIntoView: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
diagnostics.push({
|
|
72
|
+
from,
|
|
73
|
+
to,
|
|
74
|
+
severity: "error",
|
|
75
|
+
message: `Invalid RDF quad:\n\nsubject: ${quad.subject}\npredicate: ${quad.predicate}\nobject: ${quad.object}`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
const { message } = error as Error;
|
|
81
|
+
|
|
82
|
+
const { from, to } = getError(message, view);
|
|
83
|
+
|
|
84
|
+
view.dispatch({
|
|
85
|
+
scrollIntoView: true,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
diagnostics.push({
|
|
89
|
+
from,
|
|
90
|
+
to,
|
|
91
|
+
severity: "error",
|
|
92
|
+
message: (error as Error).message,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return diagnostics;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Sets up the turtle linter. Documentation: https://codemirror.net/examples/lint/
|
|
101
|
+
*/
|
|
102
|
+
export const turtleLinter: ExtensionCreator = () => linter(debouncedLinter(n3Linter));
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { EditorView, placeholder, highlightSpecialChars, lineNumbers, highlightActiveLine } from "@codemirror/view";
|
|
11
11
|
import { syntaxHighlighting, foldGutter, codeFolding } from "@codemirror/language";
|
|
12
12
|
import { Extension } from "@codemirror/state";
|
|
13
|
+
import { lintGutter } from "@codemirror/lint";
|
|
13
14
|
|
|
14
15
|
/** placeholder extension, current error '_view.placeholder is not a function' */
|
|
15
16
|
export const adaptedPlaceholder = (text?: string) =>
|
|
@@ -55,3 +56,6 @@ export const adaptedFoldGutter = (props?: any) =>
|
|
|
55
56
|
|
|
56
57
|
export const adaptedCodeFolding = (props?: any) =>
|
|
57
58
|
typeof codeFolding === "function" ? codeFolding(props) : emptyExtension;
|
|
59
|
+
|
|
60
|
+
export const adaptedLintGutter = (props?: any) =>
|
|
61
|
+
typeof lintGutter === "function" ? lintGutter(props) : emptyExtension;
|