This commit is contained in:
2246
package-lock.json
generated
2246
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -9,20 +9,20 @@
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^4.3.13",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@astrojs/rss": "^4.0.14",
|
||||
"@astrojs/sitemap": "^3.6.0",
|
||||
"@astrojs/svelte": "^7.2.4",
|
||||
"@astrojs/mdx": "^5.0.2",
|
||||
"@astrojs/react": "^5.0.1",
|
||||
"@astrojs/rss": "^4.0.17",
|
||||
"@astrojs/sitemap": "^3.7.1",
|
||||
"@astrojs/svelte": "^8.0.3",
|
||||
"@js-temporal/polyfill": "^0.5.1",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"astro": "^5.16.6",
|
||||
"@tailwindcss/vite": "^4.2.2",
|
||||
"astro": "^6.0.8",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-toc": "^9.0.0",
|
||||
"shiki": "^3.20.0",
|
||||
"shiki": "^4.0.2",
|
||||
"svelte": "^5.46.1",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"tailwindcss": "^4.2.2",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,160 +1,192 @@
|
||||
---
|
||||
import type { JSX } from "astro/jsx-runtime"
|
||||
import type { JSX } from "astro/jsx-runtime";
|
||||
|
||||
type LambdaToken = ['lambda', string, Token[], Token[]]
|
||||
type LambdaToken = ["lambda", string, Token[], Token[]];
|
||||
type Token =
|
||||
| ['comment', string]
|
||||
| ["comment", string]
|
||||
| LambdaToken
|
||||
| ['operator', string]
|
||||
| ['name', string]
|
||||
| ['whitespace', string]
|
||||
| ['placeholder', string]
|
||||
| ['macro', string]
|
||||
| ['keyword', string]
|
||||
| ['string', string]
|
||||
| ['number', string]
|
||||
| ["operator", string]
|
||||
| ["name", string]
|
||||
| ["whitespace", string]
|
||||
| ["placeholder", string]
|
||||
| ["macro", string]
|
||||
| ["keyword", string]
|
||||
| ["string", string]
|
||||
| ["number", string];
|
||||
|
||||
function matchParen(expr: string, greedy = false): string {
|
||||
for (var i = 0, lvl = 0;
|
||||
0 <= lvl && i < expr.length;
|
||||
i++) {
|
||||
if (expr[i] == '(' || expr[i] == '\\') lvl++
|
||||
else if (expr[i] == ')' || expr[i] == '.') lvl--
|
||||
else if (greedy && expr[i] == '\n' && lvl == 0) break
|
||||
for (var i = 0, lvl = 0; 0 <= lvl && i < expr.length; i++) {
|
||||
if (expr[i] == "(" || expr[i] == "\\") lvl++;
|
||||
else if (expr[i] == ")" || expr[i] == ".") lvl--;
|
||||
else if (greedy && expr[i] == "\n" && lvl == 0) break;
|
||||
}
|
||||
return expr.slice(0, i)
|
||||
return expr.slice(0, i);
|
||||
}
|
||||
|
||||
function parseLambda(expr: string): LambdaToken {
|
||||
expr = expr.slice(1) // Get rid of \
|
||||
const nameMatch = /^[\$a-zA-Z0-9_]+\s*/.exec(expr)
|
||||
if (!nameMatch) throw new Error(`Missing name in "${expr}"`)
|
||||
const name = nameMatch[0].trim()
|
||||
const afterName = nameMatch[0].length
|
||||
let type: Token[] = []
|
||||
let afterType = afterName
|
||||
if (expr[afterName] == ':') {
|
||||
const typeStr = matchParen(expr.slice(afterName + 1)).slice(0, -1)
|
||||
type = tokenizeExp(typeStr)
|
||||
afterType += typeStr.length + 1
|
||||
expr = expr.slice(1); // Get rid of \
|
||||
const nameMatch = /^[\$a-zA-Z0-9_]+\s*/.exec(expr);
|
||||
if (!nameMatch) throw new Error(`Missing name in "${expr}"`);
|
||||
const name = nameMatch[0].trim();
|
||||
const afterName = nameMatch[0].length;
|
||||
let type: Token[] = [];
|
||||
let afterType = afterName;
|
||||
if (expr[afterName] == ":") {
|
||||
const typeStr = matchParen(expr.slice(afterName + 1)).slice(0, -1);
|
||||
type = tokenizeExp(typeStr);
|
||||
afterType += typeStr.length + 1;
|
||||
}
|
||||
if (expr[afterType] != '.') throw new Error(`Missing dot in "${expr.slice(afterType)}"`)
|
||||
const body = tokenizeExp(expr.slice(afterType + 1))
|
||||
return ['lambda', name, type, body]
|
||||
if (expr[afterType] != ".")
|
||||
throw new Error(`Missing dot in "${expr.slice(afterType)}"`);
|
||||
const body = tokenizeExp(expr.slice(afterType + 1));
|
||||
return ["lambda", name, type, body];
|
||||
}
|
||||
|
||||
// Problem
|
||||
// \f:\a:a.a.\a:a.a
|
||||
|
||||
function tokenizeExp(expr: string): Token[] {
|
||||
if (expr == '') return []
|
||||
const ws = /^(\s|\n)+/.exec(expr)
|
||||
if (ws) return [['whitespace', ws[0]], ...tokenizeExp(expr.slice(ws[0].length))]
|
||||
const keyword = /^(export|import|default|replacing)\s/.exec(expr)
|
||||
if (keyword) return [['keyword', keyword[0]], ...tokenizeExp(expr.slice(keyword[0].length))]
|
||||
const macro = /^:=|^=\-?([\d\_a-fA-F]+(\.[\d\_a-fA-F]+)?(p\-?[\d_]+)?)?=>/.exec(expr)
|
||||
if (expr == "") return [];
|
||||
const ws = /^(\s|\n)+/.exec(expr);
|
||||
if (ws)
|
||||
return [["whitespace", ws[0]], ...tokenizeExp(expr.slice(ws[0].length))];
|
||||
const keyword = /^(export|import|default|replacing)\s/.exec(expr);
|
||||
if (keyword)
|
||||
return [
|
||||
["keyword", keyword[0]],
|
||||
...tokenizeExp(expr.slice(keyword[0].length)),
|
||||
];
|
||||
const macro =
|
||||
/^:=|^=\-?([\d\_a-fA-F]+(\.[\d\_a-fA-F]+)?(p\-?[\d_]+)?)?=>/.exec(expr);
|
||||
// const macro = /^[:<]=(([\d_]+(\.[\d_]+)?)?=>?)?/.exec(expr)
|
||||
if (macro) return [['macro', macro[0]], ...tokenizeExp(expr.slice(macro[0].length))]
|
||||
const number = /^\d\S*/.exec(expr)
|
||||
if (number) return [['number', number[0]], ...tokenizeExp(expr.slice(number[0].length))]
|
||||
const name = /^[A-Za-z0-9_]+/.exec(expr)
|
||||
if (name) return [['name', name[0]], ...tokenizeExp(expr.slice(name[0].length))]
|
||||
if (macro)
|
||||
return [["macro", macro[0]], ...tokenizeExp(expr.slice(macro[0].length))];
|
||||
const number = /^\d\S*/.exec(expr);
|
||||
if (number)
|
||||
return [
|
||||
["number", number[0]],
|
||||
...tokenizeExp(expr.slice(number[0].length)),
|
||||
];
|
||||
const name = /^[A-Za-z0-9_]+/.exec(expr);
|
||||
if (name)
|
||||
return [["name", name[0]], ...tokenizeExp(expr.slice(name[0].length))];
|
||||
if (expr.startsWith("--[")) {
|
||||
let end = expr.indexOf("]--") + "]--".length;
|
||||
return [
|
||||
['comment', expr.slice(0, end)],
|
||||
...tokenizeExp(expr.slice(end))
|
||||
]
|
||||
return [["comment", expr.slice(0, end)], ...tokenizeExp(expr.slice(end))];
|
||||
}
|
||||
if (expr.startsWith("--")) {
|
||||
let end = expr.indexOf("\n");
|
||||
return [
|
||||
["comment", expr.slice(0, end)],
|
||||
...tokenizeExp(expr.slice(end))
|
||||
]
|
||||
return [["comment", expr.slice(0, end)], ...tokenizeExp(expr.slice(end))];
|
||||
}
|
||||
if (expr.startsWith('\\')) {
|
||||
const lambda = matchParen(expr)
|
||||
return [parseLambda(lambda), ...tokenizeExp(expr.slice(lambda.length))]
|
||||
if (expr.startsWith("\\")) {
|
||||
const lambda = matchParen(expr);
|
||||
return [parseLambda(lambda), ...tokenizeExp(expr.slice(lambda.length))];
|
||||
}
|
||||
if (expr.startsWith('"')) {
|
||||
let i = '"'.length;
|
||||
for (; i <= expr.length; i++) {
|
||||
if (expr[i] == '\\') i++;
|
||||
if (expr[i] == "\\") i++;
|
||||
if (expr[i] == '"') break;
|
||||
}
|
||||
return [
|
||||
["string", expr.slice(0, i + 1)],
|
||||
...tokenizeExp(expr.slice(i+1))
|
||||
]
|
||||
...tokenizeExp(expr.slice(i + 1)),
|
||||
];
|
||||
}
|
||||
const ph = /^\$[a-zA-Z0-9_]+/.exec(expr)
|
||||
if (ph) return [['placeholder', ph[0]], ...tokenizeExp(expr.slice(ph[0].length))]
|
||||
const opChars = /^[^\sa-zA-Z0-9_\$\\]+/.exec(expr)
|
||||
if (opChars) return [['operator', opChars[0]], ...tokenizeExp(expr.slice(opChars[0].length))]
|
||||
throw new Error(`Logic error: none of the regices in a complete cover matched "${expr}"`)
|
||||
const ph = /^\$[a-zA-Z0-9_]+/.exec(expr);
|
||||
if (ph)
|
||||
return [["placeholder", ph[0]], ...tokenizeExp(expr.slice(ph[0].length))];
|
||||
const opChars = /^[^\sa-zA-Z0-9_\$\\]+/.exec(expr);
|
||||
if (opChars)
|
||||
return [
|
||||
["operator", opChars[0]],
|
||||
...tokenizeExp(expr.slice(opChars[0].length)),
|
||||
];
|
||||
throw new Error(
|
||||
`Logic error: none of the regices in a complete cover matched "${expr}"`,
|
||||
);
|
||||
}
|
||||
|
||||
function nameStyle(level: number | undefined): JSX.CSSProperties {
|
||||
return {
|
||||
color: level === undefined
|
||||
color:
|
||||
level === undefined
|
||||
? "hsl(30, 50%, 70%)"
|
||||
: `hsl(
|
||||
calc(170 - ${level} * 5),
|
||||
calc(50% + ${level} * 10%),
|
||||
calc(70% - ${level} * 5%)
|
||||
)`,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
interface Props {
|
||||
text?: string,
|
||||
tokens?: Token[],
|
||||
vlvlv?: Map<string, number>
|
||||
text?: string;
|
||||
tokens?: Token[];
|
||||
vlvlv?: Map<string, number>;
|
||||
}
|
||||
|
||||
let { text, tokens, vlvlv = new Map() }: Props = Astro.props;
|
||||
|
||||
const nextLvl = vlvlv.size + 1
|
||||
const nextLvl = vlvlv.size + 1;
|
||||
|
||||
const outTokens = tokens ? tokens : tokenizeExp(text!.trim());
|
||||
---
|
||||
|
||||
<code style={{
|
||||
whiteSpace: "pre-wrap",
|
||||
<code
|
||||
style={{
|
||||
display: vlvlv.size == 0 ? "inline-block" : "inline",
|
||||
padding: "unset",
|
||||
background: "unset",
|
||||
borderRadius: "unset",
|
||||
border: "unset",
|
||||
whiteSpace: "pre-line",
|
||||
fontFamily: '"Droid Sans Mono", monospace',
|
||||
fontSize: "small",
|
||||
}}>
|
||||
{outTokens.map(([name, value, ...extras], i) => { switch (name) {
|
||||
case 'comment': return <span style={{ color: "#8f8" }}>{value}</span>
|
||||
case 'name': return <span style={nameStyle(vlvlv.get(value))}>{value}</span>
|
||||
case 'operator': return <span style={{ color: "white" }}>{value}</span>
|
||||
case 'whitespace': return <span>{value}</span>
|
||||
case 'placeholder': return <span style={{ color: "#bb5" }}>{value}</span>
|
||||
case 'macro': return <span style={{ color: "#f55" }}>{value}</span>
|
||||
case 'keyword': return <span style={{ color: "#39f" }}>{value}</span>
|
||||
case 'string': return <span style={{ color: "#f8b" }}>{value}</span>
|
||||
case 'number': return <span style={{ color: "#afa" }}>{value}</span>
|
||||
case 'lambda':
|
||||
const sub_vlvlv = new Map(vlvlv)
|
||||
sub_vlvlv.set(value, nextLvl)
|
||||
return <span data-name={value}>
|
||||
<span style={{ color: "#999" }}>\</span>
|
||||
}}
|
||||
>{
|
||||
outTokens.map(([name, value, ...extras], i) => {
|
||||
switch (name) {
|
||||
case "comment":
|
||||
return <span style={{ color: "#8f8" }}>{value}</span>;
|
||||
case "name":
|
||||
return <span style={nameStyle(vlvlv.get(value))}>{value}</span>;
|
||||
case "operator":
|
||||
return <span style={{ color: "white" }}>{value}</span>;
|
||||
case "whitespace":
|
||||
return <span>{value}</span>;
|
||||
case "placeholder":
|
||||
return <span style={{ color: "#bb5" }}>{value}</span>;
|
||||
case "macro":
|
||||
return <span style={{ color: "#f55" }}>{value}</span>;
|
||||
case "keyword":
|
||||
return <span style={{ color: "#39f" }}>{value}</span>;
|
||||
case "string":
|
||||
return <span style={{ color: "#f8b" }}>{value}</span>;
|
||||
case "number":
|
||||
return <span style={{ color: "#afa" }}>{value}</span>;
|
||||
case "lambda":
|
||||
const sub_vlvlv = new Map(vlvlv);
|
||||
sub_vlvlv.set(value, nextLvl);
|
||||
return (
|
||||
<span data-name={value}>
|
||||
<span>\</span>
|
||||
<span style={nameStyle(vlvlv.get(value))}>{value}</span>
|
||||
{extras[0]!.length? <>
|
||||
{extras[0]!.length ? (
|
||||
<>
|
||||
<span style={{ color: "#999" }}>:</span>
|
||||
<span>
|
||||
<Astro.self vlvlv={sub_vlvlv} tokens={extras[0]!} />
|
||||
</span>
|
||||
</> :null}
|
||||
</>
|
||||
) : null}
|
||||
<span style={{ color: "#999" }}>.</span>
|
||||
<span>
|
||||
<Astro.self vlvlv={sub_vlvlv} tokens={extras[1]!} />
|
||||
</span>
|
||||
</span>
|
||||
}})}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
})
|
||||
}</code
|
||||
>
|
||||
|
||||
@@ -7,52 +7,81 @@
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
* {
|
||||
border-color: default;
|
||||
}
|
||||
|
||||
.astro-code {
|
||||
margin: 1ch 0;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
pre, code {
|
||||
|
||||
pre,
|
||||
code {
|
||||
background-color: var(--color-side-bg);
|
||||
padding-left: 1ch;
|
||||
padding-right: 1ch;
|
||||
}
|
||||
|
||||
pre>code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.post-content {
|
||||
a {
|
||||
color: var(--color-link);
|
||||
|
||||
&:visited {
|
||||
color: var(--color-link-visited);
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
padding-block: .5ch;
|
||||
margin-block: .5ch;
|
||||
pre,
|
||||
code {
|
||||
display: inline-block;
|
||||
/* padding-block: .5ch;
|
||||
margin-block: .5ch; */
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 500;
|
||||
|
||||
& i {
|
||||
visibility: hidden;
|
||||
color: #ccc;
|
||||
}
|
||||
&:hover i { visibility: initial; }
|
||||
|
||||
&:hover i {
|
||||
visibility: initial;
|
||||
}
|
||||
h1 { font-size: x-large; }
|
||||
h2 { margin-left: 30px; }
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #fff7;
|
||||
margin-bottom: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
& i.gg-link {
|
||||
@@ -62,16 +91,39 @@
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
#table-of-contents { display: none }
|
||||
ul {
|
||||
list-style: ' - ' outside;
|
||||
margin-bottom: 15px;
|
||||
|
||||
li {
|
||||
margin-left: 2ch;
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal outside;
|
||||
margin-bottom: 15px;
|
||||
|
||||
li {
|
||||
margin-left: 2ch;
|
||||
}
|
||||
}
|
||||
|
||||
#table-of-contents {
|
||||
display: none
|
||||
}
|
||||
|
||||
#table-of-contents+ul {
|
||||
float: right;
|
||||
background-color: var(--color-side-bg);
|
||||
padding: 5px 12px;
|
||||
width: 20ch;
|
||||
margin: 10px;
|
||||
|
||||
ul {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: decimal;
|
||||
list-style-position: inside;
|
||||
@@ -79,6 +131,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@theme {
|
||||
--breakpoint-xs: 25rem;
|
||||
--tw-border-style: solid;
|
||||
@@ -97,17 +150,20 @@
|
||||
background-color: var(--color-emph-bg);
|
||||
border-color: var(--color-emph-bg);
|
||||
}
|
||||
|
||||
.post-meta {
|
||||
color: var(--color-faint-fg);
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
margin-left: 0.3em;
|
||||
}
|
||||
|
||||
.summary {
|
||||
font-style: italic;
|
||||
color: var(---color-emph-fg);
|
||||
letter-spacing: 3px;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user