aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/editor/exposeDiagnostics.ts
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/frontend/src/editor/exposeDiagnostics.ts')
-rw-r--r--subprojects/frontend/src/editor/exposeDiagnostics.ts80
1 files changed, 80 insertions, 0 deletions
diff --git a/subprojects/frontend/src/editor/exposeDiagnostics.ts b/subprojects/frontend/src/editor/exposeDiagnostics.ts
new file mode 100644
index 00000000..82f24c93
--- /dev/null
+++ b/subprojects/frontend/src/editor/exposeDiagnostics.ts
@@ -0,0 +1,80 @@
1import { setDiagnosticsEffect } from '@codemirror/lint';
2import {
3 StateField,
4 RangeSet,
5 type Extension,
6 type EditorState,
7} from '@codemirror/state';
8
9import DiagnosticValue, { type Severity } from './DiagnosticValue';
10
11type SeverityCounts = Partial<Record<Severity, number>>;
12
13interface ExposedDiagnostics {
14 readonly diagnostics: RangeSet<DiagnosticValue>;
15
16 readonly severityCounts: SeverityCounts;
17}
18
19function countSeverities(
20 diagnostics: RangeSet<DiagnosticValue>,
21): SeverityCounts {
22 const severityCounts: SeverityCounts = {};
23 const iter = diagnostics.iter();
24 while (iter.value !== null) {
25 const {
26 value: { severity },
27 } = iter;
28 severityCounts[severity] = (severityCounts[severity] ?? 0) + 1;
29 iter.next();
30 }
31 return severityCounts;
32}
33
34const exposedDiagnosticsState = StateField.define<ExposedDiagnostics>({
35 create() {
36 return {
37 diagnostics: RangeSet.of([]),
38 severityCounts: {},
39 };
40 },
41
42 update({ diagnostics: diagnosticsSet, severityCounts }, transaction) {
43 let newDiagnosticsSet = diagnosticsSet;
44 if (transaction.docChanged) {
45 newDiagnosticsSet = newDiagnosticsSet.map(transaction.changes);
46 }
47 transaction.effects.forEach((effect) => {
48 if (effect.is(setDiagnosticsEffect)) {
49 const diagnostics = effect.value.map(({ severity, from, to }) =>
50 DiagnosticValue.VALUES[severity].range(from, to),
51 );
52 diagnostics.sort(({ from: a }, { from: b }) => a - b);
53 newDiagnosticsSet = RangeSet.of(diagnostics);
54 }
55 });
56 return {
57 diagnostics: newDiagnosticsSet,
58 severityCounts:
59 // Only recompute if the diagnostics were changed.
60 diagnosticsSet === newDiagnosticsSet
61 ? severityCounts
62 : countSeverities(newDiagnosticsSet),
63 };
64 },
65});
66
67const exposeDiagnostics: Extension = [exposedDiagnosticsState];
68
69export default exposeDiagnostics;
70
71export function getDiagnostics(state: EditorState): RangeSet<DiagnosticValue> {
72 return state.field(exposedDiagnosticsState).diagnostics;
73}
74
75export function countDiagnostics(
76 state: EditorState,
77 severity: Severity,
78): number {
79 return state.field(exposedDiagnosticsState).severityCounts[severity] ?? 0;
80}