Skip to content

Commit e37fbb8

Browse files
committed
playground: ship uutils sed
Add uutils/sed to the playground alongside grep, find and diff/cmp. sed builds a single `sed` binary and, like diffutils, has only pure-Rust dependencies (fancy-regex and regex, not onig), so its WASM build needs no WASI SDK — it joins the wasm-standalone matrix with needs_wasi: false. Register sed as its own on-demand standalone module (sed -> sed.wasm), add it to the fallback command list, the help/load hints, a substitution example, the version footer, and tests (stdin substitution, global substitution over a file, and -n line selection).
1 parent e48b463 commit e37fbb8

4 files changed

Lines changed: 55 additions & 9 deletions

File tree

.github/workflows/website.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ jobs:
118118
name: wasm-coreutils
119119
path: wasm-out
120120

121-
# grep, find and diffutils each ship a single standalone binary built the
121+
# grep, find, diffutils and sed each ship a single standalone binary built the
122122
# same way, so they share one matrix job. grep/find pull in the Oniguruma C
123123
# library (onig_sys) and need a WASI sysroot to compile its bundled C sources;
124-
# diffutils is pure Rust and sets needs_wasi: false. The `order` field keeps
125-
# the merged command/version lists in a stable sequence in the `build` job.
124+
# diffutils and sed are pure Rust and set needs_wasi: false. The `order` field
125+
# keeps the merged command/version lists in a stable sequence in `build`.
126126
wasm-standalone:
127127
name: Build ${{ matrix.name }} WASM
128128
runs-on: ubuntu-latest
@@ -151,6 +151,13 @@ jobs:
151151
commands: '"diff","cmp"'
152152
version_const: UUTILS_DIFFUTILS_VERSION
153153
order: 30
154+
- name: sed
155+
repo: uutils/sed
156+
bin: sed
157+
needs_wasi: false
158+
commands: '"sed"'
159+
version_const: UUTILS_SED_VERSION
160+
order: 40
154161
steps:
155162
- name: Checkout ${{ matrix.name }} Repository
156163
uses: actions/checkout@v7

content/playground.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ template = "page.html"
119119
parts.push('diffutils <a href="' + diffUrl + '"><code>' +
120120
UUTILS_DIFFUTILS_VERSION.short + '</code></a> (' + diffDate + ')');
121121
}
122+
if (typeof UUTILS_SED_VERSION !== "undefined") {
123+
var sedDate = UUTILS_SED_VERSION.date.split("T")[0];
124+
var sedUrl = "https://github.com/uutils/sed/commit/" + UUTILS_SED_VERSION.commit;
125+
parts.push('sed <a href="' + sedUrl + '"><code>' +
126+
UUTILS_SED_VERSION.short + '</code></a> (' + sedDate + ')');
127+
}
122128
if (typeof SITE_VERSION !== "undefined") {
123129
var siteDate = SITE_VERSION.date.split("T")[0];
124130
var siteUrl = "https://github.com/uutils/uutils.github.io/commit/" + SITE_VERSION.commit;
@@ -155,6 +161,7 @@ Click an example to run it in the terminal:
155161
<button class="playground-example">printf '🍎 apple\n🍌 banana\n🍒 cherry\n🥝 kiwi\n' | grep 🍌</button>
156162
<button class="playground-example">find . -name '*.md'</button>
157163
<button class="playground-example">diff -u shopping-old.txt shopping-new.txt</button>
164+
<button class="playground-example">sed -e 's/banana/🍌/g' -e 's/date/🌴/g' fruits.txt</button>
158165
<button class="playground-example">sort -n < numbers.txt | head -3</button>
159166
<button class="playground-example">date</button>
160167
<button class="playground-example">uname -a</button>

static/js/wasm-terminal.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ if (typeof SharedArrayBuffer === "undefined") {
1616
const WASM_URL = "/wasm/uutils.wasm";
1717
// Some utilities ship as their own standalone WASM modules rather than as part
1818
// of the coreutils multicall binary (grep lives in uutils/grep, find in
19-
// uutils/findutils, diff and cmp in uutils/diffutils). Each module is loaded on
20-
// demand and is optional — see loadStandalone. A single module can provide
21-
// several commands (diffutils → diff, cmp), which the diffutils binary
22-
// dispatches on argv[0], so each command is invoked directly by its own name.
19+
// uutils/findutils, diff and cmp in uutils/diffutils, sed in uutils/sed). Each
20+
// module is loaded on demand and is optional — see loadStandalone. A single
21+
// module can provide several commands (diffutils → diff, cmp), which the
22+
// diffutils binary dispatches on argv[0], so each command is invoked directly
23+
// by its own name.
2324
const STANDALONE_MODULES = {
2425
grep: { url: "/wasm/grep.wasm", commands: ["grep"] },
2526
find: { url: "/wasm/find.wasm", commands: ["find"] },
2627
diffutils: { url: "/wasm/diffutils.wasm", commands: ["diff", "cmp"] },
28+
sed: { url: "/wasm/sed.wasm", commands: ["sed"] },
2729
};
2830
// Map each command to the module that provides it (e.g. diff -> "diffutils").
2931
const STANDALONE_COMMAND_MODULE = Object.fromEntries(
@@ -73,7 +75,7 @@ const FALLBACK_COMMANDS = [
7375
"sha1sum", "sha224sum", "sha256sum", "sha384sum", "sha512sum",
7476
"shred", "shuf", "sleep", "sum", "tee", "true", "truncate",
7577
"uname", "unexpand", "uniq", "unlink", "vdir", "wc",
76-
"grep", "find", "diff", "cmp",
78+
"grep", "find", "diff", "cmp", "sed",
7779
];
7880
const AVAILABLE_COMMANDS =
7981
(typeof WASM_COMMANDS !== "undefined" && Array.isArray(WASM_COMMANDS) && WASM_COMMANDS.length > 0)
@@ -550,6 +552,7 @@ async function executeCommandLine(line) {
550552
" grep -i alice names.txt\n" +
551553
" find . -name '*.md'\n" +
552554
" diff -u shopping-old.txt shopping-new.txt\n" +
555+
" echo 'hello world' | sed 's/world/there/'\n" +
553556
" basename /usr/local/bin/rustc\n" +
554557
" date\n" +
555558
" uname -a\n"
@@ -932,7 +935,7 @@ async function initPlayground(containerId) {
932935
terminal.writeln("");
933936
terminal.writeln("Type \x1b[1;32mhelp\x1b[0m for available commands.");
934937
terminal.writeln("Sample data files: names.txt, numbers.txt, fruits.txt, csv.txt, words.txt");
935-
terminal.writeln("\x1b[2mgrep, find and diff/cmp load on demand — just run them, or use the buttons below.\x1b[0m");
938+
terminal.writeln("\x1b[2mgrep, find, sed and diff/cmp load on demand — just run them, or use the buttons below.\x1b[0m");
936939
} catch (e) {
937940
terminal.writeln(" \x1b[1;31mfailed\x1b[0m");
938941
terminal.writeln("Failed to load WASM binary. Commands are not available.");
@@ -1017,6 +1020,7 @@ window._uutilsTestInternals = {
10171020
get grepReady() { return !!standaloneModules.grep; },
10181021
get findReady() { return !!standaloneModules.find; },
10191022
get diffutilsReady() { return !!standaloneModules.diffutils; },
1023+
get sedReady() { return !!standaloneModules.sed; },
10201024
initWasm,
10211025
loadStandalone,
10221026
LOCALE_SHORTCUTS,

static/js/wasm-terminal.test.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,34 @@ <h1>wasm-terminal unit tests</h1>
549549
section("diffutils WASM module (SKIPPED - diffutils.wasm not loaded)");
550550
}
551551

552+
// ===== sed (standalone WASM module, loaded on demand) =====
553+
// sed ships as its own module (uutils/sed). Pre-load it via the on-demand
554+
// loader. Skips gracefully if sed.wasm is absent.
555+
await T.loadStandalone("sed");
556+
if (T.sedReady) {
557+
section("sed WASM module");
558+
559+
assert("sed in AVAILABLE_COMMANDS",
560+
AVAILABLE_COMMANDS.includes("sed"), true);
561+
562+
// Basic substitution on stdin.
563+
await assertAsync("sed substitutes on stdin",
564+
executeCommandLine("echo 'hello world' | sed 's/world/there/'"),
565+
"hello there\n");
566+
567+
// Global substitution over a sample file.
568+
await assertAsync("sed -e global substitution on a file",
569+
executeCommandLine("sed 's/banana/kiwi/g' fruits.txt"),
570+
"kiwi\napple\ncherry\ndate\napple\nkiwi\ncherry\napple\n");
571+
572+
// Line selection with -n / p.
573+
await assertAsync("sed -n prints only the selected line",
574+
executeCommandLine("sed -n '2p' numbers.txt"),
575+
"7\n");
576+
} else {
577+
section("sed WASM module (SKIPPED - sed.wasm not loaded)");
578+
}
579+
552580
} else {
553581
section("l10n WASM integration (SKIPPED - WASM not loaded)");
554582
}

0 commit comments

Comments
 (0)