-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
105 changed files
with
19,729 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
/vendor | ||
/_site | ||
.sass-cache | ||
.jekyll-cache | ||
/tmp | ||
/djot |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#!/usr/bin/env -S deno run --allow-write --allow-read | ||
|
||
/* | ||
TODO: | ||
- tables (pipes, style) | ||
- youtube video | ||
- "`quotes`" | ||
- footnotes (unsafe is a human-assited type system) | ||
- stripes in highligted lines | ||
- emdashes (`\w -- \w`) | ||
- `++` | ||
*/ | ||
|
||
const path = Deno.args[0]; | ||
let s = await Deno.readTextFile(path); | ||
s = s.replace(":page-liquid:\n", ""); | ||
s = s.replaceAll("{cpp}", "C++"); | ||
s = s.replace(/^(=+ )/mg, (m) => { | ||
return "#".repeat(m.length - 1) + " "; | ||
}); | ||
s = s.replace(/(http\S*?)(\[.*?(\n.*?)?\])/mg, (m, link, text) => { | ||
return `${text}(${link})`; | ||
}); | ||
s = s.replace(/^:(\w*?): (.*?)$/mg, (m, ref, link) => { | ||
return `[${ref}]: ${link}`; | ||
}); | ||
s = s.replace(/\{(\w*?)\}\[(.*?)\]/mg, (m, ref, text) => { | ||
return `[${text}][${ref}]`; | ||
}); | ||
s = s.replace(/^\[source\]\n----\n((.|\n)*?)\n----/mg, (m, code) => { | ||
return "```\n" + code + "\n```"; | ||
}); | ||
s = s.replace( | ||
/^\[source,(kotlin|cpp|rust|swift|c|toml|go|console|js|ts|nix)(,highlight=.*?)?\]\n----\n((.|\n)*?)\n----/mg, | ||
(m, lang, hl, code) => { | ||
let highlight = "" | ||
if (hl) { | ||
highlight = hl.substring(",highlight=".length).replaceAll('..', '-').replaceAll(';', ',').replaceAll('"', '') | ||
highlight = `{highlight="${highlight}"}\n`; | ||
} | ||
return highlight + "```" + lang + "\n" + code + "\n```"; | ||
}, | ||
); | ||
s = s.replace( | ||
/^\[source(,highlight=.*?)\]\n----\n((.|\n)*?)\n----/mg, | ||
(m, hl, code) => { | ||
let highlight = "" | ||
if (hl) { | ||
highlight = hl.substring(",highlight=".length).replaceAll('..', '-').replaceAll(';', ',').replaceAll('"', '') | ||
highlight = `{highlight="${highlight}"}\n`; | ||
} | ||
return highlight + "```\n" + code + "\n```"; | ||
}, | ||
); | ||
s = s.replace(/^\.(.*?)$\n```/mg, (m, title) => { | ||
return `{cap="${title}"}` + "\n```"; | ||
}); | ||
s = s.replace(/^image::(.*)\[\]$/mg, (m, path) => { | ||
return `![](${path})`; | ||
}); | ||
s = s.replace(/kbd:\[(.*?)\]/mg, (m, text) => { | ||
return `[${text}]{.kbd}`; | ||
}); | ||
s = s.replace(/(\n\. .*?$(\n\s\s.*?$)*){2,}/mg, (m, text) => { | ||
let i = 0; | ||
return m.replace(/^\. /mg, (m) => { | ||
i += 1; | ||
return `${i}. `; | ||
}); | ||
}); | ||
s = s.replace(/\[(NOTE|Note)\]\n====\n((.|\n)*?)\n====\n/mg, (m, note, content) => { | ||
return `::: note\n${content}\n:::\n` | ||
}) | ||
s = s.replace(/^NOTE: (.*?)$/mg, (m, content) => { | ||
return `::: note\n${content}\n:::\n` | ||
}) | ||
s = s.replace(/^\*\*\*\*\n((.|\n)*?)\n\*\*\*\*\n/mg, (m, content) => { | ||
return `::: snip\n${content}\n:::\n` | ||
}) | ||
s = s.replace(/"`(\w.*?(\w|\?))`"/mg, (m, w) => { | ||
return `"${w}"` | ||
}) | ||
s = s.replace(/^(http(s)?:\/\/.*)$/mg, (m) => { | ||
return `<${m}>` | ||
}) | ||
s = s.replace(/`\+(.*?)\+`/mg, (m, w) => { | ||
return "`" + w + "`" | ||
}) | ||
|
||
await Deno.writeTextFile(path, s); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
#!/usr/bin/env -S deno run --allow-write=./_site,./tmp --allow-read=/tmp,./ --allow-net --allow-run=./main.ts,lua | ||
import { std } from "./deps.ts"; | ||
import * as templates from "./templates.ts"; | ||
import * as djot from "./djot.ts"; | ||
import { HtmlString } from "./templates.ts"; | ||
|
||
let build_id = 0; | ||
async function watch() { | ||
async function rebuild() { | ||
try { | ||
console.log(`rebuild #${build_id}`); | ||
build_id += 1; | ||
await Deno.run({ cmd: ["./main.ts", "build", "--update"] }).status(); | ||
} catch { | ||
// ignore | ||
} | ||
} | ||
|
||
await std.fs.emptyDir("./_site"); | ||
await rebuild(); | ||
|
||
const rebuild_debounced = std.async.debounce( | ||
rebuild, | ||
16, | ||
); | ||
|
||
outer: | ||
for await (const event of Deno.watchFs("./", { recursive: true })) { | ||
for (const path of event.paths) { | ||
if (path.match(/\.\/(tmp|_site)/)) { | ||
continue outer; | ||
} | ||
} | ||
if (event.kind == "access") continue outer; | ||
rebuild_debounced(); | ||
} | ||
} | ||
|
||
async function build() { | ||
const start = performance.now(); | ||
|
||
if (Deno.args.includes("--update")) { | ||
await Deno.mkdir("_site", { recursive: true }); | ||
} else { | ||
await std.fs.emptyDir("./_site"); | ||
} | ||
|
||
const posts = await collect_posts(); | ||
|
||
await update_file("_site/index.html", templates.post_list(posts).value); | ||
await update_file("_site/feed.xml", templates.feed(posts).value); | ||
await update_file("_site/about.html", templates.about().value); | ||
for (const post of posts) { | ||
await update_file(`_site${post.path}`, templates.post(post).value); | ||
} | ||
|
||
const paths = [ | ||
"favicon.ico", | ||
"css/*", | ||
"assets/*", | ||
]; | ||
for (const path of paths) { | ||
await update_path(path); | ||
} | ||
|
||
const end = performance.now(); | ||
console.log(`${end - start}ms`); | ||
} | ||
|
||
async function update_file(path: string, contents: Uint8Array | string) { | ||
if (!contents) return; | ||
await std.fs.ensureFile(path); | ||
await std.fs.ensureDir("./tmp"); | ||
const temp = await Deno.makeTempFile({ dir: "./tmp" }); | ||
if (contents instanceof Uint8Array) { | ||
await Deno.writeFile(temp, contents); | ||
} else { | ||
await Deno.writeTextFile(temp, contents); | ||
} | ||
await Deno.rename(temp, path); | ||
} | ||
|
||
async function update_path(path: string) { | ||
if (path.endsWith("*")) { | ||
const dir = path.replace("*", ""); | ||
const futs = []; | ||
for await (const entry of Deno.readDir(`src/${dir}`)) { | ||
futs.push(update_path(`${dir}/${entry.name}`)); | ||
} | ||
await Promise.all(futs); | ||
} else { | ||
await update_file( | ||
`_site/${path}`, | ||
await Deno.readFile(`src/${path}`), | ||
); | ||
} | ||
} | ||
|
||
export type Post = { | ||
year: number; | ||
month: number; | ||
day: number; | ||
slug: string; | ||
date: Date; | ||
title: HtmlString; | ||
path: string; | ||
src: string; | ||
content: HtmlString; | ||
summary: HtmlString; | ||
}; | ||
|
||
async function collect_posts(): Promise<Post[]> { | ||
const post_walk = std.fs.walk("./src/posts", { includeDirs: false }); | ||
const work = std.async.pooledMap(8, post_walk, async (entry) => { | ||
if (!entry.name.endsWith(".djot")) return undefined; | ||
const [, y, m, d, slug] = entry.name.match( | ||
/^(\d\d\d\d)-(\d\d)-(\d\d)-(.*)\.djot$/, | ||
)!; | ||
const [year, month, day] = [y, m, d].map((it) => parseInt(it, 10)); | ||
const date = new Date(Date.UTC(year, month - 1, day)); | ||
|
||
const text = await Deno.readTextFile(entry.path); | ||
const ast = await djot.parse(text); | ||
const ctx = { date }; | ||
const html = djot.render(ast, ctx); | ||
|
||
const title = ast.child("heading")?.content ?? "untitled"; | ||
return { | ||
year, | ||
month, | ||
day, | ||
slug, | ||
date, | ||
title, | ||
content: html, | ||
summary: ctx.summary, | ||
path: `/${y}/${m}/${d}/${slug}.html`, | ||
src: `/src/posts/${y}-${m}-${d}-${slug}.djot`, | ||
}; | ||
}); | ||
|
||
const posts = []; | ||
for await (const it of work) if (it) posts.push(it); | ||
posts.sort((l, r) => l.path < r.path ? 1 : -1); | ||
return posts; | ||
} | ||
|
||
export const commands: { [key: string]: () => Promise<void> } = { | ||
watch, | ||
build, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as async from "https://deno.land/[email protected]/async/mod.ts"; | ||
import * as fs from "https://deno.land/[email protected]/fs/mod.ts"; | ||
import * as path from "https://deno.land/[email protected]/path/mod.ts"; | ||
import * as streams from "https://deno.land/[email protected]/streams/mod.ts"; | ||
|
||
export const std = { | ||
async, | ||
fs, | ||
path, | ||
streams, | ||
}; | ||
|
||
import hljs_ from "https://unpkg.com/@highlightjs/[email protected]/es/highlight.min.js"; | ||
import latex from "https://unpkg.com/@highlightjs/[email protected]/es/languages/latex.min.js"; | ||
import nix from "https://unpkg.com/@highlightjs/[email protected]/es/languages/nix.min.js"; | ||
import x86asm from "https://unpkg.com/@highlightjs/[email protected]/es/languages/x86asm.min.js"; | ||
let hljs: any = hljs_ | ||
hljs.configure({ classPrefix: "hl-" }); | ||
hljs.registerLanguage("latex", latex); | ||
hljs.registerLanguage("nix", nix); | ||
hljs.registerLanguage("x86asm", x86asm); | ||
|
||
export { hljs }; |
Oops, something went wrong.