355 lines
11 KiB
TypeScript
355 lines
11 KiB
TypeScript
import { Prec } from "@codemirror/state";
|
|
import { indentWithTab } from "@codemirror/commands";
|
|
import { tags as t } from "@lezer/highlight";
|
|
import {
|
|
keymap,
|
|
lineNumbers,
|
|
highlightSpecialChars,
|
|
drawSelection,
|
|
highlightActiveLine,
|
|
dropCursor,
|
|
highlightActiveLineGutter,
|
|
} from "@codemirror/view";
|
|
import { Extension, EditorState } from "@codemirror/state";
|
|
import { vim } from "@replit/codemirror-vim";
|
|
import {
|
|
defaultHighlightStyle,
|
|
syntaxHighlighting,
|
|
indentOnInput,
|
|
bracketMatching,
|
|
HighlightStyle,
|
|
} from "@codemirror/language";
|
|
import { defaultKeymap, historyKeymap, history } from "@codemirror/commands";
|
|
import { searchKeymap, highlightSelectionMatches } from "@codemirror/search";
|
|
import {
|
|
autocompletion,
|
|
closeBrackets,
|
|
closeBracketsKeymap,
|
|
} from "@codemirror/autocomplete";
|
|
import { lintKeymap } from "@codemirror/lint";
|
|
import { Compartment } from "@codemirror/state";
|
|
import { Editor } from "./main";
|
|
import { EditorView } from "codemirror";
|
|
import { javascript } from "@codemirror/lang-javascript";
|
|
import { inlineHoveringTips } from "./documentation/inlineHelp";
|
|
import { toposCompletions, soundCompletions } from "./documentation/inlineHelp";
|
|
import { javascriptLanguage } from "@codemirror/lang-javascript";
|
|
|
|
export const getCodeMirrorTheme = (theme: {[key: string]: string}): Extension => {
|
|
// @ts-ignore
|
|
const black = theme["black"],
|
|
red = theme["red"],
|
|
green = theme["green"],
|
|
yellow = theme["yellow"],
|
|
blue = theme["blue"],
|
|
magenta = theme["magenta"],
|
|
cyan = theme["cyan"],
|
|
white = theme["white"],
|
|
// @ts-ignore
|
|
brightblack = theme["brightblack"],
|
|
// @ts-ignore
|
|
brightred = theme["brightred"],
|
|
brightgreen = theme["brightgreen"],
|
|
// @ts-ignore
|
|
brightyellow = theme["brightyellow"],
|
|
// @ts-ignore
|
|
brightblue = theme["brightblue"],
|
|
// @ts-ignore
|
|
brightmagenta = theme["brightmagenta"],
|
|
// @ts-ignore
|
|
brightcyan = theme["brightcyan"],
|
|
brightwhite = theme["brightwhite"],
|
|
background = theme["background"],
|
|
selection_foreground = theme["selection_foreground"],
|
|
cursor = theme["cursor"],
|
|
foreground = theme["foreground"],
|
|
selection_background = theme["selection_background"];
|
|
const toposTheme = EditorView.theme( {
|
|
"&": {
|
|
color: background,
|
|
// backgroundColor: background,
|
|
backgroundColor: "transparent",
|
|
fontSize: "24px",
|
|
fontFamily: "IBM Plex Mono",
|
|
},
|
|
".cm-content": {
|
|
caretColor: cursor,
|
|
fontFamily: "IBM Plex Mono",
|
|
},
|
|
".cm-cursor, .cm-dropCursor": {
|
|
borderLeftColor: cursor,
|
|
},
|
|
"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":
|
|
{
|
|
backgroundColor: selection_foreground,
|
|
border: `0.5px solid ${selection_background}`,
|
|
},
|
|
".cm-panels": {
|
|
backgroundColor: selection_background,
|
|
color: red,
|
|
},
|
|
".cm-panels.cm-panels-top": { borderBottom: "2px solid black" },
|
|
".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" },
|
|
".cm-search.cm-panel": { backgroundColor: "transparent" },
|
|
".cm-searchMatch": {
|
|
outline: `1px solid ${magenta}`,
|
|
},
|
|
".cm-searchMatch.cm-searchMatch-selected": {
|
|
backgroundColor: red,
|
|
},
|
|
".cm-activeLine": {
|
|
// backgroundColor: highlightBackground
|
|
backgroundColor: `${selection_foreground}`,
|
|
},
|
|
".cm-selectionMatch": {
|
|
backgroundColor: yellow,
|
|
outline: `1px solid ${red}`,
|
|
},
|
|
"&.cm-focused .cm-matchingBracket": {
|
|
color: yellow,
|
|
// outline: `1px solid ${base02}`,
|
|
},
|
|
|
|
"&.cm-focused .cm-nonmatchingBracket": {
|
|
color: yellow,
|
|
},
|
|
|
|
".cm-gutters": {
|
|
//backgroundColor: base00,
|
|
backgroundColor: "transparent",
|
|
color: foreground,
|
|
},
|
|
".cm-activeLineGutter": {
|
|
backgroundColor: selection_background,
|
|
color: selection_foreground,
|
|
},
|
|
|
|
".cm-foldPlaceholder": {
|
|
border: "none",
|
|
color: `${blue}`,
|
|
},
|
|
".cm-tooltip": {
|
|
border: "none",
|
|
backgroundColor: background,
|
|
},
|
|
".cm-tooltip .cm-tooltip-arrow:before": {},
|
|
".cm-tooltip .cm-tooltip-arrow:after": {
|
|
borderTopColor: background,
|
|
borderBottomColor: background,
|
|
},
|
|
".cm-tooltip-autocomplete": {
|
|
"& > ul > li[aria-selected]": {
|
|
backgroundColor: background,
|
|
color: background,
|
|
},
|
|
},
|
|
},
|
|
{ dark: true },
|
|
);
|
|
|
|
let toposHighlightStyle = HighlightStyle.define([
|
|
{ tag: t.paren, color: brightwhite },
|
|
{ tag: [t.propertyName, t.punctuation, t.variableName], color: brightwhite },
|
|
{ tag: t.keyword, color: yellow },
|
|
{ tag: [t.name, t.deleted, t.character, t.macroName], color: red, },
|
|
{ tag: [t.function(t.variableName)], color: blue },
|
|
{ tag: [t.labelName], color: red },
|
|
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: cyan, },
|
|
{ tag: [t.definition(t.name), t.separator], color: magenta },
|
|
{ tag: [t.brace], color: white },
|
|
{ tag: [t.annotation], color: blue, },
|
|
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: yellow, },
|
|
{ tag: [t.typeName, t.className], color: magenta, },
|
|
{ tag: [t.operator, t.operatorKeyword], color: blue, },
|
|
{ tag: [t.tagName], color: blue, },
|
|
{ tag: [t.squareBracket], color: blue, },
|
|
{ tag: [t.angleBracket], color: blue, },
|
|
{ tag: [t.attributeName], color: red, },
|
|
{ tag: [t.regexp], color: brightgreen, },
|
|
{ tag: [t.quote], color: green, },
|
|
{ tag: [t.string], color: green },
|
|
{
|
|
tag: t.link,
|
|
color: green,
|
|
textDecoration: "underline",
|
|
textUnderlinePosition: "under",
|
|
},
|
|
{
|
|
tag: [t.url, t.escape, t.special(t.string)],
|
|
color: green,
|
|
},
|
|
{ tag: [t.meta], color: brightwhite },
|
|
{ tag: [t.comment], color: brightwhite, fontStyle: "italic" },
|
|
{ tag: t.monospace, color: brightwhite },
|
|
{ tag: t.strong, fontWeight: "bold", color: white },
|
|
{ tag: t.emphasis, fontStyle: "italic", color: white },
|
|
{ tag: t.strikethrough, textDecoration: "line-through" },
|
|
{ tag: t.heading, fontWeight: "bold", color: white },
|
|
{ tag: t.heading1, fontWeight: "bold", color: white },
|
|
{
|
|
tag: [t.heading2, t.heading3, t.heading4],
|
|
fontWeight: "bold",
|
|
color: yellow,
|
|
},
|
|
{
|
|
tag: [t.heading5, t.heading6],
|
|
color: red,
|
|
},
|
|
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: green},
|
|
{
|
|
tag: [t.processingInstruction, t.inserted],
|
|
color: green,
|
|
},
|
|
{
|
|
tag: [t.contentSeparator],
|
|
color: green,
|
|
},
|
|
{ tag: t.invalid, color: red, borderBottom: `1px dotted ${red}` },
|
|
]);
|
|
return [ toposTheme, syntaxHighlighting(toposHighlightStyle),
|
|
]
|
|
}
|
|
|
|
// const debugTheme = EditorView.theme({
|
|
// ".cm-line span": {
|
|
// position: "relative",
|
|
// },
|
|
// ".cm-line span:hover::after": {
|
|
// position: "absolute",
|
|
// bottom: "100%",
|
|
// left: 0,
|
|
// background: "black",
|
|
// color: "white",
|
|
// border: "solid 2px",
|
|
// borderRadius: "5px",
|
|
// content: "var(--tags)",
|
|
// width: `max-content`,
|
|
// padding: "1px 4px",
|
|
// zIndex: 10,
|
|
// pointerEvents: "none",
|
|
// },
|
|
// });
|
|
|
|
// const debugHighlightStyle = HighlightStyle.define(
|
|
// // @ts-ignore
|
|
// Object.entries(t).map(([key, value]) => {
|
|
// return { tag: value, "--tags": `"tag.${key}"` };
|
|
// })
|
|
// );
|
|
// const debug = [debugTheme, syntaxHighlighting(debugHighlightStyle)];
|
|
|
|
|
|
export const jsCompletions = javascriptLanguage.data.of({
|
|
autocomplete: toposCompletions,
|
|
});
|
|
|
|
export const toposSoundCompletions = javascriptLanguage.data.of({
|
|
autocomplete: soundCompletions,
|
|
});
|
|
|
|
export const editorSetup: Extension = (() => [
|
|
highlightActiveLineGutter(),
|
|
highlightSpecialChars(),
|
|
history(),
|
|
drawSelection(),
|
|
dropCursor(),
|
|
EditorState.allowMultipleSelections.of(true),
|
|
indentOnInput(),
|
|
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
bracketMatching(),
|
|
closeBrackets(),
|
|
autocompletion(),
|
|
highlightActiveLine(),
|
|
highlightSelectionMatches(),
|
|
keymap.of([
|
|
...searchKeymap,
|
|
...closeBracketsKeymap,
|
|
...defaultKeymap,
|
|
...historyKeymap,
|
|
...lintKeymap,
|
|
]),
|
|
])();
|
|
|
|
export const installEditor = (app: Editor) => {
|
|
app.vimModeCompartment = new Compartment();
|
|
app.hoveringCompartment = new Compartment();
|
|
app.themeCompartment = new Compartment();
|
|
app.completionsCompartment = new Compartment();
|
|
app.withLineNumbers = new Compartment();
|
|
app.chosenLanguage = new Compartment();
|
|
app.fontSize = new Compartment();
|
|
const vimPlugin = app.settings.vimMode ? vim() : [];
|
|
const lines = app.settings.line_numbers ? lineNumbers() : [];
|
|
|
|
const fontModif = EditorView.theme({
|
|
"&": {
|
|
fontSize: `${app.settings.font_size}px`,
|
|
},
|
|
$content: {
|
|
fontFamily: `${app.settings.font}`,
|
|
fontSize: `${app.settings.font_size}px`,
|
|
},
|
|
".cm-gutters": {
|
|
fontSize: `${app.settings.font_size}px`,
|
|
},
|
|
});
|
|
|
|
app.editorExtensions = [
|
|
app.vimModeCompartment.of(vimPlugin),
|
|
app.withLineNumbers.of(lines),
|
|
app.fontSize.of(fontModif),
|
|
app.hoveringCompartment.of(app.settings.tips ? inlineHoveringTips : []),
|
|
app.completionsCompartment.of(
|
|
app.settings.completions ? [jsCompletions, toposSoundCompletions] : [],
|
|
),
|
|
editorSetup,
|
|
app.themeCompartment.of(
|
|
getCodeMirrorTheme(app.getColorScheme("Tomorrow Night Burns")),
|
|
// debug
|
|
),
|
|
app.chosenLanguage.of(javascript()),
|
|
];
|
|
app.dynamicPlugins = new Compartment();
|
|
app.state = EditorState.create({
|
|
extensions: [
|
|
...app.editorExtensions,
|
|
EditorView.lineWrapping,
|
|
app.dynamicPlugins.of(app.userPlugins),
|
|
Prec.highest(
|
|
keymap.of([
|
|
{
|
|
key: "Ctrl-Enter",
|
|
run: () => {
|
|
return true;
|
|
},
|
|
},
|
|
]),
|
|
),
|
|
keymap.of([indentWithTab]),
|
|
],
|
|
doc: app.universes[app.selected_universe].global.candidate,
|
|
});
|
|
app.view = new EditorView({
|
|
parent: document.getElementById("editor") as HTMLElement,
|
|
state: app.state,
|
|
});
|
|
|
|
// Re-apply font size and font family change
|
|
app.view.dispatch({
|
|
effects: app.fontSize.reconfigure(
|
|
EditorView.theme({
|
|
"&": {
|
|
fontSize: `${app.settings.font_size}px`,
|
|
},
|
|
$content: {
|
|
fontFamily: `${app.settings.font}`,
|
|
fontSize: `${app.settings.font_size}px`,
|
|
},
|
|
".cm-gutters": {
|
|
fontSize: `${app.settings.font_size}px`,
|
|
},
|
|
}),
|
|
),
|
|
});
|
|
};
|