Skip to content

Commit 925eb8f

Browse files
committed
frontend: add html/js logic of pandoc playground
1 parent ca0b0d3 commit 925eb8f

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

.github/workflows/build.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ jobs:
3535
~/.ghc-wasm/add_to_github_path.sh
3636
popd
3737
38+
- name: checkout
39+
uses: actions/checkout@v4
40+
3841
- name: checkout
3942
uses: actions/checkout@v4
4043
with:
@@ -57,10 +60,11 @@ jobs:
5760
wasm32-wasi-cabal build pandoc-cli
5861
popd
5962
60-
- name: wasm-opt
63+
- name: dist
6164
run: |
6265
mkdir dist
6366
wasm-opt --low-memory-unused --converge --gufa --flatten --rereloop -Oz $(find pandoc -type f -name pandoc.wasm) -o dist/pandoc.wasm
67+
cp frontend/*.html frontend/*.js dist
6468
6569
- name: test
6670
run: |

frontend/index.html

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>pandoc-wasm playground</title>
7+
<style>
8+
body {
9+
display: flex;
10+
flex-direction: column;
11+
height: 100vh;
12+
margin: 0;
13+
font-family: monospace;
14+
}
15+
16+
#container {
17+
display: flex;
18+
flex: 1;
19+
overflow: hidden;
20+
}
21+
22+
textarea {
23+
width: 50%;
24+
height: 100%;
25+
border: none;
26+
padding: 1rem;
27+
resize: none;
28+
box-sizing: border-box;
29+
font-size: 1rem;
30+
font-family: monospace;
31+
}
32+
33+
#input {
34+
border-right: 1px solid #ccc;
35+
}
36+
37+
#output {
38+
background-color: #f5f5f5;
39+
color: #333;
40+
}
41+
42+
#arguments-container {
43+
padding: 0.5rem;
44+
border-top: 1px solid #ccc;
45+
background-color: #f9f9f9;
46+
}
47+
48+
#arguments {
49+
width: calc(100% - 1rem);
50+
padding: 0.5rem;
51+
font-size: 1rem;
52+
box-sizing: border-box;
53+
font-family: monospace;
54+
}
55+
</style>
56+
</head>
57+
<body>
58+
<div id="container">
59+
<textarea id="input" placeholder="Enter your input here..."></textarea>
60+
<textarea
61+
id="output"
62+
readonly
63+
placeholder="Output will be displayed here..."
64+
></textarea>
65+
</div>
66+
<div id="arguments-container">
67+
<input type="text" id="arguments" value="-f markdown -t rst" />
68+
</div>
69+
<script type="module">
70+
import { run_pandoc } from "./index.js";
71+
72+
async function updateOutput() {
73+
const inputText = document.getElementById("input").value;
74+
const argumentsText = document
75+
.getElementById("arguments")
76+
.value.trim()
77+
.split(" ");
78+
try {
79+
const output = await run_pandoc(argumentsText, inputText);
80+
document.getElementById("output").value = output;
81+
} catch (err) {
82+
document.getElementById("output").value = `Error: ${err.message}`;
83+
}
84+
}
85+
86+
document.getElementById("input").addEventListener("input", updateOutput);
87+
document
88+
.getElementById("arguments")
89+
.addEventListener("input", updateOutput);
90+
</script>
91+
</body>
92+
</html>

frontend/index.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {
2+
WASI,
3+
OpenFile,
4+
File,
5+
ConsoleStdout,
6+
} from "https://cdn.jsdelivr.net/npm/@bjorn3/[email protected]/dist/index.js";
7+
8+
const mod = await WebAssembly.compileStreaming(fetch("./pandoc.wasm"));
9+
10+
const instance_promise_pool_size = 8;
11+
12+
const instance_promise_pool = [];
13+
14+
function instance_promise_pool_fill() {
15+
if (instance_promise_pool.length < instance_promise_pool_size) {
16+
for (
17+
let i = instance_promise_pool.length;
18+
i < instance_promise_pool_size;
19+
++i
20+
) {
21+
const args = [];
22+
const env = [];
23+
const stdin_file = new File(new Uint8Array(), { readonly: true });
24+
const stdout_file = new File(new Uint8Array(), { readonly: false });
25+
const fds = [
26+
new OpenFile(stdin_file),
27+
new OpenFile(stdout_file),
28+
ConsoleStdout.lineBuffered((msg) =>
29+
console.warn(`[WASI stderr] ${msg}`)
30+
),
31+
];
32+
const options = { debug: false };
33+
const wasi = new WASI(args, env, fds, options);
34+
instance_promise_pool.push(
35+
WebAssembly.instantiate(mod, {
36+
wasi_snapshot_preview1: wasi.wasiImport,
37+
}).then((instance) => ({ instance, wasi, stdin_file, stdout_file }))
38+
);
39+
}
40+
}
41+
}
42+
43+
instance_promise_pool_fill();
44+
45+
const instances = (async function* () {
46+
while (true) {
47+
yield await instance_promise_pool.shift();
48+
instance_promise_pool_fill();
49+
}
50+
})();
51+
52+
export async function run_pandoc(args, stdin_str) {
53+
const { instance, wasi, stdin_file, stdout_file } = (await instances.next())
54+
.value;
55+
wasi.args = ["pandoc.wasm", ...args];
56+
stdin_file.data = new TextEncoder().encode(stdin_str);
57+
const ec = wasi.start(instance);
58+
if (ec !== 0) {
59+
throw new Error(`Non-zero exit code ${ec}`);
60+
}
61+
return new TextDecoder("utf-8", { fatal: true }).decode(stdout_file.data);
62+
}

0 commit comments

Comments
 (0)