aboutsummaryrefslogtreecommitdiffstats
path: root/language-web/src/main/js/editor
diff options
context:
space:
mode:
Diffstat (limited to 'language-web/src/main/js/editor')
-rw-r--r--language-web/src/main/js/editor/EditorParent.ts6
-rw-r--r--language-web/src/main/js/editor/EditorStore.ts17
-rw-r--r--language-web/src/main/js/editor/decorationSetExtension.ts39
-rw-r--r--language-web/src/main/js/editor/findOccurrences.ts35
-rw-r--r--language-web/src/main/js/editor/semanticHighlighting.ts50
5 files changed, 113 insertions, 34 deletions
diff --git a/language-web/src/main/js/editor/EditorParent.ts b/language-web/src/main/js/editor/EditorParent.ts
index ea8c13b6..b890ac3c 100644
--- a/language-web/src/main/js/editor/EditorParent.ts
+++ b/language-web/src/main/js/editor/EditorParent.ts
@@ -190,5 +190,11 @@ export const EditorParent = styled('div')(({ theme }) => {
190 textAlign: 'center', 190 textAlign: 'center',
191 }, 191 },
192 ...codeMirrorLintStyle, 192 ...codeMirrorLintStyle,
193 '.cm-problem-write': {
194 background: 'rgba(255, 255, 128, 0.3)',
195 },
196 '.cm-problem-read': {
197 background: 'rgba(255, 255, 255, 0.15)',
198 },
193 }; 199 };
194}); 200});
diff --git a/language-web/src/main/js/editor/EditorStore.ts b/language-web/src/main/js/editor/EditorStore.ts
index f47f47a0..8788e00f 100644
--- a/language-web/src/main/js/editor/EditorStore.ts
+++ b/language-web/src/main/js/editor/EditorStore.ts
@@ -30,7 +30,6 @@ import {
30 TransactionSpec, 30 TransactionSpec,
31} from '@codemirror/state'; 31} from '@codemirror/state';
32import { 32import {
33 DecorationSet,
34 drawSelection, 33 drawSelection,
35 EditorView, 34 EditorView,
36 highlightActiveLine, 35 highlightActiveLine,
@@ -43,8 +42,13 @@ import {
43 reaction, 42 reaction,
44} from 'mobx'; 43} from 'mobx';
45 44
45import { findOccurrences, IOccurrence, setOccurrences } from './findOccurrences';
46import { problemLanguageSupport } from '../language/problemLanguageSupport'; 46import { problemLanguageSupport } from '../language/problemLanguageSupport';
47import { semanticHighlighting, setSemanticHighlighting } from './semanticHighlighting'; 47import {
48 IHighlightRange,
49 semanticHighlighting,
50 setSemanticHighlighting,
51} from './semanticHighlighting';
48import type { ThemeStore } from '../theme/ThemeStore'; 52import type { ThemeStore } from '../theme/ThemeStore';
49import { getLogger } from '../utils/logger'; 53import { getLogger } from '../utils/logger';
50import { XtextClient } from '../xtext/XtextClient'; 54import { XtextClient } from '../xtext/XtextClient';
@@ -95,6 +99,7 @@ export class EditorStore {
95 EditorView.theme({}, { 99 EditorView.theme({}, {
96 dark: this.themeStore.darkMode, 100 dark: this.themeStore.darkMode,
97 }), 101 }),
102 findOccurrences,
98 highlightActiveLine(), 103 highlightActiveLine(),
99 highlightActiveLineGutter(), 104 highlightActiveLineGutter(),
100 highlightSpecialChars(), 105 highlightSpecialChars(),
@@ -204,8 +209,12 @@ export class EditorStore {
204 return null; 209 return null;
205 } 210 }
206 211
207 updateSemanticHighlighting(decorations: DecorationSet): void { 212 updateSemanticHighlighting(ranges: IHighlightRange[]): void {
208 this.dispatch(setSemanticHighlighting(decorations)); 213 this.dispatch(setSemanticHighlighting(ranges));
214 }
215
216 updateOccurrences(write: IOccurrence[], read: IOccurrence[]): void {
217 this.dispatch(setOccurrences(write, read));
209 } 218 }
210 219
211 /** 220 /**
diff --git a/language-web/src/main/js/editor/decorationSetExtension.ts b/language-web/src/main/js/editor/decorationSetExtension.ts
new file mode 100644
index 00000000..2d630c20
--- /dev/null
+++ b/language-web/src/main/js/editor/decorationSetExtension.ts
@@ -0,0 +1,39 @@
1import { StateEffect, StateField, TransactionSpec } from '@codemirror/state';
2import { EditorView, Decoration, DecorationSet } from '@codemirror/view';
3
4export type TransactionSpecFactory = (decorations: DecorationSet) => TransactionSpec;
5
6export function decorationSetExtension(): [TransactionSpecFactory, StateField<DecorationSet>] {
7 const setEffect = StateEffect.define<DecorationSet>();
8 const field = StateField.define<DecorationSet>({
9 create() {
10 return Decoration.none;
11 },
12 update(currentDecorations, transaction) {
13 let newDecorations: DecorationSet | null = null;
14 transaction.effects.forEach((effect) => {
15 if (effect.is(setEffect)) {
16 newDecorations = effect.value;
17 }
18 });
19 if (newDecorations === null) {
20 if (transaction.docChanged) {
21 return currentDecorations.map(transaction.changes);
22 }
23 return currentDecorations;
24 }
25 return newDecorations;
26 },
27 provide: (f) => EditorView.decorations.from(f),
28 });
29
30 function transactionSpecFactory(decorations: DecorationSet) {
31 return {
32 effects: [
33 setEffect.of(decorations),
34 ],
35 };
36 }
37
38 return [transactionSpecFactory, field];
39}
diff --git a/language-web/src/main/js/editor/findOccurrences.ts b/language-web/src/main/js/editor/findOccurrences.ts
new file mode 100644
index 00000000..92102746
--- /dev/null
+++ b/language-web/src/main/js/editor/findOccurrences.ts
@@ -0,0 +1,35 @@
1import { Range, RangeSet } from '@codemirror/rangeset';
2import type { TransactionSpec } from '@codemirror/state';
3import { Decoration } from '@codemirror/view';
4
5import { decorationSetExtension } from './decorationSetExtension';
6
7export interface IOccurrence {
8 from: number;
9
10 to: number;
11}
12
13const [setOccurrencesInteral, findOccurrences] = decorationSetExtension();
14
15const writeDecoration = Decoration.mark({
16 class: 'cm-problem-write',
17});
18
19const readDecoration = Decoration.mark({
20 class: 'cm-problem-read',
21});
22
23export function setOccurrences(write: IOccurrence[], read: IOccurrence[]): TransactionSpec {
24 const decorations: Range<Decoration>[] = [];
25 write.forEach(({ from, to }) => {
26 decorations.push(writeDecoration.range(from, to));
27 });
28 read.forEach(({ from, to }) => {
29 decorations.push(readDecoration.range(from, to));
30 });
31 const rangeSet = RangeSet.of(decorations, true);
32 return setOccurrencesInteral(rangeSet);
33}
34
35export { findOccurrences };
diff --git a/language-web/src/main/js/editor/semanticHighlighting.ts b/language-web/src/main/js/editor/semanticHighlighting.ts
index 2d6804f8..2aed421b 100644
--- a/language-web/src/main/js/editor/semanticHighlighting.ts
+++ b/language-web/src/main/js/editor/semanticHighlighting.ts
@@ -1,34 +1,24 @@
1import { StateEffect, StateField, TransactionSpec } from '@codemirror/state'; 1import { RangeSet } from '@codemirror/rangeset';
2import { EditorView, Decoration, DecorationSet } from '@codemirror/view'; 2import type { TransactionSpec } from '@codemirror/state';
3import { Decoration } from '@codemirror/view';
3 4
4const setSemanticHighlightingEffect = StateEffect.define<DecorationSet>(); 5import { decorationSetExtension } from './decorationSetExtension';
5 6
6export function setSemanticHighlighting(decorations: DecorationSet): TransactionSpec { 7export interface IHighlightRange {
7 return { 8 from: number;
8 effects: [ 9
9 setSemanticHighlightingEffect.of(decorations), 10 to: number;
10 ], 11
11 }; 12 classes: string[];
13}
14
15const [setSemanticHighlightingInternal, semanticHighlighting] = decorationSetExtension();
16
17export function setSemanticHighlighting(ranges: IHighlightRange[]): TransactionSpec {
18 const rangeSet = RangeSet.of(ranges.map(({ from, to, classes }) => Decoration.mark({
19 class: classes.map((c) => `cmt-problem-${c}`).join(' '),
20 }).range(from, to)), true);
21 return setSemanticHighlightingInternal(rangeSet);
12} 22}
13 23
14export const semanticHighlighting = StateField.define<DecorationSet>({ 24export { semanticHighlighting };
15 create() {
16 return Decoration.none;
17 },
18 update(currentDecorations, transaction) {
19 let newDecorations: DecorationSet | null = null;
20 transaction.effects.forEach((effect) => {
21 if (effect.is(setSemanticHighlightingEffect)) {
22 newDecorations = effect.value;
23 }
24 });
25 if (newDecorations === null) {
26 if (transaction.docChanged) {
27 return currentDecorations.map(transaction.changes);
28 }
29 return currentDecorations;
30 }
31 return newDecorations;
32 },
33 provide: (f) => EditorView.decorations.from(f),
34});