-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheditor-config.ts
More file actions
94 lines (79 loc) · 2.92 KB
/
editor-config.ts
File metadata and controls
94 lines (79 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
import { bracketMatching } from "@codemirror/language";
import { EditorState, type Extension } from "@codemirror/state";
import { EditorView, keymap, placeholder } from "@codemirror/view";
import { celLanguageSupport } from "@seljs/cel-lezer";
import { SELChecker } from "@seljs/checker";
import { selDarkTheme, selLightTheme } from "./theme";
import { createTypeDisplay } from "./type-display";
import { createSchemaCompletion } from "../completion";
import { createTokenizerConfig } from "../language";
import { createSemanticHighlighter } from "../language/semantic-highlighter";
import { createSELLinter } from "../linting";
import type { SELEditorConfig, SELEditorFeatures } from "./types";
const resolveFeatures = (features?: SELEditorFeatures) => ({
linting: features?.linting ?? true,
autocomplete: features?.autocomplete ?? true,
semanticHighlighting: features?.semanticHighlighting ?? true,
typeDisplay: features?.typeDisplay ?? false,
});
export const buildExtensions = (config: SELEditorConfig): Extension[] => {
const checker = new SELChecker(config.schema, config.checkerOptions);
const resolved = resolveFeatures(config.features);
const extensions: Extension[] = [];
// Language support (includes syntax highlighting)
extensions.push(celLanguageSupport(config.dark));
extensions.push(bracketMatching());
// Semantic highlighting (schema-aware identifier coloring)
if (resolved.semanticHighlighting) {
const tokenizerConfig = createTokenizerConfig(config.schema);
extensions.push(createSemanticHighlighter(tokenizerConfig, config.dark));
}
// Autocomplete (type-aware via checker)
if (resolved.autocomplete) {
extensions.push(createSchemaCompletion(config.schema, checker));
extensions.push(closeBrackets());
}
// Keybindings
extensions.push(
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap]),
);
extensions.push(history());
// Theme
extensions.push(config.dark ? selDarkTheme : selLightTheme);
// Validation / linting
if (resolved.linting) {
extensions.push(
createSELLinter({
validate: (expression: string) => checker.check(expression).diagnostics,
}),
);
}
// onChange listener with validity
if (config.onChange) {
const onChange = config.onChange;
extensions.push(
EditorView.updateListener.of((update) => {
if (update.docChanged) {
const value = update.state.doc.toString();
const result = checker.check(value);
onChange(value, result.valid);
}
}),
);
}
// Read-only
if (config.readOnly) {
extensions.push(EditorState.readOnly.of(true));
}
// Placeholder
if (config.placeholder) {
extensions.push(placeholder(config.placeholder));
}
// Type display panel
if (resolved.typeDisplay) {
extensions.push(createTypeDisplay(checker, config.dark ?? false));
}
return extensions;
};