fuc-new/doc/node_modules/vuepress-plugin-md-power/lib/client/composables/codeRepl.js
hellcat 6adbc04d4b 1
2025-10-03 17:17:08 +08:00

181 lines
4.5 KiB
JavaScript

import { rustExecute } from "./rustRepl-CARlbZyO.js";
import { onMounted, ref } from "vue";
import { http } from "../utils/http.js";
import { sleep } from "../utils/sleep.js";
//#region src/client/composables/codeRepl.ts
const ignoredNodes = [".diff.remove", ".vp-copy-ignore"];
const RE_LANGUAGE = /language-(\w+)/;
const api = {
go: "https://api.pengzhanbo.cn/repl/golang/run",
kotlin: "https://api.pengzhanbo.cn/repl/kotlin/run"
};
let pyodide = null;
const langAlias = {
kt: "kotlin",
kotlin: "kotlin",
go: "go",
rust: "rust",
rs: "rust",
py: "python",
python: "python"
};
const supportLang = [
"kotlin",
"go",
"rust",
"python"
];
function resolveLang(lang) {
return lang ? langAlias[lang] || lang : "";
}
function resolveCode(el) {
const clone = el.cloneNode(true);
clone.querySelectorAll(ignoredNodes.join(",")).forEach((node) => node.remove());
return clone.textContent || "";
}
function resolveCodeInfo(el) {
const wrapper = el.querySelector("div[class*=language-]");
const lang = wrapper?.className.match(RE_LANGUAGE)?.[1];
const codeEl = wrapper?.querySelector("pre");
let code = "";
if (codeEl) code = resolveCode(codeEl);
return {
lang: resolveLang(lang),
code
};
}
function useCodeRepl(el) {
const lang = ref();
const loaded = ref(true);
const firstRun = ref(true);
const finished = ref(true);
const stdout = ref([]);
const stderr = ref([]);
const error = ref("");
const backendVersion = ref("");
onMounted(() => {
if (el.value) lang.value = resolveCodeInfo(el.value).lang;
});
const executeMap = {
kotlin: executeKotlin,
go: executeGolang,
rust: executeRust,
python: executePython
};
function onCleanRun() {
loaded.value = false;
finished.value = false;
stdout.value = [];
stderr.value = [];
error.value = "";
firstRun.value = true;
backendVersion.value = "";
}
async function onRunCode() {
if (!el.value || !loaded.value) return;
const info = resolveCodeInfo(el.value);
lang.value = info.lang;
if (!lang.value || !info.code || !supportLang.includes(lang.value)) return;
if (firstRun.value) firstRun.value = false;
loaded.value = false;
finished.value = false;
stdout.value = [];
stderr.value = [];
error.value = "";
await executeMap[lang.value]?.(info.code);
}
async function executeGolang(code) {
const res = await http.post(api.go, { code });
backendVersion.value = `v${res.version}`;
loaded.value = true;
if (res.error) {
error.value = res.error;
finished.value = true;
return;
}
const events = res.events || [];
for (const event of events) if (event.kind === "stdout") {
if (event.delay) await sleep(event.delay / 1e6);
stdout.value.push(event.message);
} else if (event.kind === "stderr") stderr.value.push(event.message);
finished.value = true;
}
async function executeKotlin(code) {
const filename = "File.kt";
const res = await http.post(api.kotlin, {
args: "",
files: [{
name: filename,
publicId: "",
text: code
}]
});
backendVersion.value = `v${res.version}`;
loaded.value = true;
if (res.errors) {
const errors = Array.isArray(res.errors[filename]) ? res.errors[filename] : [res.errors[filename]];
if (errors.length) errors.forEach(({ message, severity }) => severity === "ERROR" && stderr.value.push(message));
}
stdout.value.push(res.text);
finished.value = true;
}
async function executeRust(code) {
await rustExecute(code, {
onBegin: () => {
loaded.value = true;
finished.value = false;
stdout.value = [];
stderr.value = [];
error.value = "";
backendVersion.value = "release";
},
onError(message) {
error.value = message;
},
onStdout(message) {
stdout.value.push(message);
},
onStderr(message) {
stderr.value.push(message);
},
onEnd: () => {
finished.value = true;
}
});
}
async function executePython(code) {
loaded.value = false;
finished.value = false;
if (pyodide === null) {
const { loadPyodide, version } = await import(
/* webpackChunkName: "pyodide" */
"pyodide"
);
pyodide = await loadPyodide({ indexURL: `https://cdn.jsdelivr.net/pyodide/v${version}/full/` });
}
pyodide.setStdout({ batched: (msg) => stdout.value.push(msg) });
try {
stdout.value.push(pyodide.runPython(code));
} catch (e) {
stderr.value.push(String(e));
}
loaded.value = true;
finished.value = true;
}
return {
onRunCode,
onCleanRun,
lang,
backendVersion,
firstRun,
stderr,
stdout,
loaded,
finished,
error
};
}
//#endregion
export { resolveCode, resolveCodeInfo, useCodeRepl };