From fff01530bbbfed7e7b76566d15ade9836eeaf14f Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 12 Feb 2026 12:04:03 +0800 Subject: Again. [skip CI] --- README.md | 20 ++-- doc/docs/.vitepress/theme/index.ts | 151 +++++++++++++++++++++++++++- doc/docs/de/doc/getting-started/usage.md | 2 +- doc/docs/doc/getting-started/usage.md | 2 +- doc/docs/id-id/doc/getting-started/usage.md | 2 +- doc/docs/pt-br/doc/getting-started/usage.md | 2 +- doc/docs/zh/doc/getting-started/usage.md | 2 +- doc/package.json | 2 +- doc/scripts/fix-css-link-rel.mjs | 32 ------ doc/yue-de.md | 2 +- doc/yue-en.md | 2 +- doc/yue-id-id.md | 2 +- doc/yue-pt-br.md | 2 +- doc/yue-zh.md | 2 +- 14 files changed, 171 insertions(+), 54 deletions(-) delete mode 100644 doc/scripts/fix-css-link-rel.mjs diff --git a/README.md b/README.md index 57343cf..73fadf7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![IppClub](https://img.shields.io/badge/IppClub-Certified-11A7E2?logo=data%3Aimage%2Fsvg%2Bxml%3Bcharset%3Dutf-8%3Bbase64%2CPHN2ZyB2aWV3Qm94PSIwIDAgMjg4IDI3NCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjIiPjxwYXRoIGQ9Im0xNDYgMzEgNzIgNTVWMzFoLTcyWiIgc3R5bGU9ImZpbGw6I2Y2YTgwNjtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Im0xNjkgODYtMjMtNTUgNzIgNTVoLTQ5WiIgc3R5bGU9ImZpbGw6I2VmN2EwMDtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Ik0yNiAzMXY1NWg4MEw4MSAzMUgyNloiIHN0eWxlPSJmaWxsOiMwN2ExN2M7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJNMTA4IDkydjExMmwzMS00OC0zMS02NFoiIHN0eWxlPSJmaWxsOiNkZTAwNWQ7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJNMCAyNzR2LTUyaDk3bC0zMyA1MkgwWiIgc3R5bGU9ImZpbGw6I2Y2YTgwNjtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Im03NyAyNzQgNjctMTA3djEwN0g3N1oiIHN0eWxlPSJmaWxsOiNkZjI0MzM7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJNMTUyIDI3NGgyOWwtMjktNTN2NTNaIiBzdHlsZT0iZmlsbDojMzM0ODVkO2ZpbGwtcnVsZTpub256ZXJvIi8%2BPHBhdGggZD0iTTE5MSAyNzRoNzl2LTUySDE2N2wyNCA1MloiIHN0eWxlPSJmaWxsOiM0ZTI3NWE7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJNMjg4IDEwMGgtMTdWODVoLTEzdjE1aC0xN3YxM2gxN3YxNmgxM3YtMTZoMTd2LTEzWiIgc3R5bGU9ImZpbGw6I2M1MTgxZjtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Im0yNiA4NiA1Ni01NUgyNnY1NVoiIHN0eWxlPSJmaWxsOiMzMzQ4NWQ7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJNOTMgMzFoNDJsLTMwIDI5LTEyLTI5WiIgc3R5bGU9ImZpbGw6IzExYTdlMjtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Ik0xNTggMTc2Vjg2bC0zNCAxNCAzNCA3NloiIHN0eWxlPSJmaWxsOiMwMDU5OGU7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJtMTA2IDU5IDQxLTEtMTItMjgtMjkgMjlaIiBzdHlsZT0iZmlsbDojMDU3Y2I3O2ZpbGwtcnVsZTpub256ZXJvIi8%2BPHBhdGggZD0ibTEyNCAxMDAgMjItNDEgMTIgMjctMzQgMTRaIiBzdHlsZT0iZmlsbDojNGUyNzVhO2ZpbGwtcnVsZTpub256ZXJvIi8%2BPHBhdGggZD0ibTEwNiA2MCA0MS0xLTIzIDQxLTE4LTQwWiIgc3R5bGU9ImZpbGw6IzdiMTI4NTtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Im0xMDggMjA0IDMxLTQ4aC0zMXY0OFoiIHN0eWxlPSJmaWxsOiNiYTAwNzc7ZmlsbC1ydWxlOm5vbnplcm8iLz48cGF0aCBkPSJtNjUgMjc0IDMzLTUySDBsNjUgNTJaIiBzdHlsZT0iZmlsbDojZWY3YTAwO2ZpbGwtcnVsZTpub256ZXJvIi8%2BPHBhdGggZD0iTTc3IDI3NGg2N2wtNDAtNDUtMjcgNDVaIiBzdHlsZT0iZmlsbDojYTgxZTI0O2ZpbGwtcnVsZTpub256ZXJvIi8%2BPHBhdGggZD0iTTE2NyAyMjJoNThsLTM0IDUyLTI0LTUyWiIgc3R5bGU9ImZpbGw6IzExYTdlMjtmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Im0yNzAgMjc0LTQ0LTUyLTM1IDUyaDc5WiIgc3R5bGU9ImZpbGw6IzA1N2NiNztmaWxsLXJ1bGU6bm9uemVybyIvPjxwYXRoIGQ9Ik0yNzUgNTVoLTU3VjBoMjV2MzFoMzJ2MjRaIiBzdHlsZT0iZmlsbDojZGUwMDVkO2ZpbGwtcnVsZTpub256ZXJvIi8%2BPHBhdGggZD0iTTE4NSAzMWg1N3Y1NWgtMjVWNTVoLTMyVjMxWiIgc3R5bGU9ImZpbGw6I2M1MTgxZjtmaWxsLXJ1bGU6bm9uemVybyIvPjwvc3ZnPg%3D%3D&labelColor=fff)](https://ippclub.org) [![Ubuntu](https://github.com/pigpigyyy/Yuescript/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/ubuntu.yml) [![Windows](https://github.com/pigpigyyy/Yuescript/actions/workflows/windows.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/windows.yml) [![macOS](https://github.com/pigpigyyy/Yuescript/actions/workflows/macos.yml/badge.svg)](https://github.com/pigpigyyy/Yuescript/actions/workflows/macos.yml) [![Discord Badge](https://img.shields.io/discord/844031511208001577?color=5865F2&label=Discord&logo=discord&logoColor=white&style=flat-square)](https://discord.gg/cRJ2VAm2NV) -YueScript is a MoonScript dialect. It is derived from [MoonScript language](https://github.com/leafo/moonscript) 0.5.0 and continuously adopting new features to be more up to date. +YueScript is a MoonScript dialect. It is derived from [MoonScript language](https://github.com/leafo/moonscript) 0.5.0 and continuously adopting new features to be more up to date. MoonScript is a language that compiles to Lua. Since original MoonScript has been used to write web framework [lapis](https://github.com/leafo/lapis) and run a few business web sites like [itch.io](https://itch.io) and [streak.club](https://streak.club) with some large code bases. The original language is getting too hard to adopt new features for those may break the stablility for existing applications. @@ -51,7 +51,7 @@ YueScript is being developed and maintained alongside the open-source game engin   Then require the YueScript module in Lua: -```Lua +```lua require("yue")("main") -- require `main.yue` local yue = require("yue") @@ -130,13 +130,15 @@ Options: Execute without options to enter REPL, type symbol '$' in a single line to start/stop multi-line mode ``` -  Use cases: -  Recursively compile every YueScript file with extension `.yue` under current path: `yue .` -  Compile and save results to a target path: `yue -t /target/path/ .` -  Compile and reserve debug info: `yue -l .` -  Compile and generate minified codes: `yue -m .` -  Execute raw codes: `yue -e 'print 123'` -  Execute a YueScript file: `yue -e main.yue` + +Use cases: + +* Recursively compile every YueScript file with extension `.yue` under current path: `yue .` +* Compile and save results to a target path: `yue -t /target/path/ .` +* Compile and reserve debug info: `yue -l .` +* Compile and generate minified codes: `yue -m .` +* Execute raw codes: `yue -e 'print 123'` +* Execute a YueScript file: `yue -e main.yue` diff --git a/doc/docs/.vitepress/theme/index.ts b/doc/docs/.vitepress/theme/index.ts index 7e9882e..4dd7408 100644 --- a/doc/docs/.vitepress/theme/index.ts +++ b/doc/docs/.vitepress/theme/index.ts @@ -1,7 +1,11 @@ import DefaultTheme from "vitepress/theme"; import type { Theme } from "vitepress"; -import { h } from "vue"; +import { useRoute } from "vitepress"; +import { h, nextTick, watch } from "vue"; import "./custom.css"; +import darkPlus from "@shikijs/themes/dark-plus"; +import lightPlus from "@shikijs/themes/light-plus"; +import yuescriptGrammar from "../grammars/yuescript.tmLanguage.json"; // @ts-ignore import CompilerModal from "./components/CompilerModal.vue"; @@ -12,6 +16,134 @@ import YueCompiler from "./components/YueCompiler.vue"; // @ts-ignore import YueDisplay from "./components/YueDisplay.vue"; +type ShikiHighlighter = Awaited< + ReturnType<(typeof import("shiki/core"))["createHighlighterCore"]> +>; + +let shikiHighlighterPromise: Promise | null = null; +let shikiRepairQueued = false; +let shikiRepairRetry1 = 0; +let shikiRepairRetry2 = 0; + +type SupportedLanguage = "yuescript" | "lua" | "shellscript"; + +function toSupportedLanguage(className: string): SupportedLanguage | null { + const match = className.match(/(?:^|\s)language-([a-z0-9_-]+)/i); + if (!match) return null; + const lang = match[1].toLowerCase(); + if (lang === "yuescript" || lang === "yue") return "yuescript"; + if (lang === "lua") return "lua"; + if ( + lang === "shellscript" || + lang === "shell" || + lang === "bash" || + lang === "sh" || + lang === "zsh" + ) { + return "shellscript"; + } + return null; +} + +function getShikiHighlighter() { + if (!shikiHighlighterPromise) { + shikiHighlighterPromise = Promise.all([ + import("shiki/core"), + import("shiki/engine/javascript"), + import("@shikijs/langs/lua"), + import("@shikijs/langs/shellscript"), + ]).then( + ([ + { createHighlighterCore }, + { createJavaScriptRegexEngine }, + luaLang, + shellscriptLang, + ]) => + createHighlighterCore({ + themes: [lightPlus, darkPlus], + langs: [ + { + ...yuescriptGrammar, + name: "yuescript", + scopeName: "source.yuescript", + aliases: ["yue"], + }, + ...luaLang.default, + ...shellscriptLang.default, + ], + engine: createJavaScriptRegexEngine(), + }), + ); + } + return shikiHighlighterPromise; +} + +function collectPlainCodeTargets() { + if (typeof document === "undefined") return []; + const nodes = Array.from( + document.querySelectorAll( + "pre > code[class*='language-'], code[class*='language-']", + ), + ); + return nodes.filter((code) => { + if (code.closest("pre.shiki")) return false; + const pre = code.parentElement; + if (pre && pre.tagName === "PRE" && pre.classList.contains("shiki")) { + return false; + } + return toSupportedLanguage(code.className) !== null; + }); +} + +async function repairPlainCodeBlocks() { + const targets = collectPlainCodeTargets(); + if (!targets.length) return; + + const highlighter = await getShikiHighlighter(); + + for (const code of targets) { + const lang = toSupportedLanguage(code.className); + if (!lang) continue; + const source = (code.textContent || "").replace(/\r\n?/g, "\n"); + if (!source.trim()) continue; + const html = highlighter.codeToHtml(source, { + lang, + themes: { + light: "light-plus", + dark: "dark-plus", + }, + }); + const tpl = document.createElement("template"); + tpl.innerHTML = html.trim(); + const replacement = tpl.content.firstElementChild as HTMLElement | null; + if (!replacement) continue; + replacement.classList.add("vp-code"); + const pre = code.parentElement?.tagName === "PRE" ? code.parentElement : null; + (pre || code).replaceWith(replacement); + } + + applyShikiInlineColorFallback(); +} + +function scheduleShikiRepair() { + if (typeof window === "undefined") return; + if (shikiRepairQueued) return; + shikiRepairQueued = true; + window.requestAnimationFrame(() => { + shikiRepairQueued = false; + void repairPlainCodeBlocks(); + }); +} + +function scheduleShikiRepairWithRetries() { + if (typeof window === "undefined") return; + scheduleShikiRepair(); + window.clearTimeout(shikiRepairRetry1); + window.clearTimeout(shikiRepairRetry2); + shikiRepairRetry1 = window.setTimeout(scheduleShikiRepair, 120); + shikiRepairRetry2 = window.setTimeout(scheduleShikiRepair, 500); +} + function applyShikiInlineColorFallback() { if (typeof document === "undefined") return; const isDark = document.documentElement.classList.contains("dark"); @@ -31,13 +163,28 @@ const theme: Theme = { h(DefaultTheme.Layout, null, { "layout-bottom": () => [h(HomeFooter), h(CompilerModal)], }), + setup() { + if (typeof window === "undefined") return; + const route = useRoute(); + watch( + () => route.path, + async () => { + await nextTick(); + scheduleShikiRepairWithRetries(); + }, + { immediate: true }, + ); + }, enhanceApp({ app }) { app.component("CompilerModal", CompilerModal); app.component("YueCompiler", YueCompiler); app.component("YueDisplay", YueDisplay); if (typeof window !== "undefined") { - const run = () => requestAnimationFrame(applyShikiInlineColorFallback); + const run = () => { + requestAnimationFrame(applyShikiInlineColorFallback); + scheduleShikiRepairWithRetries(); + }; window.addEventListener("DOMContentLoaded", run, { once: true }); window.addEventListener("load", run, { once: true }); diff --git a/doc/docs/de/doc/getting-started/usage.md b/doc/docs/de/doc/getting-started/usage.md index 2c10406..2a1864a 100644 --- a/doc/docs/de/doc/getting-started/usage.md +++ b/doc/docs/de/doc/getting-started/usage.md @@ -8,7 +8,7 @@ YueScript-Modul in Lua verwenden: "your_yuescript_entry.yue" in Lua require'n. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/docs/doc/getting-started/usage.md b/doc/docs/doc/getting-started/usage.md index 8818dd0..c02e8c0 100644 --- a/doc/docs/doc/getting-started/usage.md +++ b/doc/docs/doc/getting-started/usage.md @@ -8,7 +8,7 @@ Use YueScript module in Lua: Require "your_yuescript_entry.yue" in Lua. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/docs/id-id/doc/getting-started/usage.md b/doc/docs/id-id/doc/getting-started/usage.md index a9523f7..a092163 100644 --- a/doc/docs/id-id/doc/getting-started/usage.md +++ b/doc/docs/id-id/doc/getting-started/usage.md @@ -8,7 +8,7 @@ Gunakan modul YueScript di Lua: Require "your_yuescript_entry.yue" di Lua. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/docs/pt-br/doc/getting-started/usage.md b/doc/docs/pt-br/doc/getting-started/usage.md index 055c6c2..c3b5dfe 100644 --- a/doc/docs/pt-br/doc/getting-started/usage.md +++ b/doc/docs/pt-br/doc/getting-started/usage.md @@ -8,7 +8,7 @@ Use o módulo YueScript em Lua: Use require em "your_yuescript_entry.yue" no Lua. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/docs/zh/doc/getting-started/usage.md b/doc/docs/zh/doc/getting-started/usage.md index c9bad2e..b605e7c 100644 --- a/doc/docs/zh/doc/getting-started/usage.md +++ b/doc/docs/zh/doc/getting-started/usage.md @@ -8,7 +8,7 @@   在 Lua 中引入 "你的脚本入口文件.yue"。 - ```Lua + ```lua require("yue")("你的脚本入口文件") ``` diff --git a/doc/package.json b/doc/package.json index f8fa882..45fb213 100755 --- a/doc/package.json +++ b/doc/package.json @@ -10,7 +10,7 @@ "repository": "https://github.com/pigpigyyy/Yuescript/doc", "scripts": { "dev": "vitepress dev docs", - "build": "vitepress build docs && node scripts/fix-css-link-rel.mjs", + "build": "vitepress build docs", "preview": "vitepress preview docs" }, "license": "MIT", diff --git a/doc/scripts/fix-css-link-rel.mjs b/doc/scripts/fix-css-link-rel.mjs deleted file mode 100644 index 4c48868..0000000 --- a/doc/scripts/fix-css-link-rel.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; - -const distRoot = "docs/.vitepress/dist"; -const preloadStylesheetRelPattern = /rel="preload stylesheet"/g; -const stylesheetAsPattern = /(]*rel="stylesheet"[^>]*?)\s+as="style"/g; - -function walk(dir, files = []) { - for (const entry of readdirSync(dir)) { - const fullPath = join(dir, entry); - const stat = statSync(fullPath); - if (stat.isDirectory()) { - walk(fullPath, files); - } else if (fullPath.endsWith(".html")) { - files.push(fullPath); - } - } - return files; -} - -let updated = 0; -for (const filePath of walk(distRoot)) { - const original = readFileSync(filePath, "utf8"); - let fixed = original.replace(preloadStylesheetRelPattern, 'rel="stylesheet"'); - fixed = fixed.replace(stylesheetAsPattern, "$1"); - if (fixed !== original) { - writeFileSync(filePath, fixed, "utf8"); - updated += 1; - } -} - -console.log(`[fix-css-link-rel] Updated ${updated} HTML files.`); diff --git a/doc/yue-de.md b/doc/yue-de.md index 36d96cd..4db290b 100644 --- a/doc/yue-de.md +++ b/doc/yue-de.md @@ -2377,7 +2377,7 @@ YueScript-Modul in Lua verwenden: "your_yuescript_entry.yue" in Lua require'n. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/yue-en.md b/doc/yue-en.md index a16060c..04ef456 100644 --- a/doc/yue-en.md +++ b/doc/yue-en.md @@ -2379,7 +2379,7 @@ Use YueScript module in Lua: Require "your_yuescript_entry.yue" in Lua. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/yue-id-id.md b/doc/yue-id-id.md index 704ebe4..63e1969 100644 --- a/doc/yue-id-id.md +++ b/doc/yue-id-id.md @@ -2377,7 +2377,7 @@ Gunakan modul YueScript di Lua: Require "your_yuescript_entry.yue" di Lua. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/yue-pt-br.md b/doc/yue-pt-br.md index fccbdf6..65e332a 100644 --- a/doc/yue-pt-br.md +++ b/doc/yue-pt-br.md @@ -2376,7 +2376,7 @@ Use o módulo YueScript em Lua: Use require em "your_yuescript_entry.yue" no Lua. - ```Lua + ```lua require("yue")("your_yuescript_entry") ``` diff --git a/doc/yue-zh.md b/doc/yue-zh.md index 7454eab..96e19ba 100644 --- a/doc/yue-zh.md +++ b/doc/yue-zh.md @@ -2371,7 +2371,7 @@ print i, k -- 这些已经被更新   在 Lua 中引入 "你的脚本入口文件.yue"。 - ```Lua + ```lua require("yue")("你的脚本入口文件") ``` -- cgit v1.2.3-55-g6feb