chore: import upstream snapshot with attribution
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
publish / version_or_publish (push) Has been cancelled
storybook-build / changes (push) Has been cancelled
storybook-build / :storybook-build (push) Has been cancelled
Sync Gradio Skills to Hugging Face / sync-skills (push) Has been cancelled
functional / changes (push) Has been cancelled
functional / build-frontend (push) Has been cancelled
functional / functional-test-SSR=false (push) Has been cancelled
functional / functional-reload (push) Has been cancelled
js / changes (push) Has been cancelled
js / js-test (push) Has been cancelled
docs-build / changes (push) Has been cancelled
docs-build / docs-build (push) Has been cancelled
docs-build / website-build (push) Has been cancelled
functional / functional-test-SSR=true (push) Has been cancelled
hygiene / hygiene-test (push) Has been cancelled
python / changes (push) Has been cancelled
python / build (push) Has been cancelled
python / test-ubuntu-latest-flaky (push) Has been cancelled
python / test-ubuntu-latest-not-flaky (push) Has been cancelled
python / test-windows-latest-flaky (push) Has been cancelled
python / test-windows-latest-not-flaky (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,345 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import {
|
||||
EditorView,
|
||||
ViewUpdate,
|
||||
keymap,
|
||||
placeholder as placeholderExt,
|
||||
lineNumbers
|
||||
} from "@codemirror/view";
|
||||
import { StateEffect, EditorState, type Extension } from "@codemirror/state";
|
||||
import { indentWithTab } from "@codemirror/commands";
|
||||
import { autocompletion, acceptCompletion } from "@codemirror/autocomplete";
|
||||
|
||||
import { basicDark } from "cm6-theme-basic-dark";
|
||||
import { basicLight } from "cm6-theme-basic-light";
|
||||
import { basicSetup } from "./extensions";
|
||||
import { getLanguageExtension } from "./language";
|
||||
|
||||
interface Props {
|
||||
class_names?: string;
|
||||
value?: string;
|
||||
dark_mode: boolean;
|
||||
basic?: boolean;
|
||||
language: string;
|
||||
lines?: number;
|
||||
max_lines?: number | null;
|
||||
extensions?: Extension[];
|
||||
use_tab?: boolean;
|
||||
readonly?: boolean;
|
||||
placeholder?: string | HTMLElement | null | undefined;
|
||||
wrap_lines?: boolean;
|
||||
show_line_numbers?: boolean;
|
||||
autocomplete?: boolean;
|
||||
onchange?: (value: string) => void;
|
||||
onblur?: () => void;
|
||||
onfocus?: () => void;
|
||||
oninput?: () => void;
|
||||
}
|
||||
|
||||
let {
|
||||
class_names = "",
|
||||
value = $bindable(),
|
||||
dark_mode,
|
||||
basic = true,
|
||||
language,
|
||||
lines = 5,
|
||||
max_lines = null,
|
||||
extensions = [],
|
||||
use_tab = true,
|
||||
readonly = false,
|
||||
placeholder = undefined,
|
||||
wrap_lines = false,
|
||||
show_line_numbers = true,
|
||||
autocomplete = false,
|
||||
onchange,
|
||||
onblur,
|
||||
onfocus,
|
||||
oninput
|
||||
}: Props = $props();
|
||||
|
||||
let lang_extension: Extension | undefined = $state();
|
||||
let element: HTMLDivElement;
|
||||
let view: EditorView;
|
||||
|
||||
async function get_lang(val: string): Promise<void> {
|
||||
const ext = await getLanguageExtension(val);
|
||||
lang_extension = ext;
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
get_lang(language);
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
lang_extension;
|
||||
readonly;
|
||||
reconfigure();
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
set_doc(value ?? "");
|
||||
});
|
||||
|
||||
update_lines();
|
||||
|
||||
function set_doc(new_doc: string): void {
|
||||
if (view && new_doc !== view.state.doc.toString()) {
|
||||
view.dispatch({
|
||||
changes: {
|
||||
from: 0,
|
||||
to: view.state.doc.length,
|
||||
insert: new_doc
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function update_lines(): void {
|
||||
if (view) {
|
||||
view.requestMeasure({ read: resize });
|
||||
}
|
||||
}
|
||||
|
||||
function create_editor_view(): EditorView {
|
||||
const editorView = new EditorView({
|
||||
parent: element,
|
||||
state: create_editor_state(value)
|
||||
});
|
||||
editorView.dom.addEventListener("focus", handle_focus, true);
|
||||
editorView.dom.addEventListener("blur", handle_blur, true);
|
||||
return editorView;
|
||||
}
|
||||
|
||||
function handle_focus(): void {
|
||||
onfocus?.();
|
||||
}
|
||||
|
||||
function handle_blur(): void {
|
||||
onblur?.();
|
||||
}
|
||||
|
||||
function getGutterLineHeight(_view: EditorView): string | null {
|
||||
let elements = _view.dom.querySelectorAll<HTMLElement>(".cm-gutterElement");
|
||||
if (elements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
let node = elements[i];
|
||||
let height = getComputedStyle(node)?.height ?? "0px";
|
||||
if (height != "0px") {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function resize(_view: EditorView): any {
|
||||
let scroller = _view.dom.querySelector<HTMLElement>(".cm-scroller");
|
||||
if (!scroller) {
|
||||
return null;
|
||||
}
|
||||
const lineHeight = getGutterLineHeight(_view);
|
||||
if (!lineHeight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const minLines = lines == 1 ? 1 : lines + 1;
|
||||
scroller.style.minHeight = `calc(${lineHeight} * ${minLines})`;
|
||||
if (max_lines)
|
||||
scroller.style.maxHeight = `calc(${lineHeight} * ${max_lines + 1})`;
|
||||
}
|
||||
|
||||
import { Transaction } from "@codemirror/state";
|
||||
|
||||
function is_user_input(update: ViewUpdate): boolean {
|
||||
return update.transactions.some(
|
||||
(tr) => tr.annotation(Transaction.userEvent) != null
|
||||
);
|
||||
}
|
||||
|
||||
function handle_change(vu: ViewUpdate): void {
|
||||
if (!vu.docChanged) return;
|
||||
|
||||
const doc = vu.state.doc;
|
||||
const text = doc.toString();
|
||||
value = text;
|
||||
|
||||
const user_change = is_user_input(vu);
|
||||
if (user_change) {
|
||||
onchange?.(text);
|
||||
oninput?.();
|
||||
} else {
|
||||
onchange?.(text);
|
||||
}
|
||||
|
||||
view.requestMeasure({ read: resize });
|
||||
}
|
||||
|
||||
function get_extensions(): Extension[] {
|
||||
const stateExtensions = [
|
||||
...get_base_extensions(
|
||||
basic,
|
||||
use_tab,
|
||||
placeholder,
|
||||
readonly,
|
||||
lang_extension,
|
||||
show_line_numbers
|
||||
),
|
||||
FontTheme,
|
||||
...get_theme(),
|
||||
...extensions
|
||||
];
|
||||
return stateExtensions;
|
||||
}
|
||||
|
||||
const FontTheme = EditorView.theme({
|
||||
"&": {
|
||||
fontSize: "var(--text-sm)",
|
||||
backgroundColor: "var(--border-color-secondary)"
|
||||
},
|
||||
".cm-content": {
|
||||
paddingTop: "5px",
|
||||
paddingBottom: "5px",
|
||||
color: "var(--body-text-color)",
|
||||
fontFamily: "var(--font-mono)",
|
||||
minHeight: "100%"
|
||||
},
|
||||
".cm-gutterElement": {
|
||||
marginRight: "var(--spacing-xs)"
|
||||
},
|
||||
".cm-gutters": {
|
||||
marginRight: "1px",
|
||||
borderRight: "1px solid var(--border-color-primary)",
|
||||
backgroundColor: "var(--block-background-fill);",
|
||||
color: "var(--body-text-color-subdued)"
|
||||
},
|
||||
".cm-focused": {
|
||||
outline: "none"
|
||||
},
|
||||
".cm-scroller": {
|
||||
height: "auto"
|
||||
},
|
||||
".cm-cursor": {
|
||||
borderLeftColor: "var(--body-text-color)"
|
||||
}
|
||||
});
|
||||
|
||||
const AutocompleteTheme = EditorView.theme({
|
||||
".cm-tooltip-autocomplete": {
|
||||
"& > ul": {
|
||||
backgroundColor: "var(--background-fill-primary)",
|
||||
color: "var(--body-text-color)"
|
||||
},
|
||||
"& > ul > li[aria-selected]": {
|
||||
backgroundColor: "var(--color-accent-soft)",
|
||||
color: "var(--body-text-color)"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function create_editor_state(_value: string | null | undefined): EditorState {
|
||||
return EditorState.create({
|
||||
doc: _value ?? undefined,
|
||||
extensions: get_extensions()
|
||||
});
|
||||
}
|
||||
|
||||
function get_base_extensions(
|
||||
basic: boolean,
|
||||
use_tab: boolean,
|
||||
placeholder: string | HTMLElement | null | undefined,
|
||||
readonly: boolean,
|
||||
lang: Extension | null | undefined,
|
||||
show_line_numbers: boolean
|
||||
): Extension[] {
|
||||
const extensions: Extension[] = [
|
||||
EditorView.editable.of(!readonly),
|
||||
EditorState.readOnly.of(readonly),
|
||||
EditorView.contentAttributes.of({ "aria-label": "Code input container" })
|
||||
];
|
||||
|
||||
if (basic) {
|
||||
extensions.push(basicSetup);
|
||||
}
|
||||
if (use_tab) {
|
||||
extensions.push(
|
||||
keymap.of([{ key: "Tab", run: acceptCompletion }, indentWithTab])
|
||||
);
|
||||
}
|
||||
if (placeholder) {
|
||||
extensions.push(placeholderExt(placeholder));
|
||||
}
|
||||
if (lang) {
|
||||
extensions.push(lang);
|
||||
}
|
||||
if (show_line_numbers) {
|
||||
extensions.push(lineNumbers());
|
||||
}
|
||||
if (autocomplete) {
|
||||
extensions.push(autocompletion());
|
||||
extensions.push(AutocompleteTheme);
|
||||
}
|
||||
|
||||
extensions.push(EditorView.updateListener.of(handle_change));
|
||||
if (wrap_lines) {
|
||||
extensions.push(EditorView.lineWrapping);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
function get_theme(): Extension[] {
|
||||
const extensions: Extension[] = [];
|
||||
|
||||
if (dark_mode) {
|
||||
extensions.push(basicDark);
|
||||
} else {
|
||||
extensions.push(basicLight);
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
function reconfigure(): void {
|
||||
view?.dispatch({
|
||||
effects: StateEffect.reconfigure.of(get_extensions())
|
||||
});
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
view = create_editor_view();
|
||||
return () => view?.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="wrap">
|
||||
<div class="codemirror-wrapper {class_names}" bind:this={element} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.codemirror-wrapper {
|
||||
flex-grow: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:global(.cm-editor) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Dunno why this doesn't work through the theme API -- don't remove*/
|
||||
:global(.cm-selectionBackground) {
|
||||
background-color: #b9d2ff30 !important;
|
||||
}
|
||||
|
||||
:global(.cm-focused) {
|
||||
outline: none !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from "svelte";
|
||||
import { Copy, Check } from "@gradio/icons";
|
||||
import { IconButton } from "@gradio/atoms";
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
}
|
||||
|
||||
let { value }: Props = $props();
|
||||
|
||||
let copied = $state(false);
|
||||
let timer: NodeJS.Timeout;
|
||||
|
||||
function copy_feedback(): void {
|
||||
copied = true;
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
copied = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
async function handle_copy(): Promise<void> {
|
||||
if ("clipboard" in navigator) {
|
||||
await navigator.clipboard.writeText(value);
|
||||
copy_feedback();
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (timer) clearTimeout(timer);
|
||||
});
|
||||
</script>
|
||||
|
||||
<IconButton Icon={copied ? Check : Copy} label="Copy" onclick={handle_copy} />
|
||||
@@ -0,0 +1,67 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from "svelte";
|
||||
import { Download, Check } from "@gradio/icons";
|
||||
import { DownloadLink } from "@gradio/atoms";
|
||||
import { IconButton } from "@gradio/atoms";
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
language: string;
|
||||
}
|
||||
|
||||
let { value, language }: Props = $props();
|
||||
|
||||
let ext = $derived(get_ext_for_type(language));
|
||||
|
||||
function get_ext_for_type(type: string): string {
|
||||
const exts: Record<string, string> = {
|
||||
py: "py",
|
||||
python: "py",
|
||||
md: "md",
|
||||
markdown: "md",
|
||||
json: "json",
|
||||
html: "html",
|
||||
css: "css",
|
||||
js: "js",
|
||||
javascript: "js",
|
||||
ts: "ts",
|
||||
typescript: "ts",
|
||||
yaml: "yaml",
|
||||
yml: "yml",
|
||||
dockerfile: "dockerfile",
|
||||
sh: "sh",
|
||||
shell: "sh",
|
||||
r: "r",
|
||||
c: "c",
|
||||
cpp: "cpp",
|
||||
latex: "tex"
|
||||
};
|
||||
|
||||
return exts[type] || "txt";
|
||||
}
|
||||
|
||||
let copied = $state(false);
|
||||
let timer: NodeJS.Timeout;
|
||||
|
||||
function copy_feedback(): void {
|
||||
copied = true;
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
copied = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
let download_value = $derived(URL.createObjectURL(new Blob([value])));
|
||||
|
||||
onDestroy(() => {
|
||||
if (timer) clearTimeout(timer);
|
||||
});
|
||||
</script>
|
||||
|
||||
<DownloadLink
|
||||
download="file.{ext}"
|
||||
href={download_value}
|
||||
onclick={copy_feedback}
|
||||
>
|
||||
<IconButton Icon={copied ? Check : Download} label="Download" />
|
||||
</DownloadLink>
|
||||
@@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
import Copy from "./Copy.svelte";
|
||||
import Download from "./Download.svelte";
|
||||
import { IconButtonWrapper } from "@gradio/atoms";
|
||||
import type { CustomButton as CustomButtonType } from "@gradio/utils";
|
||||
|
||||
interface Props {
|
||||
value: string;
|
||||
language: string;
|
||||
buttons?: (string | CustomButtonType)[] | null;
|
||||
on_custom_button_click?: ((id: number) => void) | null;
|
||||
}
|
||||
|
||||
let {
|
||||
value,
|
||||
language,
|
||||
buttons = null,
|
||||
on_custom_button_click = null
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<IconButtonWrapper {buttons} {on_custom_button_click}>
|
||||
{#if buttons?.some((btn) => typeof btn === "string" && btn === "download")}
|
||||
<Download {value} {language} />
|
||||
{/if}
|
||||
{#if buttons?.some((btn) => typeof btn === "string" && btn === "copy")}
|
||||
<Copy {value} />
|
||||
{/if}
|
||||
</IconButtonWrapper>
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { Extension } from "@codemirror/state";
|
||||
import {
|
||||
lineNumbers,
|
||||
highlightSpecialChars,
|
||||
drawSelection,
|
||||
rectangularSelection,
|
||||
crosshairCursor,
|
||||
keymap
|
||||
} from "@codemirror/view";
|
||||
export { EditorView } from "@codemirror/view";
|
||||
import { EditorState } from "@codemirror/state";
|
||||
import {
|
||||
foldGutter,
|
||||
indentOnInput,
|
||||
syntaxHighlighting,
|
||||
defaultHighlightStyle,
|
||||
foldKeymap
|
||||
} from "@codemirror/language";
|
||||
import { history, defaultKeymap, historyKeymap } from "@codemirror/commands";
|
||||
import {
|
||||
closeBrackets,
|
||||
closeBracketsKeymap,
|
||||
completionKeymap
|
||||
} from "@codemirror/autocomplete";
|
||||
import { lintKeymap } from "@codemirror/lint";
|
||||
|
||||
export const basicSetup: Extension = /*@__PURE__*/ ((): Extension[] => [
|
||||
highlightSpecialChars(),
|
||||
history(),
|
||||
foldGutter(),
|
||||
drawSelection(),
|
||||
EditorState.allowMultipleSelections.of(true),
|
||||
indentOnInput(),
|
||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
||||
closeBrackets(),
|
||||
rectangularSelection(),
|
||||
crosshairCursor(),
|
||||
|
||||
keymap.of([
|
||||
...closeBracketsKeymap,
|
||||
...defaultKeymap,
|
||||
...historyKeymap,
|
||||
...foldKeymap,
|
||||
...completionKeymap,
|
||||
...lintKeymap
|
||||
])
|
||||
])();
|
||||
@@ -0,0 +1,61 @@
|
||||
import type {
|
||||
Element,
|
||||
MarkdownExtension,
|
||||
BlockContext,
|
||||
Line
|
||||
} from "@lezer/markdown";
|
||||
import { parseMixed } from "@lezer/common";
|
||||
import { yaml } from "@codemirror/legacy-modes/mode/yaml";
|
||||
import { foldInside, foldNodeProp, StreamLanguage } from "@codemirror/language";
|
||||
import { styleTags, tags } from "@lezer/highlight";
|
||||
|
||||
const frontMatterFence = /^---\s*$/m;
|
||||
|
||||
export const frontmatter: MarkdownExtension = {
|
||||
defineNodes: [{ name: "Frontmatter", block: true }, "FrontmatterMark"],
|
||||
props: [
|
||||
styleTags({
|
||||
Frontmatter: [tags.documentMeta, tags.monospace],
|
||||
FrontmatterMark: tags.processingInstruction
|
||||
}),
|
||||
foldNodeProp.add({
|
||||
Frontmatter: foldInside,
|
||||
FrontmatterMark: () => null
|
||||
})
|
||||
],
|
||||
wrap: parseMixed((node) => {
|
||||
const { parser } = StreamLanguage.define(yaml);
|
||||
if (node.type.name === "Frontmatter") {
|
||||
return {
|
||||
parser,
|
||||
overlay: [{ from: node.from + 4, to: node.to - 4 }]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
parseBlock: [
|
||||
{
|
||||
name: "Frontmatter",
|
||||
before: "HorizontalRule",
|
||||
parse: (cx: BlockContext, line: Line): boolean => {
|
||||
let end: number | undefined = undefined;
|
||||
const children = new Array<Element>();
|
||||
if (cx.lineStart === 0 && frontMatterFence.test(line.text)) {
|
||||
children.push(cx.elt("FrontmatterMark", 0, 4));
|
||||
while (cx.nextLine()) {
|
||||
if (frontMatterFence.test(line.text)) {
|
||||
end = cx.lineStart + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (end !== undefined) {
|
||||
children.push(cx.elt("FrontmatterMark", end - 4, end));
|
||||
cx.addElement(cx.elt("Frontmatter", 0, end, children));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
import type { Extension } from "@codemirror/state";
|
||||
import { StreamLanguage } from "@codemirror/language";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
const sql_dialects = [
|
||||
"standardSQL",
|
||||
"msSQL",
|
||||
"mySQL",
|
||||
"mariaDB",
|
||||
"sqlite",
|
||||
"cassandra",
|
||||
"plSQL",
|
||||
"hive",
|
||||
"pgSQL",
|
||||
"gql",
|
||||
"gpSQL",
|
||||
"sparkSQL",
|
||||
"esper"
|
||||
] as const;
|
||||
|
||||
const lang_map: Record<string, (() => Promise<Extension>) | undefined> = {
|
||||
python: () => import("@codemirror/lang-python").then((m) => m.python()),
|
||||
c: () =>
|
||||
import("@codemirror/legacy-modes/mode/clike").then((m) =>
|
||||
StreamLanguage.define(m.c)
|
||||
),
|
||||
cpp: () =>
|
||||
import("@codemirror/legacy-modes/mode/clike").then((m) =>
|
||||
StreamLanguage.define(m.cpp)
|
||||
),
|
||||
markdown: async () => {
|
||||
const [md, frontmatter] = await Promise.all([
|
||||
import("@codemirror/lang-markdown"),
|
||||
import("./frontmatter")
|
||||
]);
|
||||
return md.markdown({ extensions: [frontmatter.frontmatter] });
|
||||
},
|
||||
latex: () =>
|
||||
import("@codemirror/legacy-modes/mode/stex").then((m) =>
|
||||
StreamLanguage.define(m.stex)
|
||||
),
|
||||
json: () => import("@codemirror/lang-json").then((m) => m.json()),
|
||||
html: () => import("@codemirror/lang-html").then((m) => m.html()),
|
||||
css: () => import("@codemirror/lang-css").then((m) => m.css()),
|
||||
javascript: () =>
|
||||
import("@codemirror/lang-javascript").then((m) => m.javascript()),
|
||||
jinja2: () =>
|
||||
import("@codemirror/legacy-modes/mode/jinja2").then((m) =>
|
||||
StreamLanguage.define(m.jinja2)
|
||||
),
|
||||
typescript: () =>
|
||||
import("@codemirror/lang-javascript").then((m) =>
|
||||
m.javascript({ typescript: true })
|
||||
),
|
||||
yaml: () =>
|
||||
import("@codemirror/legacy-modes/mode/yaml").then((m) =>
|
||||
StreamLanguage.define(m.yaml)
|
||||
),
|
||||
dockerfile: () =>
|
||||
import("@codemirror/legacy-modes/mode/dockerfile").then((m) =>
|
||||
StreamLanguage.define(m.dockerFile)
|
||||
),
|
||||
shell: () =>
|
||||
import("@codemirror/legacy-modes/mode/shell").then((m) =>
|
||||
StreamLanguage.define(m.shell)
|
||||
),
|
||||
r: () =>
|
||||
import("@codemirror/legacy-modes/mode/r").then((m) =>
|
||||
StreamLanguage.define(m.r)
|
||||
),
|
||||
sql: () =>
|
||||
import("@codemirror/legacy-modes/mode/sql").then((m) =>
|
||||
StreamLanguage.define(m.standardSQL)
|
||||
),
|
||||
...Object.fromEntries(
|
||||
sql_dialects.map((dialect) => [
|
||||
"sql-" + dialect,
|
||||
() =>
|
||||
import("@codemirror/legacy-modes/mode/sql").then((m) =>
|
||||
StreamLanguage.define(m[dialect])
|
||||
)
|
||||
])
|
||||
)
|
||||
} as const;
|
||||
|
||||
const alias_map: Record<string, string> = {
|
||||
py: "python",
|
||||
md: "markdown",
|
||||
js: "javascript",
|
||||
ts: "typescript",
|
||||
sh: "shell"
|
||||
};
|
||||
|
||||
export async function getLanguageExtension(
|
||||
lang: string
|
||||
): Promise<Extension | undefined> {
|
||||
const _lang = lang_map[lang] || lang_map[alias_map[lang]] || undefined;
|
||||
if (_lang) {
|
||||
return _lang();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user